docs: accept partial send sandbox evidence

This commit is contained in:
zhaoyilun
2026-07-10 19:11:52 +08:00
parent 89d7f65b45
commit 138615a29c
7 changed files with 446 additions and 6 deletions

View 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

View 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
}
}