822 lines
35 KiB
PowerShell
822 lines
35 KiB
PowerShell
param(
|
|
[ValidateSet("Check", "Apply", "Verify")]
|
|
[string]$Mode = "Check",
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$TraceId,
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$RunId,
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$WorkItemId,
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$SourceRevision,
|
|
[string]$AgentRoot = "C:\Wooo\Agent99"
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
$CanonicalAsset = "signoz-110-control-plane-metadata"
|
|
$TargetHost = "192.168.0.110"
|
|
$RemoteUser = "wooo"
|
|
$IdentityFile = Join-Path $AgentRoot "keys\agent99_ed25519"
|
|
$EvidenceDir = Join-Path $AgentRoot "evidence"
|
|
$RuntimeManifestPath = Join-Path $AgentRoot "state\runtime-manifest.json"
|
|
$EntrypointPath = [string]$MyInvocation.MyCommand.Path
|
|
$SafeIdPattern = "^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$"
|
|
$BundleId = "bb6d78b67f506072b2e45e92bc1d415364e25852282a9b068900665c578df011"
|
|
$ToolchainRoot = "/backup/toolchains/signoz-metadata/$BundleId"
|
|
$PolicyPath = "$ToolchainRoot/metadata-export-policy.json"
|
|
$ExporterPath = "$ToolchainRoot/signoz-metadata-export.py"
|
|
$VerifierPath = "$ToolchainRoot/verify-signoz-metadata-export.py"
|
|
$RestoreDriverPath = "$ToolchainRoot/signoz-metadata-restore-drill.py"
|
|
$SharedContractPath = "$ToolchainRoot/signoz_metadata_contract.py"
|
|
$CredentialFile = "/etc/awoooi/secrets/signoz-metadata-api-key"
|
|
$BaseUrl = "http://127.0.0.1:8080"
|
|
$OutputDir = "/backup/signoz-metadata-export-$RunId"
|
|
$RemoteReceipt = "/backup/deploy-receipts/signoz-metadata-toolchain/export-$RunId.json"
|
|
$SignozImage = "signoz/signoz:v0.113.0"
|
|
$SignozImageId = "sha256:c17991d10966aedcb0d4d83805a0baf5310f1553d90611629036fcfaee8d969b"
|
|
$SignozContainer = "signoz"
|
|
$OperationLock = "/tmp/awoooi-signoz-backup-operation.lock"
|
|
$TargetKillAfterSeconds = 15
|
|
$TargetGuardWorstCaseSeconds = 95
|
|
$CheckVerifyTargetTimeoutSeconds = 90
|
|
$ApplyTargetTimeoutSeconds = 720
|
|
$CheckVerifyControllerWaitSeconds = 300
|
|
$ApplyControllerWaitSeconds = 900
|
|
$ControllerTransportReserveSeconds = 30
|
|
$TargetProgramTimeoutSeconds = if ($Mode -eq "Apply") { $ApplyTargetTimeoutSeconds } else { $CheckVerifyTargetTimeoutSeconds }
|
|
$ControllerWaitSeconds = if ($Mode -eq "Apply") { $ApplyControllerWaitSeconds } else { $CheckVerifyControllerWaitSeconds }
|
|
$TargetWorstCaseSeconds = $TargetGuardWorstCaseSeconds + $TargetProgramTimeoutSeconds + $TargetKillAfterSeconds
|
|
$EvidenceRunId = if ($RunId -match $SafeIdPattern) { $RunId } else { "invalid-$PID" }
|
|
$EvidencePath = Join-Path $EvidenceDir "agent99-signoz-metadata-$($Mode.ToLowerInvariant())-$EvidenceRunId.json"
|
|
$EvidenceReservationPath = "$EvidencePath.reserve"
|
|
$script:TransientTransportOutputUsed = $false
|
|
$script:TransportCleanupSucceeded = $true
|
|
$script:EvidenceReserved = $false
|
|
$script:ApplyDispatchAttempted = $false
|
|
|
|
$ToolchainFiles = [ordered]@{
|
|
$PolicyPath = "df09dbf91d30bcf4d1a2119b1c301240a252fddd446c56ecba253d5399526533"
|
|
$ExporterPath = "b184d55bd5601377d25e78e422de172d01c3f8b8ea2de948b65c915201094956"
|
|
$SharedContractPath = "f719d3f2ec86acfafe12be1883e57e6675b8b64caab0ee16d6054c8b383fa213"
|
|
$VerifierPath = "cbab56dd3919866a96550c1dce46ec67783cd6f00473e4491861e17d1430048c"
|
|
$RestoreDriverPath = "38ce70b3f891a3ce8edfaeb880ccf69d0bb6817c3f801a0aefa0f06341901997"
|
|
}
|
|
|
|
function Invoke-Agent99SignozFixedRemote {
|
|
param(
|
|
[Parameter(Mandatory = $true)][string]$RemoteCommand,
|
|
[int]$TimeoutSeconds = 120
|
|
)
|
|
|
|
$arguments = @(
|
|
"-i", $IdentityFile,
|
|
"-o", "BatchMode=yes",
|
|
"-o", "IdentitiesOnly=yes",
|
|
"-o", "StrictHostKeyChecking=yes",
|
|
"-o", "NumberOfPasswordPrompts=0",
|
|
"-o", "ConnectTimeout=8",
|
|
"-o", "ServerAliveInterval=20",
|
|
"-o", "ServerAliveCountMax=3",
|
|
"-l", $RemoteUser,
|
|
$TargetHost,
|
|
$RemoteCommand
|
|
)
|
|
$token = [Guid]::NewGuid().ToString("N")
|
|
$stdoutPath = Join-Path $env:TEMP "agent99-signoz-metadata-$token.out"
|
|
$stderrPath = Join-Path $env:TEMP "agent99-signoz-metadata-$token.err"
|
|
$script:TransientTransportOutputUsed = $true
|
|
try {
|
|
$process = Start-Process -FilePath "ssh.exe" -ArgumentList $arguments `
|
|
-NoNewWindow -RedirectStandardOutput $stdoutPath `
|
|
-RedirectStandardError $stderrPath -PassThru
|
|
if (-not $process.WaitForExit($TimeoutSeconds * 1000)) {
|
|
try { & taskkill.exe /PID $process.Id /T /F 2>&1 | Out-Null } catch {}
|
|
return [pscustomobject]@{
|
|
completed = $false
|
|
timedOut = $true
|
|
errorCode = "remote_timeout"
|
|
stdout = ""
|
|
}
|
|
}
|
|
$process.WaitForExit() | Out-Null
|
|
$stdout = if (Test-Path -LiteralPath $stdoutPath) {
|
|
([IO.File]::ReadAllText($stdoutPath, [Text.Encoding]::UTF8)).Trim()
|
|
} else { "" }
|
|
return [pscustomobject]@{
|
|
completed = $true
|
|
timedOut = $false
|
|
errorCode = ""
|
|
stdout = $stdout
|
|
}
|
|
} finally {
|
|
Remove-Item -LiteralPath $stdoutPath, $stderrPath -Force -ErrorAction SilentlyContinue
|
|
if ((Test-Path -LiteralPath $stdoutPath) -or (Test-Path -LiteralPath $stderrPath)) {
|
|
$script:TransportCleanupSucceeded = $false
|
|
}
|
|
}
|
|
}
|
|
|
|
function Test-Agent99SignozTransportOutcome {
|
|
param([object]$Result)
|
|
|
|
return [bool](
|
|
$Result -and
|
|
$Result.completed -eq $true -and
|
|
-not $Result.timedOut
|
|
)
|
|
}
|
|
|
|
function New-Agent99SignozPathStateCommand {
|
|
param(
|
|
[Parameter(Mandatory = $true)][string]$Path,
|
|
[ValidateSet("directory", "file")][string]$ExpectedKind
|
|
)
|
|
|
|
$kindTest = if ($ExpectedKind -eq "directory") { "-d" } else { "-f" }
|
|
return (
|
|
"sudo -n /bin/bash -c 'if [ -L `"$Path`" ]; then " +
|
|
"/usr/bin/printf `"agent99_path_state:symlink`"; elif [ $kindTest `"$Path`" ]; then " +
|
|
"/usr/bin/printf `"agent99_path_state:$ExpectedKind`"; elif [ -e `"$Path`" ]; then " +
|
|
"/usr/bin/printf `"agent99_path_state:other`"; else " +
|
|
"/usr/bin/printf `"agent99_path_state:absent`"; fi'"
|
|
)
|
|
}
|
|
|
|
function Convert-Agent99JsonReceipt {
|
|
param([object]$RemoteResult)
|
|
if (
|
|
-not $RemoteResult -or
|
|
$RemoteResult.completed -ne $true -or
|
|
$RemoteResult.timedOut -or
|
|
-not [string]$RemoteResult.stdout
|
|
) { return $null }
|
|
try {
|
|
return ([string]$RemoteResult.stdout | ConvertFrom-Json)
|
|
} catch {
|
|
return $null
|
|
}
|
|
}
|
|
|
|
function New-Agent99SignozLockedRemoteCommand {
|
|
param(
|
|
[Parameter(Mandatory = $true)][string]$FixedCommand,
|
|
[Parameter(Mandatory = $true)][int]$TargetTimeoutSeconds,
|
|
[ValidateSet("absent", "present")][string]$ExpectedArtifactState
|
|
)
|
|
$artifactGuard = if ($ExpectedArtifactState -eq "present") {
|
|
"[ -d `"$OutputDir`" ] && [ ! -L `"$OutputDir`" ] && " +
|
|
"[ -f `"$RemoteReceipt`" ] && [ ! -L `"$RemoteReceipt`" ]; "
|
|
} else {
|
|
"[ ! -e `"$OutputDir`" ] && [ ! -L `"$OutputDir`" ] && " +
|
|
"[ ! -e `"$RemoteReceipt`" ] && [ ! -L `"$RemoteReceipt`" ]; "
|
|
}
|
|
return (
|
|
"sudo -n /bin/bash -c 'set -euo pipefail; " +
|
|
"[ -f `"$OperationLock`" ] && [ ! -L `"$OperationLock`" ]; " +
|
|
"exec 8<`"$OperationLock`"; /usr/bin/flock -n 8; " +
|
|
$artifactGuard +
|
|
"[ `"`$(/usr/bin/timeout --kill-after=5s 15s /usr/bin/docker inspect --format={{.Image}} $SignozContainer)`" = `"$SignozImageId`" ]; " +
|
|
"[ `"`$(/usr/bin/timeout --kill-after=5s 15s /usr/bin/docker inspect --format={{.Config.Image}} $SignozContainer)`" = `"$SignozImage`" ]; " +
|
|
"[ `"`$(/usr/bin/timeout --kill-after=5s 15s /usr/bin/docker inspect --format={{.State.Running}} $SignozContainer)`" = `"true`" ]; " +
|
|
"[ `"`$(/usr/bin/timeout --kill-after=5s 15s /usr/bin/curl -sS -o /dev/null -w `"%{http_code}`" $BaseUrl/api/v1/health)`" = `"200`" ]; " +
|
|
"set +e; active_output=`$(/usr/bin/timeout --kill-after=5s 10s /usr/bin/pgrep -af `"([s]ignoz-metadata-export[.]py|[s]ignoz-metadata-restore-drill[.]py|(^|/|[[:space:]])([b]ackup-signoz|[c]lickhouse-native-backup|[c]lickhouse-native-restore-drill|[r]un-signoz-backup-canary)[.]sh([[:space:]]|$))`"); active_rc=`$?; set -e; " +
|
|
"[ `"`$active_rc`" -eq 1 ] && [ -z `"`$active_output`" ]; " +
|
|
"exec /usr/bin/timeout --signal=TERM --kill-after=$($TargetKillAfterSeconds)s " +
|
|
"$($TargetTimeoutSeconds)s $FixedCommand'"
|
|
)
|
|
}
|
|
|
|
function Get-Agent99RuntimeSourceBinding {
|
|
$result = [ordered]@{
|
|
ok = $false
|
|
manifestPresent = $false
|
|
runtimeMatched = $false
|
|
fileCount = $null
|
|
mismatchCount = $null
|
|
sourceRevision = ""
|
|
entrypointTracked = $false
|
|
entrypointHashMatched = $false
|
|
}
|
|
if (-not (Test-Path -LiteralPath $RuntimeManifestPath -PathType Leaf)) {
|
|
return [pscustomobject]$result
|
|
}
|
|
$result.manifestPresent = $true
|
|
try {
|
|
$manifest = Get-Content -LiteralPath $RuntimeManifestPath -Raw | ConvertFrom-Json
|
|
$result.runtimeMatched = [bool]$manifest.runtimeMatched
|
|
$result.fileCount = [int]$manifest.fileCount
|
|
$result.mismatchCount = [int]$manifest.mismatchCount
|
|
$result.sourceRevision = [string]$manifest.sourceRevision
|
|
$rows = @($manifest.files | Where-Object {
|
|
[string]$_.name -eq "agent99-signoz-metadata-executor.ps1"
|
|
})
|
|
$result.entrypointTracked = [bool]($rows.Count -eq 1)
|
|
if ($rows.Count -eq 1 -and $EntrypointPath -and (Test-Path -LiteralPath $EntrypointPath -PathType Leaf)) {
|
|
$actualHash = (Get-FileHash -LiteralPath $EntrypointPath -Algorithm SHA256).Hash.ToLowerInvariant()
|
|
$result.entrypointHashMatched = [bool](
|
|
[string]$rows[0].runtimeSha256 -eq $actualHash
|
|
)
|
|
}
|
|
$result.ok = [bool](
|
|
$result.runtimeMatched -and
|
|
$result.fileCount -eq 18 -and
|
|
$result.mismatchCount -eq 0 -and
|
|
$result.sourceRevision -eq $SourceRevision -and
|
|
$result.entrypointTracked -and
|
|
$result.entrypointHashMatched
|
|
)
|
|
} catch {
|
|
$result.ok = $false
|
|
}
|
|
return [pscustomobject]$result
|
|
}
|
|
|
|
function Test-Agent99SignozReceiptIdentity {
|
|
param(
|
|
[object]$Receipt,
|
|
[string]$ExpectedPhase,
|
|
[string[]]$AllowedTerminals
|
|
)
|
|
return [bool](
|
|
$Receipt -and
|
|
[string]$Receipt.schema -eq "awoooi_signoz_metadata_receipt_v1" -and
|
|
[string]$Receipt.trace_id -eq $TraceId -and
|
|
[string]$Receipt.run_id -eq $RunId -and
|
|
[string]$Receipt.work_item_id -eq $WorkItemId -and
|
|
[string]$Receipt.phase -eq $ExpectedPhase -and
|
|
[string]$Receipt.terminal -in $AllowedTerminals
|
|
)
|
|
}
|
|
|
|
function Get-Agent99SignozPreflight {
|
|
param(
|
|
[ValidateSet("absent", "present")][string]$ExpectedArtifactState,
|
|
[bool]$RequireCredential
|
|
)
|
|
|
|
$credentialCommand = (
|
|
"sudo -n /bin/bash -c 'if [ -L `"$CredentialFile`" ]; then " +
|
|
"/usr/bin/printf `"agent99_credential:symlink`"; elif [ -f `"$CredentialFile`" ]; then " +
|
|
"/usr/bin/stat -c `"agent99_credential:present:%u:%a:%s`" `"$CredentialFile`"; " +
|
|
"elif [ -e `"$CredentialFile`" ]; then /usr/bin/printf `"agent99_credential:other`"; " +
|
|
"else /usr/bin/printf `"agent99_credential:absent`"; fi'"
|
|
)
|
|
$credential = Invoke-Agent99SignozFixedRemote $credentialCommand
|
|
$credentialOutcomeAccepted = Test-Agent99SignozTransportOutcome $credential
|
|
$credentialTypedOutput = if ($credentialOutcomeAccepted) { [string]$credential.stdout } else { "" }
|
|
$credentialState = if ($credentialTypedOutput -match "^agent99_credential:(absent|symlink|other)$") {
|
|
[string]$Matches[1]
|
|
} elseif ($credentialTypedOutput -match "^agent99_credential:(present:[0-9]+:[0-9]+:[0-9]+)$") {
|
|
[string]$Matches[1]
|
|
} else { "unverified" }
|
|
$credentialReadbackVerified = [bool](
|
|
(
|
|
$credentialState -in @("absent", "symlink", "other") -or
|
|
$credentialState -match "^present:[0-9]+:[0-9]+:[0-9]+$"
|
|
)
|
|
)
|
|
$credentialReferencePresent = if ($credentialReadbackVerified) {
|
|
[bool]($credentialState -ne "absent")
|
|
} else { $null }
|
|
$credentialOwner = $null
|
|
$credentialMode = $null
|
|
$credentialSize = $null
|
|
$credentialMetadataValid = $false
|
|
if ($credentialReadbackVerified -and $credentialState -match "^present:([0-9]+):([0-9]+):([0-9]+)$") {
|
|
$credentialOwner = [int]$Matches[1]
|
|
$credentialMode = [string]$Matches[2]
|
|
$credentialSize = [int64]$Matches[3]
|
|
$credentialMetadataValid = [bool](
|
|
$credentialOwner -eq 0 -and
|
|
$credentialMode -in @("400", "600") -and
|
|
$credentialSize -gt 0 -and
|
|
$credentialSize -le 4096
|
|
)
|
|
}
|
|
|
|
$hashCommand = (
|
|
"sudo -n /bin/bash -c 'set -euo pipefail; " +
|
|
"/usr/bin/echo agent99_hashes_begin; " +
|
|
"/usr/bin/sha256sum " + (($ToolchainFiles.Keys) -join " ") + "; " +
|
|
"/usr/bin/echo agent99_hashes_end'"
|
|
)
|
|
$hashReadback = Invoke-Agent99SignozFixedRemote $hashCommand
|
|
$actualHashes = @{}
|
|
$hashOutcomeAccepted = Test-Agent99SignozTransportOutcome $hashReadback
|
|
$hashLines = if ($hashOutcomeAccepted) {
|
|
@(([string]$hashReadback.stdout -split "`r?`n") | Where-Object { [string]$_ -ne "" })
|
|
} else { @() }
|
|
$hashShapeValid = [bool](
|
|
$hashLines.Count -eq $ToolchainFiles.Count + 2 -and
|
|
[string]$hashLines[0] -eq "agent99_hashes_begin" -and
|
|
[string]$hashLines[$hashLines.Count - 1] -eq "agent99_hashes_end"
|
|
)
|
|
if ($hashShapeValid) {
|
|
foreach ($line in @($hashLines[1..($hashLines.Count - 2)])) {
|
|
if ($line -match "^([0-9a-f]{64})\s+(.+)$") {
|
|
$path = [string]$Matches[2]
|
|
if ($actualHashes.ContainsKey($path) -or -not $ToolchainFiles.Contains($path)) {
|
|
$hashShapeValid = $false
|
|
break
|
|
}
|
|
$actualHashes[$path] = [string]$Matches[1]
|
|
} else {
|
|
$hashShapeValid = $false
|
|
break
|
|
}
|
|
}
|
|
}
|
|
$toolchainReadbackVerified = [bool](
|
|
$hashShapeValid -and
|
|
$actualHashes.Count -eq $ToolchainFiles.Count
|
|
)
|
|
$toolchainExact = $toolchainReadbackVerified
|
|
foreach ($entry in $ToolchainFiles.GetEnumerator()) {
|
|
if (-not $actualHashes.ContainsKey([string]$entry.Key) -or $actualHashes[[string]$entry.Key] -ne [string]$entry.Value) {
|
|
$toolchainExact = $false
|
|
}
|
|
}
|
|
|
|
$image = Invoke-Agent99SignozFixedRemote (
|
|
"sudo -n /bin/bash -c 'set -euo pipefail; " +
|
|
"/usr/bin/printf `"agent99_image:`"; " +
|
|
"/usr/bin/docker image inspect --format={{.Id}} $SignozImage'"
|
|
)
|
|
$imageOutcomeAccepted = Test-Agent99SignozTransportOutcome $image
|
|
$imageId = if ($imageOutcomeAccepted -and [string]$image.stdout -match "^agent99_image:(sha256:[0-9a-f]{64})$") {
|
|
[string]$Matches[1]
|
|
} else { "" }
|
|
$imageReadbackVerified = [bool]($imageId -match "^sha256:[0-9a-f]{64}$")
|
|
$imageExact = [bool]($imageReadbackVerified -and $imageId -eq $SignozImageId)
|
|
$runtime = Invoke-Agent99SignozFixedRemote (
|
|
"sudo -n /bin/bash -c 'set -euo pipefail; " +
|
|
"/usr/bin/printf agent99_runtime:; " +
|
|
"/usr/bin/docker inspect --format={{.Id}},{{.Image}},{{.Config.Image}},{{.State.Running}} $SignozContainer'"
|
|
)
|
|
$runtimeOutcomeAccepted = Test-Agent99SignozTransportOutcome $runtime
|
|
$runtimeContainerId = $null
|
|
$runtimeImageId = $null
|
|
$runtimeImageRef = $null
|
|
$runtimeRunning = $false
|
|
$runtimeReadbackVerified = $false
|
|
if ($runtimeOutcomeAccepted -and [string]$runtime.stdout -match "^agent99_runtime:([0-9a-f]{64}),(sha256:[0-9a-f]{64}),([A-Za-z0-9./:_-]+),(true|false)$") {
|
|
$runtimeReadbackVerified = $true
|
|
$runtimeContainerId = [string]$Matches[1]
|
|
$runtimeImageId = [string]$Matches[2]
|
|
$runtimeImageRef = [string]$Matches[3]
|
|
$runtimeRunning = [bool]([string]$Matches[4] -eq "true")
|
|
}
|
|
$runtimeImageExact = [bool](
|
|
$runtimeRunning -and
|
|
$runtimeImageId -eq $SignozImageId -and
|
|
$runtimeImageRef -eq $SignozImage
|
|
)
|
|
$health = Invoke-Agent99SignozFixedRemote (
|
|
"sudo -n /bin/bash -c 'set -euo pipefail; " +
|
|
"/usr/bin/printf `"agent99_health:`"; " +
|
|
"/usr/bin/curl -fsS --max-time 15 $BaseUrl/api/v1/health'"
|
|
)
|
|
$healthOk = $false
|
|
$healthReadbackVerified = $false
|
|
if (
|
|
(Test-Agent99SignozTransportOutcome $health) -and
|
|
[string]$health.stdout -match "^agent99_health:(\{.+\})$"
|
|
) {
|
|
try {
|
|
$healthPayload = [string]$Matches[1] | ConvertFrom-Json
|
|
$healthReadbackVerified = [bool]($null -ne $healthPayload.PSObject.Properties["status"])
|
|
$healthOk = [bool]([string]$healthPayload.status -eq "ok")
|
|
} catch {
|
|
$healthOk = $false
|
|
}
|
|
}
|
|
|
|
$active = Invoke-Agent99SignozFixedRemote (
|
|
"sudo -n /bin/bash -c 'set -euo pipefail; set +e; " +
|
|
"active_output=`$(/usr/bin/pgrep -fc `"[s]ignoz-metadata-export.py.*--apply`" ); " +
|
|
"active_rc=`$?; set -e; " +
|
|
"[ `"`$active_rc`" -eq 0 ] || [ `"`$active_rc`" -eq 1 ]; " +
|
|
"/usr/bin/printf `"%s`" `"`$active_output`" | /usr/bin/grep -Eq `"^[0-9]+$`"; " +
|
|
"/usr/bin/printf `"agent99_active:%s`" `"`$active_output`"'"
|
|
)
|
|
$activeOperationCount = $null
|
|
$activeOutcomeAccepted = Test-Agent99SignozTransportOutcome $active
|
|
if ($activeOutcomeAccepted -and [string]$active.stdout -match "^agent99_active:([0-9]+)$") {
|
|
$activeOperationCount = [int]$Matches[1]
|
|
}
|
|
$activeReadbackVerified = [bool]($null -ne $activeOperationCount)
|
|
$activeOperationsClear = [bool](
|
|
$activeReadbackVerified -and
|
|
$activeOperationCount -eq 0
|
|
)
|
|
|
|
$outputState = Invoke-Agent99SignozFixedRemote (
|
|
New-Agent99SignozPathStateCommand $OutputDir "directory"
|
|
)
|
|
$receiptState = Invoke-Agent99SignozFixedRemote (
|
|
New-Agent99SignozPathStateCommand $RemoteReceipt "file"
|
|
)
|
|
$outputStateValue = if (
|
|
(Test-Agent99SignozTransportOutcome $outputState) -and
|
|
[string]$outputState.stdout -match "^agent99_path_state:(absent|directory|other|symlink)$"
|
|
) { [string]$Matches[1] } else { "unverified" }
|
|
$receiptStateValue = if (
|
|
(Test-Agent99SignozTransportOutcome $receiptState) -and
|
|
[string]$receiptState.stdout -match "^agent99_path_state:(absent|file|other|symlink)$"
|
|
) { [string]$Matches[1] } else { "unverified" }
|
|
$outputStateReadbackVerified = [bool]($outputStateValue -ne "unverified")
|
|
$receiptStateReadbackVerified = [bool]($receiptStateValue -ne "unverified")
|
|
$outputPresent = if ($outputStateReadbackVerified) {
|
|
[bool]($outputStateValue -ne "absent")
|
|
} else { $null }
|
|
$receiptPresent = if ($receiptStateReadbackVerified) {
|
|
[bool]($receiptStateValue -ne "absent")
|
|
} else { $null }
|
|
$stateReadable = [bool](
|
|
$outputStateReadbackVerified -and
|
|
$receiptStateReadbackVerified
|
|
)
|
|
$artifactStateReady = if ($ExpectedArtifactState -eq "present") {
|
|
[bool]($outputStateValue -eq "directory" -and $receiptStateValue -eq "file")
|
|
} else {
|
|
[bool]($outputStateValue -eq "absent" -and $receiptStateValue -eq "absent")
|
|
}
|
|
$transportReadbackVerified = [bool](
|
|
$credentialReadbackVerified -and
|
|
$toolchainReadbackVerified -and
|
|
$imageReadbackVerified -and
|
|
$runtimeReadbackVerified -and
|
|
$healthReadbackVerified -and
|
|
$activeReadbackVerified -and
|
|
$stateReadable
|
|
)
|
|
$credentialReady = [bool](-not $RequireCredential -or $credentialMetadataValid)
|
|
$ready = [bool](
|
|
$transportReadbackVerified -and
|
|
$credentialReady -and
|
|
$toolchainExact -and
|
|
$imageExact -and
|
|
$runtimeImageExact -and
|
|
$healthOk -and
|
|
$activeOperationsClear -and
|
|
$stateReadable -and
|
|
$artifactStateReady
|
|
)
|
|
|
|
return [pscustomobject]@{
|
|
ready = $ready
|
|
transportReadbackVerified = $transportReadbackVerified
|
|
credentialReadbackVerified = $credentialReadbackVerified
|
|
credentialState = $credentialState
|
|
credentialReferencePresent = $credentialReferencePresent
|
|
credentialMetadataValid = $credentialMetadataValid
|
|
credentialOwnerUid = $credentialOwner
|
|
credentialMode = $credentialMode
|
|
credentialSizeBytes = $credentialSize
|
|
credentialValueRead = $false
|
|
credentialValueOutput = $false
|
|
toolchainBundleId = $BundleId
|
|
toolchainFileCount = $ToolchainFiles.Count
|
|
toolchainReadbackVerified = $toolchainReadbackVerified
|
|
toolchainExact = $toolchainExact
|
|
signozImage = $SignozImage
|
|
signozImageId = if ($imageReadbackVerified) { $imageId } else { $null }
|
|
signozImageReadbackVerified = $imageReadbackVerified
|
|
signozImageExact = $imageExact
|
|
signozContainer = $SignozContainer
|
|
signozRuntimeContainerId = $runtimeContainerId
|
|
signozRuntimeImageId = $runtimeImageId
|
|
signozRuntimeImageRef = $runtimeImageRef
|
|
signozRuntimeRunning = $runtimeRunning
|
|
signozRuntimeReadbackVerified = $runtimeReadbackVerified
|
|
signozRuntimeImageExact = $runtimeImageExact
|
|
apiHealthReadbackVerified = $healthReadbackVerified
|
|
apiHealthOk = $healthOk
|
|
activeOperationCount = $activeOperationCount
|
|
activeOperationReadbackVerified = $activeReadbackVerified
|
|
activeOperationsClear = $activeOperationsClear
|
|
expectedArtifactState = $ExpectedArtifactState
|
|
outputState = $outputStateValue
|
|
outputStateReadbackVerified = $outputStateReadbackVerified
|
|
outputPresent = $outputPresent
|
|
receiptState = $receiptStateValue
|
|
receiptStateReadbackVerified = $receiptStateReadbackVerified
|
|
receiptPresent = $receiptPresent
|
|
artifactStateReady = $artifactStateReady
|
|
}
|
|
}
|
|
|
|
function Write-Agent99SignozEvidenceCollision {
|
|
$collision = [pscustomobject]@{
|
|
schemaVersion = "agent99_signoz_metadata_executor_dispatch_v1"
|
|
mode = $Mode
|
|
traceId = $TraceId
|
|
runId = $RunId
|
|
workItemId = $WorkItemId
|
|
terminal = "blocked_evidence_identity_collision"
|
|
errorCode = "evidence_path_or_reservation_already_exists"
|
|
evidencePath = $EvidencePath
|
|
completionClaim = $false
|
|
}
|
|
[Console]::WriteLine(($collision | ConvertTo-Json -Compress))
|
|
}
|
|
|
|
function New-Agent99SignozEvidenceReservation {
|
|
New-Item -ItemType Directory -Force -Path $EvidenceDir | Out-Null
|
|
if (
|
|
(Test-Path -LiteralPath $EvidencePath) -or
|
|
(Test-Path -LiteralPath $EvidenceReservationPath)
|
|
) {
|
|
return $false
|
|
}
|
|
$reservationStream = $null
|
|
try {
|
|
$reservationStream = [IO.File]::Open(
|
|
$EvidenceReservationPath,
|
|
[IO.FileMode]::CreateNew,
|
|
[IO.FileAccess]::Write,
|
|
[IO.FileShare]::None
|
|
)
|
|
$reservationPayload = [Text.Encoding]::UTF8.GetBytes(
|
|
"$TraceId|$RunId|$WorkItemId|$Mode" + [Environment]::NewLine
|
|
)
|
|
$reservationStream.Write($reservationPayload, 0, $reservationPayload.Length)
|
|
$reservationStream.Flush($true)
|
|
$script:EvidenceReserved = $true
|
|
return $true
|
|
} catch {
|
|
return $false
|
|
} finally {
|
|
if ($reservationStream) { $reservationStream.Dispose() }
|
|
}
|
|
}
|
|
|
|
function Write-Agent99SignozTerminal {
|
|
param(
|
|
[string]$Terminal,
|
|
[string]$ErrorCode,
|
|
[object]$Preflight,
|
|
[object]$CheckReceipt,
|
|
[object]$ApplyReceipt,
|
|
[object]$VerifierReceipt,
|
|
[object]$ArtifactWritePerformed
|
|
)
|
|
|
|
$controlledApplyPhases = [ordered]@{
|
|
sensorSource = if ($Preflight) { "observed" } else { "blocked" }
|
|
normalizedAsset = if ($Preflight) { $CanonicalAsset } else { "blocked" }
|
|
sourceTruthDiff = if ($Preflight -and $Preflight.toolchainExact) { "exact" } else { "blocked_or_drift" }
|
|
aiDecision = "fixed_allowlisted_metadata_export"
|
|
riskPolicy = "high_bounded_read_only_source_private_artifact_no_raw_sqlite"
|
|
checkMode = if ($CheckReceipt) { [string]$CheckReceipt.terminal } elseif ($Preflight -and $Preflight.ready) { "preflight_pass" } else { "blocked" }
|
|
boundedExecution = if ($ApplyReceipt) { [string]$ApplyReceipt.terminal } elseif ($Mode -eq "Apply") { "not_verified" } else { "not_run" }
|
|
independentVerifier = if ($VerifierReceipt) { [string]$VerifierReceipt.terminal } else { "not_run" }
|
|
rollbackOrNoWrite = if ($Mode -in @("Check", "Verify")) { "no_write" } elseif ($Terminal -eq "export_verified_restore_pending") { "not_required_additive_immutable_artifact" } else { "artifact_preserved_no_delete" }
|
|
learningWriteback = "pending_telegram_km_rag_mcp_playbook_ack"
|
|
}
|
|
$payload = [pscustomobject]@{
|
|
schemaVersion = "agent99_signoz_metadata_executor_dispatch_v1"
|
|
canonicalAsset = $CanonicalAsset
|
|
domain = "backup_observability"
|
|
executor = "agent99_signoz_metadata_executor"
|
|
verifier = "signoz_metadata_export_independent_verifier"
|
|
executionHub = "host:192.168.0.99"
|
|
dispatchPath = "windows99_agent99_to_host110_fixed_metadata_toolchain"
|
|
dispatchOnly = $true
|
|
mode = $Mode
|
|
traceId = $TraceId
|
|
runId = $RunId
|
|
workItemId = $WorkItemId
|
|
sourceRevision = $SourceRevision
|
|
targetHost = $TargetHost
|
|
toolchainBundleId = $BundleId
|
|
credentialReference = $CredentialFile
|
|
targetOperationLock = $OperationLock
|
|
targetOperationLockRequiredExistingNonSymlink = $true
|
|
targetTimeoutKillAfterSeconds = $TargetKillAfterSeconds
|
|
targetGuardWorstCaseSeconds = $TargetGuardWorstCaseSeconds
|
|
targetProgramTimeoutSeconds = $TargetProgramTimeoutSeconds
|
|
targetWorstCaseSeconds = $TargetWorstCaseSeconds
|
|
controllerWaitSeconds = $ControllerWaitSeconds
|
|
controllerTransportReserveSeconds = $ControllerTransportReserveSeconds
|
|
targetTimeoutFinishesBeforeControllerWait = [bool](
|
|
$TargetWorstCaseSeconds + $ControllerTransportReserveSeconds -lt $ControllerWaitSeconds
|
|
)
|
|
terminal = $Terminal
|
|
errorCode = if ($ErrorCode) { $ErrorCode } else { $null }
|
|
preflight = $Preflight
|
|
checkReceipt = $CheckReceipt
|
|
applyReceipt = $ApplyReceipt
|
|
verifierReceipt = $VerifierReceipt
|
|
controlledApplyPhases = [pscustomobject]$controlledApplyPhases
|
|
artifactWritePerformed = $ArtifactWritePerformed
|
|
productionRuntimeMutationPerformed = $false
|
|
rawSqliteRead = $false
|
|
rawVolumeRead = $false
|
|
secretValueReadByController = $false
|
|
secretValueTransmitted = $false
|
|
secretValuePersistedInEvidence = $false
|
|
credentialReferenceDispatchAttempted = $script:ApplyDispatchAttempted
|
|
credentialReferenceConsumedOnTarget = if (-not $script:ApplyDispatchAttempted) {
|
|
$false
|
|
} elseif (Test-Agent99SignozReceiptIdentity $ApplyReceipt "terminal" @("partial_degraded")) {
|
|
$true
|
|
} else {
|
|
$null
|
|
}
|
|
arbitraryCommandAllowed = $false
|
|
crossDomainFallbackAllowed = $false
|
|
restoreTerminal = "pending_isolated_same_version_target"
|
|
zeroResidueTerminal = "pending"
|
|
completionClaim = $false
|
|
telegramAcknowledged = $false
|
|
kmRagMcpPlaybookAcknowledged = $false
|
|
transientTransportOutputUsed = $script:TransientTransportOutputUsed
|
|
transientTransportOutputDeletedBeforeReceipt = [bool](
|
|
$script:TransientTransportOutputUsed -and $script:TransportCleanupSucceeded
|
|
)
|
|
rawTransportOutputPersisted = [bool](
|
|
$script:TransientTransportOutputUsed -and -not $script:TransportCleanupSucceeded
|
|
)
|
|
evidenceReservedBeforeDispatch = $script:EvidenceReserved
|
|
evidencePath = $EvidencePath
|
|
}
|
|
$json = $payload | ConvertTo-Json -Compress -Depth 14
|
|
New-Item -ItemType Directory -Force -Path $EvidenceDir | Out-Null
|
|
if (
|
|
(Test-Path -LiteralPath $EvidencePath) -or
|
|
(-not $script:EvidenceReserved -and (Test-Path -LiteralPath $EvidenceReservationPath))
|
|
) {
|
|
Write-Agent99SignozEvidenceCollision
|
|
return $false
|
|
}
|
|
$tempEvidencePath = "$EvidencePath.$PID.$([Guid]::NewGuid().ToString('N')).tmp"
|
|
try {
|
|
[IO.File]::WriteAllText(
|
|
$tempEvidencePath,
|
|
$json + [Environment]::NewLine,
|
|
(New-Object Text.UTF8Encoding($false))
|
|
)
|
|
Move-Item -LiteralPath $tempEvidencePath -Destination $EvidencePath
|
|
if ($script:EvidenceReserved) {
|
|
Remove-Item -LiteralPath $EvidenceReservationPath -Force -ErrorAction SilentlyContinue
|
|
$script:EvidenceReserved = $false
|
|
}
|
|
} finally {
|
|
Remove-Item -LiteralPath $tempEvidencePath -Force -ErrorAction SilentlyContinue
|
|
}
|
|
[Console]::WriteLine($json)
|
|
return $true
|
|
}
|
|
|
|
function Stop-Agent99SignozRun {
|
|
param(
|
|
[string]$Terminal,
|
|
[string]$ErrorCode,
|
|
[object]$Preflight,
|
|
[object]$CheckReceipt,
|
|
[object]$ApplyReceipt,
|
|
[object]$VerifierReceipt,
|
|
[object]$ArtifactWritePerformed,
|
|
[int]$ExitCode
|
|
)
|
|
if (-not (Write-Agent99SignozTerminal $Terminal $ErrorCode $Preflight $CheckReceipt $ApplyReceipt $VerifierReceipt $ArtifactWritePerformed)) {
|
|
exit 74
|
|
}
|
|
exit $ExitCode
|
|
}
|
|
|
|
foreach ($identity in @($TraceId, $RunId, $WorkItemId)) {
|
|
if ($identity -notmatch $SafeIdPattern) {
|
|
Stop-Agent99SignozRun "blocked_with_safe_next_action" "identity_missing_or_invalid" $null $null $null $null $false 64
|
|
}
|
|
}
|
|
if ($WorkItemId -ne "P0-OBS-002") {
|
|
Stop-Agent99SignozRun "blocked_with_safe_next_action" "work_item_not_allowlisted" $null $null $null $null $false 64
|
|
}
|
|
$SourceRevision = $SourceRevision.ToLowerInvariant()
|
|
if ($SourceRevision -notmatch "^[0-9a-f]{40}$") {
|
|
Stop-Agent99SignozRun "blocked_with_safe_next_action" "source_revision_missing_or_invalid" $null $null $null $null $false 64
|
|
}
|
|
if ($TargetWorstCaseSeconds + $ControllerTransportReserveSeconds -ge $ControllerWaitSeconds) {
|
|
Stop-Agent99SignozRun "blocked_with_safe_next_action" "target_timeout_not_bounded_before_controller_wait" $null $null $null $null $false 64
|
|
}
|
|
if (-not (New-Agent99SignozEvidenceReservation)) {
|
|
Write-Agent99SignozEvidenceCollision
|
|
exit 66
|
|
}
|
|
if (-not (Test-Path -LiteralPath $IdentityFile -PathType Leaf)) {
|
|
Stop-Agent99SignozRun "blocked_with_safe_next_action" "dedicated_identity_unavailable" $null $null $null $null $false 65
|
|
}
|
|
$runtimeSourceBinding = Get-Agent99RuntimeSourceBinding
|
|
if (-not $runtimeSourceBinding.ok) {
|
|
Stop-Agent99SignozRun "blocked_with_safe_next_action" "runtime_source_binding_failed" $runtimeSourceBinding $null $null $null $false 65
|
|
}
|
|
|
|
if ($Mode -eq "Verify") {
|
|
$preflight = Get-Agent99SignozPreflight -ExpectedArtifactState "present" -RequireCredential $false
|
|
if (-not $preflight.transportReadbackVerified) {
|
|
Stop-Agent99SignozRun "verification_failed" "preflight_transport_unverified" $preflight $null $null $null $false 1
|
|
}
|
|
if (-not $preflight.ready) {
|
|
Stop-Agent99SignozRun "verification_failed" "verified_bundle_preflight_failed" $preflight $null $null $null $false 1
|
|
}
|
|
$verifyProgram = (
|
|
"/usr/bin/python3 $VerifierPath " +
|
|
"--bundle-dir $OutputDir --policy $PolicyPath " +
|
|
"--expected-trace-id $TraceId --expected-run-id $RunId " +
|
|
"--expected-work-item-id $WorkItemId"
|
|
)
|
|
$verifyCommand = New-Agent99SignozLockedRemoteCommand $verifyProgram $CheckVerifyTargetTimeoutSeconds "present"
|
|
$verify = Invoke-Agent99SignozFixedRemote $verifyCommand $CheckVerifyControllerWaitSeconds
|
|
$verifyReceipt = Convert-Agent99JsonReceipt $verify
|
|
if (-not (Test-Agent99SignozTransportOutcome $verify) -or -not (Test-Agent99SignozReceiptIdentity $verifyReceipt "independent_export_verifier" @("pass_export_verified_restore_pending"))) {
|
|
Stop-Agent99SignozRun "verification_failed" "independent_export_verifier_failed" $preflight $null $null $verifyReceipt $false 1
|
|
}
|
|
$postflight = Get-Agent99SignozPreflight -ExpectedArtifactState "present" -RequireCredential $false
|
|
if (-not $postflight.transportReadbackVerified) {
|
|
Stop-Agent99SignozRun "verification_failed" "post_verifier_transport_unverified" $postflight $null $null $verifyReceipt $false 1
|
|
}
|
|
if (-not $postflight.ready) {
|
|
Stop-Agent99SignozRun "verification_failed" "post_verifier_runtime_or_artifact_drift" $postflight $null $null $verifyReceipt $false 1
|
|
}
|
|
Stop-Agent99SignozRun "export_verified_restore_pending" "" $postflight $null $null $verifyReceipt $false 0
|
|
}
|
|
|
|
$preflight = Get-Agent99SignozPreflight -ExpectedArtifactState "absent" -RequireCredential $true
|
|
if (-not $preflight.credentialReadbackVerified) {
|
|
Stop-Agent99SignozRun "blocked_with_safe_next_action" "credential_reference_readback_unverified" $preflight $null $null $null $false 2
|
|
}
|
|
if (-not $preflight.credentialReferencePresent) {
|
|
Stop-Agent99SignozRun "blocked_with_safe_next_action" "credential_reference_absent" $preflight $null $null $null $false 2
|
|
}
|
|
if (-not $preflight.credentialMetadataValid) {
|
|
Stop-Agent99SignozRun "blocked_with_safe_next_action" "credential_reference_metadata_invalid" $preflight $null $null $null $false 2
|
|
}
|
|
if (-not $preflight.transportReadbackVerified) {
|
|
Stop-Agent99SignozRun "blocked_with_safe_next_action" "preflight_transport_unverified" $preflight $null $null $null $false 1
|
|
}
|
|
if (-not $preflight.ready) {
|
|
Stop-Agent99SignozRun "blocked_with_safe_next_action" "metadata_export_preflight_failed" $preflight $null $null $null $false 1
|
|
}
|
|
|
|
$checkProgram = (
|
|
"/usr/bin/python3 $ExporterPath --check " +
|
|
"--base-url $BaseUrl --output-dir $OutputDir --credential-file $CredentialFile " +
|
|
"--policy $PolicyPath --trace-id $TraceId --run-id $RunId --work-item-id $WorkItemId"
|
|
)
|
|
$checkCommand = New-Agent99SignozLockedRemoteCommand $checkProgram $CheckVerifyTargetTimeoutSeconds "absent"
|
|
$check = Invoke-Agent99SignozFixedRemote $checkCommand $CheckVerifyControllerWaitSeconds
|
|
$checkReceipt = Convert-Agent99JsonReceipt $check
|
|
if (-not (Test-Agent99SignozTransportOutcome $check) -or -not (Test-Agent99SignozReceiptIdentity $checkReceipt "terminal" @("check_pass_no_write"))) {
|
|
Stop-Agent99SignozRun "blocked_with_safe_next_action" "metadata_export_check_failed" $preflight $checkReceipt $null $null $false 1
|
|
}
|
|
if ($Mode -eq "Check") {
|
|
Stop-Agent99SignozRun "check_ready" "" $preflight $checkReceipt $null $null $false 0
|
|
}
|
|
|
|
$applyProgram = (
|
|
"/usr/bin/python3 $ExporterPath --apply " +
|
|
"--base-url $BaseUrl --output-dir $OutputDir --credential-file $CredentialFile " +
|
|
"--policy $PolicyPath --trace-id $TraceId --run-id $RunId --work-item-id $WorkItemId " +
|
|
"--receipt-file $RemoteReceipt"
|
|
)
|
|
$applyCommand = New-Agent99SignozLockedRemoteCommand $applyProgram $ApplyTargetTimeoutSeconds "absent"
|
|
$script:ApplyDispatchAttempted = $true
|
|
$apply = Invoke-Agent99SignozFixedRemote $applyCommand $ApplyControllerWaitSeconds
|
|
$applyReceipt = Convert-Agent99JsonReceipt $apply
|
|
if (-not (Test-Agent99SignozTransportOutcome $apply) -or -not (Test-Agent99SignozReceiptIdentity $applyReceipt "terminal" @("partial_degraded"))) {
|
|
$artifactReadback = Get-Agent99SignozPreflight -ExpectedArtifactState "present" -RequireCredential $false
|
|
if ($artifactReadback.outputPresent -eq $true -or $artifactReadback.receiptPresent -eq $true) {
|
|
Stop-Agent99SignozRun "apply_failed_artifact_preserved_for_readback" "bounded_export_failed" $artifactReadback $checkReceipt $applyReceipt $null $true 1
|
|
}
|
|
if ($artifactReadback.outputPresent -eq $false -and $artifactReadback.receiptPresent -eq $false) {
|
|
Stop-Agent99SignozRun "apply_failed_no_durable_artifact_observed" "bounded_export_failed_no_final_artifact" $artifactReadback $checkReceipt $applyReceipt $null $null 1
|
|
}
|
|
Stop-Agent99SignozRun "apply_failed_artifact_state_unverified" "bounded_export_failed_artifact_readback_unverified" $artifactReadback $checkReceipt $applyReceipt $null $null 1
|
|
}
|
|
|
|
$verifyProgram = (
|
|
"/usr/bin/python3 $VerifierPath " +
|
|
"--bundle-dir $OutputDir --policy $PolicyPath " +
|
|
"--expected-trace-id $TraceId --expected-run-id $RunId " +
|
|
"--expected-work-item-id $WorkItemId"
|
|
)
|
|
$verifyCommand = New-Agent99SignozLockedRemoteCommand $verifyProgram $CheckVerifyTargetTimeoutSeconds "present"
|
|
$verify = Invoke-Agent99SignozFixedRemote $verifyCommand $CheckVerifyControllerWaitSeconds
|
|
$verifyReceipt = Convert-Agent99JsonReceipt $verify
|
|
if (-not (Test-Agent99SignozTransportOutcome $verify) -or -not (Test-Agent99SignozReceiptIdentity $verifyReceipt "independent_export_verifier" @("pass_export_verified_restore_pending"))) {
|
|
$artifactReadback = Get-Agent99SignozPreflight -ExpectedArtifactState "present" -RequireCredential $false
|
|
Stop-Agent99SignozRun "verification_failed_artifact_preserved" "independent_export_verifier_failed" $artifactReadback $checkReceipt $applyReceipt $verifyReceipt $true 1
|
|
}
|
|
|
|
$postflight = Get-Agent99SignozPreflight -ExpectedArtifactState "present" -RequireCredential $false
|
|
if (-not $postflight.transportReadbackVerified) {
|
|
Stop-Agent99SignozRun "verification_failed_artifact_preserved" "post_verifier_transport_unverified" $postflight $checkReceipt $applyReceipt $verifyReceipt $true 1
|
|
}
|
|
if (-not $postflight.ready) {
|
|
Stop-Agent99SignozRun "verification_failed_artifact_preserved" "post_verifier_runtime_or_artifact_drift" $postflight $checkReceipt $applyReceipt $verifyReceipt $true 1
|
|
}
|
|
Stop-Agent99SignozRun "export_verified_restore_pending" "" $postflight $checkReceipt $applyReceipt $verifyReceipt $true 0
|