build(ssh): add manifest signing handoff contracts

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
Jinwoo-H
2026-07-15 02:48:38 -04:00
co-authored by Orca
parent 63899c182f
commit 14355dfe05
9 changed files with 1156 additions and 19 deletions
@@ -153,6 +153,11 @@ jobs:
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
node --check config/scripts/ssh-relay-runtime-manifest-validation.mjs
node --check config/scripts/ssh-relay-runtime-manifest-assembly.mjs
node --check config/scripts/ssh-relay-runtime-manifest-assembly.test.mjs
node --check config/scripts/ssh-relay-runtime-manifest-signing-handoff.mjs
node --check config/scripts/ssh-relay-runtime-manifest-signing-handoff.test.mjs
pnpm exec vitest run --config config/vitest.config.ts \
config/scripts/ssh-relay-runtime-compatibility.test.mjs \
config/scripts/ssh-relay-node-release-verification.test.mjs \
@@ -179,6 +184,8 @@ jobs:
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-manifest-assembly.test.mjs \
config/scripts/ssh-relay-runtime-manifest-signing-handoff.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 \
@@ -514,6 +521,16 @@ jobs:
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' }
node --check config/scripts/ssh-relay-runtime-manifest-validation.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime manifest validation syntax check failed' }
node --check config/scripts/ssh-relay-runtime-manifest-assembly.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime manifest assembly syntax check failed' }
node --check config/scripts/ssh-relay-runtime-manifest-assembly.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime manifest assembly test syntax check failed' }
node --check config/scripts/ssh-relay-runtime-manifest-signing-handoff.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime manifest signing handoff syntax check failed' }
node --check config/scripts/ssh-relay-runtime-manifest-signing-handoff.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime manifest signing handoff test syntax check failed' }
pnpm exec vitest run --config config/vitest.config.ts `
config/scripts/ssh-relay-runtime-compatibility.test.mjs `
config/scripts/ssh-relay-node-release-verification.test.mjs `
@@ -540,6 +557,8 @@ jobs:
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-manifest-assembly.test.mjs `
config/scripts/ssh-relay-runtime-manifest-signing-handoff.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 `
@@ -0,0 +1,152 @@
import { createHash } from 'node:crypto'
import { parseSshRelayRuntimeUnsignedManifest } from './ssh-relay-runtime-manifest-validation.mjs'
// Why: this exceeds the eight-tuple entry/attestation maximum while bounding signer input memory.
const MAX_CANONICAL_BYTES = 32 * 1024 * 1024
function compareAscii(left, right) {
return left < right ? -1 : left > right ? 1 : 0
}
function canonicalCompatibility(compatibility) {
if (compatibility.kind === 'linux') {
return {
kind: compatibility.kind,
minimumKernelVersion: compatibility.minimumKernelVersion,
libc: {
family: compatibility.libc.family,
minimumVersion: compatibility.libc.minimumVersion,
minimumLibstdcxxVersion: compatibility.libc.minimumLibstdcxxVersion,
minimumGlibcxxVersion: compatibility.libc.minimumGlibcxxVersion
}
}
}
if (compatibility.kind === 'darwin') {
return { kind: compatibility.kind, minimumVersion: compatibility.minimumVersion }
}
return {
kind: compatibility.kind,
minimumBuild: compatibility.minimumBuild,
minimumOpenSshVersion: compatibility.minimumOpenSshVersion,
minimumPowerShellVersion: compatibility.minimumPowerShellVersion,
minimumDotNetFrameworkRelease: compatibility.minimumDotNetFrameworkRelease
}
}
function canonicalEntry(entry) {
return entry.type === 'directory'
? { path: entry.path, type: entry.type, mode: entry.mode }
: {
path: entry.path,
type: entry.type,
role: entry.role,
size: entry.size,
mode: entry.mode,
sha256: entry.sha256
}
}
function canonicalTuple(tuple) {
return {
tupleId: tuple.tupleId,
os: tuple.os,
architecture: tuple.architecture,
compatibility: canonicalCompatibility(tuple.compatibility),
nodeVersion: tuple.nodeVersion,
dependencies: {
nodePtyVersion: tuple.dependencies.nodePtyVersion,
parcelWatcherVersion: tuple.dependencies.parcelWatcherVersion
},
entries: [...tuple.entries]
.sort((left, right) => compareAscii(left.path, right.path))
.map(canonicalEntry),
contentId: tuple.contentId,
archive: {
name: tuple.archive.name,
size: tuple.archive.size,
expandedSize: tuple.archive.expandedSize,
fileCount: tuple.archive.fileCount,
sha256: tuple.archive.sha256
},
metadataAssets: {
sbom: {
name: tuple.metadataAssets.sbom.name,
size: tuple.metadataAssets.sbom.size,
sha256: tuple.metadataAssets.sbom.sha256
},
provenance: {
name: tuple.metadataAssets.provenance.name,
size: tuple.metadataAssets.provenance.size,
sha256: tuple.metadataAssets.provenance.sha256
}
},
nativeVerification: {
policy: tuple.nativeVerification.policy,
tool: {
name: tuple.nativeVerification.tool.name,
version: tuple.nativeVerification.tool.version
},
verifiedAt: tuple.nativeVerification.verifiedAt,
files: [...tuple.nativeVerification.files]
.sort((left, right) => compareAscii(left.path, right.path))
.map((file) => ({ path: file.path, sha256: file.sha256 }))
}
}
}
export function assembleCanonicalSshRelayRuntimeManifest(input) {
const parsed = parseSshRelayRuntimeUnsignedManifest(input)
// Why: release and desktop verification must authenticate one fixed projection across runners.
const manifest = {
schemaVersion: parsed.schemaVersion,
build: {
tag: parsed.build.tag,
channel: parsed.build.channel,
version: parsed.build.version,
relayProtocolVersion: parsed.build.relayProtocolVersion
},
createdAt: parsed.createdAt,
tuples: [...parsed.tuples]
.sort((left, right) => compareAscii(left.tupleId, right.tupleId))
.map(canonicalTuple)
}
const canonicalBytes = Buffer.from(JSON.stringify(manifest), 'utf8')
if (canonicalBytes.length === 0 || canonicalBytes.length > MAX_CANONICAL_BYTES) {
throw new Error('SSH relay runtime canonical manifest exceeds its size limit')
}
return {
manifest,
canonicalBytes,
sha256: `sha256:${createHash('sha256').update(canonicalBytes).digest('hex')}`
}
}
export function parseCanonicalSshRelayRuntimeManifestBytes(input) {
if (!Buffer.isBuffer(input) && !(input instanceof Uint8Array)) {
throw new Error('SSH relay runtime canonical manifest must be bytes')
}
const bytes = Buffer.from(input)
if (bytes.length === 0 || bytes.length > MAX_CANONICAL_BYTES) {
throw new Error('SSH relay runtime canonical manifest exceeds its size limit')
}
let source
try {
source = new TextDecoder('utf-8', { fatal: true }).decode(bytes)
} catch {
throw new Error('SSH relay runtime canonical manifest must be valid UTF-8')
}
let inputManifest
try {
inputManifest = JSON.parse(source)
} catch {
throw new Error('SSH relay runtime canonical manifest must be valid JSON')
}
const assembled = assembleCanonicalSshRelayRuntimeManifest(inputManifest)
if (!assembled.canonicalBytes.equals(bytes)) {
throw new Error('SSH relay runtime manifest bytes are not the canonical unsigned projection')
}
return assembled.manifest
}
export { MAX_CANONICAL_BYTES as SSH_RELAY_RUNTIME_MAX_CANONICAL_MANIFEST_BYTES }
@@ -0,0 +1,137 @@
import { createHash } from 'node:crypto'
import { describe, expect, it } from 'vitest'
import { createSshRelayArtifactTestManifest } from '../../src/main/ssh/ssh-relay-artifact-test-manifest.ts'
import { canonicalUnsignedSshRelayManifestBytes } from '../../src/main/ssh/ssh-relay-manifest-signature.ts'
import {
assembleCanonicalSshRelayRuntimeManifest,
parseCanonicalSshRelayRuntimeManifestBytes
} from './ssh-relay-runtime-manifest-assembly.mjs'
import { sshRelayRuntimeCompatibility } from './ssh-relay-runtime-compatibility.mjs'
import { computeSshRelayRuntimeContentId } from './ssh-relay-runtime-identity.mjs'
function unsignedManifest() {
const { signatures: _signatures, ...unsigned } = createSshRelayArtifactTestManifest()
return unsigned
}
function arm64TupleFrom(source) {
const tuple = structuredClone(source)
tuple.tupleId = 'linux-arm64-glibc'
tuple.architecture = 'arm64'
tuple.compatibility = structuredClone(sshRelayRuntimeCompatibility[tuple.tupleId])
for (const entry of tuple.entries) {
entry.path = entry.path.replaceAll('watcher-linux-x64-glibc', 'watcher-linux-arm64-glibc')
}
for (const file of tuple.nativeVerification.files) {
file.path = file.path.replaceAll('watcher-linux-x64-glibc', 'watcher-linux-arm64-glibc')
}
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`
return tuple
}
describe('SSH relay runtime canonical manifest assembly', () => {
it('matches the desktop canonical unsigned test vector exactly', () => {
const assembled = assembleCanonicalSshRelayRuntimeManifest(unsignedManifest())
expect(assembled.canonicalBytes.at(-1)).not.toBe('\n'.charCodeAt(0))
expect(createHash('sha256').update(assembled.canonicalBytes).digest('hex')).toBe(
'e78bf4416628a91055035dc7926035cbf633f29d3618be34e041c6dc5e0794fb'
)
expect(assembled.sha256).toBe(
'sha256:e78bf4416628a91055035dc7926035cbf633f29d3618be34e041c6dc5e0794fb'
)
expect(parseCanonicalSshRelayRuntimeManifestBytes(assembled.canonicalBytes)).toEqual(
assembled.manifest
)
})
it('sorts tuples, entries, and native attestations by portable ASCII identity', () => {
const input = unsignedManifest()
const arm64 = arm64TupleFrom(input.tuples[0])
input.tuples = [input.tuples[0], arm64].toReversed()
for (const tuple of input.tuples) {
tuple.entries = tuple.entries.toReversed()
tuple.nativeVerification.files = tuple.nativeVerification.files.toReversed()
}
const first = assembleCanonicalSshRelayRuntimeManifest(input)
input.tuples = input.tuples.toReversed()
for (const tuple of input.tuples) {
tuple.entries = tuple.entries.toReversed()
tuple.nativeVerification.files = tuple.nativeVerification.files.toReversed()
}
const second = assembleCanonicalSshRelayRuntimeManifest(input)
expect(first.canonicalBytes).toEqual(second.canonicalBytes)
expect(second.canonicalBytes).toEqual(canonicalUnsignedSshRelayManifestBytes(input))
expect(first.manifest.tuples.map((tuple) => tuple.tupleId)).toEqual([
'linux-arm64-glibc',
'linux-x64-glibc'
])
for (const tuple of first.manifest.tuples) {
expect(tuple.entries.map((entry) => entry.path)).toEqual(
tuple.entries.map((entry) => entry.path).toSorted()
)
expect(tuple.nativeVerification.files.map((entry) => entry.path)).toEqual(
tuple.nativeVerification.files.map((entry) => entry.path).toSorted()
)
}
})
it('rejects signatures, unknown fields, and non-canonical byte encodings', () => {
expect(() =>
assembleCanonicalSshRelayRuntimeManifest(createSshRelayArtifactTestManifest())
).toThrow(/unsigned|signature|field/i)
const extra = unsignedManifest()
extra.latest = true
expect(() => assembleCanonicalSshRelayRuntimeManifest(extra)).toThrow(/unrecognized|field/i)
const canonical = assembleCanonicalSshRelayRuntimeManifest(unsignedManifest()).canonicalBytes
expect(() =>
parseCanonicalSshRelayRuntimeManifestBytes(Buffer.concat([canonical, Buffer.from('\n')]))
).toThrow(/canonical/i)
expect(() => parseCanonicalSshRelayRuntimeManifestBytes(Buffer.from([0xff]))).toThrow(/utf-?8/i)
})
it('fails closed on inconsistent identity, archive, metadata, and native trust content', () => {
const mutations = [
(manifest) => {
manifest.tuples[0].contentId = `sha256:${'f'.repeat(64)}`
},
(manifest) => {
manifest.tuples[0].archive.fileCount += 1
},
(manifest) => {
manifest.tuples[0].metadataAssets.sbom.name = 'latest.json'
},
(manifest) => {
manifest.tuples[0].nativeVerification.files[0].sha256 = `sha256:${'f'.repeat(64)}`
}
]
for (const mutate of mutations) {
const manifest = unsignedManifest()
mutate(manifest)
expect(() => assembleCanonicalSshRelayRuntimeManifest(manifest)).toThrow()
}
})
it('rejects duplicate tuples and invalid release/timestamp identities', () => {
const duplicate = unsignedManifest()
duplicate.tuples.push(structuredClone(duplicate.tuples[0]))
expect(() => assembleCanonicalSshRelayRuntimeManifest(duplicate)).toThrow(/duplicate tuple/i)
const channel = unsignedManifest()
channel.build.channel = 'stable'
expect(() => assembleCanonicalSshRelayRuntimeManifest(channel)).toThrow(/release|build/i)
const timestamp = unsignedManifest()
timestamp.createdAt = '2026-07-14T00:00:00Z'
expect(() => assembleCanonicalSshRelayRuntimeManifest(timestamp)).toThrow(/timestamp/i)
})
})
@@ -0,0 +1,173 @@
import { createHash } from 'node:crypto'
import nacl from 'tweetnacl'
import {
parseCanonicalSshRelayRuntimeManifestBytes,
SSH_RELAY_RUNTIME_MAX_CANONICAL_MANIFEST_BYTES
} from './ssh-relay-runtime-manifest-assembly.mjs'
const DIGEST_PATTERN = /^sha256:[0-9a-f]{64}$/u
const SIGNATURE_PATTERN = /^[A-Za-z0-9+/]+={0,2}$/u
const MAX_SIGNATURES = 4
export const SSH_RELAY_RUNTIME_MANIFEST_SIGNING_LIMITS = Object.freeze({
maximumCanonicalBytes: SSH_RELAY_RUNTIME_MAX_CANONICAL_MANIFEST_BYTES
})
function assertObject(value, label) {
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
throw new Error(`SSH relay runtime manifest signing ${label} must be an object`)
}
}
function assertExactFields(value, fields, label) {
assertObject(value, label)
const actual = Object.keys(value).sort()
const expected = [...fields].sort()
if (actual.length !== expected.length || actual.some((key, index) => key !== expected[index])) {
throw new Error(`SSH relay runtime manifest signing ${label} has unexpected or missing fields`)
}
}
function sha256(bytes) {
return `sha256:${createHash('sha256').update(bytes).digest('hex')}`
}
function canonicalSignatureBytes(value) {
if (typeof value !== 'string' || !SIGNATURE_PATTERN.test(value)) {
throw new Error('SSH relay runtime manifest returned signature is not canonical base64')
}
const bytes = Buffer.from(value, 'base64')
if (bytes.length !== nacl.sign.signatureLength || bytes.toString('base64') !== value) {
throw new Error('SSH relay runtime manifest returned signature must contain exactly 64 bytes')
}
return bytes
}
function validateRequest(request) {
assertExactFields(
request,
['algorithm', 'canonicalBytes', 'payloadSha256', 'payloadSize'],
'request'
)
if (request.algorithm !== 'ed25519-v1') {
throw new Error('SSH relay runtime manifest signing request algorithm is unsupported')
}
if (!Buffer.isBuffer(request.canonicalBytes) && !(request.canonicalBytes instanceof Uint8Array)) {
throw new Error('SSH relay runtime manifest signing request payload must be bytes')
}
const canonicalBytes = Buffer.from(request.canonicalBytes)
if (
!Number.isSafeInteger(request.payloadSize) ||
request.payloadSize <= 0 ||
request.payloadSize > SSH_RELAY_RUNTIME_MANIFEST_SIGNING_LIMITS.maximumCanonicalBytes ||
request.payloadSize !== canonicalBytes.length
) {
throw new Error('SSH relay runtime manifest signing request payload size is inconsistent')
}
if (
!DIGEST_PATTERN.test(request.payloadSha256) ||
request.payloadSha256 !== sha256(canonicalBytes)
) {
throw new Error('SSH relay runtime manifest signing request payload SHA-256 is inconsistent')
}
const manifest = parseCanonicalSshRelayRuntimeManifestBytes(canonicalBytes)
return { canonicalBytes, manifest }
}
export function sshRelayRuntimeManifestKeyId(publicKey) {
if (!(publicKey instanceof Uint8Array) || publicKey.byteLength !== nacl.sign.publicKeyLength) {
throw new Error('SSH relay runtime manifest Ed25519 public key must contain exactly 32 bytes')
}
return sha256(publicKey)
}
export function createSshRelayRuntimeManifestSigningRequest(input) {
if (!Buffer.isBuffer(input) && !(input instanceof Uint8Array)) {
throw new Error('SSH relay runtime manifest signing payload must be bytes')
}
const canonicalBytes = Buffer.from(input)
if (
canonicalBytes.length === 0 ||
canonicalBytes.length > SSH_RELAY_RUNTIME_MANIFEST_SIGNING_LIMITS.maximumCanonicalBytes
) {
throw new Error('SSH relay runtime manifest signing payload exceeds its size limit')
}
parseCanonicalSshRelayRuntimeManifestBytes(canonicalBytes)
return {
algorithm: 'ed25519-v1',
canonicalBytes,
payloadSha256: sha256(canonicalBytes),
payloadSize: canonicalBytes.length
}
}
function acceptedKeyMap(input) {
if (!Array.isArray(input) || input.length === 0 || input.length > MAX_SIGNATURES) {
throw new Error(
'SSH relay runtime manifest signing accepted keys must be a bounded non-empty array'
)
}
const keys = new Map()
for (const [index, key] of input.entries()) {
assertExactFields(key, ['keyId', 'publicKey'], `accepted key ${index}`)
const derivedKeyId = sshRelayRuntimeManifestKeyId(key.publicKey)
if (key.keyId !== derivedKeyId) {
throw new Error('SSH relay runtime manifest signing accepted key ID disagrees with its bytes')
}
if (keys.has(key.keyId)) {
throw new Error(
`SSH relay runtime manifest signing has a duplicate accepted key: ${key.keyId}`
)
}
keys.set(key.keyId, key.publicKey)
}
return keys
}
function verifySigningResults(results, keys, canonicalBytes) {
if (!Array.isArray(results) || results.length === 0 || results.length > MAX_SIGNATURES) {
throw new Error('SSH relay runtime manifest signing results must be a bounded non-empty array')
}
const seen = new Set()
return results.map((result, index) => {
// Why: the protected signer may return only the authenticated key identity and signature bytes.
assertExactFields(result, ['keyId', 'signature'], `result ${index}`)
if (!DIGEST_PATTERN.test(result.keyId)) {
throw new Error('SSH relay runtime manifest signing result key ID is malformed')
}
if (seen.has(result.keyId)) {
throw new Error(
`SSH relay runtime manifest signing has a duplicate result key: ${result.keyId}`
)
}
seen.add(result.keyId)
const publicKey = keys.get(result.keyId)
if (!publicKey) {
throw new Error(`SSH relay runtime manifest signing returned an unknown key: ${result.keyId}`)
}
const signature = canonicalSignatureBytes(result.signature)
if (!nacl.sign.detached.verify(canonicalBytes, signature, publicKey)) {
throw new Error(
`SSH relay runtime manifest signing returned an invalid signature: ${result.keyId}`
)
}
return { algorithm: 'ed25519-v1', keyId: result.keyId, signature: result.signature }
})
}
export function finalizeSshRelayRuntimeManifestSigningHandoff({
request,
signingResults,
acceptedKeys
}) {
const { canonicalBytes, manifest: unsignedManifest } = validateRequest(request)
const keys = acceptedKeyMap(acceptedKeys)
const signatures = verifySigningResults(signingResults, keys, canonicalBytes).sort(
(left, right) => (left.keyId < right.keyId ? -1 : left.keyId > right.keyId ? 1 : 0)
)
const manifest = { ...unsignedManifest, signatures }
const bytes = Buffer.from(JSON.stringify(manifest), 'utf8')
return { manifest, bytes, sha256: sha256(bytes) }
}
@@ -0,0 +1,168 @@
import nacl from 'tweetnacl'
import { describe, expect, it } from 'vitest'
import { createSshRelayArtifactTestManifest } from '../../src/main/ssh/ssh-relay-artifact-test-manifest.ts'
import { verifySshRelayArtifactManifest } from '../../src/main/ssh/ssh-relay-manifest-signature.ts'
import { assembleCanonicalSshRelayRuntimeManifest } from './ssh-relay-runtime-manifest-assembly.mjs'
import {
SSH_RELAY_RUNTIME_MANIFEST_SIGNING_LIMITS,
createSshRelayRuntimeManifestSigningRequest,
finalizeSshRelayRuntimeManifestSigningHandoff,
sshRelayRuntimeManifestKeyId
} from './ssh-relay-runtime-manifest-signing-handoff.mjs'
const keyPair = nacl.sign.keyPair.fromSeed(Uint8Array.from({ length: 32 }, (_, index) => index))
const nextKeyPair = nacl.sign.keyPair.fromSeed(
Uint8Array.from({ length: 32 }, (_, index) => 31 - index)
)
function assembly() {
const { signatures: _signatures, ...unsigned } = createSshRelayArtifactTestManifest()
return assembleCanonicalSshRelayRuntimeManifest(unsigned)
}
function signingResult(request, pair = keyPair) {
return {
keyId: sshRelayRuntimeManifestKeyId(pair.publicKey),
signature: Buffer.from(nacl.sign.detached(request.canonicalBytes, pair.secretKey)).toString(
'base64'
)
}
}
function acceptedKey(pair = keyPair) {
return { keyId: sshRelayRuntimeManifestKeyId(pair.publicKey), publicKey: pair.publicKey }
}
describe('SSH relay runtime manifest signing handoff', () => {
it('creates a bounded request over the exact canonical unsigned bytes', () => {
const canonical = assembly().canonicalBytes
const request = createSshRelayRuntimeManifestSigningRequest(canonical)
expect(SSH_RELAY_RUNTIME_MANIFEST_SIGNING_LIMITS).toEqual({
maximumCanonicalBytes: 32 * 1024 * 1024
})
expect(Object.keys(request).sort()).toEqual([
'algorithm',
'canonicalBytes',
'payloadSha256',
'payloadSize'
])
expect(request).toMatchObject({
algorithm: 'ed25519-v1',
payloadSha256: 'sha256:e78bf4416628a91055035dc7926035cbf633f29d3618be34e041c6dc5e0794fb',
payloadSize: canonical.length
})
expect(request.canonicalBytes).toEqual(canonical)
})
it('accepts only key ID plus a verified returned signature', () => {
const request = createSshRelayRuntimeManifestSigningRequest(assembly().canonicalBytes)
const result = signingResult(request)
expect(Object.keys(result).sort()).toEqual(['keyId', 'signature'])
const finalized = finalizeSshRelayRuntimeManifestSigningHandoff({
request,
signingResults: [result],
acceptedKeys: [acceptedKey()]
})
expect(finalized.manifest.signatures).toEqual([{ algorithm: 'ed25519-v1', ...result }])
expect(finalized.bytes.at(-1)).not.toBe('\n'.charCodeAt(0))
expect(JSON.parse(finalized.bytes.toString('utf8'))).toEqual(finalized.manifest)
expect(verifySshRelayArtifactManifest(finalized.manifest, [acceptedKey()])).toEqual(
finalized.manifest
)
})
it('reconstructs canonical content and rejects request drift', () => {
const request = createSshRelayRuntimeManifestSigningRequest(assembly().canonicalBytes)
const result = signingResult(request)
for (const mutate of [
(copy) => {
copy.payloadSize += 1
},
(copy) => {
copy.payloadSha256 = `sha256:${'f'.repeat(64)}`
},
(copy) => {
copy.algorithm = 'rsa-v1'
},
(copy) => {
copy.canonicalBytes = Buffer.concat([copy.canonicalBytes, Buffer.from('\n')])
}
]) {
const copy = { ...request, canonicalBytes: Buffer.from(request.canonicalBytes) }
mutate(copy)
expect(() =>
finalizeSshRelayRuntimeManifestSigningHandoff({
request: copy,
signingResults: [result],
acceptedKeys: [acceptedKey()]
})
).toThrow()
}
})
it('fails closed on malformed, unknown, duplicate, or invalid returned signatures', () => {
const request = createSshRelayRuntimeManifestSigningRequest(assembly().canonicalBytes)
const result = signingResult(request)
const cases = [
{ signingResults: [], acceptedKeys: [acceptedKey()] },
{ signingResults: [{ ...result, extra: true }], acceptedKeys: [acceptedKey()] },
{
signingResults: [{ ...result, signature: Buffer.alloc(63).toString('base64') }],
acceptedKeys: [acceptedKey()]
},
{ signingResults: [result], acceptedKeys: [acceptedKey(nextKeyPair)] },
{
signingResults: [{ ...result, signature: Buffer.alloc(64).toString('base64') }],
acceptedKeys: [acceptedKey()]
},
{ signingResults: [result, structuredClone(result)], acceptedKeys: [acceptedKey()] }
]
for (const testCase of cases) {
expect(() =>
finalizeSshRelayRuntimeManifestSigningHandoff({ request, ...testCase })
).toThrow()
}
})
it('sorts verified dual signatures by key ID for deterministic final bytes', () => {
const request = createSshRelayRuntimeManifestSigningRequest(assembly().canonicalBytes)
const results = [
signingResult(request, nextKeyPair),
signingResult(request, keyPair)
].toReversed()
const acceptedKeys = [acceptedKey(nextKeyPair), acceptedKey(keyPair)].toReversed()
const first = finalizeSshRelayRuntimeManifestSigningHandoff({
request,
signingResults: results,
acceptedKeys
})
const second = finalizeSshRelayRuntimeManifestSigningHandoff({
request,
signingResults: results.toReversed(),
acceptedKeys: acceptedKeys.toReversed()
})
expect(first.bytes).toEqual(second.bytes)
expect(first.manifest.signatures.map((entry) => entry.keyId)).toEqual(
first.manifest.signatures.map((entry) => entry.keyId).toSorted()
)
})
it('rejects empty, non-byte, and oversized signing payloads before handoff', () => {
expect(() => createSshRelayRuntimeManifestSigningRequest(Buffer.alloc(0))).toThrow(
/empty|size/i
)
expect(() => createSshRelayRuntimeManifestSigningRequest('{}')).toThrow(/bytes/i)
expect(() =>
createSshRelayRuntimeManifestSigningRequest(
Buffer.alloc(SSH_RELAY_RUNTIME_MANIFEST_SIGNING_LIMITS.maximumCanonicalBytes + 1)
)
).toThrow(/size|limit/i)
})
})
@@ -0,0 +1,369 @@
import { z } from 'zod'
import { computeSshRelayRuntimeContentId } from './ssh-relay-runtime-identity.mjs'
const MAX_ARCHIVE_SIZE = 100 * 1024 * 1024
const MAX_EXPANDED_SIZE = 350 * 1024 * 1024
const MAX_FILE_SIZE = 250 * 1024 * 1024
const MAX_ENTRIES = 5_000
const MAX_PATH_BYTES = 240
const MAX_PATH_DEPTH = 32
const VERSION = /^\d+\.\d+(?:\.\d+)?(?:[-+][0-9A-Za-z.-]+)?$/u
const NUMERIC_VERSION = /^\d+\.\d+(?:\.\d+)?$/u
const OPENSSH_VERSION = /^\d+\.\d+p\d+$/u
const ASSET_NAME = /^[A-Za-z0-9._-]+$/u
const PORTABLE_PATH = /^[A-Za-z0-9._@+/-]+$/u
const WINDOWS_DEVICE_NAME = /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/iu
const TIMESTAMP = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/u
const digestSchema = z.string().regex(/^sha256:[0-9a-f]{64}$/u)
const safeSizeSchema = z.number().int().min(0).max(Number.MAX_SAFE_INTEGER)
const versionSchema = z.string().regex(VERSION).max(64)
const numericVersionSchema = z.string().regex(NUMERIC_VERSION).max(64)
const timestampSchema = z
.string()
.regex(TIMESTAMP)
.refine(
(value) => {
const milliseconds = Date.parse(value)
return !Number.isNaN(milliseconds) && new Date(milliseconds).toISOString() === value
},
{ message: 'invalid canonical UTC timestamp' }
)
const directoryEntrySchema = z
.object({ path: z.string(), type: z.literal('directory'), mode: z.literal(0o755) })
.strict()
const fileEntrySchema = z
.object({
path: z.string(),
type: z.literal('file'),
role: z.enum([
'node',
'relay',
'relay-watcher',
'node-pty-native',
'parcel-watcher-native',
'native-runtime',
'runtime-javascript',
'license'
]),
size: safeSizeSchema.max(MAX_FILE_SIZE),
mode: z.union([z.literal(0o644), z.literal(0o755)]),
sha256: digestSchema
})
.strict()
const entrySchema = z.discriminatedUnion('type', [directoryEntrySchema, fileEntrySchema])
const glibcSchema = z
.object({
family: z.literal('glibc'),
minimumVersion: numericVersionSchema,
minimumLibstdcxxVersion: numericVersionSchema,
minimumGlibcxxVersion: numericVersionSchema
})
.strict()
const muslSchema = z
.object({
family: z.literal('musl'),
minimumVersion: numericVersionSchema,
minimumLibstdcxxVersion: z.null(),
minimumGlibcxxVersion: z.null()
})
.strict()
const compatibilitySchema = z.discriminatedUnion('kind', [
z
.object({
kind: z.literal('linux'),
minimumKernelVersion: numericVersionSchema,
libc: z.discriminatedUnion('family', [glibcSchema, muslSchema])
})
.strict(),
z.object({ kind: z.literal('darwin'), minimumVersion: numericVersionSchema }).strict(),
z
.object({
kind: z.literal('windows'),
minimumBuild: safeSizeSchema,
minimumOpenSshVersion: z.string().regex(OPENSSH_VERSION).max(64),
minimumPowerShellVersion: numericVersionSchema,
minimumDotNetFrameworkRelease: safeSizeSchema
})
.strict()
])
const metadataAssetSchema = z
.object({ name: z.string().regex(ASSET_NAME), size: safeSizeSchema, sha256: digestSchema })
.strict()
const nativeVerificationSchema = z
.object({
policy: z.enum(['linux-hash-only-v1', 'apple-developer-id-v1', 'signpath-authenticode-v1']),
tool: z
.object({
name: z.string().regex(ASSET_NAME),
version: z
.string()
.regex(/^[\x20-\x7e]+$/u)
.max(64)
})
.strict(),
verifiedAt: timestampSchema,
files: z
.array(z.object({ path: z.string(), sha256: digestSchema }).strict())
.min(1)
.max(MAX_ENTRIES)
})
.strict()
const tupleSchema = z
.object({
tupleId: z.enum([
'linux-x64-glibc',
'linux-arm64-glibc',
'linux-x64-musl',
'linux-arm64-musl',
'darwin-x64',
'darwin-arm64',
'win32-x64',
'win32-arm64'
]),
os: z.enum(['linux', 'darwin', 'win32']),
architecture: z.enum(['x64', 'arm64']),
compatibility: compatibilitySchema,
nodeVersion: versionSchema,
dependencies: z
.object({ nodePtyVersion: versionSchema, parcelWatcherVersion: versionSchema })
.strict(),
entries: z.array(entrySchema).min(1).max(MAX_ENTRIES),
contentId: digestSchema,
archive: z
.object({
name: z.string().regex(ASSET_NAME),
size: safeSizeSchema.max(MAX_ARCHIVE_SIZE),
expandedSize: safeSizeSchema.max(MAX_EXPANDED_SIZE),
fileCount: safeSizeSchema.max(MAX_ENTRIES),
sha256: digestSchema
})
.strict(),
metadataAssets: z
.object({ sbom: metadataAssetSchema, provenance: metadataAssetSchema })
.strict(),
nativeVerification: nativeVerificationSchema
})
.strict()
const unsignedManifestSchema = z
.object({
schemaVersion: z.literal(1),
build: z
.object({
tag: z.string().max(64),
channel: z.enum(['stable', 'rc', 'perf']),
version: z.string().max(64),
relayProtocolVersion: z.number().int().min(1).max(Number.MAX_SAFE_INTEGER)
})
.strict(),
createdAt: timestampSchema,
tuples: z.array(tupleSchema).min(1).max(8)
})
.strict()
function assertSafePath(path) {
if (!path || Buffer.byteLength(path, 'utf8') > MAX_PATH_BYTES || !PORTABLE_PATH.test(path)) {
throw new Error(`SSH relay runtime manifest contains an unsafe artifact path: ${path}`)
}
const segments = path.split('/')
if (path.startsWith('/') || segments.length > MAX_PATH_DEPTH) {
throw new Error(`SSH relay runtime manifest contains an unsafe artifact path: ${path}`)
}
for (const segment of segments) {
if (
!segment ||
segment === '.' ||
segment === '..' ||
segment.endsWith('.') ||
segment.endsWith(' ') ||
WINDOWS_DEVICE_NAME.test(segment)
) {
throw new Error(`SSH relay runtime manifest contains an unsafe artifact path: ${path}`)
}
}
}
function expectedTupleId(tuple) {
if (tuple.os === 'linux' && tuple.compatibility.kind === 'linux') {
return `linux-${tuple.architecture}-${tuple.compatibility.libc.family}`
}
return `${tuple.os}-${tuple.architecture}`
}
function expectedArchiveName(tuple) {
const extension = tuple.os === 'win32' ? 'zip' : 'tar.xz'
return `orca-ssh-relay-runtime-v1-${tuple.tupleId}-${tuple.contentId.slice(7)}.${extension}`
}
function assertTupleEntries(tuple) {
const exactPaths = new Set()
const foldedPaths = new Set()
const directories = new Set()
for (const entry of tuple.entries) {
assertSafePath(entry.path)
const folded = entry.path.toLowerCase()
if (exactPaths.has(entry.path) || foldedPaths.has(folded)) {
throw new Error(`SSH relay runtime manifest has a colliding path: ${entry.path}`)
}
exactPaths.add(entry.path)
foldedPaths.add(folded)
if (entry.type === 'directory') {
directories.add(entry.path)
}
}
for (const entry of tuple.entries) {
const separator = entry.path.lastIndexOf('/')
if (separator > 0 && !directories.has(entry.path.slice(0, separator))) {
throw new Error(`SSH relay runtime manifest has an undeclared parent: ${entry.path}`)
}
}
const files = tuple.entries.filter((entry) => entry.type === 'file')
const expectedPaths = new Map([
['node', tuple.os === 'win32' ? 'bin/node.exe' : 'bin/node'],
['relay', 'relay.js'],
['relay-watcher', 'relay-watcher.js']
])
for (const role of [
'node',
'relay',
'relay-watcher',
'node-pty-native',
'parcel-watcher-native'
]) {
const matching = files.filter((entry) => entry.role === role)
if (
matching.length !== 1 ||
(expectedPaths.has(role) && matching[0].path !== expectedPaths.get(role))
) {
throw new Error(`SSH relay runtime manifest requires one valid ${role} entry`)
}
}
if (
!files.some((entry) => entry.path === 'node_modules/node-pty/package.json') ||
!files.some((entry) => entry.path === 'node_modules/@parcel/watcher/package.json') ||
!files.some((entry) => entry.role === 'license')
) {
throw new Error('SSH relay runtime manifest is missing required package or license content')
}
if (files.find((entry) => entry.role === 'node').mode !== 0o755) {
throw new Error('SSH relay runtime manifest bundled Node must be executable')
}
return files
}
function assertNativeVerification(tuple, files) {
const watcherPackage =
tuple.os === 'linux' && tuple.compatibility.kind === 'linux'
? `node_modules/@parcel/watcher-linux-${tuple.architecture}-${tuple.compatibility.libc.family}`
: `node_modules/@parcel/watcher-${tuple.os}-${tuple.architecture}`
for (const entry of tuple.entries) {
if (
entry.path.startsWith('node_modules/@parcel/watcher-') &&
entry.path !== watcherPackage &&
!entry.path.startsWith(`${watcherPackage}/`)
) {
throw new Error('SSH relay runtime manifest contains an extra native watcher package')
}
}
const expectedPolicy =
tuple.os === 'linux'
? 'linux-hash-only-v1'
: tuple.os === 'darwin'
? 'apple-developer-id-v1'
: 'signpath-authenticode-v1'
if (tuple.nativeVerification.policy !== expectedPolicy) {
throw new Error('SSH relay runtime manifest has the wrong native verification policy')
}
const attested = new Map()
for (const file of tuple.nativeVerification.files) {
assertSafePath(file.path)
if (attested.has(file.path)) {
throw new Error(`SSH relay runtime manifest has duplicate native attestation: ${file.path}`)
}
attested.set(file.path, file.sha256)
}
const nativeRoles = new Set([
'node',
'node-pty-native',
'parcel-watcher-native',
'native-runtime'
])
for (const file of files) {
if (nativeRoles.has(file.role) && attested.get(file.path) !== file.sha256) {
throw new Error(`SSH relay runtime manifest has an invalid attested hash: ${file.path}`)
}
}
for (const [path, sha256] of attested) {
const file = files.find((entry) => entry.path === path)
if (!file || file.sha256 !== sha256) {
throw new Error(`SSH relay runtime manifest attests missing or mismatched content: ${path}`)
}
}
}
function assertTupleConsistency(tuple) {
const compatibilityKind = tuple.os === 'win32' ? 'windows' : tuple.os
if (expectedTupleId(tuple) !== tuple.tupleId || tuple.compatibility.kind !== compatibilityKind) {
throw new Error(`SSH relay runtime manifest tuple identity is inconsistent: ${tuple.tupleId}`)
}
const files = assertTupleEntries(tuple)
assertNativeVerification(tuple, files)
const expandedSize = files.reduce((total, entry) => total + entry.size, 0)
if (tuple.archive.fileCount !== files.length || tuple.archive.expandedSize !== expandedSize) {
throw new Error(`SSH relay runtime manifest archive metadata is inconsistent: ${tuple.tupleId}`)
}
if (tuple.contentId !== computeSshRelayRuntimeContentId(tuple)) {
throw new Error(`SSH relay runtime manifest content identity is inconsistent: ${tuple.tupleId}`)
}
if (tuple.archive.name !== expectedArchiveName(tuple)) {
throw new Error(`SSH relay runtime manifest archive name is inconsistent: ${tuple.tupleId}`)
}
const metadataPrefix = `orca-ssh-relay-runtime-${tuple.tupleId}`
if (
tuple.metadataAssets.sbom.name !== `${metadataPrefix}.spdx.json` ||
tuple.metadataAssets.provenance.name !== `${metadataPrefix}.provenance.json`
) {
throw new Error(
`SSH relay runtime manifest metadata asset name is inconsistent: ${tuple.tupleId}`
)
}
}
function parseReleaseTag(tag) {
for (const [pattern, channel] of [
[/^v(\d+\.\d+\.\d+)$/u, 'stable'],
[/^v(\d+\.\d+\.\d+-rc\.\d+)$/u, 'rc'],
[/^v(\d+\.\d+\.\d+-rc\.\d+\.perf)$/u, 'perf']
]) {
const match = pattern.exec(tag)
if (match) {
return { channel, version: match[1] }
}
}
throw new Error('SSH relay runtime manifest release tag is invalid')
}
export function parseSshRelayRuntimeUnsignedManifest(input) {
const parsed = unsignedManifestSchema.parse(input)
const release = parseReleaseTag(parsed.build.tag)
if (release.channel !== parsed.build.channel || release.version !== parsed.build.version) {
throw new Error('SSH relay runtime manifest build identity does not match its exact release')
}
const tupleIds = new Set()
for (const tuple of parsed.tuples) {
if (tupleIds.has(tuple.tupleId)) {
throw new Error(`SSH relay runtime manifest has a duplicate tuple: ${tuple.tupleId}`)
}
tupleIds.add(tuple.tupleId)
assertTupleConsistency(tuple)
}
return parsed
}
@@ -107,6 +107,14 @@ describe('SSH relay runtime artifact workflow', () => {
expect(source.split(`${script}.test.mjs`)).toHaveLength(5)
expect(source.split(`node --check config/scripts/${script}.mjs`)).toHaveLength(3)
}
expect(
source.match(/node --check config\/scripts\/ssh-relay-runtime-manifest-validation\.mjs/g)
).toHaveLength(2)
for (const moduleName of ['manifest-assembly', 'manifest-signing-handoff']) {
const script = `ssh-relay-runtime-${moduleName}`
expect(source.split(`${script}.test.mjs`)).toHaveLength(5)
expect(source.split(`node --check config/scripts/${script}.mjs`)).toHaveLength(3)
}
expect(
source.match(/node --check config\/scripts\/ssh-relay-runtime-native-signing-plan\.mjs/g)
).toHaveLength(2)
@@ -64,10 +64,11 @@ complete a box.
Windows compatibility-kind parity is closed locally and on all six target-native jobs in
exact-head run
[29393022768](https://github.com/stablyai/orca/actions/runs/29393022768) under
`E-M4-WINDOWS-MANIFEST-PARITY-LOCAL-001` and `E-M4-WINDOWS-MANIFEST-PARITY-CI-001`. Next,
canonicalize only validated unsigned manifest bytes, create the bounded signing request, and
verify returned signatures without production credentials. No production workflow,
publication, desktop consumer, signing credential, or tuple is connected.
`E-M4-WINDOWS-MANIFEST-PARITY-LOCAL-001` and `E-M4-WINDOWS-MANIFEST-PARITY-CI-001`.
Disconnected canonical assembly and signing-handoff modules are implemented locally. Focused
and broad local gates pass under `E-M4-MANIFEST-HANDOFF-LOCAL-001` and
`E-M4-MANIFEST-HANDOFF-LOCAL-002`; exact-head native CI remains pending. No production
workflow, publication, desktop consumer, signing credential, or tuple is connected.
## Work packages, in required order
@@ -113,7 +114,10 @@ complete a box.
- [ ] **In progress — 2026-07-15, Codex implementation owner:** add disconnected canonical unsigned
manifest assembly, a bounded signing request, and returned-signature verification. Keep final
detached-signature asset encoding, production credentials, publication, desktop consumers, and
every tuple outside this slice until their contracts and gates are explicit.
every tuple outside this slice until their contracts and gates are explicit. Purpose-named RED
and GREEN suites plus broad local regressions are recorded under
`E-M4-MANIFEST-HANDOFF-LOCAL-RED-001`, `E-M4-MANIFEST-HANDOFF-LOCAL-001`, and
`E-M4-MANIFEST-HANDOFF-LOCAL-002`; exact-head native CI is next.
- [ ] Add target-native runtime jobs as desktop release prerequisites.
- [ ] Add native signing jobs; hash only the returned signed bytes.
- [ ] Add a fail-closed aggregate and immutable manifest-signing job.
@@ -9,7 +9,7 @@ work; keep exact commands, runner identities, hashes, metrics, and residual gaps
Date created: 2026-07-14<br>
Last updated: 2026-07-15<br>
Current phase: Milestone 4 / Work Package 3 credential-free canonical manifest/signing handoff — **In progress — 2026-07-15, Codex implementation owner**. The disconnected release-DAG, aggregate/read-back byte boundaries, and Windows artifact/manifest parity prerequisite are closed locally and on all six native build jobs under E-M4-RELEASE-DAG-LOCAL-001, E-M4-RELEASE-DAG-CI-001, E-M4-AGGREGATE-READBACK-LOCAL-001, E-M4-AGGREGATE-READBACK-CI-001, E-M4-WINDOWS-MANIFEST-PARITY-LOCAL-001, and E-M4-WINDOWS-MANIFEST-PARITY-CI-001. The active package is limited to canonical unsigned-manifest bytes, a bounded signing request, and returned-signature verification; it may not choose final detached-signature asset encoding, publish, connect desktop consumers, use production signing credentials, or enable a tuple. Production/default behavior is unchanged, no bundled-runtime path is enabled, and no artifact is published.<br>
Session checkpoint: **In progress — 2026-07-15, Codex implementation owner** — exact-head artifact run [29393022768](https://github.com/stablyai/orca/actions/runs/29393022768) at `c68a99039e4633d41e21fb30afdfeaa06f776369` executes the corrected compatibility/schema/workflow contracts under Node 24.18.0 and rebuilds, verifies, smokes, compares, and uploads all six unpublished target-native artifacts. Both regenerated Windows identities use compatibility `kind: "windows"`; x64 content ID is `sha256:4224aee6de820a94263f05ebfc58edd421921431e8cbdf1d5ec6ddcf783afc26` and arm64 content ID is `sha256:02edf462be83c2864a89546d5344d348f9e07ce10964660342608a8c614e47db`. Both Linux supplemental userland jobs and the Windows x64 floor job pass. The workflow remains red only because Windows arm64 runner build 26200 is not the required build 26100, after complete runtime smoke settles in 8,382.8952 ms with 49,811,456-byte RSS. Golden E2E [29393022784](https://github.com/stablyai/orca/actions/runs/29393022784) and PR Checks [29393022761](https://github.com/stablyai/orca/actions/runs/29393022761) are green. The parity prerequisite is closed under E-M4-WINDOWS-MANIFEST-PARITY-CI-001; canonical manifest/signature-handoff RED tests are next. Real Apple/SignPath signing, returned production signatures, Gatekeeper/notarization, Defender/WDAC, missing exact-floor snapshots, protected manifest signing, and native trust remain separately gated. Nothing is published or enabled, and legacy remains the production default.<br>
Session checkpoint: **In progress — 2026-07-15, Codex implementation owner** — exact-head artifact run [29393022768](https://github.com/stablyai/orca/actions/runs/29393022768) at `c68a99039e4633d41e21fb30afdfeaa06f776369` executes the corrected compatibility/schema/workflow contracts under Node 24.18.0 and rebuilds, verifies, smokes, compares, and uploads all six unpublished target-native artifacts. Both regenerated Windows identities use compatibility `kind: "windows"`; x64 content ID is `sha256:4224aee6de820a94263f05ebfc58edd421921431e8cbdf1d5ec6ddcf783afc26` and arm64 content ID is `sha256:02edf462be83c2864a89546d5344d348f9e07ce10964660342608a8c614e47db`. Both Linux supplemental userland jobs and the Windows x64 floor job pass. The workflow remains red only because Windows arm64 runner build 26200 is not the required build 26100, after complete runtime smoke settles in 8,382.8952 ms with 49,811,456-byte RSS. Golden E2E [29393022784](https://github.com/stablyai/orca/actions/runs/29393022784) and PR Checks [29393022761](https://github.com/stablyai/orca/actions/runs/29393022761) are green. The parity prerequisite is closed under E-M4-WINDOWS-MANIFEST-PARITY-CI-001. Disconnected canonical assembly and signing-handoff modules are now implemented; focused and broad local gates pass under E-M4-MANIFEST-HANDOFF-LOCAL-001 and E-M4-MANIFEST-HANDOFF-LOCAL-002, including 38 release-side files / 214 tests, 3 desktop files / 47 tests, syntax, typecheck, full lint, formatting, max-lines, and diff checks. Exact-head native CI remains pending. Real Apple/SignPath signing, returned production signatures, Gatekeeper/notarization, Defender/WDAC, missing exact-floor snapshots, protected manifest signing, and native trust remain separately gated. Nothing is published or enabled, and legacy remains the production default.<br>
Primary design: [SSH relay GitHub Release plan](./2026-07-14-ssh-relay-github-release-plan.html)<br>
Motivating issues: [#8450](https://github.com/stablyai/orca/issues/8450), [#1693](https://github.com/stablyai/orca/issues/1693)
@@ -73,8 +73,9 @@ same change as the work it records.
canonical bytes only from fully validated inputs, create a bounded credential-free signing request,
and reconstruct and verify the returned Ed25519 signature before emitting a final manifest. Final
detached-signature asset encoding, production credentials, publication, desktop consumers, and
tuple enablement remain outside this slice. No broader Milestone 4 box is checked until the
corresponding implementation and exact tests exist.
tuple enablement remain outside this slice. Focused and broad local gates are green under
E-M4-MANIFEST-HANDOFF-LOCAL-001 and E-M4-MANIFEST-HANDOFF-LOCAL-002; exact-head native CI remains
pending. No broader Milestone 4 box is checked until its evidence exists.
- Completed Work Package 2 gate: target-native Windows source-signature reports from exact-head
artifact jobs 87267322867 and 87267322870 were independently downloaded and matched to their
identities and signing-stage reports under E-M3-WINDOWS-SOURCE-SIGNATURE-CI-001. PR Checks
@@ -192,11 +193,11 @@ same change as the work it records.
per-target opt-in selects bundled-preferred behavior, and implementing the setting does not
authorize default-on rollout or legacy removal (E-M1-ROLLOUT-DECISION-001).
- Legacy fallback removal: not authorized.
- Next required action: add RED tests and implement disconnected canonical unsigned-manifest
assembly, a bounded credential-free signing request, and returned-signature reconstruction and
verification. Keep final detached-signature asset encoding, real native/manifest signing
credentials, endpoint trust, missing exact-floor snapshots, production workflow wiring,
publication, desktop consumers, and every tuple's enabled state outside this slice.
- Next required action: commit and push the locally verified disconnected handoff, then prove the exact
head on all six native artifact jobs plus PR Checks and Golden E2E before recording this package
complete. Keep final detached-signature asset encoding, real native/manifest signing credentials,
endpoint trust, missing exact-floor snapshots, production workflow wiring, publication, desktop
consumers, and every tuple's enabled state outside this slice.
## Non-Negotiable Invariants
@@ -1537,6 +1538,9 @@ focused commands as their scripts/tests are introduced.
- [x] `pnpm exec vitest run --config config/vitest.config.ts --maxWorkers=1 config/scripts/ssh-relay-runtime-aggregate-input.test.mjs config/scripts/ssh-relay-runtime-draft-readback.test.mjs config/scripts/ssh-relay-runtime-workflow.test.mjs` (E-M4-AGGREGATE-READBACK-LOCAL-001; static native-job wiring only)
- [x] `pnpm exec vitest run --config config/vitest.config.ts --maxWorkers=1 config/scripts/ssh-relay-runtime-compatibility.test.mjs` (E-M4-WINDOWS-MANIFEST-PARITY-LOCAL-RED-001, E-M4-WINDOWS-MANIFEST-PARITY-LOCAL-001; exact Windows compatibility discriminator and canonical vector)
- [x] `pnpm exec vitest run --config config/vitest.config.ts --maxWorkers=1 config/scripts/ssh-relay-runtime-compatibility.test.mjs config/scripts/ssh-relay-runtime-workflow.test.mjs src/main/ssh/ssh-relay-artifact-schema.test.ts` (E-M4-WINDOWS-MANIFEST-PARITY-LOCAL-RED-001, E-M4-WINDOWS-MANIFEST-PARITY-LOCAL-001; build/desktop contract parity and static native-job wiring)
- [x] `pnpm exec vitest run --config config/vitest.config.ts --maxWorkers=1 config/scripts/ssh-relay-runtime-manifest-assembly.test.mjs config/scripts/ssh-relay-runtime-manifest-signing-handoff.test.mjs` (E-M4-MANIFEST-HANDOFF-LOCAL-RED-001, E-M4-MANIFEST-HANDOFF-LOCAL-001)
- [x] `pnpm exec vitest run --config config/vitest.config.ts --maxWorkers=1 config/scripts/ssh-relay*.test.mjs` (E-M4-MANIFEST-HANDOFF-LOCAL-002; all release-side SSH-relay contracts)
- [x] `pnpm exec vitest run --config config/vitest.config.ts --maxWorkers=1 src/main/ssh/ssh-relay-artifact-schema.test.ts src/main/ssh/ssh-relay-manifest-signature.test.ts src/main/ssh/ssh-relay-release-asset.test.ts` (E-M4-MANIFEST-HANDOFF-LOCAL-002; desktop schema/signature parity)
### Commands/scripts that must be added or formally identified
@@ -9219,6 +9223,109 @@ diff --check`.
request, and returned-signature verification. Keep final detached-signature asset encoding,
production credentials, publication, desktop consumers, and tuple enablement disconnected.
### E-M4-MANIFEST-HANDOFF-LOCAL-RED-001 — Release-side assembly and signing handoff are absent
- Date: 2026-07-15
- Owner: Codex implementation owner
- Source: exact base `63899c182f3a831d61fb1f6566a0d0318bca4192` plus uncommitted
purpose-named tests; draft PR [#8741](https://github.com/stablyai/orca/pull/8741).
- Runner/network: local macOS 26.2 build 25C56 arm64, Node v26.0.0 and pnpm 10.24.0; no network,
runner, signing credential, release, publication, desktop consumer, SSH host, or production call.
- Command:
```sh
/usr/bin/time -l pnpm exec vitest run --config config/vitest.config.ts --maxWorkers=1 \
config/scripts/ssh-relay-runtime-manifest-assembly.test.mjs \
config/scripts/ssh-relay-runtime-manifest-signing-handoff.test.mjs
```
- Result: expected RED. Both suites fail before collecting tests because
`ssh-relay-runtime-manifest-assembly.mjs` is absent; the signing-handoff suite also depends on that
boundary. Vitest reports 2 failed files in 264 ms; `/usr/bin/time -l` records 1.12 seconds wall,
131,710,976-byte maximum RSS, zero swaps, and 95,835,440-byte peak memory footprint.
- Oracle proved: the existing desktop canonical/signature contract has no release-side module that
assembles and re-parses the exact canonical unsigned bytes, bounds the credential-free signing
request, or verifies the returned key ID/signature before final-manifest emission.
- Does not prove: implementation correctness, byte parity, Ed25519 return verification, native
runner behavior, production credentials, publication, desktop embedding, SSH behavior, or an
enabled tuple.
- Follow-up: implement only the two disconnected release-side boundaries and retain every
production/default behavior and final detached-signature asset-encoding decision unchanged.
### E-M4-MANIFEST-HANDOFF-LOCAL-001 — Disconnected canonical assembly and signature return verify locally
- Date: 2026-07-15
- Owner: Codex implementation owner
- Source: exact base `63899c182f3a831d61fb1f6566a0d0318bca4192` plus the uncommitted
manifest validation, assembly, signing-handoff, test, and static workflow wiring changes; draft PR
[#8741](https://github.com/stablyai/orca/pull/8741).
- Runner/network: local macOS 26.2 build 25C56 arm64, Node v26.0.0 and pnpm 10.24.0; no network,
runner, signing credential, release, publication, desktop consumer, SSH host, or production call.
- Command:
```sh
/usr/bin/time -l pnpm exec vitest run --config config/vitest.config.ts --maxWorkers=1 \
config/scripts/ssh-relay-runtime-manifest-assembly.test.mjs \
config/scripts/ssh-relay-runtime-manifest-signing-handoff.test.mjs
```
- Result: GREEN. Vitest reports 2 files / 11 tests passed in 1.35 seconds; `/usr/bin/time -l`
records 15.14 seconds wall, 188,792,832-byte maximum RSS, zero swaps, and 96,490,920-byte peak
memory footprint.
- Oracle proved: validated tuple projections produce byte-identical canonical unsigned bytes to the
desktop contract; signing requests bind exact bytes, size, SHA-256, and `ed25519-v1`; returned key
IDs and signatures are allowlisted, deduplicated, cryptographically verified, deterministically
ordered, and revalidated through the desktop signed-manifest verifier before final emission.
- Does not prove: the broader SSH-relay suite, typecheck/lint/formatting gates, native runner parity,
production credentials, final detached-signature asset encoding, publication, desktop embedding,
SSH behavior, or an enabled tuple.
- Follow-up: run broader local gates, then exact-head all-six native CI; keep every production and
rollout boundary disconnected.
### E-M4-MANIFEST-HANDOFF-LOCAL-002 — Broad local manifest-handoff regressions and static gates
- Date: 2026-07-15
- Owner: Codex implementation owner
- Source: exact base `63899c182f3a831d61fb1f6566a0d0318bca4192` plus the uncommitted
manifest validation, assembly, signing-handoff, test, workflow, and checklist changes; draft PR
[#8741](https://github.com/stablyai/orca/pull/8741).
- Runner/network: local macOS 26.2 build 25C56 arm64, Node v26.0.0 and pnpm 10.24.0; no network,
signing credential, release, publication, desktop consumer, SSH host, or production call. The
repository's Node 24 requirement is intentionally deferred to the exact native CI jobs rather than
inferred from this Node 26 run.
- Commands and results:
- `/usr/bin/time -l pnpm exec vitest run --config config/vitest.config.ts --maxWorkers=1 config/scripts/ssh-relay*.test.mjs`
— GREEN, 38 files / 214 tests in 8.97 seconds; 10.13 seconds wall, 188,219,392-byte maximum
RSS, zero swaps, and 95,589,680-byte peak memory footprint.
- `/usr/bin/time -l pnpm exec vitest run --config config/vitest.config.ts --maxWorkers=1 src/main/ssh/ssh-relay-artifact-schema.test.ts src/main/ssh/ssh-relay-manifest-signature.test.ts src/main/ssh/ssh-relay-release-asset.test.ts`
— GREEN, 3 files / 47 tests in 1.34 seconds; 2.40 seconds wall, 131,973,120-byte maximum RSS,
zero swaps, and 96,081,200-byte peak memory footprint.
- `node --check` for the validation, assembly, assembly-test, signing-handoff, and
signing-handoff-test modules — GREEN with no output.
- Focused `pnpm exec oxlint` for all six touched script/test files — GREEN with no findings.
- Focused `pnpm exec oxfmt --check` for all nine touched code/workflow/checklist files — GREEN in
1,023 ms.
- `/usr/bin/time -l pnpm run typecheck` — GREEN in 9.44 seconds wall with 1,182,597,120-byte
maximum RSS and zero swaps.
- `pnpm run lint` — GREEN in 26.12 seconds wall. Full oxlint, switch exhaustiveness, styled
scrollbars, 41 reliability gates, 355-entry max-lines ratchet, bundled-skill guides,
localization catalog/parity, and localization coverage pass. The 26 printed warnings are in
untouched existing files; none is introduced by this package.
- `pnpm run check:max-lines-ratchet` — GREEN, 355 grandfathered suppressions and no new bypasses.
- `git diff --check` — GREEN with no output.
- Structural bound audit — a maximum 240-byte file projection is 407 bytes and native attestation
projection is 334 bytes; `8 * 5,000 * (407 + 334) = 29,640,000`, leaving 3,914,432 bytes beneath
the 32 MiB canonical/signing ceiling for tuple and build envelopes.
- Oracle proved: the disconnected handoff preserves all existing release-side SSH-relay contracts,
emits bytes accepted by the desktop schema/signature implementation, stays syntactically and
statically valid, introduces no formatting/max-lines regression, and has a bounded ceiling
consistent with the declared eight-tuple/5,000-entry schema.
- Does not prove: Node 24/native-runner behavior, target-native build non-regression, production
credentials, final detached-signature asset encoding, publication, desktop embedding, SSH
transfer/install behavior, or an enabled tuple.
- Follow-up: commit and push the exact locally verified package, then record the all-six native jobs,
PR Checks, and Golden E2E at that exact head.
## Accepted Gaps
No product gap is accepted merely because it appears in this list. Each entry requires explicit
@@ -9276,12 +9383,12 @@ The project is not complete until every applicable item below is checked with ev
## Next Required Action
Add RED tests and implement credential-free canonical unsigned-manifest assembly, a bounded signing
request, and returned-signature reconstruction and verification. Do not choose final detached-
signature asset encoding, connect release publication, use production signing credentials, or add a
desktop consumer in this slice. In parallel, provision qualifying exact-floor execution for Linux
kernel 4.18, macOS 13.5, and Windows arm64 build 26100 and real macOS/Windows signing and trust. Keep
every tuple disabled until the applicable baseline and trust cells pass.
Commit and push the locally verified credential-free manifest handoff, then prove that exact head on
all six native artifact jobs plus PR Checks and Golden E2E. Do not choose final detached-signature
asset encoding, connect release publication, use production signing credentials, or add a desktop
consumer in this slice. In parallel, provision qualifying exact-floor execution for Linux kernel
4.18, macOS 13.5, and Windows arm64 build 26100 and real macOS/Windows signing and trust. Keep every
tuple disabled until the applicable baseline and trust cells pass.
Cross-family Layer B targets, the protected manifest-signing environment, oldest-baseline/native-
trust cells, and the paired legacy performance baseline remain release/default-path blockers. No