fix(agent99): verify legacy Telegram sender quarantine

This commit is contained in:
Your Name
2026-07-19 11:35:18 +08:00
parent 5382ce348f
commit ae7dab8e05
4 changed files with 488 additions and 4 deletions

View File

@@ -17,11 +17,17 @@ $ProgressPreference = "SilentlyContinue"
$LegacyTaskName = "Wooo-Agent99-Host188-Performance-Guard"
$ReplacementTaskName = "Wooo-Agent99-Performance-Guard"
$ExpectedLegacyActionSha256 = "a2f98560673ebed5aa1f828b4e577c8a34d1c277b2e498044c3526a4ffe15379"
$ExpectedPowerShellExecutable = Join-Path $env:SystemRoot "System32\WindowsPowerShell\v1.0\powershell.exe"
$ExpectedReplacementLauncher = Join-Path $AgentRoot "agent99-run.ps1"
$ExpectedReplacementArguments = "-NoProfile -ExecutionPolicy Bypass -File `"$ExpectedReplacementLauncher`" -Mode Perf -ControlledApply"
$EvidenceRoot = Join-Path $AgentRoot "evidence\controlled-task-quarantine"
$ReceiptPath = Join-Path $EvidenceRoot "$RunId.json"
$RollbackPath = Join-Path $EvidenceRoot "$RunId.rollback.xml"
$TemporaryReceiptPath = "$ReceiptPath.tmp"
$SafeIdentityPattern = "^[A-Za-z0-9](?:[A-Za-z0-9_.:-]{0,158}[A-Za-z0-9])?$"
$ExecutorSourceSha256 = (Get-FileHash `
-LiteralPath $MyInvocation.MyCommand.Path `
-Algorithm SHA256).Hash.ToLowerInvariant()
function Get-ActionArgumentSha256 {
param([Parameter(Mandatory = $true)][object]$Action)
@@ -42,6 +48,15 @@ function Get-ControlledTaskState {
$replacementActions = @($replacement.Actions)
if ($legacyActions.Count -ne 1) { throw "legacy_task_action_count_mismatch" }
if (-not [StringComparer]::OrdinalIgnoreCase.Equals(
[string]$legacyActions[0].Execute,
[string]$ExpectedPowerShellExecutable
)) {
throw "legacy_task_executable_identity_mismatch"
}
if (([string]$legacyActions[0].WorkingDirectory).Length -ne 0) {
throw "legacy_task_working_directory_identity_mismatch"
}
if ((Get-ActionArgumentSha256 $legacyActions[0]) -ne $ExpectedLegacyActionSha256) {
throw "legacy_task_action_identity_mismatch"
}
@@ -50,8 +65,18 @@ function Get-ControlledTaskState {
throw "canonical_replacement_not_ready"
}
$replacementArguments = [string]$replacementActions[0].Arguments
if ($replacementArguments -notmatch "agent99-run\.ps1.+-Mode\s+Perf") {
$replacementAction = $replacementActions[0]
$replacementArguments = [string]$replacementAction.Arguments
if (-not [StringComparer]::OrdinalIgnoreCase.Equals(
[string]$replacementAction.Execute,
[string]$ExpectedPowerShellExecutable
)) {
throw "canonical_replacement_executable_identity_mismatch"
}
if (([string]$replacementAction.WorkingDirectory).Length -ne 0) {
throw "canonical_replacement_working_directory_identity_mismatch"
}
if ($replacementArguments -cne $ExpectedReplacementArguments) {
throw "canonical_replacement_action_mismatch"
}
if ($replacementArguments -match "api\.telegram\.org|sendMessage|BotToken|ChatId") {
@@ -63,6 +88,8 @@ function Get-ControlledTaskState {
legacyState = [string]$legacy.State
replacementEnabled = [bool]$replacement.Settings.Enabled
legacyActionSha256 = $ExpectedLegacyActionSha256
legacyActionIdentityVerified = $true
replacementActionIdentityVerified = $true
}
}
@@ -109,7 +136,63 @@ if ($Mode -eq "Check") {
if ($Mode -eq "Verify") {
$receiptAvailable = Test-Path -LiteralPath $ReceiptPath -PathType Leaf
$verified = [bool](-not $state.legacyEnabled -and $state.replacementEnabled -and $receiptAvailable)
$receiptValid = $false
if ($receiptAvailable) {
try {
$receipt = Get-Content -LiteralPath $ReceiptPath -Raw | ConvertFrom-Json
$rollbackAvailable = Test-Path -LiteralPath $RollbackPath -PathType Leaf
$rollbackSha256 = if ($rollbackAvailable) {
(Get-FileHash -LiteralPath $RollbackPath -Algorithm SHA256).Hash.ToLowerInvariant()
} else {
""
}
$receiptBooleanTypesValid = [bool](
$receipt.legacyActionIdentityVerified -is [bool] -and
$receipt.replacementActionIdentityVerified -is [bool] -and
$receipt.legacyEnabledBefore -is [bool] -and
$receipt.legacyEnabledAfter -is [bool] -and
$receipt.replacementEnabledAfter -is [bool] -and
$receipt.remoteWritePerformed -is [bool] -and
$receipt.scheduledTaskModification -is [bool] -and
$receipt.taskDeleted -is [bool] -and
$receipt.serviceRestart -is [bool] -and
$receipt.hostReboot -is [bool] -and
$receipt.vmPowerChange -is [bool] -and
$receipt.secretValueRead -is [bool] -and
$receipt.privateKeyValueRead -is [bool] -and
$receipt.tokenValueRead -is [bool] -and
$receipt.environmentSecretRead -is [bool] -and
$receipt.rawTaskArgumentsStored -is [bool] -and
$receipt.rollbackAvailable -is [bool] -and
$receipt.verifierPassed -is [bool]
)
$receiptValid = [bool](
$receiptBooleanTypesValid -and
[string]$receipt.schemaVersion -eq "agent99_legacy_sender_quarantine_receipt_v1" -and
[string]$receipt.traceId -eq $TraceId -and
[string]$receipt.runId -eq $RunId -and
[string]$receipt.workItemId -eq $WorkItemId -and
[string]$receipt.canonicalAssetId -eq "windows-vmware:host_99" -and
[string]$receipt.legacyTask -eq $LegacyTaskName -and
[string]$receipt.replacementTask -eq $ReplacementTaskName -and
[string]$receipt.legacyActionSha256 -eq $ExpectedLegacyActionSha256 -and
[string]$receipt.executorSourceSha256 -eq $ExecutorSourceSha256 -and
$rollbackAvailable -and
[string]$receipt.rollbackArtifactSha256 -eq $rollbackSha256 -and
$receipt.legacyActionIdentityVerified -eq $true -and
$receipt.replacementActionIdentityVerified -eq $true -and
$receipt.legacyEnabledAfter -eq $false -and
$receipt.replacementEnabledAfter -eq $true -and
$receipt.taskDeleted -eq $false -and
$receipt.secretValueRead -eq $false -and
$receipt.rawTaskArgumentsStored -eq $false -and
$receipt.verifierPassed -eq $true
)
} catch {
$receiptValid = $false
}
}
$verified = [bool](-not $state.legacyEnabled -and $state.replacementEnabled -and $receiptValid)
[ordered]@{
schemaVersion = "agent99_legacy_sender_quarantine_verify_v1"
status = if ($verified) { "quarantine_verified" } else { "quarantine_unverified" }
@@ -121,6 +204,12 @@ if ($Mode -eq "Verify") {
legacyEnabled = $state.legacyEnabled
replacementEnabled = $state.replacementEnabled
durableReceiptAvailable = $receiptAvailable
durableReceiptValid = $receiptValid
durableReceiptSha256 = if ($receiptAvailable) {
(Get-FileHash -LiteralPath $ReceiptPath -Algorithm SHA256).Hash.ToLowerInvariant()
} else {
$null
}
remoteWritePerformed = $false
secretValueRead = $false
} | ConvertTo-Json -Compress -Depth 6
@@ -161,6 +250,9 @@ try {
legacyTask = $LegacyTaskName
replacementTask = $ReplacementTaskName
legacyActionSha256 = $ExpectedLegacyActionSha256
executorSourceSha256 = $ExecutorSourceSha256
legacyActionIdentityVerified = $after.legacyActionIdentityVerified
replacementActionIdentityVerified = $after.replacementActionIdentityVerified
rollbackArtifactSha256 = $rollbackSha256
legacyEnabledBefore = $state.legacyEnabled
legacyEnabledAfter = $after.legacyEnabled
@@ -175,6 +267,7 @@ try {
privateKeyValueRead = $false
tokenValueRead = $false
environmentSecretRead = $false
rawTaskArgumentsStored = $false
rollbackAvailable = $true
verifierPassed = $true
nextSafeAction = "persist_exact_legacy_sender_sunset_policy_in_gitea_and_verify_no_new_wooo_bot_receipts"

View File

@@ -4,6 +4,7 @@ from pathlib import Path
ROOT = Path(__file__).resolve().parents[3]
SCRIPT = ROOT / "scripts/reboot-recovery/agent99-legacy-sender-quarantine.ps1"
REGISTER_TASKS = ROOT / "agent99-register-tasks.ps1"
CONTROL_PLANE = ROOT / "agent99-control-plane.ps1"
def test_legacy_sender_quarantine_is_exact_bounded_and_rollback_ready() -> None:
@@ -21,6 +22,16 @@ def test_legacy_sender_quarantine_is_exact_bounded_and_rollback_ready() -> None:
assert "Restart-Service" not in source
assert "Restart-Computer" not in source
assert r"api\.telegram\.org|sendMessage|BotToken|ChatId" in source
assert "legacy_task_executable_identity_mismatch" in source
assert "legacy_task_working_directory_identity_mismatch" in source
assert "canonical_replacement_executable_identity_mismatch" in source
assert "canonical_replacement_working_directory_identity_mismatch" in source
assert "$replacementArguments -cne $ExpectedReplacementArguments" in source
assert "durableReceiptValid" in source
assert "receiptBooleanTypesValid" in source
assert "executorSourceSha256" in source
assert "rollbackArtifactSha256 -eq $rollbackSha256" in source
assert "rawTaskArgumentsStored = $false" in source
assert "secretValueRead = $false" in source
assert "taskDeleted = $false" in source
@@ -42,11 +53,59 @@ def test_legacy_sender_quarantine_has_check_apply_verify_receipts() -> None:
def test_task_registration_persists_the_exact_legacy_sender_sunset() -> None:
source = REGISTER_TASKS.read_text(encoding="utf-8")
quarantine_source = source[source.index("# Superseded by the canonical all-host performance guard.") :]
assert '"Wooo-Agent99-Host188-Performance-Guard"' in source
assert "a2f98560673ebed5aa1f828b4e577c8a34d1c277b2e498044c3526a4ffe15379" in source
assert "Disable-ScheduledTask" in source
assert "Unregister-ScheduledTask" not in source
assert "legacy_host188_sender_action_identity_mismatch" in source
assert "legacy_host188_sender_executable_identity_mismatch" in source
assert "legacy_host188_sender_working_directory_identity_mismatch" in source
assert "legacy_host188_sender_running_refuse_quarantine" in source
assert "legacy_host188_sender_quarantine_post_verifier_failed" in source
assert "agent99_legacy_sender_deployment_quarantine_v1" in source
assert "agent99-legacy-sender-deployment-quarantine.json" in source
assert "canonical_performance_sender_not_ready" in source
assert "canonical_performance_sender_direct_telegram_marker" in source
assert "canonical_performance_sender_executable_identity_mismatch" in source
assert "canonical_performance_sender_working_directory_identity_mismatch" in source
assert "$canonicalPerformanceArguments -cne $perfArgs" in source
assert "legacyActionIdentityVerified" in source
assert "replacementActionIdentityVerified" in source
assert "$registerTaskProducerManifestBound = [bool](" in source
assert "producerManifestBound = $registerTaskProducerManifestBound" in source
assert "rawTaskArgumentsStored = $false" in source
assert "secretValueRead = $false" in source
assert "receiptWritePerformed = $true" in source
assert "Move-Item -Force" in source
assert quarantine_source.index("$canonicalPerformanceTask = Get-ScheduledTask") < quarantine_source.index(
"Disable-ScheduledTask"
)
def test_selfcheck_independently_verifies_legacy_sender_quarantine() -> None:
source = CONTROL_PLANE.read_text(encoding="utf-8")
assert "function Test-AgentLegacySenderQuarantine" in source
assert "agent99_legacy_sender_deployment_quarantine_v1" in source
assert "legacy_sender_quarantine_receipt_missing" in source
assert "legacy_sender_quarantine_verified" in source
assert "legacy_sender_quarantine_drift" in source
assert "currentStateMatchesReceipt" in source
assert "receiptStatusMatchesState" in source
assert "replacementActionValid" in source
assert "legacyActionValid" in source
assert "$legacyActionSha256 = Get-AgentSha256Hex" in source
assert "$replacementArguments -ceq $expectedReplacementArguments" in source
assert "[StringComparer]::OrdinalIgnoreCase.Equals" in source
assert "legacyActionIdentityVerified -eq $true" in source
assert "replacementActionIdentityVerified -eq $true" in source
assert "receiptBooleanTypesValid" in source
assert "producerIdentityValid" in source
assert "producerManifestBound -is [bool]" in source
assert "legacyTaskFound -is [bool]" in source
assert "rawTaskArgumentsStored -eq $false" in source
assert "$legacySenderQuarantine = Test-AgentLegacySenderQuarantine" in source
assert 'if ($legacySenderQuarantine.severity -eq "critical")' in source
assert "legacySenderQuarantineEvidenceRef" in source