mirror of
https://github.com/stablyai/orca.git
synced 2026-10-03 00:02:19 +00:00
ci(ssh): qualify the Windows SSH provider on x64 as well as ARM64
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
name: Diagnostic stable Bun ARM SSH provider qualification
|
||||
name: Diagnostic stable Bun Windows SSH provider qualification
|
||||
on:
|
||||
push:
|
||||
branches: [OrcaWin/np-windows-ssh-provider-diagnostic]
|
||||
@@ -7,7 +7,7 @@ permissions:
|
||||
contents: read
|
||||
actions: read
|
||||
concurrency:
|
||||
group: arm-ssh-provider-${{ github.ref }}
|
||||
group: windows-ssh-provider-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
jobs:
|
||||
windows_watcher:
|
||||
@@ -17,7 +17,17 @@ jobs:
|
||||
ref: 2084c58ba5410106ce61153a9fb16cdb4b6e5301
|
||||
qualify:
|
||||
needs: windows_watcher
|
||||
runs-on: windows-11-arm
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- arch: arm64
|
||||
runner: windows-11-arm
|
||||
archive: OpenSSH-ARM64.zip
|
||||
- arch: x64
|
||||
runner: windows-2022
|
||||
archive: OpenSSH-Win64.zip
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: 45
|
||||
env:
|
||||
ORCA_BACKGROUND_LAUNCH: '1'
|
||||
@@ -63,29 +73,29 @@ jobs:
|
||||
shell: pwsh
|
||||
run: |
|
||||
$tools=Join-Path $pwd '.build/qualification-tools/config/ci/windows-ssh-provider'
|
||||
node (Join-Path $tools 'verify-bun-output.mjs') candidate .build/producer . arm64 .build/ssh-provider-receipts/candidate.json $env:PRODUCER_RUN
|
||||
node (Join-Path $tools 'verify-bun-output.mjs') candidate .build/producer . ${{ matrix.arch }} .build/ssh-provider-receipts/candidate.json $env:PRODUCER_RUN
|
||||
if($LASTEXITCODE -ne 0){throw 'Stable producer/candidate admission failed'}
|
||||
$receipt=(Resolve-Path .build/ssh-provider-receipts/candidate.json).Path
|
||||
$hash=(Get-FileHash -Algorithm SHA256 -LiteralPath $receipt).Hash.ToLowerInvariant()
|
||||
"CANDIDATE_RECEIPT=$receipt" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||
"CANDIDATE_RECEIPT_SHA256=$hash" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||
@{candidateReceiptSha256=$hash;producerRun=$env:PRODUCER_RUN;product=$env:QUALIFICATION_SOURCE_SHA;candidateOverride=$true;expectedSourcePin=$false;scope='diagnostic in-memory ARM executable pin and private cache only'} | ConvertTo-Json | Set-Content .build/ssh-provider-receipts/admission.json
|
||||
@{candidateReceiptSha256=$hash;producerRun=$env:PRODUCER_RUN;product=$env:QUALIFICATION_SOURCE_SHA;candidateOverride=$true;expectedSourcePin=$false;scope='diagnostic in-memory ${{ matrix.arch }} executable pin and private cache only'} | ConvertTo-Json | Set-Content .build/ssh-provider-receipts/admission.json
|
||||
- name: Build production relay artifacts and native process table
|
||||
shell: pwsh
|
||||
run: |
|
||||
node config/scripts/build-cli-runtime.mjs --platform win32 --arch arm64
|
||||
node config/scripts/build-cli-runtime.mjs --platform win32 --arch ${{ matrix.arch }}
|
||||
if($LASTEXITCODE -ne 0){throw 'CLI runtime build failed'}
|
||||
node config/scripts/build-windows-process-tree-relay-addon.mjs --arch=arm64
|
||||
node config/scripts/build-windows-process-tree-relay-addon.mjs --arch=${{ matrix.arch }}
|
||||
if($LASTEXITCODE -ne 0){throw 'Native process-table build failed'}
|
||||
$env:ORCA_REQUIRE_RELAY_NATIVE_ADDONS='arm64'
|
||||
$env:ORCA_REQUIRE_RELAY_NATIVE_ADDONS='${{ matrix.arch }}'
|
||||
node config/scripts/build-relay.mjs
|
||||
if($LASTEXITCODE -ne 0){throw 'Relay build failed'}
|
||||
- name: Run watcher fault harness with production-pinned CLI Bun
|
||||
shell: pwsh
|
||||
timeout-minutes: 5
|
||||
run: |
|
||||
Write-Output 'Scope: production-pinned bundled CLI Bun; actual SSH provider qualification separately uses the admitted stable candidate.' | Tee-Object .build/ssh-provider-receipts/watcher-fault-arm64.log
|
||||
node config/scripts/relay-watcher-fault-harness.mjs 2>&1 | Tee-Object -Append .build/ssh-provider-receipts/watcher-fault-arm64.log
|
||||
Write-Output 'Scope: production-pinned bundled CLI Bun; actual SSH provider qualification separately uses the admitted stable candidate.' | Tee-Object .build/ssh-provider-receipts/watcher-fault-${{ matrix.arch }}.log
|
||||
node config/scripts/relay-watcher-fault-harness.mjs 2>&1 | Tee-Object -Append .build/ssh-provider-receipts/watcher-fault-${{ matrix.arch }}.log
|
||||
if($LASTEXITCODE -ne 0){throw 'Production-pinned CLI Bun watcher fault harness failed'}
|
||||
- name: Parse and typecheck all fixture code before provisioning
|
||||
shell: pwsh
|
||||
@@ -99,7 +109,7 @@ jobs:
|
||||
& (Join-Path $tools 'preview-ssh/test-preview-diagnostics.ps1')
|
||||
$copied=[Collections.Generic.List[string]]::new()
|
||||
try {
|
||||
foreach($name in @('windows-arm-provider-route.test.ts','windows-provider-candidate.ts','windows-provider-repaint.ts','windows-provider-loaded-images.ts')){
|
||||
foreach($name in @('windows-provider-route.test.ts','windows-provider-candidate.ts','windows-provider-repaint.ts','windows-provider-loaded-images.ts')){
|
||||
$destination=Join-Path $pwd "src/main/ssh/$name"
|
||||
if(Test-Path -LiteralPath $destination){throw 'Fixture destination already exists'}
|
||||
Copy-Item -LiteralPath (Join-Path $tools $name) -Destination $destination
|
||||
@@ -116,23 +126,23 @@ jobs:
|
||||
run: |
|
||||
$tools=Join-Path $pwd '.build/qualification-tools/config/ci/windows-ssh-provider'
|
||||
$sourceRoot=$pwd.Path
|
||||
$archive=Join-Path $env:RUNNER_TEMP 'preview-OpenSSH-ARM64.zip'
|
||||
& "$env:WINDIR\System32\curl.exe" --fail --location --connect-timeout 15 --max-time 90 --output $archive 'https://github.com/PowerShell/Win32-OpenSSH/releases/download/10.0.0.0p2-Preview/OpenSSH-ARM64.zip'
|
||||
$archive=Join-Path $env:RUNNER_TEMP 'preview-${{ matrix.archive }}'
|
||||
& "$env:WINDIR\System32\curl.exe" --fail --location --connect-timeout 15 --max-time 90 --output $archive 'https://github.com/PowerShell/Win32-OpenSSH/releases/download/10.0.0.0p2-Preview/${{ matrix.archive }}'
|
||||
if($LASTEXITCODE -ne 0){throw 'SSH archive fetch failed'}
|
||||
$callback={param($user,$port,$identity,$known)
|
||||
& (Join-Path $tools 'invoke-provider-route.ps1') -SourceRoot $sourceRoot -SourceCommit $env:QUALIFICATION_SOURCE_SHA -Username $user -Port $port -IdentityFile $identity -KnownHosts $known -ReceiptRoot "$env:RUNNER_TEMP\arm-provider-route" -CandidateReceipt $env:CANDIDATE_RECEIPT -CandidateReceiptSha256 $env:CANDIDATE_RECEIPT_SHA256
|
||||
& (Join-Path $tools 'invoke-provider-route.ps1') -SourceRoot $sourceRoot -SourceCommit $env:QUALIFICATION_SOURCE_SHA -Username $user -Port $port -IdentityFile $identity -KnownHosts $known -ReceiptRoot "$env:RUNNER_TEMP\provider-route" -CandidateReceipt $env:CANDIDATE_RECEIPT -CandidateReceiptSha256 $env:CANDIDATE_RECEIPT_SHA256 -Arch '${{ matrix.arch }}'
|
||||
}.GetNewClosure()
|
||||
& (Join-Path $tools 'preview-ssh/prove-preview-openssh.ps1') -Archive $archive -Receipt "$env:RUNNER_TEMP\arm-provider-server.json" -ProductionRouteProbe $callback 2>&1 | Tee-Object .build/ssh-provider-receipts/native-route.log
|
||||
& (Join-Path $tools 'preview-ssh/prove-preview-openssh.ps1') -Archive $archive -Arch '${{ matrix.arch }}' -Receipt "$env:RUNNER_TEMP\provider-server.json" -ProductionRouteProbe $callback 2>&1 | Tee-Object .build/ssh-provider-receipts/native-route.log
|
||||
- uses: actions/upload-artifact@v7
|
||||
if: always()
|
||||
with:
|
||||
name: stable-bun-arm-ssh-provider-receipts
|
||||
name: stable-bun-${{ matrix.arch }}-ssh-provider-receipts
|
||||
path: |
|
||||
.build/ssh-provider-receipts/
|
||||
.build/producer/results/
|
||||
.build/producer/work/source-cache-receipt.json
|
||||
.build/producer/producer-run.json
|
||||
${{ runner.temp }}/arm-provider-server.json
|
||||
${{ runner.temp }}/arm-provider-route/production-route.json
|
||||
${{ runner.temp }}/arm-provider-route/repaint-events.json
|
||||
${{ runner.temp }}/provider-server.json
|
||||
${{ runner.temp }}/provider-route/production-route.json
|
||||
${{ runner.temp }}/provider-route/repaint-events.json
|
||||
retention-days: 7
|
||||
|
||||
@@ -7,7 +7,8 @@ param(
|
||||
[Parameter(Mandatory=$true)][string]$KnownHosts,
|
||||
[Parameter(Mandatory=$true)][string]$ReceiptRoot,
|
||||
[Parameter(Mandatory=$true)][string]$CandidateReceipt,
|
||||
[Parameter(Mandatory=$true)][string]$CandidateReceiptSha256
|
||||
[Parameter(Mandatory=$true)][string]$CandidateReceiptSha256,
|
||||
[Parameter(Mandatory=$true)][ValidateSet('arm64','x64')][string]$Arch
|
||||
)
|
||||
$ErrorActionPreference='Stop'
|
||||
if($env:GITHUB_ACTIONS -ne 'true' -or $env:ORCA_ISOLATED_SSH_CI -ne '1'){throw 'Disposable CI only'}
|
||||
@@ -22,7 +23,7 @@ if($knownExisted){$priorKnown=[IO.File]::ReadAllBytes($knownPath)}
|
||||
try {
|
||||
$observed=(& git rev-parse HEAD).Trim()
|
||||
if($LASTEXITCODE -ne 0 -or $observed -ne $SourceCommit){throw 'Source checkout mismatch'}
|
||||
if(!(Test-Path 'out\relay\win32-arm64\relay.js')){throw 'Build real relay artifacts before server provisioning'}
|
||||
if(!(Test-Path "out\relay\win32-$Arch\relay.js")){throw 'Build real relay artifacts before server provisioning'}
|
||||
New-Item -ItemType Directory -Path $ReceiptRoot -Force | Out-Null
|
||||
New-Item -ItemType Directory -Path (Split-Path $knownPath) -Force | Out-Null
|
||||
$pinned=[IO.File]::ReadAllText($KnownHosts)
|
||||
@@ -35,13 +36,13 @@ try {
|
||||
$env:ORCA_RELAY_PATH=Join-Path $SourceRoot 'out\relay'
|
||||
$env:ORCA_SSH_PROBE_CONFIG=Join-Path $ReceiptRoot 'config.json'
|
||||
@{sourceCommit=$SourceCommit;observedSourceCommit=$observed;username=$Username;port=$Port;identityFile=$IdentityFile;candidateReceiptPath=$CandidateReceipt;candidateReceiptSha256=$CandidateReceiptSha256;receiptPath=(Join-Path $ReceiptRoot 'production-route.json')} | ConvertTo-Json | Set-Content $env:ORCA_SSH_PROBE_CONFIG
|
||||
foreach($name in @('windows-arm-provider-route.test.ts','windows-provider-candidate.ts','windows-provider-repaint.ts','windows-provider-loaded-images.ts')) {
|
||||
foreach($name in @('windows-provider-route.test.ts','windows-provider-candidate.ts','windows-provider-repaint.ts','windows-provider-loaded-images.ts')) {
|
||||
$destination=Join-Path $SourceRoot "src\main\ssh\$name"
|
||||
if(Test-Path -LiteralPath $destination){throw 'Diagnostic source destination already exists'}
|
||||
Copy-Item -LiteralPath (Join-Path $PSScriptRoot $name) -Destination $destination
|
||||
$copiedPaths.Add($destination)
|
||||
}
|
||||
& node node_modules/vitest/vitest.mjs run --config config/vitest.config.ts src/main/ssh/windows-arm-provider-route.test.ts --no-file-parallelism --reporter=verbose
|
||||
& node node_modules/vitest/vitest.mjs run --config config/vitest.config.ts src/main/ssh/windows-provider-route.test.ts --no-file-parallelism --reporter=verbose
|
||||
if($LASTEXITCODE -ne 0){throw 'Production SSH route qualification failed'}
|
||||
$result=Get-Content (Join-Path $ReceiptRoot 'production-route.json') -Raw | ConvertFrom-Json
|
||||
if(!$result.sameShellState -or !$result.cleanupVerified -or !$result.sourcePinRestored -or !$result.candidateAdmission.candidateOverride -or $result.repaint.koreanRows -ne 8 -or $result.repaint.latinRows -ne 8 -or !$result.repaint.exactRowsOnly -or !$result.repaint.provider.modules){throw 'Provider route cleanup/evidence incomplete'}
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
{
|
||||
"release": "10.0.0.0p2-Preview",
|
||||
"archiveSha256": "23f50f3458c4c5d0b12217c6a5ddfde0137210a30fa870e98b29827f7b43aba5",
|
||||
"files": [
|
||||
{
|
||||
"name": "libcrypto.dll",
|
||||
"sha256": "4652e861c0335ee80a51306ceab75aa35c8865b235f97ce7dd5a0fd9dab44b5d",
|
||||
"machine": "0x8664",
|
||||
"certificateTableBytes": 10312
|
||||
},
|
||||
{
|
||||
"name": "scp.exe",
|
||||
"sha256": "ca014ddb0a3c058719e7061eb604de7dfe1f7732954792ac8176e6c1fc99b4a3",
|
||||
"machine": "0x8664",
|
||||
"certificateTableBytes": 10312
|
||||
},
|
||||
{
|
||||
"name": "sftp-server.exe",
|
||||
"sha256": "63462c6904943f5f32ca363065f2eb7e883ee308f40c7c1637a307a253522151",
|
||||
"machine": "0x8664",
|
||||
"certificateTableBytes": 10312
|
||||
},
|
||||
{
|
||||
"name": "sftp.exe",
|
||||
"sha256": "97271ea46fa2eeb5e9e22cd5e919931727a2a11f79993c1ef151b4f618d9fd22",
|
||||
"machine": "0x8664",
|
||||
"certificateTableBytes": 10296
|
||||
},
|
||||
{
|
||||
"name": "ssh-add.exe",
|
||||
"sha256": "b6fec08648deaf7a77b50bc34ea8ac17c3cf240d06d0f1bffc60bf56d6f914b1",
|
||||
"machine": "0x8664",
|
||||
"certificateTableBytes": 10312
|
||||
},
|
||||
{
|
||||
"name": "ssh-agent.exe",
|
||||
"sha256": "138df27c7a8c35fbadde6fee35592336b04e058f4690b03f459ad79edd68ab63",
|
||||
"machine": "0x8664",
|
||||
"certificateTableBytes": 10272
|
||||
},
|
||||
{
|
||||
"name": "ssh-keygen.exe",
|
||||
"sha256": "b51fdd26be0f7c83398d18e5354a0acb0406a9de25516791758fe63bbe3ae870",
|
||||
"machine": "0x8664",
|
||||
"certificateTableBytes": 10272
|
||||
},
|
||||
{
|
||||
"name": "ssh-keyscan.exe",
|
||||
"sha256": "32eb6a2b80443207a2481085582c0ed01bbddcfef4b1f3f2cc680aa16d0f3135",
|
||||
"machine": "0x8664",
|
||||
"certificateTableBytes": 10296
|
||||
},
|
||||
{
|
||||
"name": "ssh-pkcs11-helper.exe",
|
||||
"sha256": "0f1ee63b38af0a96670ffc3f1c5421c4fba678d96ab0485854b550467b987ff5",
|
||||
"machine": "0x8664",
|
||||
"certificateTableBytes": 10272
|
||||
},
|
||||
{
|
||||
"name": "ssh-shellhost.exe",
|
||||
"sha256": "f090cb45e3b9dd830201993fc274e75a9be2058c1d4e900e85eff334dfd5a84c",
|
||||
"machine": "0x8664",
|
||||
"certificateTableBytes": 10296
|
||||
},
|
||||
{
|
||||
"name": "ssh-sk-helper.exe",
|
||||
"sha256": "4550082d459bccc5baf13cfe43c36c1e484bb012c4e0efb3990ae33a79e71c96",
|
||||
"machine": "0x8664",
|
||||
"certificateTableBytes": 10312
|
||||
},
|
||||
{
|
||||
"name": "ssh.exe",
|
||||
"sha256": "6890c128c86cc2c38aad9fcb32a82b851ff3d38c714a1f656b8e445d7cd5e1c6",
|
||||
"machine": "0x8664",
|
||||
"certificateTableBytes": 10296
|
||||
},
|
||||
{
|
||||
"name": "sshd-auth.exe",
|
||||
"sha256": "71b11418681e1ae8a3eb84494658f4ca66a7dac7ccc7674f3c74a36a3a5b7d14",
|
||||
"machine": "0x8664",
|
||||
"certificateTableBytes": 10272
|
||||
},
|
||||
{
|
||||
"name": "sshd-session.exe",
|
||||
"sha256": "5b28ad2046596454bd1e0b1ab19e8d66945def1d18ec9bec6f0ef538600a03cf",
|
||||
"machine": "0x8664",
|
||||
"certificateTableBytes": 10296
|
||||
},
|
||||
{
|
||||
"name": "sshd.exe",
|
||||
"sha256": "d66150486d472b8748cae2d6f5078a210dae91621447974bde028f077a4ef90c",
|
||||
"machine": "0x8664",
|
||||
"certificateTableBytes": 10272
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
# Ephemeral CI only. Preview ZIP server qualification, not inbox capability coverage.
|
||||
param([Parameter(Mandatory=$true)][string]$Receipt,[Parameter(Mandatory=$true)][string]$Archive,[scriptblock]$ProductionRouteProbe)
|
||||
param([Parameter(Mandatory=$true)][string]$Receipt,[Parameter(Mandatory=$true)][string]$Archive,[Parameter(Mandatory=$true)][ValidateSet('arm64','x64')][string]$Arch,[scriptblock]$ProductionRouteProbe)
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$report = @{scope='Microsoft Win32-OpenSSH 10.0.0.0p2-Preview ARM64 private loopback authentication and stock cmd.exe dispatch; NOT inbox server or relay deployment'; status='running'; imageVersion=$env:ImageVersion; cleanup=@('not-confirmed'); globalBootstrapCleanup='Not qualified: service bootstrap may create ProgramData SSH and OpenSSH registry entries; disposable CI VM destruction is the boundary'; observations=@(); stages=@(); diagnosticCaptureFailures=@()}
|
||||
$target=@{arm64=@{os='Arm64';folder='OpenSSH-ARM64';machine='0xAA64';archive='698c6aec31c1dd0fb996206e8741f4531a97355686b5431ef347d531b07fcd42'};x64=@{os='X64';folder='OpenSSH-Win64';machine='0x8664';archive='23f50f3458c4c5d0b12217c6a5ddfde0137210a30fa870e98b29827f7b43aba5'}}[$Arch]
|
||||
$report = @{scope='Microsoft Win32-OpenSSH 10.0.0.0p2-Preview $Arch private loopback authentication and stock cmd.exe dispatch; NOT inbox server or relay deployment'; status='running'; imageVersion=$env:ImageVersion; cleanup=@('not-confirmed'); globalBootstrapCleanup='Not qualified: service bootstrap may create ProgramData SSH and OpenSSH registry entries; disposable CI VM destruction is the boundary'; observations=@(); stages=@(); diagnosticCaptureFailures=@()}
|
||||
$script:receiptWritten=$false
|
||||
function Write-Stage([string]$Stage) {
|
||||
$timestamp=[DateTime]::UtcNow.ToString('o')
|
||||
@@ -18,7 +19,7 @@ function Write-Stage([string]$Stage) {
|
||||
}
|
||||
Write-Stage 'preflight-start'
|
||||
if(-not $script:receiptWritten){throw 'Initial progress receipt unavailable; refuse provisioning'}
|
||||
if ($env:GITHUB_ACTIONS -ne 'true' -or $env:ORCA_ISOLATED_SSH_CI -ne '1' -or [Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString() -ne 'Arm64') { throw 'Requires isolated native ARM64 GitHub runner' }
|
||||
if ($env:GITHUB_ACTIONS -ne 'true' -or $env:ORCA_ISOLATED_SSH_CI -ne '1' -or [Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString() -ne $target.os) { throw "Requires isolated native $Arch GitHub runner" }
|
||||
$admin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
if (-not $admin) { throw 'Administrative private service/account setup required' }
|
||||
Write-Stage 'existing-server-query-start'
|
||||
@@ -37,7 +38,7 @@ New-Item -ItemType Directory -Path $root | Out-Null
|
||||
Write-Stage 'private-directory-create-complete'
|
||||
$report.root=$root
|
||||
$createdUser=$false; $createdService=$false; $sid=$null; $ownedServerPid=$null
|
||||
$sshDir=Join-Path $root 'OpenSSH-ARM64'
|
||||
$sshDir=Join-Path $root $target.folder
|
||||
$sshdLog=Join-Path $root 'private-sshd.log'
|
||||
$serviceStartAttempt=$null
|
||||
function Diagnostic-Categories([string]$Text) {
|
||||
@@ -119,7 +120,7 @@ function Machine([string]$Path){
|
||||
}
|
||||
try {
|
||||
Write-Stage 'preview-archive-verify-start'
|
||||
$expectedArchive='698c6aec31c1dd0fb996206e8741f4531a97355686b5431ef347d531b07fcd42'
|
||||
$expectedArchive=$target.archive
|
||||
if((Get-FileHash -LiteralPath $Archive -Algorithm SHA256).Hash.ToLowerInvariant() -ne $expectedArchive){throw 'Preview archive hash mismatch'}
|
||||
$report.archiveSha256=$expectedArchive
|
||||
Write-Stage 'preview-archive-verify-complete'
|
||||
@@ -128,7 +129,7 @@ try {
|
||||
[IO.Compression.ZipFile]::ExtractToDirectory($Archive,$root)
|
||||
Write-Stage 'preview-extract-complete'
|
||||
Write-Stage 'preview-native-input-verification-start'
|
||||
$manifest=Get-Content -LiteralPath (Join-Path $PSScriptRoot 'preview-native-inputs.json') -Raw | ConvertFrom-Json
|
||||
$manifest=Get-Content -LiteralPath (Join-Path $PSScriptRoot "preview-native-inputs-$Arch.json") -Raw | ConvertFrom-Json
|
||||
if($manifest.archiveSha256 -ne $expectedArchive -or $manifest.files.Count -ne 15){throw 'Preview input manifest mismatch'}
|
||||
$nativeFiles=@(Get-ChildItem -LiteralPath $sshDir -File | Where-Object {$_.Extension -in @('.exe','.dll')})
|
||||
if($nativeFiles.Count -ne $manifest.files.Count){throw 'Unexpected preview native input count'}
|
||||
@@ -136,10 +137,10 @@ try {
|
||||
foreach($file in $nativeFiles){
|
||||
$expected=@($manifest.files | Where-Object name -eq $file.Name)
|
||||
if($expected.Count -ne 1 -or (Get-FileHash -LiteralPath $file.FullName -Algorithm SHA256).Hash.ToLowerInvariant() -ne $expected[0].sha256){throw 'Preview native input hash mismatch'}
|
||||
if((Machine $file.FullName) -ne '0xAA64'){throw 'Preview native input is not ARM64'}
|
||||
if((Machine $file.FullName) -ne $target.machine){throw "Preview native input is not $Arch"}
|
||||
$signature=Get-AuthenticodeSignature -LiteralPath $file.FullName
|
||||
if($signature.Status -ne 'Valid' -or $signature.SignerCertificate.Subject -notmatch '(?:^|, )O=Microsoft Corporation(?:,|$)'){throw 'Preview native input Microsoft signature invalid'}
|
||||
$verified+=@{name=$file.Name;sha256=$expected[0].sha256;machine='0xAA64';signature='Valid';publisher=$signature.SignerCertificate.Subject}
|
||||
$verified+=@{name=$file.Name;sha256=$expected[0].sha256;machine=$target.machine;signature='Valid';publisher=$signature.SignerCertificate.Subject}
|
||||
}
|
||||
$report.nativeInputs=$verified
|
||||
Write-Stage 'preview-native-input-verification-complete'
|
||||
|
||||
@@ -24,17 +24,19 @@ export function installCandidateOverride(config: Record<string, unknown>, state:
|
||||
assert.equal(receipt.patch, '276f475c90c6761c58b9f56b3f4bfafa079d0c29c5861b23d2320c9ff39c35fb')
|
||||
assert.equal(receipt.product, '2084c58ba5410106ce61153a9fb16cdb4b6e5301')
|
||||
assert.equal(String(receipt.producerRun), '36503596770')
|
||||
assert.equal(receipt.architecture, 'arm64')
|
||||
assert(process.arch === 'arm64' || process.arch === 'x64')
|
||||
assert.equal(receipt.architecture, process.arch)
|
||||
const platform = `win32-${process.arch}` as const
|
||||
assert(typeof receipt.binary === 'string' && /^[a-f0-9]{64}$/.test(receipt.sha256))
|
||||
assert.equal(
|
||||
createHash('sha256').update(readFileSync(receipt.binary)).digest('hex'),
|
||||
receipt.sha256
|
||||
)
|
||||
const cache = join(state, 'orcad-artifacts', 'bun', `v${ORCAD_BUN_VERSION}`, 'win32-arm64')
|
||||
const cache = join(state, 'orcad-artifacts', 'bun', `v${ORCAD_BUN_VERSION}`, platform)
|
||||
mkdirSync(cache, { recursive: true })
|
||||
copyFileSync(receipt.binary, join(cache, 'bun-runtime.exe'))
|
||||
const original = ORCAD_BUN_RELEASE_ASSETS['win32-arm64'].executableSha256
|
||||
ORCAD_BUN_RELEASE_ASSETS['win32-arm64'].executableSha256 = receipt.sha256
|
||||
const original = ORCAD_BUN_RELEASE_ASSETS[platform].executableSha256
|
||||
ORCAD_BUN_RELEASE_ASSETS[platform].executableSha256 = receipt.sha256
|
||||
return {
|
||||
receipt: {
|
||||
...receipt,
|
||||
@@ -45,7 +47,7 @@ export function installCandidateOverride(config: Record<string, unknown>, state:
|
||||
scope: 'diagnostic process only; private cache; production deployment validation retained'
|
||||
},
|
||||
restore: () => {
|
||||
ORCAD_BUN_RELEASE_ASSETS['win32-arm64'].executableSha256 = original
|
||||
ORCAD_BUN_RELEASE_ASSETS[platform].executableSha256 = original
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,9 @@ import { runProcess } from '../../shared/child-process/run-process'
|
||||
import { readWindowsProcessTableFresh } from '../windows/windows-process-table'
|
||||
import { WINDOWS_CONPTY_FILES } from '../../shared/windows-conpty-release'
|
||||
|
||||
// Hashes for the runner's own architecture; the harness never cross-deploys.
|
||||
const providerHashes = WINDOWS_CONPTY_FILES[process.arch === 'x64' ? 'x64' : 'arm64']
|
||||
|
||||
export async function inspectProviderImages(
|
||||
daemon: { pid: number; creationTimeMs?: number },
|
||||
relayDirectory: string
|
||||
@@ -90,12 +93,12 @@ export async function inspectProviderImages(
|
||||
)
|
||||
assert.equal(
|
||||
createHash('sha256').update(readFileSync(image.path)).digest('hex'),
|
||||
WINDOWS_CONPTY_FILES.arm64['OpenConsole.exe']
|
||||
providerHashes['OpenConsole.exe']
|
||||
)
|
||||
}
|
||||
assert.equal(
|
||||
createHash('sha256').update(readFileSync(evidence.modules[0])).digest('hex'),
|
||||
WINDOWS_CONPTY_FILES.arm64['conpty.dll']
|
||||
providerHashes['conpty.dll']
|
||||
)
|
||||
const after = await readWindowsProcessTableFresh()
|
||||
for (const original of [daemon, ...consoles]) {
|
||||
@@ -112,5 +115,5 @@ export async function inspectProviderImages(
|
||||
assert(typeof row.creationTimeMs === 'number', 'descendant cleanup identity unavailable')
|
||||
return { pid: row.pid, creationTimeMs: row.creationTimeMs }
|
||||
})
|
||||
return { ...evidence, providerHashes: WINDOWS_CONPTY_FILES.arm64, daemon, descendantIdentities }
|
||||
return { ...evidence, providerHashes, daemon, descendantIdentities }
|
||||
}
|
||||
|
||||
+7
-6
@@ -274,13 +274,14 @@ it('does not retain unknown identifiers, paths, numeric source echoes or incompl
|
||||
})
|
||||
const configPath = process.env.ORCA_SSH_PROBE_CONFIG
|
||||
it(
|
||||
'native ARM OpenSSH candidate provider preserves all settled rows and shell state',
|
||||
'native OpenSSH candidate provider preserves all settled rows and shell state',
|
||||
{ timeout: 600_000 },
|
||||
async () => {
|
||||
if (!configPath || !process.env.ORCA_SSH_PROBE_STATE)
|
||||
throw new Error('Explicit private SSH fixture configuration is required')
|
||||
expect(process.platform).toBe('win32')
|
||||
expect(process.arch).toBe('arm64')
|
||||
expect(['arm64', 'x64']).toContain(process.arch)
|
||||
const platform = `win32-${process.arch}` as const
|
||||
const config = record(JSON.parse(readFileSync(configPath!, 'utf8')))
|
||||
const source = textField(config, 'sourceCommit')
|
||||
expect(source).toMatch(/^[a-f0-9]{40}$/)
|
||||
@@ -289,7 +290,7 @@ it(
|
||||
const port = config.port
|
||||
if (typeof port !== 'number' || !Number.isInteger(port))
|
||||
throw new Error('Invalid private SSH port')
|
||||
const instance = `arm-native-${randomUUID()}`
|
||||
const instance = `${process.arch}-native-${randomUUID()}`
|
||||
const createConnection = (): SshConnection =>
|
||||
new SshConnection(
|
||||
{
|
||||
@@ -347,7 +348,7 @@ it(
|
||||
instance
|
||||
)
|
||||
stage = 'artifact-and-runtime-identity'
|
||||
expect(result.platform).toBe('win32-arm64')
|
||||
expect(result.platform).toBe(platform)
|
||||
expect(result.nodePath?.toLowerCase()).toContain('bun')
|
||||
if (!result.remoteRelayDir) throw new Error('Missing actual remote relay directory')
|
||||
const artifactHashes: Record<string, string> = {}
|
||||
@@ -358,7 +359,7 @@ it(
|
||||
...RELAY_WINDOWS_CONPTY_FILENAMES
|
||||
]) {
|
||||
const expected = createHash('sha256')
|
||||
.update(readFileSync(join(process.cwd(), 'out', 'relay', 'win32-arm64', filename)))
|
||||
.update(readFileSync(join(process.cwd(), 'out', 'relay', platform, filename)))
|
||||
.digest('hex')
|
||||
const actual = createHash('sha256')
|
||||
.update(readFileSync(join(result.remoteRelayDir, filename)))
|
||||
@@ -370,7 +371,7 @@ it(
|
||||
const runtimePath = result.nodePath
|
||||
if (!runtimePath) throw new Error('Missing actual runtime executable')
|
||||
const runtimeHash = createHash('sha256').update(readFileSync(runtimePath)).digest('hex')
|
||||
expect(runtimeHash).toBe(ORCAD_BUN_RELEASE_ASSETS['win32-arm64'].executableSha256)
|
||||
expect(runtimeHash).toBe(ORCAD_BUN_RELEASE_ASSETS[platform].executableSha256)
|
||||
remoteRelayDirectory = result.remoteRelayDir
|
||||
deployedRuntime = runtimePath
|
||||
receipts.runtime = {
|
||||
Reference in New Issue
Block a user