build(ssh): use portable relay archives

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
Jinwoo-H
2026-07-15 16:30:48 -04:00
co-authored by Orca
parent c5fe474e6f
commit c9f6da55e4
32 changed files with 295 additions and 165 deletions
@@ -246,6 +246,7 @@ jobs:
node --check config/scripts/ssh-relay-runtime-post-sign-metadata.test.mjs
node --check config/scripts/ssh-relay-runtime-archive-extraction.mjs
node --check config/scripts/ssh-relay-runtime-archive-extraction.test.mjs
node --check config/scripts/ssh-relay-runtime-portable-archive.test.mjs
node --check config/scripts/ssh-relay-runtime-native-signing-stage-report.mjs
node --check config/scripts/ssh-relay-runtime-macos-signing.mjs
node --check config/scripts/ssh-relay-runtime-macos-signing.test.mjs
@@ -272,6 +273,7 @@ jobs:
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-portable-archive.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 \
@@ -388,7 +390,7 @@ jobs:
--git-commit "$source_commit"
first_output="$output_root/first"
identity="$first_output/orca-ssh-relay-runtime-${{ matrix.tuple }}.identity.json"
archive=$(find "$first_output" -maxdepth 1 -name '*.tar.xz' -print -quit)
archive=$(find "$first_output" -maxdepth 1 -name '*.tar.br' -print -quit)
test -n "$archive"
executed_runtime="$output_root/readback-executed"
# Why: exercise only local verified bytes; release writes and remote consumers stay disconnected.
@@ -449,7 +451,7 @@ jobs:
--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)
archive=$(find "$output" -maxdepth 1 -name '*.tar.br' -print -quit)
test -n "$archive"
/usr/bin/time -p node config/scripts/verify-ssh-relay-runtime.mjs \
--runtime-directory "$output/runtime" \
@@ -467,7 +469,7 @@ jobs:
--first-output-directory "$first_output" \
--second-output-directory "$second_output"
identity="$first_output/orca-ssh-relay-runtime-${{ matrix.tuple }}.identity.json"
archive=$(find "$first_output" -maxdepth 1 -name '*.tar.xz' -print -quit)
archive=$(find "$first_output" -maxdepth 1 -name '*.tar.br' -print -quit)
test -n "$archive"
executed_runtime="$output_root/readback-executed"
# Why: exercise only local verified bytes; release writes and remote consumers stay disconnected.
@@ -496,7 +498,7 @@ jobs:
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 \
cp "$first_output"/*.tar.br "$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
@@ -739,6 +741,8 @@ jobs:
if ($LASTEXITCODE -ne 0) { throw 'runtime archive extraction syntax check failed' }
node --check config/scripts/ssh-relay-runtime-archive-extraction.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime archive extraction test syntax check failed' }
node --check config/scripts/ssh-relay-runtime-portable-archive.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime portable archive test syntax check failed' }
node --check config/scripts/ssh-relay-runtime-native-signing-stage-report.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime signing stage report syntax check failed' }
node --check config/scripts/ssh-relay-runtime-macos-signing.mjs
@@ -775,6 +779,7 @@ jobs:
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-portable-archive.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 `
@@ -1079,7 +1084,7 @@ jobs:
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)
mapfile -d '' archives < <(find "$evidence" -maxdepth 1 -type f -name '*.tar.br' -print0)
if (( ${#identities[@]} != 1 || ${#archives[@]} != 1 )); then
printf 'runtime baseline evidence is ambiguous: identities=%s archives=%s\n' \
"${#identities[@]}" "${#archives[@]}" >&2
@@ -1088,8 +1093,10 @@ jobs:
identity=${identities[0]}
archive=${archives[0]}
runtime="$RUNNER_TEMP/baseline-runtime/${{ matrix.tuple }}"
mkdir -p "$runtime"
tar -xJf "$archive" -C "$runtime"
node config/scripts/ssh-relay-runtime-archive-extraction.mjs \
--identity "$identity" \
--archive "$archive" \
--output-directory "$runtime"
node config/scripts/verify-ssh-relay-runtime.mjs \
--runtime-directory "$runtime" \
--identity "$identity" \
@@ -63,8 +63,6 @@ jobs:
shell: bash
run: |
set -euo pipefail
brew list xz >/dev/null 2>&1 || brew install xz
command -v xz
test -x /usr/bin/codesign
security help >/dev/null
@@ -80,7 +78,7 @@ jobs:
set -euo pipefail
evidence="$RUNNER_TEMP/ssh-relay-runtime-build/${{ matrix.tuple }}"
identity="$evidence/orca-ssh-relay-runtime-${{ matrix.tuple }}.identity.json"
archive=$(find "$evidence" -maxdepth 1 -type f -name 'orca-ssh-relay-runtime-v1-*.tar.xz' -print)
archive=$(find "$evidence" -maxdepth 1 -type f -name 'orca-ssh-relay-runtime-v1-*.tar.br' -print)
test "$(printf '%s\n' "$archive" | sed '/^$/d' | wc -l | tr -d ' ')" = 1
runtime="$RUNNER_TEMP/ssh-relay-runtime-source/${{ matrix.tuple }}"
node config/scripts/ssh-relay-runtime-archive-extraction.mjs \
@@ -33,7 +33,7 @@ function assertExactFields(value, fields, label) {
function expectedArchiveName(tupleId, contentId) {
const digest = contentId.slice('sha256:'.length)
const extension = tupleId.startsWith('win32-') ? 'zip' : 'tar.xz'
const extension = tupleId.startsWith('win32-') ? 'zip' : 'tar.br'
return `orca-ssh-relay-runtime-v1-${tupleId}-${digest}.${extension}`
}
@@ -16,7 +16,7 @@ async function fixture() {
temporaryDirectories.push(inputDirectory)
const contentId = `sha256:${'a'.repeat(64)}`
const bytes = Buffer.from('verified runtime bytes')
const name = `orca-ssh-relay-runtime-v1-linux-x64-glibc-${contentId.slice(7)}.tar.xz`
const name = `orca-ssh-relay-runtime-v1-linux-x64-glibc-${contentId.slice(7)}.tar.br`
await writeFile(join(inputDirectory, name), bytes)
return {
inputDirectory,
@@ -80,7 +80,7 @@ describe('SSH relay runtime aggregate inputs', () => {
it('rejects duplicate tuples, names, and unsupported identities', async () => {
const duplicateTuple = await fixture()
duplicateTuple.assets.push({ ...duplicateTuple.assets[0], name: 'different.tar.xz' })
duplicateTuple.assets.push({ ...duplicateTuple.assets[0], name: 'different.tar.br' })
await expect(verifySshRelayRuntimeAggregateInputs(duplicateTuple)).rejects.toThrow(
/duplicate tuple/i
)
@@ -100,7 +100,7 @@ describe('SSH relay runtime aggregate inputs', () => {
it('derives the archive name from tuple and content identity', async () => {
const input = await fixture()
input.assets[0].name = 'latest.tar.xz'
input.assets[0].name = 'latest.tar.br'
await expect(verifySshRelayRuntimeAggregateInputs(input)).rejects.toThrow(/archive name/i)
})
@@ -1,14 +1,17 @@
import { spawn } from 'node:child_process'
import { createHash } from 'node:crypto'
import { createReadStream } from 'node:fs'
import { lstat, mkdir, realpath, rm } from 'node:fs/promises'
import { basename, dirname, resolve } from 'node:path'
import { pipeline } from 'node:stream/promises'
import { pathToFileURL } from 'node:url'
import { createBrotliDecompress } from 'node:zlib'
import { extract } from 'tar'
import { inspectSshRelayRuntimeArchive } from './ssh-relay-runtime-archive.mjs'
import {
inspectSshRelayRuntimeArchive,
SSH_RELAY_RUNTIME_POSIX_ARCHIVE_LIMITS
} from './ssh-relay-runtime-archive.mjs'
import { assertSshRelayRuntimeClosureEntries } from './ssh-relay-runtime-closure.mjs'
import { computeSshRelayRuntimeContentId } from './ssh-relay-runtime-identity.mjs'
import { readSshRelayRuntimeNativeSigningIdentity } from './ssh-relay-runtime-native-signing-plan.mjs'
@@ -17,10 +20,9 @@ import { verifyRuntimeTree } from './verify-ssh-relay-runtime.mjs'
const MAX_ARCHIVE_BYTES = 100 * 1024 * 1024
const EXTRACTION_TIMEOUT_MS = 5 * 60_000
const MAX_DIAGNOSTIC_BYTES = 64 * 1024
function expectedArchiveName(identity) {
const extension = identity.os === 'win32' ? 'zip' : 'tar.xz'
const extension = identity.os === 'win32' ? 'zip' : 'tar.br'
return `orca-ssh-relay-runtime-v1-${identity.tupleId}-${identity.contentId.slice('sha256:'.length)}.${extension}`
}
@@ -97,27 +99,7 @@ async function assertOutputAbsent(outputDirectory) {
throw new Error('Runtime archive extraction requires an exclusive output directory')
}
async function extractTarXz(archivePath, outputDirectory, signal) {
const child = spawn('xz', ['--decompress', '--stdout', '--single-stream', '--', archivePath], {
stdio: ['ignore', 'pipe', 'pipe'],
windowsHide: true,
signal
})
let stderr = ''
child.stderr.setEncoding('utf8')
child.stderr.on('data', (chunk) => {
stderr = `${stderr}${chunk}`.slice(-MAX_DIAGNOSTIC_BYTES)
})
const completion = new Promise((resolvePromise, reject) => {
child.once('error', reject)
child.once('close', (code, closeSignal) => {
if (code === 0) {
resolvePromise()
} else {
reject(new Error(`xz extraction failed (${code ?? closeSignal ?? 'unknown'}): ${stderr}`))
}
})
})
async function extractTarBrotli(archivePath, outputDirectory, signal) {
const unpack = extract({
cwd: outputDirectory,
strict: true,
@@ -125,15 +107,16 @@ async function extractTarXz(archivePath, outputDirectory, signal) {
noChmod: false,
unlink: false
})
try {
await Promise.all([pipeline(child.stdout, unpack, { signal }), completion])
} catch (error) {
if (child.exitCode === null && child.signalCode === null) {
child.kill()
}
await completion.catch(() => {})
throw error
}
await pipeline(
createReadStream(archivePath, {
highWaterMark: SSH_RELAY_RUNTIME_POSIX_ARCHIVE_LIMITS.chunkBytes
}),
createBrotliDecompress({
chunkSize: SSH_RELAY_RUNTIME_POSIX_ARCHIVE_LIMITS.chunkBytes
}),
unpack,
{ signal }
)
}
export async function extractSshRelayRuntimeArchive({
@@ -169,7 +152,7 @@ export async function extractSshRelayRuntimeArchive({
identity: finalIdentity,
signal: effectiveSignal
})
: extractTarXz(absoluteArchive, physicalOutput, effectiveSignal))
: extractTarBrotli(absoluteArchive, physicalOutput, effectiveSignal))
const tree = await verifyRuntimeTree(physicalOutput, finalIdentity, { signal: effectiveSignal })
const after = await describeArchive(absoluteArchive, identity.archive.size, effectiveSignal)
if (!sameFileState(before.state, after.state) || before.sha256 !== after.sha256) {
+67 -87
View File
@@ -1,95 +1,66 @@
import { spawn } from 'node:child_process'
import { createHash } from 'node:crypto'
import { createReadStream, createWriteStream } from 'node:fs'
import { mkdtemp, rm, stat } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { rm, stat } from 'node:fs/promises'
import { join } from 'node:path'
import { pipeline } from 'node:stream/promises'
import { constants as zlibConstants, createBrotliCompress, createBrotliDecompress } from 'node:zlib'
import { create, Parser } from 'tar'
import { createSshRelayRuntimeZip, inspectSshRelayRuntimeZip } from './ssh-relay-runtime-zip.mjs'
const MAX_ARCHIVE_BYTES = 100 * 1024 * 1024
const MAX_DIAGNOSTIC_BYTES = 64 * 1024
const XZ_TIMEOUT_MS = 5 * 60 * 1000
const ARCHIVE_TIMEOUT_MS = 5 * 60 * 1000
const BROTLI_CHUNK_BYTES = 64 * 1024
const BROTLI_QUALITY = 9
const BROTLI_WINDOW_BITS = 20
function archiveName(tuple, contentId) {
const match = /^sha256:([0-9a-f]{64})$/.exec(contentId)
if (!match) {
throw new Error('Runtime content identity is not a SHA-256 digest')
}
const suffix = tuple.startsWith('win32-') ? 'zip' : 'tar.xz'
const suffix = tuple.startsWith('win32-') ? 'zip' : 'tar.br'
return `orca-ssh-relay-runtime-v1-${tuple}-${match[1]}.${suffix}`
}
async function compressTar(tarPath, archivePath, signal) {
const child = spawn(
'xz',
['--compress', '--stdout', '--threads=1', '--check=crc64', '-9e', '--', tarPath],
{ stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true, signal }
async function compressRuntimeTree({
runtimeRoot,
paths,
sourceDateEpoch,
archivePath,
signal,
markOutputCreated
}) {
const archiveOutput = createWriteStream(archivePath, { flags: 'wx', mode: 0o600 })
archiveOutput.once('open', markOutputCreated)
const tarStream = create(
{
cwd: runtimeRoot,
portable: true,
noPax: true,
noDirRecurse: true,
mtime: new Date(sourceDateEpoch * 1000)
},
paths
)
let stderr = ''
child.stderr.setEncoding('utf8')
child.stderr.on('data', (chunk) => {
stderr = `${stderr}${chunk}`.slice(-MAX_DIAGNOSTIC_BYTES)
})
const completion = new Promise((resolve, reject) => {
child.once('error', reject)
child.once('close', (code, closeSignal) => {
if (code === 0) {
resolve()
} else {
reject(new Error(`xz failed (${code ?? closeSignal ?? 'unknown'}): ${stderr.trim()}`))
}
})
})
try {
await Promise.all([
pipeline(child.stdout, createWriteStream(archivePath, { flags: 'wx', mode: 0o600 }), {
signal
}),
completion
])
} catch (error) {
if (child.exitCode === null && child.signalCode === null) {
child.kill()
const compression = createBrotliCompress({
chunkSize: BROTLI_CHUNK_BYTES,
params: {
[zlibConstants.BROTLI_PARAM_QUALITY]: BROTLI_QUALITY,
[zlibConstants.BROTLI_PARAM_LGWIN]: BROTLI_WINDOW_BITS
}
await completion.catch(() => {})
throw error
}
})
await pipeline(tarStream, compression, archiveOutput, { signal })
}
async function decompressArchive(archivePath, destination, signal) {
const child = spawn('xz', ['--decompress', '--stdout', '--single-stream', '--', archivePath], {
stdio: ['ignore', 'pipe', 'pipe'],
windowsHide: true,
signal
})
let stderr = ''
child.stderr.setEncoding('utf8')
child.stderr.on('data', (chunk) => {
stderr = `${stderr}${chunk}`.slice(-MAX_DIAGNOSTIC_BYTES)
})
const completion = new Promise((resolve, reject) => {
child.once('error', reject)
child.once('close', (code, closeSignal) => {
if (code === 0) {
resolve()
} else {
reject(new Error(`xz failed (${code ?? closeSignal ?? 'unknown'}): ${stderr.trim()}`))
}
})
})
try {
await Promise.all([pipeline(child.stdout, destination, { signal }), completion])
} catch (error) {
if (child.exitCode === null && child.signalCode === null) {
child.kill()
}
await completion.catch(() => {})
throw error
}
await pipeline(
createReadStream(archivePath, { highWaterMark: BROTLI_CHUNK_BYTES }),
createBrotliDecompress({ chunkSize: BROTLI_CHUNK_BYTES }),
destination,
{ signal }
)
}
export async function createSshRelayRuntimeArchive({
@@ -111,25 +82,25 @@ export async function createSshRelayRuntimeArchive({
if (!Number.isSafeInteger(sourceDateEpoch) || sourceDateEpoch < 0) {
throw new Error('Runtime archive SOURCE_DATE_EPOCH must be a non-negative safe integer')
}
const temporaryDirectory = await mkdtemp(join(tmpdir(), 'orca-runtime-tar-'))
const tarPath = join(temporaryDirectory, 'runtime.tar')
const name = archiveName(identity.tupleId, identity.contentId)
const archivePath = join(outputDirectory, name)
const effectiveSignal = signal ?? AbortSignal.timeout(XZ_TIMEOUT_MS)
const timeoutSignal = AbortSignal.timeout(ARCHIVE_TIMEOUT_MS)
const effectiveSignal = signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal
effectiveSignal.throwIfAborted()
let outputCreated = false
try {
const paths = identity.entries.map((entry) => entry.path).sort()
await create(
{
cwd: runtimeRoot,
file: tarPath,
portable: true,
noPax: true,
noDirRecurse: true,
mtime: new Date(sourceDateEpoch * 1000)
},
paths
)
await compressTar(tarPath, archivePath, effectiveSignal)
await compressRuntimeTree({
runtimeRoot,
paths,
sourceDateEpoch,
archivePath,
signal: effectiveSignal,
// Why: an exclusive-open failure must never delete an output owned by another build.
markOutputCreated: () => {
outputCreated = true
}
})
const metadata = await stat(archivePath)
if (!metadata.isFile() || metadata.size === 0 || metadata.size > MAX_ARCHIVE_BYTES) {
throw new Error('Runtime archive exceeds the release-manifest compressed-size limit')
@@ -145,10 +116,10 @@ export async function createSshRelayRuntimeArchive({
sha256: `sha256:${digest.digest('hex')}`
}
} catch (error) {
await rm(archivePath, { force: true })
if (outputCreated) {
await rm(archivePath, { force: true })
}
throw error
} finally {
await rm(temporaryDirectory, { recursive: true, force: true })
}
}
@@ -202,7 +173,10 @@ export async function inspectSshRelayRuntimeArchive(archivePath, identity, { sig
parser.abort(error)
}
})
await decompressArchive(archivePath, parser, signal ?? AbortSignal.timeout(XZ_TIMEOUT_MS))
const timeoutSignal = AbortSignal.timeout(ARCHIVE_TIMEOUT_MS)
const effectiveSignal = signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal
effectiveSignal.throwIfAborted()
await decompressArchive(archivePath, parser, effectiveSignal)
await Promise.all(pendingFiles)
const missing = [...expected.keys()].filter((path) => !seen.has(path))
if (missing.length > 0) {
@@ -214,3 +188,9 @@ export async function inspectSshRelayRuntimeArchive(archivePath, identity, { sig
expandedBytes: identity.expandedSize
}
}
export const SSH_RELAY_RUNTIME_POSIX_ARCHIVE_LIMITS = Object.freeze({
chunkBytes: BROTLI_CHUNK_BYTES,
quality: BROTLI_QUALITY,
windowBits: BROTLI_WINDOW_BITS
})
@@ -11,7 +11,7 @@ const REPO = 'stablyai/orca'
const RELEASE_ID = 42
const TAG = 'v1.4.140-rc.1'
const TOKEN = 'secret-token'
const NAME = 'orca-ssh-relay-runtime-v1-linux-x64-glibc-a.tar.xz'
const NAME = 'orca-ssh-relay-runtime-v1-linux-x64-glibc-a.tar.br'
const BYTES = Buffer.from('immutable release bytes')
const SECOND_NAME = 'orca-ssh-relay-runtime-manifest.json'
const SECOND_BYTES = Buffer.from('immutable manifest bytes')
@@ -7,7 +7,7 @@ const REPO = 'stablyai/orca'
const TOKEN = 'secret-token'
const bytes = Buffer.from('immutable release bytes')
const expected = {
name: 'orca-ssh-relay-runtime-v1-linux-x64-glibc-a.tar.xz',
name: 'orca-ssh-relay-runtime-v1-linux-x64-glibc-a.tar.br',
sha256: 'sha256:5396515749878bd28c5dae110040b4fbae1c33f59318b9c23f446319d68e236a',
size: bytes.length
}
@@ -11,7 +11,7 @@ function asset(name, digit) {
function fixture() {
const expectedAssets = [
asset('orca-ssh-relay-runtime-v1-linux-x64-glibc-a.tar.xz', '1'),
asset('orca-ssh-relay-runtime-v1-linux-x64-glibc-a.tar.br', '1'),
asset('orca-ssh-relay-runtime-v1-win32-x64-b.zip', '2'),
asset('orca-ssh-relay-runtime-manifest.json', '3'),
asset('orca-ssh-relay-runtime-manifest.sig', '4')
@@ -11,7 +11,7 @@ const DIGEST_PATTERN = /^sha256:[0-9a-f]{64}$/u
const REPOSITORY_PATTERN = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u
const TAG_PATTERN = /^v\d+\.\d+\.\d+(?:-rc\.\d+(?:\.[0-9A-Za-z]+)?)?$/u
const TUPLE_PATTERN = /^(?:linux-(?:x64|arm64)-glibc|darwin-(?:x64|arm64)|win32-(?:x64|arm64))$/u
const RUNTIME_ARCHIVE_PATTERN = /^orca-ssh-relay-runtime-v1-.+\.(?:tar\.xz|zip)$/u
const RUNTIME_ARCHIVE_PATTERN = /^orca-ssh-relay-runtime-v1-.+\.(?:tar\.br|zip)$/u
const MANAGED_ASSET_PATTERN = /^orca-ssh-relay-runtime-[A-Za-z0-9._-]+$/u
const MAX_ASSET_BYTES = 100 * 1024 * 1024
const MAX_ASSETS = 26
@@ -12,7 +12,7 @@ const RELEASE_ID = 42
const TAG = 'v1.5.0-rc.1'
const SOURCE_COMMIT = 'a'.repeat(40)
const TOKEN = 'test-token'
const ARCHIVE_NAME = 'orca-ssh-relay-runtime-v1-linux-x64-glibc-a.tar.xz'
const ARCHIVE_NAME = 'orca-ssh-relay-runtime-v1-linux-x64-glibc-a.tar.br'
const ARCHIVE_BYTES = Buffer.from('verified runtime archive')
const SECOND_ARCHIVE_NAME = 'orca-ssh-relay-runtime-v1-win32-x64-c.zip'
const SECOND_ARCHIVE_BYTES = Buffer.from('verified Windows runtime archive')
@@ -12,7 +12,7 @@ const RELEASE_ID = 42
const TAG = 'v1.5.0-rc.1'
const SOURCE_COMMIT = 'a'.repeat(40)
const TOKEN = 'test-token'
const NAME = 'orca-ssh-relay-runtime-v1-linux-x64-glibc-a.tar.xz'
const NAME = 'orca-ssh-relay-runtime-v1-linux-x64-glibc-a.tar.br'
const BYTES = Buffer.from('immutable relay runtime bytes')
const SECOND_NAME = 'orca-ssh-relay-runtime-manifest.json'
const SECOND_BYTES = Buffer.from('immutable signed manifest bytes')
@@ -333,7 +333,7 @@ describe('SSH relay runtime macOS signature verification', () => {
}
}
const staleArchive = structuredClone(fixture.finalIdentity)
staleArchive.archive = { fileName: 'unsigned.tar.xz' }
staleArchive.archive = { fileName: 'unsigned.tar.br' }
await expect(
verifySshRelayRuntimeMacosSignatures({ ...common, finalIdentity: staleArchive })
).rejects.toThrow(/does not match its unsigned source/i)
@@ -133,7 +133,7 @@ function tupleFor(tupleId) {
tuple.metadataAssets.sbom.name = `orca-ssh-relay-runtime-${tupleId}.spdx.json`
tuple.metadataAssets.provenance.name = `orca-ssh-relay-runtime-${tupleId}.provenance.json`
tuple.contentId = computeSshRelayRuntimeContentId(tuple)
const extension = os === 'win32' ? 'zip' : 'tar.xz'
const extension = os === 'win32' ? 'zip' : 'tar.br'
tuple.archive.name = `orca-ssh-relay-runtime-v1-${tupleId}-${tuple.contentId.slice(7)}.${extension}`
return tuple
}
@@ -42,7 +42,7 @@ function arm64TupleFrom(source) {
tuple.metadataAssets.sbom.name = 'orca-ssh-relay-runtime-linux-arm64-glibc.spdx.json'
tuple.metadataAssets.provenance.name = 'orca-ssh-relay-runtime-linux-arm64-glibc.provenance.json'
tuple.contentId = computeSshRelayRuntimeContentId(tuple)
tuple.archive.name = `orca-ssh-relay-runtime-v1-${tuple.tupleId}-${tuple.contentId.slice('sha256:'.length)}.tar.xz`
tuple.archive.name = `orca-ssh-relay-runtime-v1-${tuple.tupleId}-${tuple.contentId.slice('sha256:'.length)}.tar.br`
return tuple
}
@@ -30,7 +30,7 @@ function arm64TupleFrom(source) {
tuple.metadataAssets.sbom.name = 'orca-ssh-relay-runtime-linux-arm64-glibc.spdx.json'
tuple.metadataAssets.provenance.name = 'orca-ssh-relay-runtime-linux-arm64-glibc.provenance.json'
tuple.contentId = computeSshRelayRuntimeContentId(tuple)
tuple.archive.name = `orca-ssh-relay-runtime-v1-${tuple.tupleId}-${tuple.contentId.slice('sha256:'.length)}.tar.xz`
tuple.archive.name = `orca-ssh-relay-runtime-v1-${tuple.tupleId}-${tuple.contentId.slice('sha256:'.length)}.tar.br`
return tuple
}
@@ -40,10 +40,10 @@ describe('SSH relay runtime canonical manifest assembly', () => {
expect(assembled.canonicalBytes.at(-1)).not.toBe('\n'.charCodeAt(0))
expect(createHash('sha256').update(assembled.canonicalBytes).digest('hex')).toBe(
'e78bf4416628a91055035dc7926035cbf633f29d3618be34e041c6dc5e0794fb'
'dc36bff51330eb3aa4791bf30c25eeedd6e8d4cbc57470d50f377c24e0a5ed06'
)
expect(assembled.sha256).toBe(
'sha256:e78bf4416628a91055035dc7926035cbf633f29d3618be34e041c6dc5e0794fb'
'sha256:dc36bff51330eb3aa4791bf30c25eeedd6e8d4cbc57470d50f377c24e0a5ed06'
)
expect(parseCanonicalSshRelayRuntimeManifestBytes(assembled.canonicalBytes)).toEqual(
assembled.manifest
@@ -50,7 +50,7 @@ describe('SSH relay runtime manifest signing handoff', () => {
])
expect(request).toMatchObject({
algorithm: 'ed25519-v1',
payloadSha256: 'sha256:e78bf4416628a91055035dc7926035cbf633f29d3618be34e041c6dc5e0794fb',
payloadSha256: 'sha256:dc36bff51330eb3aa4791bf30c25eeedd6e8d4cbc57470d50f377c24e0a5ed06',
payloadSize: canonical.length
})
expect(request.canonicalBytes).toEqual(canonical)
@@ -57,7 +57,7 @@ async function physicalDirectory(path, label) {
function expectedNames(identity) {
const digest = identity.contentId.slice('sha256:'.length)
const extension = identity.tupleId.startsWith('win32-') ? 'zip' : 'tar.xz'
const extension = identity.tupleId.startsWith('win32-') ? 'zip' : 'tar.br'
const prefix = `orca-ssh-relay-runtime-${identity.tupleId}`
return {
archive: `orca-ssh-relay-runtime-v1-${identity.tupleId}-${digest}.${extension}`,
@@ -197,7 +197,7 @@ function expectedTupleId(tuple) {
}
function expectedArchiveName(tuple) {
const extension = tuple.os === 'win32' ? 'zip' : 'tar.xz'
const extension = tuple.os === 'win32' ? 'zip' : 'tar.br'
return `orca-ssh-relay-runtime-v1-${tuple.tupleId}-${tuple.contentId.slice(7)}.${extension}`
}
@@ -69,6 +69,9 @@ describe('SSH relay runtime native signing workflow', () => {
expect(actionRefs(source).every((ref) => /^[0-9a-f]{40}$/u.test(ref))).toBe(true)
expect(source).not.toContain('continue-on-error')
expect(source).not.toMatch(/\b(?:gh\s+release|softprops\/action-gh-release)\b/u)
expect(source).toContain('orca-ssh-relay-runtime-v1-*.tar.br')
expect(source).not.toContain('brew install xz')
expect(source).not.toContain('command -v xz')
expect(source.match(/ssh-relay-runtime-archive-extraction\.mjs/g)).toHaveLength(2)
expect(source.match(/ssh-relay-runtime-native-signing-stage\.mjs/g)).toHaveLength(2)
expect(source.match(/ssh-relay-runtime-native-signing-finalization\.mjs/g)).toHaveLength(2)
@@ -0,0 +1,156 @@
import { createHash } from 'node:crypto'
import { chmod, mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { afterEach, describe, expect, it } from 'vitest'
import * as runtimeArchive from './ssh-relay-runtime-archive.mjs'
import { computeSshRelayRuntimeContentId } from './ssh-relay-runtime-identity.mjs'
const temporaryDirectories = []
function digest(bytes) {
return `sha256:${createHash('sha256').update(bytes).digest('hex')}`
}
function archiveName(identity) {
return `orca-ssh-relay-runtime-v1-${identity.tupleId}-${identity.contentId.slice('sha256:'.length)}.tar.br`
}
async function fixture() {
const root = await mkdtemp(join(tmpdir(), 'ssh-relay-portable-archive-'))
temporaryDirectories.push(root)
const runtimeRoot = join(root, 'runtime')
const outputDirectory = join(root, 'output')
const nodeBytes = Buffer.from('portable bundled node')
await Promise.all([mkdir(join(runtimeRoot, 'bin'), { recursive: true }), mkdir(outputDirectory)])
await writeFile(join(runtimeRoot, 'bin', 'node'), nodeBytes)
await chmod(join(runtimeRoot, 'bin', 'node'), 0o755)
const base = {
tupleId: 'darwin-arm64',
os: 'darwin',
architecture: 'arm64',
compatibility: { kind: 'darwin', minimumVersion: '13.5' },
nodeVersion: '24.18.0',
dependencies: { nodePtyVersion: '1.1.0', parcelWatcherVersion: '2.5.6' },
entries: [
{ path: 'bin', type: 'directory', mode: 0o755 },
{
path: 'bin/node',
type: 'file',
role: 'node',
size: nodeBytes.length,
mode: 0o755,
sha256: digest(nodeBytes)
}
],
fileCount: 1,
expandedSize: nodeBytes.length
}
return {
runtimeRoot,
outputDirectory,
identity: { ...base, contentId: computeSshRelayRuntimeContentId(base) }
}
}
afterEach(async () => {
await Promise.all(
temporaryDirectories
.splice(0)
.map((directory) => rm(directory, { recursive: true, force: true }))
)
})
describe('SSH relay portable POSIX archive', () => {
it.skipIf(process.platform === 'win32')(
'creates deterministic Brotli archives and verifies their exact entries',
async () => {
const value = await fixture()
const secondOutput = join(value.outputDirectory, 'second')
await mkdir(secondOutput)
const first = await runtimeArchive.createSshRelayRuntimeArchive({
...value,
sourceDateEpoch: 1_788_739_200
})
const second = await runtimeArchive.createSshRelayRuntimeArchive({
runtimeRoot: value.runtimeRoot,
outputDirectory: secondOutput,
identity: value.identity,
sourceDateEpoch: 1_788_739_200
})
expect(first.name).toMatch(/\.tar\.br$/u)
expect(await readFile(first.path)).toEqual(await readFile(second.path))
await expect(
runtimeArchive.inspectSshRelayRuntimeArchive(first.path, value.identity)
).resolves.toEqual({ entries: 2, files: 1, expandedBytes: value.identity.expandedSize })
}
)
it('declares the bounded architecture-independent compression contract', () => {
expect(runtimeArchive.SSH_RELAY_RUNTIME_POSIX_ARCHIVE_LIMITS).toEqual({
chunkBytes: 64 * 1024,
quality: 9,
windowBits: 20
})
})
it.skipIf(process.platform === 'win32')(
'rejects truncated Brotli and preserves outputs it did not create',
async () => {
const truncated = await fixture()
const archive = await runtimeArchive.createSshRelayRuntimeArchive({
...truncated,
sourceDateEpoch: 1_788_739_200
})
const bytes = await readFile(archive.path)
await writeFile(archive.path, bytes.subarray(0, -1))
await expect(
runtimeArchive.inspectSshRelayRuntimeArchive(archive.path, truncated.identity)
).rejects.toThrow()
const existing = await fixture()
const existingPath = join(existing.outputDirectory, archiveName(existing.identity))
await writeFile(existingPath, 'owned by another build')
await expect(
runtimeArchive.createSshRelayRuntimeArchive({
...existing,
sourceDateEpoch: 1_788_739_200
})
).rejects.toMatchObject({ code: 'EEXIST' })
await expect(readFile(existingPath, 'utf8')).resolves.toBe('owned by another build')
}
)
it.skipIf(process.platform === 'win32')(
'settles pre-cancellation without retaining a partial archive',
async () => {
const value = await fixture()
await expect(
runtimeArchive.createSshRelayRuntimeArchive({
...value,
sourceDateEpoch: 1_788_739_200,
signal: AbortSignal.abort()
})
).rejects.toThrow(/abort/i)
await expect(
readFile(join(value.outputDirectory, archiveName(value.identity)))
).rejects.toMatchObject({ code: 'ENOENT' })
}
)
it('does not depend on a client-native or system XZ executable', async () => {
const source = await readFile(
new URL('./ssh-relay-runtime-archive.mjs', import.meta.url),
'utf8'
)
expect(source).not.toContain("from 'node:child_process'")
expect(source).not.toContain("spawn('xz'")
expect(source).toContain('createBrotliCompress')
expect(source).toContain('createBrotliDecompress')
})
})
@@ -37,7 +37,7 @@ async function physicalDirectory(path, label) {
function expectedNames(identity) {
const prefix = `orca-ssh-relay-runtime-${identity.tupleId}`
const extension = identity.os === 'win32' ? 'zip' : 'tar.xz'
const extension = identity.os === 'win32' ? 'zip' : 'tar.br'
return {
archive: `orca-ssh-relay-runtime-v1-${identity.tupleId}-${identity.contentId.slice('sha256:'.length)}.${extension}`,
sbom: `${prefix}.spdx.json`,
@@ -44,7 +44,7 @@ function fixture() {
tuple,
identity,
archive: {
name: `orca-ssh-relay-runtime-v1-${tuple}-${'f'.repeat(64)}.tar.xz`,
name: `orca-ssh-relay-runtime-v1-${tuple}-${'f'.repeat(64)}.tar.br`,
size: 123,
sha256: sha256('a')
},
@@ -20,7 +20,7 @@ import {
parseSshRelayRuntimeReadbackArchiveExecutionArguments
} from './ssh-relay-runtime-readback-archive-execution.mjs'
const ARCHIVE_NAME = 'orca-ssh-relay-runtime-v1-linux-x64-glibc-a.tar.xz'
const ARCHIVE_NAME = 'orca-ssh-relay-runtime-v1-linux-x64-glibc-a.tar.br'
const ARCHIVE_BYTES = Buffer.from('verified materialized archive bytes')
const ARCHIVE_SHA256 = `sha256:${createHash('sha256').update(ARCHIVE_BYTES).digest('hex')}`
@@ -37,7 +37,7 @@ function stage(id, output, overrides = {}) {
}
function successfulFixture() {
const linux = asset(LINUX, 'orca-ssh-relay-runtime-linux.tar.xz', SHA.linux, 'a')
const linux = asset(LINUX, 'orca-ssh-relay-runtime-linux.tar.br', SHA.linux, 'a')
const windowsUnsigned = asset(
WINDOWS,
'orca-ssh-relay-runtime-windows-unsigned.zip',
@@ -111,7 +111,7 @@ describe('SSH relay runtime release stage gate', () => {
expect(result.candidateTupleIds).toEqual([LINUX, WINDOWS])
expect(result.finalRuntimeAssets.map((entry) => entry.tupleId)).toEqual([LINUX, WINDOWS])
expect(result.releaseAssets.map((entry) => entry.name)).toEqual([
'orca-ssh-relay-runtime-linux.tar.xz',
'orca-ssh-relay-runtime-linux.tar.br',
'orca-ssh-relay-runtime-windows-signed.zip',
'orca-ssh-relay-runtime-manifest.json',
'orca-ssh-relay-runtime-manifest.sig'
@@ -12,7 +12,7 @@ const tuple = 'linux-x64-glibc'
const contentId = `sha256:${'a'.repeat(64)}`
const archiveBytes = 'archive bytes'
const archiveSha256 = `sha256:${createHash('sha256').update(archiveBytes).digest('hex')}`
const archiveName = `orca-ssh-relay-runtime-v1-${tuple}-${contentId.slice('sha256:'.length)}.tar.xz`
const archiveName = `orca-ssh-relay-runtime-v1-${tuple}-${contentId.slice('sha256:'.length)}.tar.br`
afterEach(async () => {
await Promise.all(temporaryDirectories.splice(0).map((path) => rm(path, { recursive: true })))
@@ -232,7 +232,10 @@ describe('SSH relay runtime artifact workflow', () => {
)
expect(source).not.toContain('work_directory="$output_root/build-work"')
expect(source).not.toContain("Join-Path $outputRoot 'build-work'")
expect(source).toContain('cp "$first_output"/*.tar.xz')
expect(source).toContain('cp "$first_output"/*.tar.br')
expect(source).toContain("-name '*.tar.br'")
expect(source).not.toContain('tar -xJf "$archive"')
expect(source.match(/ssh-relay-runtime-portable-archive\.test\.mjs/g)).toHaveLength(4)
expect(source).toContain("Get-ChildItem -LiteralPath $firstOutput -Filter '*.zip'")
expect(source).toContain('ssh-relay-node-zip-inspection.test.mjs')
expect(source).toContain('ssh-relay-runtime-pty-smoke.test.mjs')
@@ -336,7 +336,7 @@ describe('SSH relay artifact manifest schema', () => {
expect(() => parseSshRelayArtifactManifest(identityMismatch)).toThrow(/content identity/i)
const nameMismatch = createSshRelayArtifactTestManifest()
nameMismatch.tuples[0].archive.name = 'latest.tar.xz'
nameMismatch.tuples[0].archive.name = 'latest.tar.br'
expect(() => parseSshRelayArtifactManifest(nameMismatch)).toThrow(/archive name/i)
})
@@ -50,7 +50,7 @@ describe('SSH relay manifest signatures', () => {
const canonical = canonicalUnsignedSshRelayManifestBytes(manifest)
expect(canonicalUnsignedSshRelayManifestBytes(reordered)).toEqual(canonical)
expect(createHash('sha256').update(canonical).digest('hex')).toBe(
'e78bf4416628a91055035dc7926035cbf633f29d3618be34e041c6dc5e0794fb'
'dc36bff51330eb3aa4791bf30c25eeedd6e8d4cbc57470d50f377c24e0a5ed06'
)
})
@@ -95,7 +95,7 @@ describe('SSH relay manifest signatures', () => {
])
expect(() => {
Object.defineProperty(verified.tuples[0].archive, 'name', { value: 'latest.tar.xz' })
Object.defineProperty(verified.tuples[0].archive, 'name', { value: 'latest.tar.br' })
}).toThrow(TypeError)
})
+1 -1
View File
@@ -25,7 +25,7 @@ describe('SSH relay release asset identity', () => {
it('derives a content-qualified archive name and exact direct URL', () => {
const name = sshRelayRuntimeArchiveName('linux-x64-glibc', contentId)
expect(name).toBe(`orca-ssh-relay-runtime-v1-linux-x64-glibc-${'a'.repeat(64)}.tar.xz`)
expect(name).toBe(`orca-ssh-relay-runtime-v1-linux-x64-glibc-${'a'.repeat(64)}.tar.br`)
expect(sshRelayRuntimeDownloadUrl('v1.2.3-rc.4', name)).toBe(
`https://github.com/stablyai/orca/releases/download/v1.2.3-rc.4/${name}`
)
+2 -2
View File
@@ -33,13 +33,13 @@ export function sshRelayRuntimeArchiveName(
if (!match) {
throw new Error(`Invalid SSH relay runtime content identity: ${contentId}`)
}
const extension = tupleId.startsWith('win32-') ? 'zip' : 'tar.xz'
const extension = tupleId.startsWith('win32-') ? 'zip' : 'tar.br'
return `orca-ssh-relay-runtime-v1-${tupleId}-${match[1]}.${extension}`
}
export function sshRelayRuntimeDownloadUrl(tag: string, archiveName: string): string {
parseSshRelayReleaseTag(tag)
if (!/^orca-ssh-relay-runtime-v1-[A-Za-z0-9.-]+\.(?:tar\.xz|zip)$/.test(archiveName)) {
if (!/^orca-ssh-relay-runtime-v1-[A-Za-z0-9.-]+\.(?:tar\.br|zip)$/.test(archiveName)) {
throw new Error(`Invalid SSH relay runtime archive name: ${archiveName}`)
}
return `https://github.com/stablyai/orca/releases/download/${encodeURIComponent(tag)}/${encodeURIComponent(archiveName)}`
@@ -49,7 +49,7 @@ describe('SSH relay runtime content identity', () => {
const manifest = createSshRelayArtifactTestManifest()
const tuple = structuredClone(manifest.tuples[0])
tuple.entries.reverse()
tuple.archive.name = 'ignored-by-runtime-identity.tar.xz'
tuple.archive.name = 'ignored-by-runtime-identity.tar.br'
tuple.archive.sha256 = `sha256:${'f'.repeat(64)}`
tuple.metadataAssets.sbom.sha256 = `sha256:${'e'.repeat(64)}`
tuple.nativeVerification.verifiedAt = '2030-01-01T00:00:00.000Z'