[CmdletBinding()]
|
param(
|
[Parameter(Mandatory = $true)][string]$ProjectRoot,
|
[Parameter(Mandatory = $true)][string]$RunRoot,
|
[Parameter(Mandatory = $true)][string]$CscPath,
|
[Parameter(Mandatory = $true)][string]$ExpectedVectorsPath
|
)
|
|
Set-StrictMode -Version Latest
|
$ErrorActionPreference = 'Stop'
|
|
$runId = 'RUN-DEV-ANA-SEMI-ROOT-PREFLIGHT-V007-REPAIR-IMPLEMENTATION-20260725-001'
|
$authorizationId = 'AUTH-DEV-ANA-SEMI-ROOT-PREFLIGHT-V007-REPAIR-IMPLEMENTATION-20260725-001'
|
$attemptId = 'HANDOFF-MGADMIN-DEV-ANA-SEMI-ROOT-PREFLIGHT-V007-REPAIR-IMPLEMENTATION-AUTH-20260725-001-A001'
|
$expectedProjectRoot = 'E:\mb-ms-doc\project-info'
|
$expectedRunRoot = 'E:\mb-ms-doc\project-info\dev\ana-dev\tmp\RUN-DEV-ANA-SEMI-ROOT-PREFLIGHT-V007-REPAIR-IMPLEMENTATION-20260725-001'
|
$expectedCsc = 'C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe'
|
$expectedVectors = 'E:\mb-ms-doc\project-info\dev\ana-dev\test\V007ExpectedVectors.R1.json'
|
$emptySha = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
|
|
function Get-Sha256Bytes([byte[]]$Bytes) {
|
$sha = [Security.Cryptography.SHA256]::Create()
|
try { return ([BitConverter]::ToString($sha.ComputeHash($Bytes)).Replace('-', '').ToLowerInvariant()) }
|
finally { $sha.Dispose() }
|
}
|
function Get-Sha256File([string]$Path) {
|
$stream = [IO.File]::Open($Path, [IO.FileMode]::Open, [IO.FileAccess]::Read, [IO.FileShare]::None)
|
try {
|
$sha = [Security.Cryptography.SHA256]::Create()
|
try { return ([BitConverter]::ToString($sha.ComputeHash($stream)).Replace('-', '').ToLowerInvariant()) }
|
finally { $sha.Dispose() }
|
}
|
finally { $stream.Dispose() }
|
}
|
function Get-ArgvHash([string[]]$Argv) {
|
$stream = New-Object IO.MemoryStream
|
try {
|
$domain = [Text.Encoding]::UTF8.GetBytes('ANA-SEMI-ARGV-V001')
|
$stream.Write($domain, 0, $domain.Length)
|
foreach ($token in $Argv) {
|
$stream.WriteByte(0)
|
$bytes = [Text.Encoding]::UTF8.GetBytes($token)
|
$stream.Write($bytes, 0, $bytes.Length)
|
}
|
return Get-Sha256Bytes $stream.ToArray()
|
}
|
finally { $stream.Dispose() }
|
}
|
function Quote-WindowsToken([string]$Token) {
|
if ($Token.Length -gt 0 -and $Token.IndexOfAny([char[]]@(' ', [char]9, '"')) -lt 0) { return $Token }
|
$builder = New-Object Text.StringBuilder
|
[void]$builder.Append('"')
|
$slashes = 0
|
foreach ($ch in $Token.ToCharArray()) {
|
if ($ch -eq '\') { $slashes++; continue }
|
if ($ch -eq '"') {
|
[void]$builder.Append(('\' * (($slashes * 2) + 1)))
|
[void]$builder.Append('"')
|
$slashes = 0
|
continue
|
}
|
if ($slashes -gt 0) { [void]$builder.Append(('\' * $slashes)); $slashes = 0 }
|
[void]$builder.Append($ch)
|
}
|
if ($slashes -gt 0) { [void]$builder.Append(('\' * ($slashes * 2))) }
|
[void]$builder.Append('"')
|
return $builder.ToString()
|
}
|
function Join-WindowsArguments([string[]]$Arguments) {
|
return [string]::Join(' ', @($Arguments | ForEach-Object { Quote-WindowsToken $_ }))
|
}
|
function Write-Utf8LfCreateNew([string]$Path, [string]$Text) {
|
$normalized = $Text.Replace([char]13, '').TrimEnd([char]10) + [char]10
|
$bytes = (New-Object Text.UTF8Encoding($false, $true)).GetBytes($normalized)
|
$stream = New-Object IO.FileStream($Path, [IO.FileMode]::CreateNew, [IO.FileAccess]::Write, [IO.FileShare]::None)
|
try { $stream.Write($bytes, 0, $bytes.Length); $stream.Flush($true) }
|
finally { $stream.Dispose() }
|
}
|
function Escape-Csv([AllowNull()][string]$Value) {
|
if ($null -eq $Value) { return '' }
|
if ($Value.IndexOfAny([char[]]@(',', '"', [char]13, [char]10)) -ge 0) { return '"' + $Value.Replace('"', '""') + '"' }
|
return $Value
|
}
|
function Assert-CanonicalSource([string]$Path, [bool]$Json) {
|
$bytes = [IO.File]::ReadAllBytes($Path)
|
if ($bytes.Length -eq 0) { throw 'STOP_VALIDATION_PRECHECK' }
|
if ($bytes.Length -ge 3 -and $bytes[0] -eq 239 -and $bytes[1] -eq 187 -and $bytes[2] -eq 191) { throw 'STOP_VALIDATION_PRECHECK' }
|
if (@($bytes | Where-Object { $_ -eq 13 }).Count -ne 0) { throw 'STOP_VALIDATION_PRECHECK' }
|
[void](New-Object Text.UTF8Encoding($false, $true)).GetString($bytes)
|
if ($Json) {
|
if ($bytes[-1] -eq 10) { throw 'STOP_VALIDATION_PRECHECK' }
|
}
|
elseif ($bytes[-1] -ne 10 -or ($bytes.Length -gt 1 -and $bytes[-2] -eq 10)) { throw 'STOP_VALIDATION_PRECHECK' }
|
}
|
function Get-StopCode([Management.Automation.ErrorRecord]$Record) {
|
if ($null -ne $Record.Exception -and $Record.Exception.Data.Contains('StopCode')) { return [string]$Record.Exception.Data['StopCode'] }
|
if ($null -ne $Record.Exception -and -not [string]::IsNullOrEmpty($Record.Exception.Message)) { return [string]$Record.Exception.Message }
|
return 'STOP_UNKNOWN_CODE'
|
}
|
|
try {
|
if ([IO.Path]::GetFullPath($ProjectRoot) -cne $expectedProjectRoot -or
|
[IO.Path]::GetFullPath($RunRoot) -cne $expectedRunRoot -or
|
[IO.Path]::GetFullPath($CscPath) -cne $expectedCsc -or
|
[IO.Path]::GetFullPath($ExpectedVectorsPath) -cne $expectedVectors -or
|
(Test-Path -LiteralPath $RunRoot)) { exit 11 }
|
if ((Get-Item -LiteralPath $CscPath).Length -ne 2569696 -or
|
(Get-Sha256File $CscPath) -cne 'aae1db57f898ca8bda18590c56f86ced6d0ead80c22033b76fdfe9119706f116') { exit 11 }
|
|
$relativeSources = @(
|
'dev/ana-dev/AnaSemi.NativeProcessRunnerV006.R1.cs',
|
'dev/ana-dev/AnaSemi.JcsEvidenceWriterV001.psm1',
|
'dev/ana-dev/Invoke-AnaSemiWrapperSelftestV006.R1.ps1',
|
'dev/ana-dev/synthetic-child-v006-r1.ps1',
|
'dev/ana-dev/test/Test-AnaSemiNativeProcessRunnerV006.R1.Static.ps1',
|
'dev/ana-dev/test/Test-InvokeAnaSemiWrapperSelftestV006.R1.Static.ps1',
|
'dev/ana-dev/test/V007ExpectedVectors.R1.json',
|
'dev/ana-dev/test/Invoke-AnaSemiImplementationValidationV002.ps1'
|
)
|
for ($index = 0; $index -lt $relativeSources.Count; $index++) {
|
$path = Join-Path $ProjectRoot $relativeSources[$index]
|
if (-not (Test-Path -LiteralPath $path -PathType Leaf)) { exit 11 }
|
Assert-CanonicalSource $path ($index -eq 6)
|
}
|
$modulePath = Join-Path $ProjectRoot $relativeSources[1]
|
$module = Import-Module -Name $modulePath -Force -PassThru
|
$moduleMatches = @(Get-Module | Where-Object { [IO.Path]::GetFullPath($_.Path) -ceq [IO.Path]::GetFullPath($modulePath) })
|
if ($moduleMatches.Count -ne 1) { exit 11 }
|
$exports = @($module.ExportedFunctions.Keys)
|
[Array]::Sort($exports, [StringComparer]::Ordinal)
|
if ([string]::Join([char]0, $exports) -cne 'ConvertTo-AnaSemiJcsUtf8BytesV001' + [char]0 + 'Test-AnaSemiJcsFileV001' + [char]0 + 'Write-AnaSemiJcsCreateNewV001') { exit 11 }
|
|
$vectors = [IO.File]::ReadAllText($ExpectedVectorsPath, (New-Object Text.UTF8Encoding($false, $true))) | ConvertFrom-Json
|
if ($vectors.schema_id -cne 'ANA-SEMI-V007-EXPECTED-VECTORS-R1-JCS-V001') { exit 11 }
|
|
foreach ($directory in @('staging','build','process','test','receipt','manifest')) {
|
[void][IO.Directory]::CreateDirectory((Join-Path $RunRoot $directory))
|
}
|
$stagingPath = Join-Path $RunRoot 'staging/AnaSemi.NativeProcessRunnerV006.dll'
|
$publishedPath = Join-Path $RunRoot 'build/AnaSemi.NativeProcessRunnerV006.dll'
|
$stdoutPath = Join-Path $RunRoot 'process/csc.stdout.bin'
|
$stderrPath = Join-Path $RunRoot 'process/csc.stderr.bin'
|
$processResultPath = Join-Path $RunRoot 'process/csc.result.json'
|
$l0Path = Join-Path $RunRoot 'test/l0-static.json'
|
$l1Path = Join-Path $RunRoot 'test/l1-contract.json'
|
$jcsContractPath = Join-Path $RunRoot 'test/jcs-canonical-contract.json'
|
$closureContractPath = Join-Path $RunRoot 'test/l0-failure-closure-contract.json'
|
$terminalPath = Join-Path $RunRoot 'process/validation-terminal.json'
|
$receiptPath = Join-Path $RunRoot 'receipt/implementation-receipt.md'
|
$manifestPath = Join-Path $RunRoot 'manifest/implementation-source-manifest.csv'
|
foreach ($path in @($stagingPath,$publishedPath,$stdoutPath,$stderrPath,$processResultPath,$l0Path,$l1Path,$jcsContractPath,$closureContractPath,$terminalPath,$receiptPath,$manifestPath)) {
|
if (Test-Path -LiteralPath $path) { exit 11 }
|
}
|
|
$jcsRows = New-Object Collections.Generic.List[object]
|
$jcsMismatch = 0
|
foreach ($row in @($vectors.jcs_contract.rows)) {
|
$bytes = [Convert]::FromBase64String([string]$row.base64)
|
$actualStatus = 'PASS'
|
$actualStop = $null
|
try {
|
if ([string]$row.case_id -ceq 'NEG-CREATE-NEW-CONFLICT') {
|
[void](Write-AnaSemiJcsCreateNewV001 -Path $ExpectedVectorsPath -Value ([ordered]@{ conflict = $true }))
|
}
|
else {
|
[void](& $module { param([byte[]]$InputBytes) Test-AnaSemiJcsBytesInternalV001 -Bytes $InputBytes } $bytes)
|
}
|
}
|
catch {
|
$actualStatus = 'STOP'
|
$actualStop = Get-StopCode $_
|
}
|
$hash = Get-Sha256Bytes $bytes
|
$passed = ($bytes.Length -eq [int]$row.preimage_bytes -and $hash -ceq [string]$row.preimage_sha256 -and
|
$actualStatus -ceq [string]$row.expected_status -and
|
(($null -eq $row.expected_stop_code -and $null -eq $actualStop) -or ([string]$row.expected_stop_code -ceq $actualStop)))
|
if (-not $passed) { $jcsMismatch++ }
|
[void]$jcsRows.Add([ordered]@{
|
actual_status = $actualStatus
|
actual_stop_code = $actualStop
|
case_id = [string]$row.case_id
|
expected_status = [string]$row.expected_status
|
expected_stop_code = if ($null -eq $row.expected_stop_code) { $null } else { [string]$row.expected_stop_code }
|
passed = [bool]$passed
|
preimage_bytes = [uint64]$bytes.Length
|
preimage_sha256 = $hash
|
})
|
}
|
$jcsResult = [ordered]@{
|
case_count = [uint16]$jcsRows.Count
|
cases = $jcsRows.ToArray()
|
mismatch_count = [uint16]$jcsMismatch
|
run_id = $runId
|
schema_id = 'ANA-SEMI-JCS-CONTRACT-RESULT-V001'
|
status = if ($jcsMismatch -eq 0 -and $jcsRows.Count -eq 12) { 'CONTRACT_PASS' } else { 'CONTRACT_FAIL' }
|
}
|
[void](Write-AnaSemiJcsCreateNewV001 -Path $jcsContractPath -Value $jcsResult)
|
if ($jcsMismatch -ne 0 -or $jcsRows.Count -ne 12) { exit 11 }
|
|
$closureRows = New-Object Collections.Generic.List[object]
|
$closureMismatch = 0
|
foreach ($row in @($vectors.closure_contract.rows)) {
|
$expectedBytes = (New-Object Text.UTF8Encoding($false, $true)).GetBytes([string]$row.canonical_preimage)
|
$actualBytes = ConvertTo-AnaSemiJcsUtf8BytesV001 -Value $row.value
|
$passed = ($expectedBytes.Length -eq $actualBytes.Length -and (Get-Sha256Bytes $expectedBytes) -ceq (Get-Sha256Bytes $actualBytes))
|
if (-not $passed) { $closureMismatch++ }
|
[void]$closureRows.Add([ordered]@{
|
canonical_bytes = [uint64]$actualBytes.Length
|
canonical_sha256 = Get-Sha256Bytes $actualBytes
|
case_id = [string]$row.case_id
|
passed = [bool]$passed
|
})
|
}
|
$literalCount = 0
|
foreach ($set in @($vectors.closure_vectors.rows) + @($vectors.native_final_examples.rows)) {
|
$actualBytes = ConvertTo-AnaSemiJcsUtf8BytesV001 -Value $set.value
|
$passed = ($actualBytes.Length -eq [int]$set.canonical_bytes -and (Get-Sha256Bytes $actualBytes) -ceq [string]$set.canonical_sha256)
|
if (-not $passed) { $closureMismatch++ }
|
$literalCount++
|
}
|
$passNative = @($vectors.native_final_examples.rows | Where-Object { $_.object_id -ceq 'B0-C0-PASS' })[0].value
|
if ($passNative.primary_phase -cne 'COMPLETE' -or $passNative.primary_exit_code -ne 0 -or $null -ne $passNative.primary_stop_code) { $closureMismatch++ }
|
$outerUnknown = @($vectors.native_final_examples.rows | Where-Object { $_.object_id -ceq 'B27-C7-OUTER-UNKNOWN' })[0].value
|
if ($outerUnknown.prepackage_terminal_state -cne 'STATE_UNCERTAIN' -or $null -ne $outerUnknown.outer_exit_code -or $outerUnknown.final_exit_code -ne 27) { $closureMismatch++ }
|
$closureResult = [ordered]@{
|
closure_case_count = [uint16]$closureRows.Count
|
closure_cases = $closureRows.ToArray()
|
literal_case_count = [uint16]$literalCount
|
mismatch_count = [uint16]$closureMismatch
|
run_id = $runId
|
schema_id = 'ANA-SEMI-L0-CLOSURE-CONTRACT-RESULT-V001'
|
status = if ($closureMismatch -eq 0 -and $closureRows.Count -eq 8 -and $literalCount -eq 34) { 'CONTRACT_PASS' } else { 'CONTRACT_FAIL' }
|
}
|
[void](Write-AnaSemiJcsCreateNewV001 -Path $closureContractPath -Value $closureResult)
|
if ($closureMismatch -ne 0 -or $closureRows.Count -ne 8 -or $literalCount -ne 34) { exit 11 }
|
|
$cscArgv = [string[]]@(
|
$CscPath,'/nologo','/target:library','/optimize+','/debug-','/checked+','/platform:anycpu','/warnaserror+','/utf8output',
|
('/out:' + $stagingPath),(Join-Path $ProjectRoot $relativeSources[0])
|
)
|
$cscArgvHash = Get-ArgvHash $cscArgv
|
if ($cscArgv.Count -ne 11 -or $cscArgvHash -cne 'd80313814b3aa19fa559e9ee0ec50e58fc78f87f9405d77a73e156ec95865a6e') { exit 11 }
|
|
$stdoutStream = New-Object IO.FileStream($stdoutPath, [IO.FileMode]::CreateNew, [IO.FileAccess]::Write, [IO.FileShare]::Read)
|
$stderrStream = New-Object IO.FileStream($stderrPath, [IO.FileMode]::CreateNew, [IO.FileAccess]::Write, [IO.FileShare]::Read)
|
$process = New-Object Diagnostics.Process
|
$startedAt = [DateTimeOffset]::UtcNow
|
$started = $false
|
try {
|
$startInfo = New-Object Diagnostics.ProcessStartInfo
|
$startInfo.FileName = $CscPath
|
$startInfo.Arguments = Join-WindowsArguments $cscArgv[1..10]
|
$startInfo.UseShellExecute = $false
|
$startInfo.CreateNoWindow = $true
|
$startInfo.RedirectStandardOutput = $true
|
$startInfo.RedirectStandardError = $true
|
$process.StartInfo = $startInfo
|
try { $started = $process.Start() } catch { $started = $false }
|
if (-not $started) {
|
$stdoutStream.Flush($true); $stderrStream.Flush($true)
|
$stdoutStream.Dispose(); $stderrStream.Dispose(); $process.Dispose()
|
exit 12
|
}
|
$stdoutTask = $process.StandardOutput.BaseStream.CopyToAsync($stdoutStream)
|
$stderrTask = $process.StandardError.BaseStream.CopyToAsync($stderrStream)
|
if (-not $process.WaitForExit(60000)) {
|
try { $process.Kill() } catch {}
|
if (-not $process.WaitForExit(10000)) { exit 27 }
|
[void]$stdoutTask.GetAwaiter().GetResult(); [void]$stderrTask.GetAwaiter().GetResult()
|
$stdoutStream.Flush($true); $stderrStream.Flush($true)
|
$stdoutStream.Dispose(); $stderrStream.Dispose()
|
exit 13
|
}
|
[void]$stdoutTask.GetAwaiter().GetResult(); [void]$stderrTask.GetAwaiter().GetResult()
|
$stdoutStream.Flush($true); $stderrStream.Flush($true)
|
$stdoutStream.Dispose(); $stderrStream.Dispose()
|
$finishedAt = [DateTimeOffset]::UtcNow
|
$processId = [uint32]$process.Id
|
$cscExit = [int32]$process.ExitCode
|
}
|
finally {
|
if ($null -ne $stdoutStream) { try { $stdoutStream.Dispose() } catch {} }
|
if ($null -ne $stderrStream) { try { $stderrStream.Dispose() } catch {} }
|
if ($null -ne $process) { $process.Dispose() }
|
}
|
if ($cscExit -ne 0) { exit 14 }
|
if ((Get-Item -LiteralPath $stdoutPath).Length -ne 0 -or (Get-Item -LiteralPath $stderrPath).Length -ne 0) { exit 15 }
|
if (-not (Test-Path -LiteralPath $stagingPath -PathType Leaf)) { exit 15 }
|
$stagingName = [Reflection.AssemblyName]::GetAssemblyName($stagingPath)
|
if ($stagingName.Name -cne 'AnaSemi.NativeProcessRunnerV006' -or $stagingName.Version.ToString() -cne '1.0.0.0') { exit 15 }
|
$stagingInfo = Get-Item -LiteralPath $stagingPath
|
$stagingHash = Get-Sha256File $stagingPath
|
|
try {
|
$source = [IO.File]::Open($stagingPath, [IO.FileMode]::Open, [IO.FileAccess]::Read, [IO.FileShare]::None)
|
$target = New-Object IO.FileStream($publishedPath, [IO.FileMode]::CreateNew, [IO.FileAccess]::Write, [IO.FileShare]::None)
|
try { $source.CopyTo($target); $target.Flush($true) }
|
finally { $target.Dispose(); $source.Dispose() }
|
$publishedInfo = Get-Item -LiteralPath $publishedPath
|
$publishedHash = Get-Sha256File $publishedPath
|
if ($publishedInfo.Length -ne $stagingInfo.Length -or $publishedHash -cne $stagingHash) { exit 16 }
|
}
|
catch { exit 16 }
|
|
$processResult = [ordered]@{
|
argv_count = [uint16]11
|
argv_sha256 = $cscArgvHash
|
child_liveness = 'EXITED'
|
exit_code = [int32]0
|
finished_at = $finishedAt.ToString('o')
|
process_id = $processId
|
process_started = $true
|
publish_bytes = [uint64]$publishedInfo.Length
|
publish_path = $publishedPath
|
publish_sha256 = $publishedHash
|
schema_id = 'ANA-SEMI-IMPLEMENTATION-PROCESS-RESULT-JCS-V003'
|
staging_bytes = [uint64]$stagingInfo.Length
|
staging_path = $stagingPath
|
staging_sha256 = $stagingHash
|
started_at = $startedAt.ToString('o')
|
status = 'PASS'
|
stderr_bytes = [uint64]0
|
stderr_path = $stderrPath
|
stderr_sha256 = $emptySha
|
stdout_bytes = [uint64]0
|
stdout_path = $stdoutPath
|
stdout_sha256 = $emptySha
|
stop_code = $null
|
timed_out = $false
|
tool_bytes = [uint64]2569696
|
tool_path = $CscPath
|
tool_sha256 = 'aae1db57f898ca8bda18590c56f86ced6d0ead80c22033b76fdfe9119706f116'
|
}
|
[void](Write-AnaSemiJcsCreateNewV001 -Path $processResultPath -Value $processResult)
|
|
$resolvedPublished = [IO.Path]::GetFullPath($publishedPath)
|
$before = @([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GetName().Name -ceq 'AnaSemi.NativeProcessRunnerV006' })
|
if ($before.Count -ne 0) { exit 18 }
|
try { $assembly = [Reflection.Assembly]::LoadFile($resolvedPublished) } catch { exit 19 }
|
if ($null -eq $assembly -or $assembly.FullName -cne 'AnaSemi.NativeProcessRunnerV006, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' -or
|
[IO.Path]::GetFullPath($assembly.Location) -cne $resolvedPublished) { exit 21 }
|
$after = @([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GetName().Name -ceq 'AnaSemi.NativeProcessRunnerV006' })
|
if ($after.Count -ne 1 -or -not [object]::ReferenceEquals($after[0], $assembly)) { exit 20 }
|
$expectedTypes = @('AnaSemi.NativeProcessContractExceptionV006','AnaSemi.NativeProcessResultV006','AnaSemi.NativeProcessRunnerV006','AnaSemi.ProcessResultEnvelopeValidatorV006','AnaSemi.ProcessResultSidecarCsvV006','AnaSemi.WindowsCommandLineV006')
|
$actualTypes = @($assembly.GetExportedTypes() | ForEach-Object { $_.FullName })
|
[Array]::Sort($expectedTypes, [StringComparer]::Ordinal)
|
[Array]::Sort($actualTypes, [StringComparer]::Ordinal)
|
if ([string]::Join([char]0, $expectedTypes) -cne [string]::Join([char]0, $actualTypes)) { exit 21 }
|
|
$l0Module = Join-Path $ProjectRoot $relativeSources[4]
|
$l1Module = Join-Path $ProjectRoot $relativeSources[5]
|
$dot0 = @(. $l0Module)
|
if ($dot0.Count -ne 0) { exit 22 }
|
try {
|
$out0 = @(Invoke-AnaSemiL0StaticValidationV001 -ProjectRoot $ProjectRoot -RunnerAssemblyPath $publishedPath -ExpectedVectorsPath $ExpectedVectorsPath -OutputPath $l0Path)
|
if ($out0.Count -ne 0) { exit 22 }
|
}
|
catch { exit 23 }
|
$dot1 = @(. $l1Module)
|
if ($dot1.Count -ne 0) { exit 22 }
|
try {
|
$out1 = @(Invoke-AnaSemiL1ContractValidationV001 -ProjectRoot $ProjectRoot -RunnerAssemblyPath $publishedPath -ExpectedVectorsPath $ExpectedVectorsPath -OutputPath $l1Path)
|
if ($out1.Count -ne 0) { exit 22 }
|
}
|
catch { exit 24 }
|
|
$materializedIds = 1..18 | ForEach-Object { 'R{0:d2}' -f $_ }
|
$terminalResult = [ordered]@{
|
absent_as_of_target_ids = @()
|
as_of_closure_state = 'PRIMARY_CLOSED'
|
as_of_exit_code = [int32]0
|
as_of_phase = 'PRE_PACKAGE_BEFORE_RECEIPT'
|
csc_process_count = [uint16]1
|
credential_count = [uint16]0
|
database_count = [uint16]0
|
harness_process_count = [uint16]0
|
materialized_as_of_target_ids = @($materializedIds)
|
network_count = [uint16]0
|
outer_process_count = [uint16]1
|
primary_evidence_state = 'VALID_PASS'
|
primary_evidence_target_id = 'R15'
|
primary_exit_code = [int32]0
|
primary_phase = 'COMPLETE'
|
primary_stop_code = $null
|
run_id = $runId
|
schema_id = 'ANA-SEMI-IMPLEMENTATION-PREPACKAGE-ASOF-JCS-V002'
|
status = 'PASS'
|
synthetic_child_process_count = [uint16]0
|
}
|
[void](Write-AnaSemiJcsCreateNewV001 -Path $terminalPath -Value $terminalResult)
|
|
$preReceiptPaths = @(
|
(Join-Path $ProjectRoot $relativeSources[0]),(Join-Path $ProjectRoot $relativeSources[1]),
|
(Join-Path $ProjectRoot $relativeSources[2]),(Join-Path $ProjectRoot $relativeSources[3]),
|
(Join-Path $ProjectRoot $relativeSources[4]),(Join-Path $ProjectRoot $relativeSources[5]),
|
(Join-Path $ProjectRoot $relativeSources[6]),(Join-Path $ProjectRoot $relativeSources[7]),
|
$stagingPath,$publishedPath,$stdoutPath,$stderrPath,$processResultPath,$l0Path,$l1Path,$jcsContractPath,$closureContractPath,$terminalPath
|
)
|
$receiptLines = New-Object Collections.Generic.List[string]
|
foreach ($heading in @('Metadata','Toolchain','Source And Test Hashes','JCS Contract','Closure Contract','Compiler Process','L0 Result','L1 Result','Counts And Boundaries','Stop Or Pass')) {
|
[void]$receiptLines.Add('## ' + $heading)
|
switch ($heading) {
|
'Metadata' { [void]$receiptLines.Add('- run_id=' + $runId); [void]$receiptLines.Add('- authorization_id=' + $authorizationId); [void]$receiptLines.Add('- attempt_id=' + $attemptId); [void]$receiptLines.Add('- schema_id=ANA-SEMI-IMPLEMENTATION-RECEIPT-MD-V003') }
|
'Toolchain' { [void]$receiptLines.Add('- powershell=455680/9785001b0dcf755eddb8af294a373c0b87b2498660f724e76c4d53f9c217c7a3'); [void]$receiptLines.Add('- csc=2569696/aae1db57f898ca8bda18590c56f86ced6d0ead80c22033b76fdfe9119706f116') }
|
'Source And Test Hashes' { for ($i=0;$i -lt $preReceiptPaths.Count;$i++) { $info=Get-Item -LiteralPath $preReceiptPaths[$i]; [void]$receiptLines.Add(('- R{0:d2}={1}/{2}' -f ($i+1),$info.Length,(Get-Sha256File $preReceiptPaths[$i]))) } }
|
'JCS Contract' { [void]$receiptLines.Add('- status=CONTRACT_PASS'); [void]$receiptLines.Add('- cases=12/12') }
|
'Closure Contract' { [void]$receiptLines.Add('- status=CONTRACT_PASS'); [void]$receiptLines.Add('- closures=8/8'); [void]$receiptLines.Add('- literals=34/34') }
|
'Compiler Process' { [void]$receiptLines.Add('- outer_argv=15/88d1d345c5b0d27776f6473e042d6c2a3220ad4e4bb013792526ef681cf4089b'); [void]$receiptLines.Add('- csc_argv=11/' + $cscArgvHash); [void]$receiptLines.Add('- csc_exit=0') }
|
'L0 Result' { [void]$receiptLines.Add('- status=TEST_PASS') }
|
'L1 Result' { [void]$receiptLines.Add('- status=TEST_PASS') }
|
'Counts And Boundaries' { [void]$receiptLines.Add('- external_process_count=2'); [void]$receiptLines.Add('- network_count=0'); [void]$receiptLines.Add('- database_count=0'); [void]$receiptLines.Add('- credential_count=0'); [void]$receiptLines.Add('- formal_target_count=0'); [void]$receiptLines.Add('- BATCH-001=HELD') }
|
'Stop Or Pass' { [void]$receiptLines.Add('- status=PASS'); [void]$receiptLines.Add('- stop_code=null') }
|
}
|
[void]$receiptLines.Add('')
|
}
|
Write-Utf8LfCreateNew $receiptPath ([string]::Join([char]10, $receiptLines.ToArray()))
|
|
$allPaths = $preReceiptPaths + @($receiptPath,$manifestPath)
|
$roles = @('RUNNER_SOURCE','JCS_MODULE_SOURCE','WRAPPER_SOURCE','CHILD_SOURCE','L0_TEST_SOURCE','L1_TEST_SOURCE','EXPECTED_VECTORS','VALIDATION_ENTRY','COMPILER_STAGING','PUBLISHED_ASSEMBLY','CSC_STDOUT','CSC_STDERR','CSC_PROCESS_RESULT','L0_RESULT','L1_RESULT','JCS_CONTRACT_RESULT','CLOSURE_CONTRACT_RESULT','PREPACKAGE_TERMINAL','IMPLEMENTATION_RECEIPT','IMPLEMENTATION_MANIFEST')
|
$media = @('text/x-csharp; charset=utf-8','text/x-powershell; charset=utf-8','text/x-powershell; charset=utf-8','text/x-powershell; charset=utf-8','text/x-powershell; charset=utf-8','text/x-powershell; charset=utf-8','application/json','text/x-powershell; charset=utf-8','application/vnd.microsoft.portable-executable','application/vnd.microsoft.portable-executable','application/octet-stream','application/octet-stream','application/json','application/json','application/json','application/json','application/json','application/json','text/markdown; charset=utf-8','text/csv; charset=utf-8')
|
$schemas = @('ANA-SEMI-NATIVE-WRAPPER-CS-R1-V001','ANA-SEMI-JCS-EVIDENCE-WRITER-PSM1-V001','ANA-SEMI-WRAPPER-HARNESS-PS1-R1-V001','ANA-SEMI-SYNTHETIC-CHILD-PS1-R1-V001','ANA-SEMI-L0-VALIDATOR-PS1-R1-V001','ANA-SEMI-L1-VALIDATOR-PS1-R1-V001','ANA-SEMI-V007-EXPECTED-VECTORS-R1-JCS-V001','ANA-SEMI-IMPLEMENTATION-VALIDATION-PS1-V002','PE-DOTNET48-STAGING-V001','PE-DOTNET48-V001','RAW-BYTES-V001','RAW-BYTES-V001','ANA-SEMI-IMPLEMENTATION-PROCESS-RESULT-JCS-V003','ANA-SEMI-IMPLEMENTATION-L0-JCS-V003','ANA-SEMI-IMPLEMENTATION-L1-JCS-V003','ANA-SEMI-JCS-CONTRACT-RESULT-V001','ANA-SEMI-L0-CLOSURE-CONTRACT-RESULT-V001','ANA-SEMI-IMPLEMENTATION-PREPACKAGE-ASOF-JCS-V002','ANA-SEMI-IMPLEMENTATION-RECEIPT-MD-V003','ANA-SEMI-IMPLEMENTATION-MANIFEST-CSV-V003')
|
$expectedPresence = @('REQUIRED_BEFORE_OUTER','REQUIRED_BEFORE_OUTER','REQUIRED_BEFORE_OUTER','REQUIRED_BEFORE_OUTER','REQUIRED_BEFORE_OUTER','REQUIRED_BEFORE_OUTER','REQUIRED_BEFORE_OUTER','REQUIRED_BEFORE_OUTER','CONDITIONAL_ON_CSC_ATTEMPT','CONDITIONAL_ON_PUBLISH_ATTEMPT','CONDITIONAL_ON_CSC_STAGE','CONDITIONAL_ON_CSC_STAGE','CONDITIONAL_ON_CSC_STAGE','CONDITIONAL_ON_L0_PRODUCER','CONDITIONAL_ON_L1_PRODUCER','REQUIRED_ON_CONTRACT_STAGE','CONDITIONAL_ON_R16_PASS','REQUIRED_ON_INNER_TERMINAL','CONDITIONAL_ON_R18_VALID','SELF_CONDITIONAL_ON_R19_VALID')
|
$statuses = @('SOURCE_FROZEN','SOURCE_FROZEN','SOURCE_FROZEN','SOURCE_FROZEN','SOURCE_FROZEN','SOURCE_FROZEN','SOURCE_FROZEN','SOURCE_FROZEN','COMPILER_STAGING_READY','BUILD_PUBLISHED','RAW_CAPTURED','RAW_CAPTURED','PROCESS_RESULT_PASS','TEST_PASS','TEST_PASS','CONTRACT_PASS','CONTRACT_PASS','PREPACKAGE_TERMINAL_PASS','RECEIPT_FINALIZED','MANIFEST_SELF_EXTERNAL_HASH')
|
$relative = $relativeSources + @(
|
('dev/ana-dev/tmp/' + $runId + '/staging/AnaSemi.NativeProcessRunnerV006.dll'),
|
('dev/ana-dev/tmp/' + $runId + '/build/AnaSemi.NativeProcessRunnerV006.dll'),
|
('dev/ana-dev/tmp/' + $runId + '/process/csc.stdout.bin'),
|
('dev/ana-dev/tmp/' + $runId + '/process/csc.stderr.bin'),
|
('dev/ana-dev/tmp/' + $runId + '/process/csc.result.json'),
|
('dev/ana-dev/tmp/' + $runId + '/test/l0-static.json'),
|
('dev/ana-dev/tmp/' + $runId + '/test/l1-contract.json'),
|
('dev/ana-dev/tmp/' + $runId + '/test/jcs-canonical-contract.json'),
|
('dev/ana-dev/tmp/' + $runId + '/test/l0-failure-closure-contract.json'),
|
('dev/ana-dev/tmp/' + $runId + '/process/validation-terminal.json'),
|
('dev/ana-dev/tmp/' + $runId + '/receipt/implementation-receipt.md'),
|
('dev/ana-dev/tmp/' + $runId + '/manifest/implementation-source-manifest.csv')
|
)
|
$header = 'run_id,target_id,artifact_role,project_relative_path,media_type,schema_id,expected_presence,materialized,exists,bytes,sha256,status,created_at,upstream_stop_code'
|
$rows = New-Object Collections.Generic.List[string]
|
[void]$rows.Add($header)
|
for ($i=0;$i -lt 20;$i++) {
|
if ($i -eq 19) { $fileBytes=''; $fileHash='' }
|
else { $item=Get-Item -LiteralPath $allPaths[$i]; $fileBytes=[string]$item.Length; $fileHash=Get-Sha256File $allPaths[$i] }
|
$created = [DateTimeOffset]::UtcNow.ToString('o')
|
$values = @($runId,('R{0:d2}' -f ($i+1)),$roles[$i],$relative[$i],$media[$i],$schemas[$i],$expectedPresence[$i],'true','true',$fileBytes,$fileHash,$statuses[$i],$created,'')
|
[void]$rows.Add([string]::Join(',', @($values | ForEach-Object { Escape-Csv ([string]$_) })))
|
}
|
Write-Utf8LfCreateNew $manifestPath ([string]::Join([char]10, $rows.ToArray()))
|
exit 0
|
}
|
catch {
|
exit 28
|
}
|