Files
story/scripts/smoke-ci-supply-chain-conformance.ps1
T

47 lines
3.5 KiB
PowerShell

$ErrorActionPreference = 'Stop'
$root = Split-Path -Parent $PSScriptRoot
$temporaryRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("voice-ci-conformance-" + [guid]::NewGuid().ToString('N'))
New-Item -ItemType Directory -Path $temporaryRoot | Out-Null
try {
$candidate = '0.64.0-rc.local'
$buildDigest = 'sha256:' + ('a' * 64)
$sourceCommit = '1' * 40
$checks = @('GO_FORMAT','GO_VET_TEST','OPENAPI_GENERATION','WEB_TYPECHECK_BUILD','COMPOSE_VALIDATION','BACKEND_IMAGE_BUILD','WEB_IMAGE_BUILD','GO_VULNERABILITY_LICENSE','FRONTEND_VULNERABILITY_LICENSE','REPOSITORY_SECRET_SCAN','INFRASTRUCTURE_CONFIG_SCAN','BACKEND_IMAGE_SCAN','WEB_IMAGE_SCAN','CYCLONEDX_SBOM')
$capture = [ordered]@{
schema_version = 'remote-ci-supply-chain-capture-v1'; evidence_source = 'LOCAL_TOOLCHAIN'; candidate_version = $candidate
build_digest = $buildDigest; source_commit = $sourceCommit; provider = 'LOCAL_GO_TEST'; repository_ref = 'local:workspace'
workflow_ref = '.github/workflows/ci.yml'; run_id = 'local-smoke'; run_url = 'https://example.invalid/local-smoke'
trigger = 'WORKFLOW_DISPATCH'; ref = 'local-worktree'; attempt = 1; conclusion = 'SUCCESS'
started_at = '2026-08-25T08:00:00Z'; completed_at = '2026-08-25T08:01:00Z'; collected_at = '2026-08-25T08:02:00Z'
executed_by_ref = 'local-developer'; reviewed_by_ref = 'local-reviewer'; review_ref = 'local-toolchain-only'
checks = @($checks | ForEach-Object { [ordered]@{code=$_; status='PASS'; evidence_ref="local:test/$($_.ToLower())"} })
images = @(
[ordered]@{subject='BACKEND_IMAGE'; reference='local:backend'; digest=('sha256:' + ('b' * 64)); evidence_ref='local:image/backend'},
[ordered]@{subject='WEB_IMAGE'; reference='local:web'; digest=('sha256:' + ('c' * 64)); evidence_ref='local:image/web'}
)
sboms = @(
[ordered]@{subject='SOURCE'; format='CYCLONEDX_JSON'; digest=('sha256:' + ('d' * 64)); evidence_ref='local:sbom/source'},
[ordered]@{subject='BACKEND_IMAGE'; format='CYCLONEDX_JSON'; digest=('sha256:' + ('e' * 64)); evidence_ref='local:sbom/backend'},
[ordered]@{subject='WEB_IMAGE'; format='CYCLONEDX_JSON'; digest=('sha256:' + ('f' * 64)); evidence_ref='local:sbom/web'}
)
}
$capturePath = Join-Path $temporaryRoot 'capture.json'
$reportPath = Join-Path $temporaryRoot 'report.json'
$captureJson = $capture | ConvertTo-Json -Depth 8
[System.IO.File]::WriteAllText($capturePath, $captureJson, (New-Object System.Text.UTF8Encoding($false)))
Push-Location $root
try {
& go run ./cmd/ci-supply-chain-conformance -capture $capturePath -candidate-version $candidate -build-digest $buildDigest -source-commit $sourceCommit -output $reportPath
if ($LASTEXITCODE -ne 0) { throw 'Local CI supply-chain conformance command failed' }
} finally { Pop-Location }
$reportJson = [System.IO.File]::ReadAllText($reportPath, (New-Object System.Text.UTF8Encoding($false)))
$report = $reportJson | ConvertFrom-Json
if ($report.result -ne 'PASS' -or $report.evidence_scope -ne 'LOCAL_CI_TOOLCHAIN' -or -not $report.external_validation_required -or @($report.completed_checks).Count -ne 14 -or @($report.image_digests.PSObject.Properties).Count -ne 2 -or @($report.sbom_digests.PSObject.Properties).Count -ne 3) {
throw 'Local toolchain report must not satisfy the remote CI supply-chain gate'
}
Write-Host 'CI supply-chain toolchain smoke passed: checks=14 images=2 sboms=3 external_validation_required=true.'
} finally {
if (Test-Path -LiteralPath $temporaryRoot) { Remove-Item -LiteralPath $temporaryRoot -Recurse -Force }
}