Files
orca/.github/workflows/ssh-relay-runtime-artifacts.yml
T
2026-07-15 01:30:16 -04:00

913 lines
50 KiB
YAML

name: SSH Relay Runtime Artifacts
on:
pull_request:
paths:
- '.github/workflows/ssh-relay-runtime-artifacts.yml'
- 'config/patches/node-pty@1.1.0.patch'
- 'config/ssh-relay-runtime-linux-builder.Containerfile'
- 'config/scripts/build-relay.mjs'
- 'config/scripts/*ssh-relay*'
- 'config/ssh-relay-node-release-keys/**'
- 'config/ssh-relay-node-release-v24.18.0.json'
- 'package.json'
- 'pnpm-lock.yaml'
- 'src/main/ipc/parcel-watcher-process-entry.ts'
- 'src/relay/**'
workflow_dispatch:
concurrency:
group: ssh-relay-runtime-artifacts-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
build-posix-runtime:
name: Build ${{ matrix.tuple }} runtime
strategy:
fail-fast: false
matrix:
include:
- runner: ubuntu-24.04
tuple: linux-x64-glibc
node_archive: node-v24.18.0-linux-x64.tar.xz
container_image: docker.io/library/rockylinux@sha256:2d05a9266523bbf24f33ebc3a9832e4d5fd74b973c220f2204ca802286aa275d
- runner: ubuntu-24.04-arm
tuple: linux-arm64-glibc
node_archive: node-v24.18.0-linux-arm64.tar.xz
container_image: docker.io/library/rockylinux@sha256:3c2d0ce12bf79fc5ff05e43b1000e30ff062dc89405525f3307cbff71661f1a0
- runner: macos-15-intel
tuple: darwin-x64
node_archive: node-v24.18.0-darwin-x64.tar.xz
- runner: macos-15
tuple: darwin-arm64
node_archive: node-v24.18.0-darwin-arm64.tar.xz
runs-on: ${{ matrix.runner }}
timeout-minutes: 20
env:
ORCA_RUNTIME_REQUESTED_RUNNER: ${{ matrix.runner }}
steps:
- name: Checkout exact source revision
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
# Why: artifact evidence must name the exact reviewed source, not GitHub's synthetic merge.
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Setup pnpm
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6
with:
run_install: false
- name: Setup Node 24.18.0
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: 24.18.0
cache: pnpm
- name: Record native runner identity
shell: bash
run: |
set -euo pipefail
printf 'requested_runner=%s\n' '${{ matrix.runner }}'
printf 'resolved_image_os=%s\n' "${ImageOS:-unknown}"
printf 'resolved_image_version=%s\n' "${ImageVersion:-unknown}"
printf 'runner_arch=%s\n' "$RUNNER_ARCH"
printf 'runner_environment=%s\n' "$RUNNER_ENVIRONMENT"
uname -a
node --version
printf 'source_commit=%s\n' "$(git rev-parse HEAD)"
- name: Install Linux build and verification tools
if: runner.os == 'Linux'
shell: bash
run: |
set -euo pipefail
sudo apt-get update -qq
sudo apt-get install -y -qq build-essential ca-certificates curl gnupg gpgv python3 xz-utils
- name: Install macOS signature verifier
if: runner.os == 'macOS'
shell: bash
run: |
set -euo pipefail
brew list gnupg >/dev/null 2>&1 || brew install gnupg
command -v xz
xcodebuild -version
- name: Install source dependencies without native postinstall
shell: bash
run: |
set -euo pipefail
pnpm install --frozen-lockfile --ignore-scripts
git diff --exit-code package.json pnpm-lock.yaml
- name: Run runtime artifact contract tests
shell: bash
run: |
set -euo pipefail
node --check config/scripts/ssh-relay-runtime-reproducibility.mjs
node --check config/scripts/ssh-relay-runtime-reproducibility.test.mjs
node --check config/scripts/ssh-relay-runtime-baseline.mjs
node --check config/scripts/ssh-relay-runtime-baseline.test.mjs
node --check config/scripts/ssh-relay-runtime-linux-build-evidence.mjs
node --check config/scripts/ssh-relay-runtime-linux-build-evidence.test.mjs
node --check config/scripts/ssh-relay-linux-node-gyp-compiler.mjs
node --check config/scripts/ssh-relay-linux-node-gyp-compiler.test.mjs
node --check config/scripts/build-ssh-relay-runtime.mjs
node --check config/scripts/ssh-relay-runtime-build.test.mjs
node --check config/scripts/ssh-relay-runtime-closure.mjs
node --check config/scripts/ssh-relay-runtime-closure.test.mjs
node --check config/scripts/ssh-relay-runtime-sbom.mjs
node --check config/scripts/ssh-relay-runtime-sbom.test.mjs
node --check config/scripts/ssh-relay-runtime-provenance.test.mjs
node --check config/scripts/ssh-relay-runtime-toolchain.mjs
node --check config/scripts/ssh-relay-runtime-toolchain.test.mjs
node --check config/scripts/ssh-relay-runtime-native-signing-plan.mjs
node --check config/scripts/ssh-relay-runtime-native-signing-plan.test.mjs
node --check config/scripts/ssh-relay-runtime-native-signing-selection.mjs
node --check config/scripts/ssh-relay-runtime-native-signing-selection.test.mjs
node --check config/scripts/ssh-relay-runtime-native-signing-payload.mjs
node --check config/scripts/ssh-relay-runtime-native-signing-payload.test.mjs
node --check config/scripts/ssh-relay-runtime-windows-authenticode-assessment.mjs
node --check config/scripts/ssh-relay-runtime-windows-authenticode-assessment.test.mjs
node --check config/scripts/ssh-relay-runtime-native-signing-stage.mjs
node --check config/scripts/ssh-relay-runtime-native-signing-stage.test.mjs
node --check config/scripts/ssh-relay-runtime-native-signing-apply.mjs
node --check config/scripts/ssh-relay-runtime-native-signing-apply.test.mjs
node --check config/scripts/ssh-relay-runtime-macos-signature-verification.mjs
node --check config/scripts/ssh-relay-runtime-macos-signature-verification.test.mjs
node --check config/scripts/ssh-relay-runtime-windows-signature-verification.mjs
node --check config/scripts/ssh-relay-runtime-windows-signature-verification.test.mjs
node --check config/scripts/ssh-relay-runtime-windows-source-signature-verification.mjs
node --check config/scripts/ssh-relay-runtime-windows-source-signature-verification.test.mjs
node --check config/scripts/ssh-relay-runtime-release-stage-gate.mjs
node --check config/scripts/ssh-relay-runtime-release-stage-gate.test.mjs
node --check config/scripts/ssh-relay-runtime-draft-recovery.mjs
node --check config/scripts/ssh-relay-runtime-draft-recovery.test.mjs
node --check config/scripts/ssh-relay-runtime-aggregate-input.mjs
node --check config/scripts/ssh-relay-runtime-aggregate-input.test.mjs
node --check config/scripts/ssh-relay-runtime-draft-readback.mjs
node --check config/scripts/ssh-relay-runtime-draft-readback.test.mjs
pnpm exec vitest run --config config/vitest.config.ts \
config/scripts/ssh-relay-node-release-verification.test.mjs \
config/scripts/ssh-relay-node-tar-inspection.test.mjs \
config/scripts/ssh-relay-linux-node-gyp-compiler.test.mjs \
config/scripts/ssh-relay-node-pty-build.test.mjs \
config/scripts/ssh-relay-node-pty-windows-build-determinism.test.mjs \
config/scripts/ssh-relay-node-pty-windows-settlement.test.mjs \
config/scripts/ssh-relay-node-zip-inspection.test.mjs \
config/scripts/ssh-relay-runtime-artifact.test.mjs \
config/scripts/ssh-relay-runtime-baseline.test.mjs \
config/scripts/ssh-relay-runtime-build.test.mjs \
config/scripts/ssh-relay-runtime-linux-build-evidence.test.mjs \
config/scripts/ssh-relay-runtime-native-signing-plan.test.mjs \
config/scripts/ssh-relay-runtime-native-signing-selection.test.mjs \
config/scripts/ssh-relay-runtime-native-signing-payload.test.mjs \
config/scripts/ssh-relay-runtime-windows-authenticode-assessment.test.mjs \
config/scripts/ssh-relay-runtime-native-signing-stage.test.mjs \
config/scripts/ssh-relay-runtime-native-signing-apply.test.mjs \
config/scripts/ssh-relay-runtime-macos-signature-verification.test.mjs \
config/scripts/ssh-relay-runtime-windows-signature-verification.test.mjs \
config/scripts/ssh-relay-runtime-windows-source-signature-verification.test.mjs \
config/scripts/ssh-relay-runtime-release-stage-gate.test.mjs \
config/scripts/ssh-relay-runtime-draft-recovery.test.mjs \
config/scripts/ssh-relay-runtime-aggregate-input.test.mjs \
config/scripts/ssh-relay-runtime-draft-readback.test.mjs \
config/scripts/ssh-relay-runtime-closure.test.mjs \
config/scripts/ssh-relay-runtime-pty-smoke.test.mjs \
config/scripts/ssh-relay-runtime-reproducibility.test.mjs \
config/scripts/ssh-relay-runtime-resource-diagnostics.test.mjs \
config/scripts/ssh-relay-runtime-provenance.test.mjs \
config/scripts/ssh-relay-runtime-sbom.test.mjs \
config/scripts/ssh-relay-runtime-toolchain.test.mjs \
config/scripts/ssh-relay-runtime-windows-tree.test.mjs \
config/scripts/ssh-relay-runtime-zip.test.mjs \
config/scripts/ssh-relay-runtime-workflow.test.mjs
- name: Download exact Node release inputs
shell: bash
run: |
set -euo pipefail
inputs="$RUNNER_TEMP/node-release-inputs"
mkdir -p "$inputs"
base='https://nodejs.org/dist/v24.18.0'
for asset in SHASUMS256.txt SHASUMS256.txt.sig '${{ matrix.node_archive }}'; do
curl --fail --silent --show-error --location --proto '=https' --tlsv1.2 \
--connect-timeout 20 --max-time 300 --retry 2 --retry-delay 2 --retry-all-errors \
"$base/$asset" --output "$inputs/$asset"
done
printf 'NODE_INPUTS=%s\n' "$inputs" >> "$GITHUB_ENV"
- name: Prepare digest-pinned Linux floor builder
if: runner.os == 'Linux'
shell: bash
run: |
set -euo pipefail
image='${{ matrix.container_image }}'
builder="orca-ssh-relay-linux-builder:${GITHUB_RUN_ID}-${{ matrix.tuple }}"
docker pull "$image"
docker build --pull=false \
--build-arg "BASE_IMAGE=$image" \
--file config/ssh-relay-runtime-linux-builder.Containerfile \
--tag "$builder" .
docker image inspect "$image" --format 'linux_floor_base={{index .RepoDigests 0}}'
docker image inspect "$builder" --format 'linux_floor_builder_id={{.Id}}'
printf 'ORCA_LINUX_BUILDER=%s\n' "$builder" >> "$GITHUB_ENV"
- name: Build twice, inspect, smoke, and compare exact runtime
shell: bash
run: |
set -euo pipefail
output_root="$RUNNER_TEMP/ssh-relay-runtime/${{ matrix.tuple }}"
work_directory="$RUNNER_TEMP/orca-ssh-relay-runtime-build-work"
source_commit=$(git rev-parse HEAD)
source_date_epoch=$(git show -s --format=%ct "$source_commit")
if [[ '${{ matrix.tuple }}' == linux-* ]]; then
# Why: package installation is isolated earlier; native compilation itself has no egress.
docker run --rm --network none --read-only --cap-drop all \
--user "$(id -u):$(id -g)" \
--security-opt no-new-privileges --pids-limit 512 --memory 6g --cpus 4 \
--tmpfs /tmp:rw,nosuid,size=1g,mode=1777 \
--mount "type=bind,src=$GITHUB_WORKSPACE,dst=$GITHUB_WORKSPACE" \
--mount "type=bind,src=$RUNNER_TEMP,dst=$RUNNER_TEMP" \
--workdir "$GITHUB_WORKSPACE" \
--env "GITHUB_ACTIONS=$GITHUB_ACTIONS" \
--env "GITHUB_REPOSITORY=$GITHUB_REPOSITORY" \
--env "GITHUB_RUN_ID=$GITHUB_RUN_ID" \
--env "GITHUB_WORKFLOW_REF=$GITHUB_WORKFLOW_REF" \
--env "RUNNER_OS=$RUNNER_OS" \
--env "RUNNER_ARCH=$RUNNER_ARCH" \
--env "RUNNER_ENVIRONMENT=$RUNNER_ENVIRONMENT" \
--env "ORCA_RUNTIME_REQUESTED_RUNNER=$ORCA_RUNTIME_REQUESTED_RUNNER" \
--env 'ImageOS=rockylinux-8' \
--env 'ImageVersion=${{ matrix.container_image }}' \
--env 'HOME=/tmp' \
"$ORCA_LINUX_BUILDER" \
/usr/bin/node config/scripts/ssh-relay-runtime-linux-build-evidence.mjs \
--tuple '${{ matrix.tuple }}' \
--inputs-directory "$NODE_INPUTS" \
--output-root "$output_root" \
--work-directory "$work_directory" \
--evidence-directory "$GITHUB_WORKSPACE/runtime-evidence/${{ matrix.tuple }}" \
--source-date-epoch "$source_date_epoch" \
--git-commit "$source_commit"
first_output="$output_root/first"
identity="$first_output/orca-ssh-relay-runtime-${{ matrix.tuple }}.identity.json"
signing_stage="$output_root/signing-stage"
signing_report="$output_root/orca-ssh-relay-runtime-${{ matrix.tuple }}.signing-stage.json"
node config/scripts/ssh-relay-runtime-native-signing-stage.mjs \
--identity "$identity" \
--runtime-directory "$first_output/runtime" \
--staging-directory "$signing_stage" > "$signing_report"
node -e '
const { readFileSync } = require("node:fs")
const report = JSON.parse(readFileSync(process.argv[1], "utf8"))
if (report.platform !== "linux" || report.assessments.length !== 0 ||
report.signingFiles.length !== 0 || report.preservedUpstreamFiles.length !== 0 ||
report.payload.stagingRequired !== false || report.payload.stagedFiles.length !== 0) {
throw new Error("Linux signing-stage report violates the hash-only contract")
}
' "$signing_report"
test ! -e "$signing_stage"
cp "$signing_report" "$GITHUB_WORKSPACE/runtime-evidence/${{ matrix.tuple }}/"
exit 0
fi
mkdir -p "$output_root"
first_output="$output_root/first"
second_output="$output_root/second"
for output in "$first_output" "$second_output"; do
printf 'clean_build_output=%s\n' "$output"
/usr/bin/time -p node config/scripts/build-ssh-relay-runtime.mjs \
--tuple '${{ matrix.tuple }}' \
--inputs-directory "$NODE_INPUTS" \
--output-directory "$output" \
--work-directory "$work_directory" \
--source-date-epoch "$source_date_epoch" \
--git-commit "$source_commit"
identity="$output/orca-ssh-relay-runtime-${{ matrix.tuple }}.identity.json"
archive=$(find "$output" -maxdepth 1 -name '*.tar.xz' -print -quit)
test -n "$archive"
/usr/bin/time -p node config/scripts/verify-ssh-relay-runtime.mjs \
--runtime-directory "$output/runtime" \
--identity "$identity" \
--archive "$archive"
if find "$output/runtime" -type f \( -name npm -o -name npx -o -name corepack -o -name '*.map' \) -print -quit | grep -q .; then
echo 'Runtime contains a prohibited package manager or source map.' >&2
exit 1
fi
parcel_packages=$(find "$output/runtime/node_modules/@parcel" -mindepth 1 -maxdepth 1 -type d | wc -l | tr -d ' ')
test "$parcel_packages" = 2
done
node config/scripts/ssh-relay-runtime-reproducibility.mjs \
--tuple '${{ matrix.tuple }}' \
--first-output-directory "$first_output" \
--second-output-directory "$second_output"
signing_stage="$output_root/signing-stage"
signing_report="$output_root/orca-ssh-relay-runtime-${{ matrix.tuple }}.signing-stage.json"
node config/scripts/ssh-relay-runtime-native-signing-stage.mjs \
--identity "$first_output/orca-ssh-relay-runtime-${{ matrix.tuple }}.identity.json" \
--runtime-directory "$first_output/runtime" \
--staging-directory "$signing_stage" > "$signing_report"
node -e '
const { readFileSync } = require("node:fs")
const report = JSON.parse(readFileSync(process.argv[1], "utf8"))
if (report.platform !== "darwin" || report.assessments.length !== 0 ||
report.signingFiles.length !== 3 || report.preservedUpstreamFiles.length !== 0 ||
report.payload.stagingRequired !== true || report.payload.stagedFiles.length !== 3) {
throw new Error("macOS signing-stage report violates the Developer ID contract")
}
' "$signing_report"
test "$(find "$signing_stage" -type f | wc -l | tr -d ' ')" = 3
test ! -e "$signing_stage/bin/node"
rm -rf -- "$signing_stage"
mkdir -p "$GITHUB_WORKSPACE/runtime-evidence/${{ matrix.tuple }}"
cp "$first_output"/*.tar.xz "$first_output"/*.spdx.json "$first_output"/*.provenance.json "$first_output"/*.identity.json \
"$signing_report" "$GITHUB_WORKSPACE/runtime-evidence/${{ matrix.tuple }}/"
- name: Upload unpublished artifact evidence
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: ssh-relay-runtime-${{ matrix.tuple }}
path: runtime-evidence/${{ matrix.tuple }}/
if-no-files-found: error
retention-days: 7
build-windows-runtime:
name: Build ${{ matrix.tuple }} runtime
strategy:
fail-fast: false
matrix:
include:
- runner: windows-2022
tuple: win32-x64
node_archive: node-v24.18.0-win-x64.zip
node_library: win-x64/node.lib
msvc_arch: x64
- runner: windows-11-arm
tuple: win32-arm64
node_archive: node-v24.18.0-win-arm64.zip
node_library: win-arm64/node.lib
msvc_arch: arm64
runs-on: ${{ matrix.runner }}
timeout-minutes: 30
env:
ORCA_RUNTIME_REQUESTED_RUNNER: ${{ matrix.runner }}
steps:
- name: Checkout exact source revision
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
# Why: artifact evidence must name the exact reviewed source, not GitHub's synthetic merge.
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Configure target-native MSVC
uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1
with:
arch: ${{ matrix.msvc_arch }}
- name: Setup pnpm
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6
with:
run_install: false
- name: Setup Node 24.18.0
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: 24.18.0
cache: pnpm
- name: Record native runner identity
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
"requested_runner=${{ matrix.runner }}"
"resolved_image_os=$env:ImageOS"
"resolved_image_version=$env:ImageVersion"
"runner_arch=$env:RUNNER_ARCH"
"runner_environment=$env:RUNNER_ENVIRONMENT"
Get-ComputerInfo | Select-Object WindowsProductName, WindowsVersion, OsBuildNumber
node --version
"source_commit=$(git rev-parse HEAD)"
- name: Select bundled Git signature tools
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
$gitUsrBin = Join-Path $env:ProgramFiles 'Git/usr/bin'
foreach ($tool in @('gpg.exe', 'gpgv.exe')) {
if (-not (Test-Path -LiteralPath (Join-Path $gitUsrBin $tool) -PathType Leaf)) {
throw "Git for Windows does not provide required signature tool: $tool"
}
}
$gitUsrBin | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- name: Install source dependencies without native postinstall
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
pnpm install --frozen-lockfile --ignore-scripts
if ($LASTEXITCODE -ne 0) { throw 'pnpm install failed' }
git diff --exit-code package.json pnpm-lock.yaml
if ($LASTEXITCODE -ne 0) { throw 'frozen install changed dependency files' }
- name: Run runtime artifact contract tests
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
node --check config/scripts/ssh-relay-runtime-reproducibility.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime reproducibility script syntax check failed' }
node --check config/scripts/ssh-relay-runtime-reproducibility.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime reproducibility test syntax check failed' }
node --check config/scripts/ssh-relay-runtime-baseline.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime baseline script syntax check failed' }
node --check config/scripts/ssh-relay-runtime-baseline.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime baseline test syntax check failed' }
node --check config/scripts/ssh-relay-runtime-linux-build-evidence.mjs
if ($LASTEXITCODE -ne 0) { throw 'Linux runtime evidence script syntax check failed' }
node --check config/scripts/ssh-relay-runtime-linux-build-evidence.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'Linux runtime evidence test syntax check failed' }
node --check config/scripts/ssh-relay-linux-node-gyp-compiler.mjs
if ($LASTEXITCODE -ne 0) { throw 'Linux node-gyp compiler script syntax check failed' }
node --check config/scripts/ssh-relay-linux-node-gyp-compiler.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'Linux node-gyp compiler test syntax check failed' }
node --check config/scripts/ssh-relay-runtime-windows-pe-diagnostic.mjs
if ($LASTEXITCODE -ne 0) { throw 'Windows PE diagnostic script syntax check failed' }
node --check config/scripts/ssh-relay-runtime-windows-pe-diagnostic.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'Windows PE diagnostic test syntax check failed' }
node --check config/scripts/build-ssh-relay-runtime.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime build script syntax check failed' }
node --check config/scripts/ssh-relay-runtime-build.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime build test syntax check failed' }
node --check config/scripts/ssh-relay-runtime-closure.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime closure script syntax check failed' }
node --check config/scripts/ssh-relay-runtime-closure.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime closure test syntax check failed' }
node --check config/scripts/ssh-relay-runtime-sbom.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime SBOM script syntax check failed' }
node --check config/scripts/ssh-relay-runtime-sbom.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime SBOM test syntax check failed' }
node --check config/scripts/ssh-relay-runtime-provenance.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime provenance test syntax check failed' }
node --check config/scripts/ssh-relay-runtime-toolchain.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime toolchain script syntax check failed' }
node --check config/scripts/ssh-relay-runtime-toolchain.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime toolchain test syntax check failed' }
node --check config/scripts/ssh-relay-runtime-native-signing-plan.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime native signing plan script syntax check failed' }
node --check config/scripts/ssh-relay-runtime-native-signing-plan.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime native signing plan test syntax check failed' }
node --check config/scripts/ssh-relay-runtime-native-signing-selection.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime native signing selection script syntax check failed' }
node --check config/scripts/ssh-relay-runtime-native-signing-selection.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime native signing selection test syntax check failed' }
node --check config/scripts/ssh-relay-runtime-native-signing-payload.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime native signing payload script syntax check failed' }
node --check config/scripts/ssh-relay-runtime-native-signing-payload.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime native signing payload test syntax check failed' }
node --check config/scripts/ssh-relay-runtime-windows-authenticode-assessment.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime Windows Authenticode assessment script syntax check failed' }
node --check config/scripts/ssh-relay-runtime-windows-authenticode-assessment.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime Windows Authenticode assessment test syntax check failed' }
node --check config/scripts/ssh-relay-runtime-native-signing-stage.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime native signing stage script syntax check failed' }
node --check config/scripts/ssh-relay-runtime-native-signing-stage.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime native signing stage test syntax check failed' }
node --check config/scripts/ssh-relay-runtime-native-signing-apply.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime native signing apply script syntax check failed' }
node --check config/scripts/ssh-relay-runtime-native-signing-apply.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime native signing apply test syntax check failed' }
node --check config/scripts/ssh-relay-runtime-macos-signature-verification.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime macOS signature verification script syntax check failed' }
node --check config/scripts/ssh-relay-runtime-macos-signature-verification.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime macOS signature verification test syntax check failed' }
node --check config/scripts/ssh-relay-runtime-windows-signature-verification.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime Windows signature verification script syntax check failed' }
node --check config/scripts/ssh-relay-runtime-windows-signature-verification.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime Windows signature verification test syntax check failed' }
node --check config/scripts/ssh-relay-runtime-windows-source-signature-verification.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime Windows source signature verification script syntax check failed' }
node --check config/scripts/ssh-relay-runtime-windows-source-signature-verification.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime Windows source signature verification test syntax check failed' }
node --check config/scripts/ssh-relay-runtime-release-stage-gate.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime release stage gate syntax check failed' }
node --check config/scripts/ssh-relay-runtime-release-stage-gate.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime release stage gate test syntax check failed' }
node --check config/scripts/ssh-relay-runtime-draft-recovery.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime draft recovery syntax check failed' }
node --check config/scripts/ssh-relay-runtime-draft-recovery.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime draft recovery test syntax check failed' }
node --check config/scripts/ssh-relay-runtime-aggregate-input.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime aggregate input syntax check failed' }
node --check config/scripts/ssh-relay-runtime-aggregate-input.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime aggregate input test syntax check failed' }
node --check config/scripts/ssh-relay-runtime-draft-readback.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime draft read-back syntax check failed' }
node --check config/scripts/ssh-relay-runtime-draft-readback.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime draft read-back test syntax check failed' }
pnpm exec vitest run --config config/vitest.config.ts `
config/scripts/ssh-relay-node-release-verification.test.mjs `
config/scripts/ssh-relay-node-tar-inspection.test.mjs `
config/scripts/ssh-relay-linux-node-gyp-compiler.test.mjs `
config/scripts/ssh-relay-node-pty-build.test.mjs `
config/scripts/ssh-relay-node-pty-windows-build-determinism.test.mjs `
config/scripts/ssh-relay-node-pty-windows-settlement.test.mjs `
config/scripts/ssh-relay-node-zip-inspection.test.mjs `
config/scripts/ssh-relay-runtime-artifact.test.mjs `
config/scripts/ssh-relay-runtime-baseline.test.mjs `
config/scripts/ssh-relay-runtime-build.test.mjs `
config/scripts/ssh-relay-runtime-linux-build-evidence.test.mjs `
config/scripts/ssh-relay-runtime-native-signing-plan.test.mjs `
config/scripts/ssh-relay-runtime-native-signing-selection.test.mjs `
config/scripts/ssh-relay-runtime-native-signing-payload.test.mjs `
config/scripts/ssh-relay-runtime-windows-authenticode-assessment.test.mjs `
config/scripts/ssh-relay-runtime-native-signing-stage.test.mjs `
config/scripts/ssh-relay-runtime-native-signing-apply.test.mjs `
config/scripts/ssh-relay-runtime-macos-signature-verification.test.mjs `
config/scripts/ssh-relay-runtime-windows-signature-verification.test.mjs `
config/scripts/ssh-relay-runtime-windows-source-signature-verification.test.mjs `
config/scripts/ssh-relay-runtime-release-stage-gate.test.mjs `
config/scripts/ssh-relay-runtime-draft-recovery.test.mjs `
config/scripts/ssh-relay-runtime-aggregate-input.test.mjs `
config/scripts/ssh-relay-runtime-draft-readback.test.mjs `
config/scripts/ssh-relay-runtime-closure.test.mjs `
config/scripts/ssh-relay-runtime-pty-smoke.test.mjs `
config/scripts/ssh-relay-runtime-reproducibility.test.mjs `
config/scripts/ssh-relay-runtime-resource-diagnostics.test.mjs `
config/scripts/ssh-relay-runtime-provenance.test.mjs `
config/scripts/ssh-relay-runtime-sbom.test.mjs `
config/scripts/ssh-relay-runtime-toolchain.test.mjs `
config/scripts/ssh-relay-runtime-windows-pe-diagnostic.test.mjs `
config/scripts/ssh-relay-runtime-windows-tree.test.mjs `
config/scripts/ssh-relay-runtime-zip.test.mjs `
config/scripts/ssh-relay-runtime-workflow.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime artifact contract tests failed' }
- name: Download exact Node release inputs
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
$inputs = Join-Path $env:RUNNER_TEMP 'node-release-inputs'
New-Item -ItemType Directory -Path $inputs | Out-Null
$base = 'https://nodejs.org/dist/v24.18.0'
$assets = @(
'SHASUMS256.txt',
'SHASUMS256.txt.sig',
'${{ matrix.node_archive }}',
'node-v24.18.0-headers.tar.gz',
'${{ matrix.node_library }}'
)
foreach ($asset in $assets) {
$destination = Join-Path $inputs $asset
New-Item -ItemType Directory -Path (Split-Path -Parent $destination) -Force | Out-Null
& curl.exe --fail --silent --show-error --location --proto '=https' --tlsv1.2 `
--connect-timeout 20 --max-time 300 --retry 2 --retry-delay 2 --retry-all-errors `
"$base/$asset" --output $destination
if ($LASTEXITCODE -ne 0) { throw "Node input download failed: $asset" }
}
"NODE_INPUTS=$inputs" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
- name: Build twice, inspect, smoke, and compare exact runtime
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
$outputRoot = Join-Path $env:RUNNER_TEMP 'ssh-relay-runtime/${{ matrix.tuple }}'
New-Item -ItemType Directory -Path $outputRoot -Force | Out-Null
$firstOutput = Join-Path $outputRoot 'first'
$secondOutput = Join-Path $outputRoot 'second'
$workDirectory = Join-Path $env:RUNNER_TEMP 'orca-ssh-relay-runtime-build-work'
$sourceCommit = git rev-parse HEAD
$sourceDateEpoch = git show -s --format=%ct $sourceCommit
foreach ($output in @($firstOutput, $secondOutput)) {
"clean_build_output=$output"
node config/scripts/build-ssh-relay-runtime.mjs `
--tuple '${{ matrix.tuple }}' `
--inputs-directory $env:NODE_INPUTS `
--output-directory $output `
--work-directory $workDirectory `
--source-date-epoch $sourceDateEpoch `
--git-commit $sourceCommit
if ($LASTEXITCODE -ne 0) { throw 'runtime build failed' }
$identity = Join-Path $output 'orca-ssh-relay-runtime-${{ matrix.tuple }}.identity.json'
$archive = Get-ChildItem -LiteralPath $output -Filter '*.zip' -File | Select-Object -First 1
if (-not $archive) { throw 'runtime ZIP is missing' }
node config/scripts/verify-ssh-relay-runtime.mjs `
--runtime-directory (Join-Path $output 'runtime') `
--identity $identity `
--archive $archive.FullName
if ($LASTEXITCODE -ne 0) { throw 'runtime verification failed' }
$prohibited = Get-ChildItem -LiteralPath (Join-Path $output 'runtime') -Recurse -File |
Where-Object { $_.Name -in @('npm', 'npm.cmd', 'npx', 'npx.cmd', 'corepack', 'corepack.cmd') -or $_.Name.EndsWith('.map') } |
Select-Object -First 1
if ($prohibited) { throw "Runtime contains a prohibited file: $($prohibited.FullName)" }
$parcelRoot = Join-Path $output 'runtime/node_modules/@parcel'
if (@(Get-ChildItem -LiteralPath $parcelRoot -Directory).Count -ne 2) {
throw 'Runtime must contain exactly the watcher wrapper and one native package'
}
}
node config/scripts/ssh-relay-runtime-reproducibility.mjs `
--tuple '${{ matrix.tuple }}' `
--first-output-directory $firstOutput `
--second-output-directory $secondOutput
if ($LASTEXITCODE -ne 0) {
$firstPe = Join-Path $firstOutput 'runtime/node_modules/node-pty/build/Release/conpty_console_list.node'
$secondPe = Join-Path $secondOutput 'runtime/node_modules/node-pty/build/Release/conpty_console_list.node'
if ((Test-Path -LiteralPath $firstPe -PathType Leaf) -and (Test-Path -LiteralPath $secondPe -PathType Leaf)) {
# Why: rejected PE bytes remain local, but bounded headers/ranges identify the producer drift.
node config/scripts/ssh-relay-runtime-windows-pe-diagnostic.mjs `
--first-pe $firstPe `
--second-pe $secondPe
if ($LASTEXITCODE -ne 0) { Write-Output 'windows_pe_diagnostic=failed' }
if ('${{ matrix.tuple }}' -eq 'win32-arm64') {
$llvmObjdump = Get-Command llvm-objdump.exe -ErrorAction SilentlyContinue
if ($llvmObjdump) {
foreach ($candidate in @(
@{ Label = 'first'; Path = $firstPe },
@{ Label = 'second'; Path = $secondPe }
)) {
"windows_arm64_disassembly=$($candidate.Label)"
# Why: the first 512 code bytes classify the repeated instruction without retaining rejected files.
& $llvmObjdump.Source --disassemble --start-address=0x180001000 --stop-address=0x180001200 $candidate.Path
if ($LASTEXITCODE -ne 0) { Write-Output 'windows_arm64_disassembly=failed' }
}
} else {
Write-Output 'windows_arm64_disassembly=tool-unavailable'
}
}
} else {
Write-Output 'windows_pe_diagnostic=skipped_missing_input'
}
throw 'runtime reproducibility verification failed'
}
$signingStage = Join-Path $outputRoot 'signing-stage'
$signingReport = Join-Path $outputRoot 'orca-ssh-relay-runtime-${{ matrix.tuple }}.signing-stage.json'
$reportLines = & node config/scripts/ssh-relay-runtime-native-signing-stage.mjs `
--identity (Join-Path $firstOutput 'orca-ssh-relay-runtime-${{ matrix.tuple }}.identity.json') `
--runtime-directory (Join-Path $firstOutput 'runtime') `
--staging-directory $signingStage
if ($LASTEXITCODE -ne 0) { throw 'runtime native signing assessment/staging failed' }
$reportJson = $reportLines -join [Environment]::NewLine
$report = $reportJson | ConvertFrom-Json
if (
$report.platform -ne 'win32' -or
@($report.assessments).Count -ne 5 -or
@($report.signingFiles).Count -ne 3 -or
@($report.preservedUpstreamFiles).Count -ne 2 -or
-not $report.payload.stagingRequired -or
@($report.payload.stagedFiles).Count -ne 3
) {
throw 'Windows signing-stage report violates the Authenticode contract'
}
$preservedPaths = @($report.preservedUpstreamFiles | ForEach-Object { $_.path })
foreach ($path in @(
'node_modules/node-pty/build/Release/conpty/OpenConsole.exe',
'node_modules/node-pty/build/Release/conpty/conpty.dll'
)) {
if ($path -notin $preservedPaths) { throw "Required upstream signature was not preserved: $path" }
}
if (@(Get-ChildItem -LiteralPath $signingStage -Recurse -File).Count -ne 3) {
throw 'Windows signing stage must contain exactly three unsigned PE files'
}
if (Test-Path -LiteralPath (Join-Path $signingStage 'bin/node.exe')) {
throw 'Official Node must never enter the Windows signing stage'
}
[System.IO.File]::WriteAllText(
$signingReport,
"$reportJson`n",
[System.Text.UTF8Encoding]::new($false)
)
$reportJson
$sourceSignatureReport = Join-Path $outputRoot 'orca-ssh-relay-runtime-${{ matrix.tuple }}.source-signatures.json'
$sourceSignatureLines = & node config/scripts/ssh-relay-runtime-windows-source-signature-verification.mjs `
--identity (Join-Path $firstOutput 'orca-ssh-relay-runtime-${{ matrix.tuple }}.identity.json') `
--runtime-directory (Join-Path $firstOutput 'runtime') `
--signing-report $signingReport
if ($LASTEXITCODE -ne 0) { throw 'runtime Windows source signature verification failed' }
$sourceSignatureJson = $sourceSignatureLines -join [Environment]::NewLine
$sourceSignature = $sourceSignatureJson | ConvertFrom-Json
if (
$sourceSignature.tupleId -ne '${{ matrix.tuple }}' -or
@($sourceSignature.verifiedFiles).Count -ne 3 -or
@($sourceSignature.verifiedFiles | Where-Object { $_.signerKind -eq 'official-node' }).Count -ne 1 -or
@($sourceSignature.verifiedFiles | Where-Object { $_.signerKind -eq 'preserved-upstream' }).Count -ne 2
) {
throw 'Windows source signature report violates the immutable/preserved trust contract'
}
[System.IO.File]::WriteAllText(
$sourceSignatureReport,
"$sourceSignatureJson`n",
[System.Text.UTF8Encoding]::new($false)
)
$sourceSignatureJson
Remove-Item -LiteralPath $signingStage -Recurse -Force
$evidence = Join-Path $env:GITHUB_WORKSPACE 'runtime-evidence/${{ matrix.tuple }}'
New-Item -ItemType Directory -Path $evidence -Force | Out-Null
$firstArchive = Get-ChildItem -LiteralPath $firstOutput -Filter '*.zip' -File | Select-Object -First 1
Copy-Item -LiteralPath $firstArchive.FullName -Destination $evidence
Get-ChildItem -LiteralPath $firstOutput -File |
Where-Object { $_.Name -match '\.(?:spdx|provenance|identity)\.json$' } |
Copy-Item -Destination $evidence
Copy-Item -LiteralPath $signingReport -Destination $evidence
Copy-Item -LiteralPath $sourceSignatureReport -Destination $evidence
- name: Upload unpublished artifact evidence
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: ssh-relay-runtime-${{ matrix.tuple }}
path: runtime-evidence/${{ matrix.tuple }}/
if-no-files-found: error
retention-days: 7
verify-linux-runtime-baseline-userland:
name: Supplement ${{ matrix.tuple }} oldest userland (kernel gap remains)
needs: build-posix-runtime
strategy:
fail-fast: false
matrix:
include:
- runner: ubuntu-24.04
tuple: linux-x64-glibc
container_image: docker.io/library/rockylinux@sha256:2d05a9266523bbf24f33ebc3a9832e4d5fd74b973c220f2204ca802286aa275d
- runner: ubuntu-24.04-arm
tuple: linux-arm64-glibc
container_image: docker.io/library/rockylinux@sha256:3c2d0ce12bf79fc5ff05e43b1000e30ff062dc89405525f3307cbff71661f1a0
runs-on: ${{ matrix.runner }}
timeout-minutes: 15
env:
ORCA_RUNTIME_REQUESTED_RUNNER: ${{ matrix.runner }}
steps:
- name: Checkout exact source revision
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Setup pnpm
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6
with:
run_install: false
- name: Setup Node 24.18.0
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: 24.18.0
cache: pnpm
- name: Record supplemental baseline runner identity
shell: bash
run: |
set -euo pipefail
printf 'requested_runner=%s\n' "$ORCA_RUNTIME_REQUESTED_RUNNER"
printf 'resolved_image_os=%s\n' "${ImageOS:-unknown}"
printf 'resolved_image_version=%s\n' "${ImageVersion:-unknown}"
printf 'runner_arch=%s\n' "$RUNNER_ARCH"
uname -a
- name: Install verification dependencies without native postinstall
shell: bash
run: |
set -euo pipefail
pnpm install --frozen-lockfile --ignore-scripts
git diff --exit-code package.json pnpm-lock.yaml
- name: Download exact unpublished runtime evidence
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ssh-relay-runtime-${{ matrix.tuple }}
path: runtime-evidence/${{ matrix.tuple }}
- name: Verify bytes before supplemental baseline execution
shell: bash
run: |
set -euo pipefail
evidence="$GITHUB_WORKSPACE/runtime-evidence/${{ matrix.tuple }}"
mapfile -d '' identities < <(find "$evidence" -maxdepth 1 -type f -name '*.identity.json' -print0)
mapfile -d '' archives < <(find "$evidence" -maxdepth 1 -type f -name '*.tar.xz' -print0)
if (( ${#identities[@]} != 1 || ${#archives[@]} != 1 )); then
printf 'runtime baseline evidence is ambiguous: identities=%s archives=%s\n' \
"${#identities[@]}" "${#archives[@]}" >&2
exit 1
fi
identity=${identities[0]}
archive=${archives[0]}
runtime="$RUNNER_TEMP/baseline-runtime/${{ matrix.tuple }}"
mkdir -p "$runtime"
tar -xJf "$archive" -C "$runtime"
node config/scripts/verify-ssh-relay-runtime.mjs \
--runtime-directory "$runtime" \
--identity "$identity" \
--archive "$archive"
printf 'BASELINE_RUNTIME=%s\n' "$runtime" >> "$GITHUB_ENV"
- name: Prove oldest Linux userland and retain the kernel gap
shell: bash
run: |
set -euo pipefail
image='${{ matrix.container_image }}'
docker pull "$image"
docker image inspect "$image" --format 'container_image={{index .RepoDigests 0}}'
docker run --rm --network none --read-only --cap-drop all \
--security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 2 \
--tmpfs /tmp:rw,nosuid,size=64m \
--mount "type=bind,src=$GITHUB_WORKSPACE,dst=/workspace,readonly" \
--mount "type=bind,src=$BASELINE_RUNTIME,dst=/runtime,readonly" \
--workdir /workspace \
"$image" \
/runtime/bin/node config/scripts/ssh-relay-runtime-smoke-child.cjs /runtime
# Why: the container proves glibc/libstdc++ floors but shares the newer hosted kernel.
docker run --rm --network none --read-only --cap-drop all \
--security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 2 \
--tmpfs /tmp:rw,nosuid,size=64m \
--mount "type=bind,src=$GITHUB_WORKSPACE,dst=/workspace,readonly" \
--mount "type=bind,src=$BASELINE_RUNTIME,dst=/runtime,readonly" \
--workdir /workspace \
"$image" \
/runtime/bin/node config/scripts/ssh-relay-runtime-baseline.mjs \
--tuple '${{ matrix.tuple }}' \
--scope linux-userland \
--runtime-directory /runtime
verify-windows-runtime-baseline:
name: Verify ${{ matrix.tuple }} oldest Windows baseline
needs: build-windows-runtime
strategy:
fail-fast: false
matrix:
include:
- runner: windows-2022
tuple: win32-x64
- runner: windows-11-arm
tuple: win32-arm64
runs-on: ${{ matrix.runner }}
timeout-minutes: 15
env:
ORCA_RUNTIME_REQUESTED_RUNNER: ${{ matrix.runner }}
steps:
- name: Checkout exact source revision
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Setup pnpm
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6
with:
run_install: false
- name: Setup Node 24.18.0
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: 24.18.0
cache: pnpm
- name: Record oldest-baseline runner identity
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
"requested_runner=$env:ORCA_RUNTIME_REQUESTED_RUNNER"
"resolved_image_os=$env:ImageOS"
"resolved_image_version=$env:ImageVersion"
"runner_arch=$env:RUNNER_ARCH"
Get-ComputerInfo | Select-Object WindowsProductName, WindowsVersion, OsBuildNumber
- name: Install verification dependencies without native postinstall
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
pnpm install --frozen-lockfile --ignore-scripts
if ($LASTEXITCODE -ne 0) { throw 'pnpm install failed' }
git diff --exit-code package.json pnpm-lock.yaml
if ($LASTEXITCODE -ne 0) { throw 'frozen install changed dependency files' }
- name: Download exact unpublished runtime evidence
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ssh-relay-runtime-${{ matrix.tuple }}
path: runtime-evidence/${{ matrix.tuple }}
- name: Verify bytes and execute on the declared Windows floor
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
$evidence = Join-Path $env:GITHUB_WORKSPACE 'runtime-evidence/${{ matrix.tuple }}'
$identities = @(Get-ChildItem -LiteralPath $evidence -Filter '*.identity.json' -File)
$archives = @(Get-ChildItem -LiteralPath $evidence -Filter '*.zip' -File)
if ($identities.Count -ne 1 -or $archives.Count -ne 1) {
throw "runtime baseline evidence is ambiguous: identities=$($identities.Count) archives=$($archives.Count)"
}
$identity = $identities[0]
$archive = $archives[0]
$runtime = Join-Path $env:RUNNER_TEMP 'baseline-runtime/${{ matrix.tuple }}'
Expand-Archive -LiteralPath $archive.FullName -DestinationPath $runtime
node config/scripts/verify-ssh-relay-runtime.mjs `
--runtime-directory $runtime `
--identity $identity.FullName `
--archive $archive.FullName
if ($LASTEXITCODE -ne 0) { throw 'runtime baseline verification failed' }
node config/scripts/ssh-relay-runtime-baseline.mjs `
--tuple '${{ matrix.tuple }}' `
--scope full
if ($LASTEXITCODE -ne 0) { throw 'runner does not prove the declared Windows floor' }