Merge remote-tracking branch 'origin/main' into codex/p0-obs-001-20260714
This commit is contained in:
@@ -648,7 +648,7 @@ try {
|
||||
$expectedTransportPayloadMode = if ($mode -eq "apply") {
|
||||
"ephemeral_file_delete_before_receiver"
|
||||
} else {
|
||||
"stdin_sentinel"
|
||||
"control_command_no_stdin"
|
||||
}
|
||||
if ($transportPayloadMode -ne $expectedTransportPayloadMode) { throw "invalid_transport_payload_mode" }
|
||||
if ($transportPayloadContainsSecrets) { throw "transport_payload_secret_contract_failed" }
|
||||
|
||||
@@ -263,7 +263,7 @@ envelope = {
|
||||
"transportPayloadMode": (
|
||||
"ephemeral_file_delete_before_receiver"
|
||||
if mode == "apply"
|
||||
else "stdin_sentinel"
|
||||
else "control_command_no_stdin"
|
||||
),
|
||||
"transportPayloadContainsSecrets": False,
|
||||
"mode": mode,
|
||||
@@ -405,45 +405,132 @@ if [[ -n "${IDENTITY_FILE}" ]]; then
|
||||
SCP_OPTIONS+=( -i "${IDENTITY_FILE}" )
|
||||
fi
|
||||
|
||||
readonly REMOTE_COMMAND="$(python3 - <<'PY'
|
||||
readonly REMOTE_CHECK_COMMAND="$(python3 - "${ENVELOPE_PATH}" <<'PY'
|
||||
from __future__ import annotations
|
||||
|
||||
import base64
|
||||
import hashlib
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
decoder = r'''$sentinel = "__AWOOOI_AGENT99_REMOTE_BOOTSTRAP_END_V1__"
|
||||
$lines = New-Object System.Collections.Generic.List[string]
|
||||
$lineCount = 0
|
||||
$charCount = 0
|
||||
$terminated = $false
|
||||
while (($line = [Console]::In.ReadLine()) -ne $null) {
|
||||
if ($line -ceq $sentinel) {
|
||||
$terminated = $true
|
||||
break
|
||||
envelope = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))
|
||||
source_revision = envelope["sourceRevision"]
|
||||
manifest_sha256 = envelope["manifestSha256"]
|
||||
fixed_names = [row["name"] for row in envelope["files"]]
|
||||
fixed_rows = ",\n ".join("'" + name.replace("'", "''") + "'" for name in fixed_names)
|
||||
stage_identity = f"check||||{source_revision}"
|
||||
stage_token = hashlib.sha256(stage_identity.encode("utf-8")).hexdigest()[:20]
|
||||
script = r'''$ErrorActionPreference = "Stop"
|
||||
$agentRoot = "C:\Wooo\Agent99"
|
||||
$binDir = Join-Path $agentRoot "bin"
|
||||
$manifestPath = Join-Path $agentRoot "state\runtime-manifest.json"
|
||||
$fixedFiles = @(
|
||||
__FIXED_ROWS__
|
||||
)
|
||||
$current = [pscustomobject]@{
|
||||
exists = $false
|
||||
sourceRevision = ""
|
||||
runtimeMatched = $false
|
||||
recordedRuntimeMatched = $false
|
||||
fileCount = 0
|
||||
mismatchCount = -1
|
||||
recordedMismatchCount = -1
|
||||
parseError = ""
|
||||
}
|
||||
if (Test-Path -LiteralPath $manifestPath -PathType Leaf) {
|
||||
try {
|
||||
$manifest = Get-Content -LiteralPath $manifestPath -Raw | ConvertFrom-Json
|
||||
$rows = @($manifest.files)
|
||||
$byName = @{}
|
||||
$shapeValid = [bool]($rows.Count -eq $fixedFiles.Count)
|
||||
foreach ($row in $rows) {
|
||||
$name = [string]$row.name
|
||||
if (-not $name -or $byName.ContainsKey($name)) {
|
||||
$shapeValid = $false
|
||||
continue
|
||||
}
|
||||
$byName[$name] = $row
|
||||
}
|
||||
$actualMismatchCount = 0
|
||||
foreach ($name in $fixedFiles) {
|
||||
if (-not $byName.ContainsKey($name)) {
|
||||
$shapeValid = $false
|
||||
$actualMismatchCount += 1
|
||||
continue
|
||||
}
|
||||
$recordedSha = ([string]$byName[$name].runtimeSha256).ToLowerInvariant()
|
||||
$runtimePath = Join-Path $binDir $name
|
||||
$actualSha = if (Test-Path -LiteralPath $runtimePath -PathType Leaf) {
|
||||
(Get-FileHash -LiteralPath $runtimePath -Algorithm SHA256).Hash.ToLowerInvariant()
|
||||
} else {
|
||||
"missing"
|
||||
}
|
||||
if (-not $recordedSha -or $recordedSha -ne $actualSha) {
|
||||
$actualMismatchCount += 1
|
||||
}
|
||||
}
|
||||
$runtimeMatched = [bool](
|
||||
$shapeValid -and
|
||||
[bool]$manifest.runtimeMatched -and
|
||||
[int]$manifest.fileCount -eq $fixedFiles.Count -and
|
||||
[int]$manifest.mismatchCount -eq 0 -and
|
||||
$actualMismatchCount -eq 0
|
||||
)
|
||||
$current = [pscustomobject]@{
|
||||
exists = $true
|
||||
sourceRevision = [string]$manifest.sourceRevision
|
||||
runtimeMatched = $runtimeMatched
|
||||
recordedRuntimeMatched = [bool]$manifest.runtimeMatched
|
||||
fileCount = [int]$manifest.fileCount
|
||||
mismatchCount = $actualMismatchCount
|
||||
recordedMismatchCount = [int]$manifest.mismatchCount
|
||||
parseError = ""
|
||||
}
|
||||
} catch {
|
||||
$current.exists = $true
|
||||
$current.parseError = $_.Exception.GetType().Name
|
||||
}
|
||||
$lineCount += 1
|
||||
$charCount += $line.Length + 2
|
||||
if ($lineCount -gt 8 -or $charCount -gt 1048576) {
|
||||
throw "remote_bootstrap_input_limit_exceeded"
|
||||
}
|
||||
[pscustomobject]@{
|
||||
schemaVersion = "agent99_remote_atomic_deploy_receipt_v1"
|
||||
status = "check_ready"
|
||||
mode = "check"
|
||||
sourceRevision = "__SOURCE_REVISION__"
|
||||
expectedRuntimeFileCount = 14
|
||||
manifestSha256 = "__MANIFEST_SHA256__"
|
||||
plannedStagingPath = "C:\Wooo\Agent99\deploy\remote-source-__STAGE_TOKEN__"
|
||||
runtimeManifest = $current
|
||||
livePreflight = [pscustomobject]@{ executed = $false; reason = "apply_only_after_validate_only" }
|
||||
transportPayloadMode = "control_command_no_stdin"
|
||||
transientTransportPayloadStored = $false
|
||||
transientTransportPayloadDeletedBeforeReceiver = $false
|
||||
transportPayloadContainsSecrets = $false
|
||||
operationBoundaries = [pscustomobject]@{
|
||||
remoteWritePerformed = $false
|
||||
liveRuntimeWritePerformed = $false
|
||||
livePromotionAttempted = $false
|
||||
livePromotionPerformed = $false
|
||||
secretValueRead = $false
|
||||
privateKeyValueRead = $false
|
||||
tokenValueRead = $false
|
||||
environmentSecretRead = $false
|
||||
uiInteraction = $false
|
||||
vmPowerChange = $false
|
||||
hostReboot = $false
|
||||
serviceRestart = $false
|
||||
scheduledTaskRestart = $false
|
||||
scheduledTaskModification = $false
|
||||
}
|
||||
[void]$lines.Add($line)
|
||||
}
|
||||
if (-not $terminated) {
|
||||
throw "remote_bootstrap_sentinel_missing"
|
||||
}
|
||||
$payload = [string]::Join("", $lines)
|
||||
$compressed = [Convert]::FromBase64String(($payload -replace '\s', ''))
|
||||
$inputStream = New-Object IO.MemoryStream(,$compressed)
|
||||
$gzip = New-Object IO.Compression.GzipStream($inputStream, [IO.Compression.CompressionMode]::Decompress)
|
||||
$reader = New-Object IO.StreamReader($gzip, [Text.Encoding]::UTF8)
|
||||
try {
|
||||
$inputText = $reader.ReadToEnd()
|
||||
} finally {
|
||||
$reader.Dispose()
|
||||
$gzip.Dispose()
|
||||
$inputStream.Dispose()
|
||||
}
|
||||
& ([ScriptBlock]::Create($inputText))'''
|
||||
encoded = base64.b64encode(decoder.encode("utf-16le")).decode("ascii")
|
||||
nextSafeAction = "rerun_with_apply_and_trace_run_work_item_after_source_commit_and_transport_check"
|
||||
} | ConvertTo-Json -Compress -Depth 8'''
|
||||
script = (
|
||||
script.replace("__FIXED_ROWS__", fixed_rows)
|
||||
.replace("__SOURCE_REVISION__", source_revision)
|
||||
.replace("__MANIFEST_SHA256__", manifest_sha256)
|
||||
.replace("__STAGE_TOKEN__", stage_token)
|
||||
)
|
||||
encoded = base64.b64encode(script.encode("utf-16le")).decode("ascii")
|
||||
print(
|
||||
"powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass "
|
||||
f"-EncodedCommand {encoded}"
|
||||
@@ -569,7 +656,7 @@ cleanup_remote_payload() {
|
||||
if [[ "${MODE}" == "check" ]]; then
|
||||
set +e
|
||||
timeout --signal=TERM --kill-after=10 "${REMOTE_EXECUTION_TIMEOUT_SECONDS}s" \
|
||||
ssh "${SSH_OPTIONS[@]}" "${TARGET}" "${REMOTE_COMMAND}" <"${BOOTSTRAP_PAYLOAD_PATH}"
|
||||
ssh "${SSH_OPTIONS[@]}" "${TARGET}" "${REMOTE_CHECK_COMMAND}" </dev/null
|
||||
status=$?
|
||||
set -e
|
||||
exit "${status}"
|
||||
|
||||
@@ -155,16 +155,19 @@ def test_sender_builds_sha256_envelope_and_streams_it_without_remote_cli_data()
|
||||
assert "[Console]::In.ReadToEnd()" not in source
|
||||
assert "$reader.ReadToEnd()" in source
|
||||
assert "__AWOOOI_AGENT99_REMOTE_BOOTSTRAP_END_V1__" in source
|
||||
assert "[Console]::In.ReadLine()" in source
|
||||
assert "[Console]::In.ReadLine()" not in source
|
||||
assert "[IO.File]::ReadAllLines" in source
|
||||
assert '"control_command_no_stdin"' in source
|
||||
assert "REMOTE_CHECK_COMMAND" in source
|
||||
assert "remote_bootstrap_input_limit_exceeded" in source
|
||||
assert "remote_bootstrap_sentinel_missing" in source
|
||||
assert "line_width = 65536" in source
|
||||
assert "len(payload_lines) > 8" in source
|
||||
assert '"\\n".join(payload_lines)' in source
|
||||
assert "remote_bootstrap_payload_line_contract_failed" in source
|
||||
assert "$lineCount -gt 8" in source
|
||||
assert "$payloadLines.Count -gt 8" in source
|
||||
assert "$charCount -gt 1048576" in source
|
||||
assert '<"${BOOTSTRAP_PAYLOAD_PATH}"' in source
|
||||
assert '<"${BOOTSTRAP_PAYLOAD_PATH}"' not in source
|
||||
assert "rawEnvelope" not in source
|
||||
assert "sshpass" not in source
|
||||
|
||||
@@ -580,7 +583,7 @@ def test_apply_without_all_three_identities_fails_before_ssh() -> None:
|
||||
assert "known_hosts_file_missing" not in result.stderr
|
||||
|
||||
|
||||
def test_check_mode_builds_and_streams_bundle_over_bounded_fake_transport(
|
||||
def test_check_mode_uses_bounded_control_command_without_ssh_stdin(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
fake_bin = tmp_path / "bin"
|
||||
@@ -660,8 +663,8 @@ def test_check_mode_builds_and_streams_bundle_over_bounded_fake_transport(
|
||||
assert "PasswordAuthentication=no" in args
|
||||
assert "Administrator@192.168.0.99" in args
|
||||
assert str(identity) in args
|
||||
payload_bytes = int(bytes_path.read_text(encoding="utf-8"))
|
||||
assert 50_000 < payload_bytes < 1_048_576
|
||||
stdin_bytes = int(bytes_path.read_text(encoding="utf-8"))
|
||||
assert stdin_bytes == 0
|
||||
|
||||
|
||||
def test_apply_uses_ephemeral_file_transport_and_cleans_up_without_ssh_stdin(
|
||||
|
||||
Reference in New Issue
Block a user