fix(agent99): gate reboot recovery on full SOP
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[3]
|
||||
|
||||
|
||||
def read(relative: str) -> str:
|
||||
return (ROOT / relative).read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def test_recover_requires_full_sop_coordinator_before_verified_resolution() -> None:
|
||||
control = read("agent99-control-plane.ps1")
|
||||
|
||||
assert "Invoke-AgentRecoveryCoordinatorReadback" in control
|
||||
assert 'New-AgentOutcomeCheck "full_sop_coordinator_verified"' in control
|
||||
assert "-and $coordinatorOk" in control
|
||||
assert 'New-AgentRecoveryPhase "full_sop_scorecard"' in control
|
||||
assert 'schemaVersion = "agent99_recovery_slo_v2"' in control
|
||||
assert 'scope = $recoveryScope' in control
|
||||
assert 'rebootSloClaimed = $rebootSloClaimed' in control
|
||||
|
||||
|
||||
def test_coordinator_covers_all_hosts_and_full_recovery_evidence() -> None:
|
||||
control = read("agent99-control-plane.ps1")
|
||||
|
||||
for alias in ("99", "110", "111", "112", "120", "121", "188"):
|
||||
assert f'"{alias}"' in control
|
||||
|
||||
for field in (
|
||||
"SERVICE_GREEN",
|
||||
"PRODUCT_DATA_GREEN",
|
||||
"STOCK_FRESHNESS_STATUS",
|
||||
"BACKUP_CORE_GREEN",
|
||||
"HOST_188_SERVICE_GREEN",
|
||||
"HOST_188_HYGIENE_BLOCKED",
|
||||
"EDGE_FALLBACK_READY",
|
||||
"VMWARE_AUTOSTART_VERIFY_READY",
|
||||
"WINDOWS_UPDATE_NO_AUTO_REBOOT_READY",
|
||||
"SCORECARD_FRESH_REBOOT_WINDOW",
|
||||
"SCORECARD_CAN_CLAIM",
|
||||
"SCORECARD_BLOCKER_COUNT",
|
||||
):
|
||||
assert field in control
|
||||
|
||||
|
||||
def test_fresh_reboot_claim_requires_fresh_artifact_and_zero_blockers() -> None:
|
||||
control = read("agent99-control-plane.ps1")
|
||||
|
||||
assert 'name = "artifact_fresh_for_recovery"' in control
|
||||
assert 'name = "fresh_reboot_window_observed"' in control
|
||||
assert 'name = "scorecard_can_claim_slo"' in control
|
||||
assert 'name = "scorecard_has_no_blockers"' in control
|
||||
assert "$artifactEpoch -ge ($startedEpoch - $CoordinatorConfig.artifactClockSkewSeconds)" in control
|
||||
assert "-not $requiresFreshWindow -or $rebootSloClaimed" in control
|
||||
|
||||
|
||||
def test_runtime_deployer_migrates_recovery_coordinator_defaults() -> None:
|
||||
deployer = read("agent99-deploy.ps1")
|
||||
config = read("agent99.config.99.example.json")
|
||||
|
||||
assert 'Add-DefaultProperty $config "recoveryCoordinator"' in deployer
|
||||
assert 'Add-DefaultProperty $config.recoveryCoordinator "controllerHost" "192.168.0.110"' in deployer
|
||||
assert 'Add-DefaultProperty $config.recoveryCoordinator "requiredHostAliases"' in deployer
|
||||
assert '"recoveryCoordinator"' in config
|
||||
assert '"freshWaitTimeoutSeconds": 420' in config
|
||||
|
||||
|
||||
def test_coordinator_reads_only_bounded_summary_artifacts() -> None:
|
||||
control = read("agent99-control-plane.ps1")
|
||||
coordinator = control.split("function Invoke-AgentRecoveryCoordinatorReadback", 1)[1]
|
||||
coordinator = coordinator.split("function Convert-AgentDouble", 1)[0]
|
||||
|
||||
assert "summary.txt" in coordinator
|
||||
assert "host-probe.txt" in coordinator
|
||||
assert "public-maintenance-edge-fallback.txt" in coordinator
|
||||
assert "windows99-vmware-verify.txt" in coordinator
|
||||
assert "scorecard.json" in coordinator
|
||||
assert "*.log" not in coordinator
|
||||
assert ".env" not in coordinator
|
||||
assert "auth.json" not in coordinator
|
||||
assert "session" not in coordinator.lower()
|
||||
|
||||
|
||||
def test_live_preflight_is_no_secret_and_no_remote_write() -> None:
|
||||
preflight = read("scripts/reboot-recovery/agent99-live-preflight.ps1")
|
||||
|
||||
assert 'secretValueRead = $false' in preflight
|
||||
assert 'remoteWritePerformed = $false' in preflight
|
||||
assert 'Write-Output "SECRET_VALUE_READ=0"' in preflight
|
||||
assert 'Write-Output "REMOTE_WRITE_PERFORMED=0"' in preflight
|
||||
assert "runtime-manifest.json" in preflight
|
||||
assert "Get-ScheduledTask" in preflight
|
||||
assert "Get-NetTCPConnection -LocalPort 8787" in preflight
|
||||
assert ".env" not in preflight
|
||||
assert "auth.json" not in preflight
|
||||
assert "agent99.config.json" not in preflight
|
||||
Reference in New Issue
Block a user