docs: accept partial send sandbox evidence
This commit is contained in:
61
scripts/test-validate-returned-send-sandbox-package.ps1
Normal file
61
scripts/test-validate-returned-send-sandbox-package.ps1
Normal file
@@ -0,0 +1,61 @@
|
||||
param(
|
||||
[string]$FixtureZip = "C:\Users\zhaoy\Downloads\1631.zip"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
Set-StrictMode -Version Latest
|
||||
|
||||
$repo = (Resolve-Path -LiteralPath (Join-Path $PSScriptRoot "..")).Path
|
||||
$validator = Join-Path $repo "scripts\validate-returned-send-sandbox-package.ps1"
|
||||
|
||||
if (-not (Test-Path -LiteralPath $validator)) {
|
||||
throw "missing validator script: $validator"
|
||||
}
|
||||
if (-not (Test-Path -LiteralPath $FixtureZip)) {
|
||||
throw "missing fixture zip: $FixtureZip"
|
||||
}
|
||||
|
||||
$output = & powershell -NoProfile -ExecutionPolicy Bypass -File $validator -PackagePath $FixtureZip
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "validator failed with exit code $LASTEXITCODE"
|
||||
}
|
||||
$output | ForEach-Object { Write-Host $_ }
|
||||
$lastLine = @($output | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) | Select-Object -Last 1
|
||||
$result = $lastLine | ConvertFrom-Json
|
||||
|
||||
if ($result.ok -ne $true) {
|
||||
throw "validator ok mismatch: $($result.ok)"
|
||||
}
|
||||
if ($result.partial_evidence_usable -ne $true) {
|
||||
throw "partial_evidence_usable mismatch: $($result.partial_evidence_usable)"
|
||||
}
|
||||
if ($result.r6d_gate_pass -ne $false) {
|
||||
throw "r6d_gate_pass mismatch: $($result.r6d_gate_pass)"
|
||||
}
|
||||
if ($result.capability_test_ok -ne $true) {
|
||||
throw "capability_test_ok mismatch: $($result.capability_test_ok)"
|
||||
}
|
||||
if ($result.capability_tool_count -ne 9) {
|
||||
throw "capability_tool_count mismatch: $($result.capability_tool_count)"
|
||||
}
|
||||
if ($result.content_hash_matches -ne $true) {
|
||||
throw "content_hash_matches mismatch: $($result.content_hash_matches)"
|
||||
}
|
||||
if ($result.operator_observed_success -ne $true) {
|
||||
throw "operator_observed_success mismatch: $($result.operator_observed_success)"
|
||||
}
|
||||
if ($result.has_after_probe -ne $false) {
|
||||
throw "has_after_probe mismatch: $($result.has_after_probe)"
|
||||
}
|
||||
if ($result.production_send_enabled -ne $false) {
|
||||
throw "production_send_enabled mismatch: $($result.production_send_enabled)"
|
||||
}
|
||||
|
||||
[ordered]@{
|
||||
ok = $true
|
||||
fixture = $FixtureZip
|
||||
partial_evidence_usable = $result.partial_evidence_usable
|
||||
r6d_gate_pass = $result.r6d_gate_pass
|
||||
capability_tool_count = $result.capability_tool_count
|
||||
production_send_enabled = $result.production_send_enabled
|
||||
} | ConvertTo-Json -Depth 4 -Compress
|
||||
165
scripts/validate-returned-send-sandbox-package.ps1
Normal file
165
scripts/validate-returned-send-sandbox-package.ps1
Normal file
@@ -0,0 +1,165 @@
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$PackagePath,
|
||||
[string]$WorkDir = ""
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
Set-StrictMode -Version Latest
|
||||
|
||||
function ConvertTo-Sha256Hex([string]$Text) {
|
||||
$bytes = [System.Text.Encoding]::UTF8.GetBytes($Text)
|
||||
$sha = [System.Security.Cryptography.SHA256]::Create()
|
||||
try {
|
||||
return -join ($sha.ComputeHash($bytes) | ForEach-Object { $_.ToString("x2") })
|
||||
}
|
||||
finally {
|
||||
$sha.Dispose()
|
||||
}
|
||||
}
|
||||
|
||||
function Read-FirstJsonLine([string]$Path) {
|
||||
if (-not (Test-Path -LiteralPath $Path)) {
|
||||
return $null
|
||||
}
|
||||
foreach ($line in Get-Content -LiteralPath $Path) {
|
||||
$trimmed = $line.Trim()
|
||||
if ($trimmed.StartsWith("{") -and $trimmed.EndsWith("}")) {
|
||||
return ($trimmed | ConvertFrom-Json)
|
||||
}
|
||||
}
|
||||
return $null
|
||||
}
|
||||
|
||||
function Test-NonEmptyString($Value) {
|
||||
if ($null -eq $Value) {
|
||||
return $false
|
||||
}
|
||||
return -not [string]::IsNullOrWhiteSpace([string]$Value)
|
||||
}
|
||||
|
||||
if (-not (Test-Path -LiteralPath $PackagePath)) {
|
||||
throw "package not found: $PackagePath"
|
||||
}
|
||||
|
||||
$resolvedPackage = (Resolve-Path -LiteralPath $PackagePath).Path
|
||||
$cleanup = $false
|
||||
if ([string]::IsNullOrWhiteSpace($WorkDir)) {
|
||||
$WorkDir = Join-Path ([System.IO.Path]::GetTempPath()) ("isphere-returned-send-sandbox-" + [guid]::NewGuid().ToString("N"))
|
||||
$cleanup = $true
|
||||
}
|
||||
|
||||
if (Test-Path -LiteralPath $WorkDir) {
|
||||
Remove-Item -LiteralPath $WorkDir -Recurse -Force
|
||||
}
|
||||
New-Item -ItemType Directory -Force -Path $WorkDir | Out-Null
|
||||
|
||||
try {
|
||||
if ($resolvedPackage.EndsWith(".zip", [System.StringComparison]::OrdinalIgnoreCase)) {
|
||||
Expand-Archive -LiteralPath $resolvedPackage -DestinationPath $WorkDir -Force
|
||||
$root = $WorkDir
|
||||
}
|
||||
else {
|
||||
$root = $resolvedPackage
|
||||
}
|
||||
|
||||
$allFiles = Get-ChildItem -LiteralPath $root -Recurse -File
|
||||
$inputsFile = $allFiles | Where-Object { $_.Name -like "SANDBOX-SEND-INPUTS*.json" } | Sort-Object FullName | Select-Object -First 1
|
||||
if (-not $inputsFile) {
|
||||
throw "missing SANDBOX-SEND-INPUTS json"
|
||||
}
|
||||
$inputs = Get-Content -LiteralPath $inputsFile.FullName -Raw | ConvertFrom-Json
|
||||
|
||||
$capabilityLog = $allFiles | Where-Object { $_.Name -like "*capability-test*.txt" -or $_.Name -like "*capability*.log" } | Sort-Object FullName | Select-Object -First 1
|
||||
$capability = $null
|
||||
if ($capabilityLog) {
|
||||
$capability = Read-FirstJsonLine $capabilityLog.FullName
|
||||
}
|
||||
|
||||
$liveProbeZips = @($allFiles | Where-Object { $_.Name -like "isphere-live-probe-*.zip" })
|
||||
$beforeMarkers = @($allFiles | Where-Object { $_.FullName -match "\\before\\" -or $_.FullName -match "/before/" -or $_.Name -like "*before*" })
|
||||
$afterMarkers = @($allFiles | Where-Object { $_.FullName -match "\\after\\" -or $_.FullName -match "/after/" -or $_.Name -like "*after*" })
|
||||
|
||||
$contentText = [string]$inputs.content_text_to_send
|
||||
$expectedHash = [string]$inputs.content_sha256
|
||||
$actualHash = ConvertTo-Sha256Hex $contentText
|
||||
$contentHashMatches = ($actualHash -eq $expectedHash)
|
||||
|
||||
$capabilityOK = $false
|
||||
$capabilityToolCount = 0
|
||||
$productionSendEnabled = $false
|
||||
if ($null -ne $capability) {
|
||||
$capabilityOK = ($capability.ok -eq $true)
|
||||
if ($null -ne $capability.tool_count) {
|
||||
$capabilityToolCount = [int]$capability.tool_count
|
||||
}
|
||||
if ($null -ne $capability.production_send_enabled) {
|
||||
$productionSendEnabled = [bool]$capability.production_send_enabled
|
||||
}
|
||||
}
|
||||
|
||||
$hasExplicitTarget = (Test-NonEmptyString $inputs.sandbox_target_type) -and (Test-NonEmptyString $inputs.sandbox_target_id)
|
||||
$hasIdempotencyKey = Test-NonEmptyString $inputs.idempotency_key
|
||||
$hasSuccessRecord = Test-NonEmptyString $inputs.success_ack_or_sent_record
|
||||
$manualStartPresent = Test-NonEmptyString $inputs.manual_send_started_at_local
|
||||
$manualFinishPresent = Test-NonEmptyString $inputs.manual_send_finished_at_local
|
||||
$operatorSuccess = ($inputs.operator_observed_success -eq $true)
|
||||
$noSecondSend = ($inputs.do_not_send_second_time_confirmed -eq $true)
|
||||
$hasBeforeProbe = ($liveProbeZips.Count -gt 0 -or $beforeMarkers.Count -gt 0)
|
||||
$hasAfterProbe = ($afterMarkers.Count -gt 0)
|
||||
|
||||
$partialUsable = (
|
||||
$capabilityOK -and
|
||||
$capabilityToolCount -eq 9 -and
|
||||
-not $productionSendEnabled -and
|
||||
$hasExplicitTarget -and
|
||||
$contentHashMatches -and
|
||||
$hasIdempotencyKey -and
|
||||
$operatorSuccess -and
|
||||
$hasSuccessRecord -and
|
||||
$noSecondSend -and
|
||||
$hasBeforeProbe
|
||||
)
|
||||
|
||||
$r6dGatePass = (
|
||||
$partialUsable -and
|
||||
$manualStartPresent -and
|
||||
$manualFinishPresent -and
|
||||
$hasAfterProbe
|
||||
)
|
||||
|
||||
$missing = New-Object System.Collections.Generic.List[string]
|
||||
if (-not $manualStartPresent) { $missing.Add("manual_send_started_at_local") }
|
||||
if (-not $manualFinishPresent) { $missing.Add("manual_send_finished_at_local") }
|
||||
if (-not $hasAfterProbe) { $missing.Add("after_recorder_output") }
|
||||
|
||||
[ordered]@{
|
||||
ok = $true
|
||||
package = $resolvedPackage
|
||||
input_file_name = $inputsFile.Name
|
||||
partial_evidence_usable = $partialUsable
|
||||
r6d_gate_pass = $r6dGatePass
|
||||
target_type_present = Test-NonEmptyString $inputs.sandbox_target_type
|
||||
target_id_present = Test-NonEmptyString $inputs.sandbox_target_id
|
||||
content_hash_matches = $contentHashMatches
|
||||
idempotency_key_present = $hasIdempotencyKey
|
||||
operator_observed_success = $operatorSuccess
|
||||
success_ack_or_sent_record_present = $hasSuccessRecord
|
||||
do_not_send_second_time_confirmed = $noSecondSend
|
||||
manual_send_started_at_local_present = $manualStartPresent
|
||||
manual_send_finished_at_local_present = $manualFinishPresent
|
||||
capability_test_ok = $capabilityOK
|
||||
capability_tool_count = $capabilityToolCount
|
||||
production_send_enabled = $productionSendEnabled
|
||||
has_before_probe = $hasBeforeProbe
|
||||
has_after_probe = $hasAfterProbe
|
||||
live_probe_zip_count = $liveProbeZips.Count
|
||||
missing_for_full_gate = @($missing)
|
||||
decision = if ($r6dGatePass) { "full_gate_pass" } elseif ($partialUsable) { "partial_use_only" } else { "not_usable" }
|
||||
} | ConvertTo-Json -Depth 6 -Compress
|
||||
}
|
||||
finally {
|
||||
if ($cleanup -and (Test-Path -LiteralPath $WorkDir)) {
|
||||
Remove-Item -LiteralPath $WorkDir -Recurse -Force
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user