build(ssh): verify runtime release bytes

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
Jinwoo-H
2026-07-15 01:30:16 -04:00
co-authored by Orca
parent 97164470cb
commit e995186545
8 changed files with 923 additions and 22 deletions
@@ -147,6 +147,10 @@ jobs:
node --check config/scripts/ssh-relay-runtime-release-stage-gate.test.mjs
node --check config/scripts/ssh-relay-runtime-draft-recovery.mjs
node --check config/scripts/ssh-relay-runtime-draft-recovery.test.mjs
node --check config/scripts/ssh-relay-runtime-aggregate-input.mjs
node --check config/scripts/ssh-relay-runtime-aggregate-input.test.mjs
node --check config/scripts/ssh-relay-runtime-draft-readback.mjs
node --check config/scripts/ssh-relay-runtime-draft-readback.test.mjs
pnpm exec vitest run --config config/vitest.config.ts \
config/scripts/ssh-relay-node-release-verification.test.mjs \
config/scripts/ssh-relay-node-tar-inspection.test.mjs \
@@ -170,6 +174,8 @@ jobs:
config/scripts/ssh-relay-runtime-windows-source-signature-verification.test.mjs \
config/scripts/ssh-relay-runtime-release-stage-gate.test.mjs \
config/scripts/ssh-relay-runtime-draft-recovery.test.mjs \
config/scripts/ssh-relay-runtime-aggregate-input.test.mjs \
config/scripts/ssh-relay-runtime-draft-readback.test.mjs \
config/scripts/ssh-relay-runtime-closure.test.mjs \
config/scripts/ssh-relay-runtime-pty-smoke.test.mjs \
config/scripts/ssh-relay-runtime-reproducibility.test.mjs \
@@ -493,6 +499,14 @@ jobs:
if ($LASTEXITCODE -ne 0) { throw 'runtime draft recovery syntax check failed' }
node --check config/scripts/ssh-relay-runtime-draft-recovery.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime draft recovery test syntax check failed' }
node --check config/scripts/ssh-relay-runtime-aggregate-input.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime aggregate input syntax check failed' }
node --check config/scripts/ssh-relay-runtime-aggregate-input.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime aggregate input test syntax check failed' }
node --check config/scripts/ssh-relay-runtime-draft-readback.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime draft read-back syntax check failed' }
node --check config/scripts/ssh-relay-runtime-draft-readback.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime draft read-back test syntax check failed' }
pnpm exec vitest run --config config/vitest.config.ts `
config/scripts/ssh-relay-node-release-verification.test.mjs `
config/scripts/ssh-relay-node-tar-inspection.test.mjs `
@@ -516,6 +530,8 @@ jobs:
config/scripts/ssh-relay-runtime-windows-source-signature-verification.test.mjs `
config/scripts/ssh-relay-runtime-release-stage-gate.test.mjs `
config/scripts/ssh-relay-runtime-draft-recovery.test.mjs `
config/scripts/ssh-relay-runtime-aggregate-input.test.mjs `
config/scripts/ssh-relay-runtime-draft-readback.test.mjs `
config/scripts/ssh-relay-runtime-closure.test.mjs `
config/scripts/ssh-relay-runtime-pty-smoke.test.mjs `
config/scripts/ssh-relay-runtime-reproducibility.test.mjs `
@@ -0,0 +1,150 @@
import { createHash } from 'node:crypto'
import { createReadStream } from 'node:fs'
import { lstat, readdir } from 'node:fs/promises'
import { basename, join, resolve } from 'node:path'
import { sshRelayRuntimeCompatibility } from './ssh-relay-runtime-compatibility.mjs'
const DIGEST_PATTERN = /^sha256:[0-9a-f]{64}$/u
const ASSET_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,239}$/u
const MAX_ARCHIVE_BYTES = 100 * 1024 * 1024
const MAX_TUPLES = 8
const AGGREGATE_TIMEOUT_MS = 15 * 60_000
const ASSET_FIELDS = ['tupleId', 'name', 'contentId', 'sha256', 'size']
function assertObject(value, label) {
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
throw new Error(`SSH relay runtime aggregate ${label} must be an object`)
}
}
function assertExactFields(value, fields, label) {
assertObject(value, label)
const actual = Object.keys(value).sort()
const expected = [...fields].sort()
if (JSON.stringify(actual) !== JSON.stringify(expected)) {
throw new Error(`SSH relay runtime aggregate ${label} has unexpected or missing fields`)
}
}
function expectedArchiveName(tupleId, contentId) {
const digest = contentId.slice('sha256:'.length)
const extension = tupleId.startsWith('win32-') ? 'zip' : 'tar.xz'
return `orca-ssh-relay-runtime-v1-${tupleId}-${digest}.${extension}`
}
function normalizeAssets(assets) {
if (!Array.isArray(assets) || assets.length === 0 || assets.length > MAX_TUPLES) {
throw new Error('SSH relay runtime aggregate assets must be a bounded non-empty array')
}
const tupleIds = new Set()
const names = new Set()
return assets.map((asset, index) => {
assertExactFields(asset, ASSET_FIELDS, `asset ${index}`)
if (!Object.hasOwn(sshRelayRuntimeCompatibility, asset.tupleId)) {
throw new Error(`SSH relay runtime aggregate has an unsupported tuple: ${asset.tupleId}`)
}
if (tupleIds.has(asset.tupleId)) {
throw new Error(`SSH relay runtime aggregate has a duplicate tuple: ${asset.tupleId}`)
}
tupleIds.add(asset.tupleId)
if (typeof asset.name !== 'string' || !ASSET_NAME_PATTERN.test(asset.name)) {
throw new Error('SSH relay runtime aggregate asset has an invalid name')
}
if (names.has(asset.name)) {
throw new Error(`SSH relay runtime aggregate has a duplicate asset: ${asset.name}`)
}
names.add(asset.name)
if (!DIGEST_PATTERN.test(asset.contentId)) {
throw new Error('SSH relay runtime aggregate asset has an invalid content identity')
}
if (!DIGEST_PATTERN.test(asset.sha256)) {
throw new Error('SSH relay runtime aggregate asset has an invalid SHA-256')
}
if (!Number.isSafeInteger(asset.size) || asset.size <= 0 || asset.size > MAX_ARCHIVE_BYTES) {
throw new Error('SSH relay runtime aggregate asset has an invalid size')
}
if (asset.name !== expectedArchiveName(asset.tupleId, asset.contentId)) {
throw new Error(`SSH relay runtime aggregate archive name is inconsistent: ${asset.name}`)
}
return { ...asset }
})
}
function sameFileState(before, after) {
return (
before.dev === after.dev &&
before.ino === after.ino &&
before.size === after.size &&
before.mtimeNs === after.mtimeNs &&
before.ctimeNs === after.ctimeNs
)
}
async function hashArchive(path, asset, signal) {
signal?.throwIfAborted()
const before = await lstat(path, { bigint: true })
if (!before.isFile() || before.isSymbolicLink()) {
throw new Error(`SSH relay runtime aggregate input is not a regular file: ${asset.name}`)
}
if (before.size !== BigInt(asset.size)) {
throw new Error(`SSH relay runtime aggregate input size mismatch: ${asset.name}`)
}
const hash = createHash('sha256')
let bytes = 0
for await (const chunk of createReadStream(path, { signal })) {
signal?.throwIfAborted()
bytes += chunk.length
if (bytes > asset.size) {
throw new Error(`SSH relay runtime aggregate input exceeded its size: ${asset.name}`)
}
hash.update(chunk)
}
const after = await lstat(path, { bigint: true })
// Why: aggregate identity must describe one stable file, not bytes swapped during hashing.
if (!sameFileState(before, after)) {
throw new Error(`SSH relay runtime aggregate input changed while hashing: ${asset.name}`)
}
if (bytes !== asset.size) {
throw new Error(`SSH relay runtime aggregate input size mismatch: ${asset.name}`)
}
const digest = `sha256:${hash.digest('hex')}`
if (digest !== asset.sha256) {
throw new Error(`SSH relay runtime aggregate input SHA-256 mismatch: ${asset.name}`)
}
}
export async function verifySshRelayRuntimeAggregateInputs({ inputDirectory, assets, signal }) {
const effectiveSignal = signal
? AbortSignal.any([signal, AbortSignal.timeout(AGGREGATE_TIMEOUT_MS)])
: AbortSignal.timeout(AGGREGATE_TIMEOUT_MS)
effectiveSignal.throwIfAborted()
if (typeof inputDirectory !== 'string' || inputDirectory.length === 0) {
throw new Error('SSH relay runtime aggregate input directory is required')
}
const normalized = normalizeAssets(assets)
const root = resolve(inputDirectory)
const rootMetadata = await lstat(root)
if (!rootMetadata.isDirectory() || rootMetadata.isSymbolicLink()) {
throw new Error('SSH relay runtime aggregate input root must be a real directory')
}
const entries = await readdir(root, { withFileTypes: true })
const actualNames = entries.map((entry) => entry.name).sort()
const expectedNames = normalized.map((asset) => asset.name).sort()
if (JSON.stringify(actualNames) !== JSON.stringify(expectedNames)) {
throw new Error('SSH relay runtime aggregate input directory has missing or unexpected files')
}
for (const entry of entries) {
if (!entry.isFile() || entry.isSymbolicLink()) {
throw new Error(`SSH relay runtime aggregate input is not a regular file: ${entry.name}`)
}
}
for (const asset of normalized) {
const path = join(root, asset.name)
if (basename(path) !== asset.name) {
throw new Error(`SSH relay runtime aggregate asset path is unsafe: ${asset.name}`)
}
await hashArchive(path, asset, effectiveSignal)
}
return normalized
}
@@ -0,0 +1,114 @@
import { mkdtemp, rm, symlink, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { afterEach, describe, expect, it } from 'vitest'
import { verifySshRelayRuntimeAggregateInputs } from './ssh-relay-runtime-aggregate-input.mjs'
const temporaryDirectories = []
async function fixture() {
const inputDirectory = await mkdtemp(join(tmpdir(), 'orca-runtime-aggregate-'))
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`
await writeFile(join(inputDirectory, name), bytes)
return {
inputDirectory,
assets: [
{
tupleId: 'linux-x64-glibc',
name,
contentId,
sha256: 'sha256:d4c28c942ea1505c048b33251b3afb8b7f1ce9c54d629c9e4c8923afd93d9f45',
size: bytes.length
}
]
}
}
afterEach(async () => {
await Promise.all(
temporaryDirectories
.splice(0)
.map((directory) => rm(directory, { recursive: true, force: true }))
)
})
describe('SSH relay runtime aggregate inputs', () => {
it('accepts only exact immutable runtime archive bytes', async () => {
const input = await fixture()
await expect(verifySshRelayRuntimeAggregateInputs(input)).resolves.toEqual(input.assets)
})
it('rejects a hash or size mismatch', async () => {
const hash = await fixture()
hash.assets[0].sha256 = `sha256:${'f'.repeat(64)}`
await expect(verifySshRelayRuntimeAggregateInputs(hash)).rejects.toThrow(/sha-?256/i)
const size = await fixture()
size.assets[0].size += 1
await expect(verifySshRelayRuntimeAggregateInputs(size)).rejects.toThrow(/size/i)
})
it('rejects missing or extra inputs', async () => {
const missing = await fixture()
await rm(join(missing.inputDirectory, missing.assets[0].name))
await expect(verifySshRelayRuntimeAggregateInputs(missing)).rejects.toThrow(/missing|exact/i)
const extra = await fixture()
await writeFile(join(extra.inputDirectory, 'unexpected.bin'), 'extra')
await expect(verifySshRelayRuntimeAggregateInputs(extra)).rejects.toThrow(/unexpected|exact/i)
})
it.skipIf(process.platform === 'win32')('rejects a linked archive input', async () => {
const input = await fixture()
const path = join(input.inputDirectory, input.assets[0].name)
const target = join(input.inputDirectory, 'target')
await writeFile(target, 'target')
await rm(path)
await symlink(target, path)
await expect(verifySshRelayRuntimeAggregateInputs(input)).rejects.toThrow(/unexpected|regular/i)
})
it('rejects duplicate tuples, names, and unsupported identities', async () => {
const duplicateTuple = await fixture()
duplicateTuple.assets.push({ ...duplicateTuple.assets[0], name: 'different.tar.xz' })
await expect(verifySshRelayRuntimeAggregateInputs(duplicateTuple)).rejects.toThrow(
/duplicate tuple/i
)
const duplicateName = await fixture()
duplicateName.assets.push({ ...duplicateName.assets[0], tupleId: 'linux-arm64-glibc' })
await expect(verifySshRelayRuntimeAggregateInputs(duplicateName)).rejects.toThrow(
/duplicate asset/i
)
const unsupported = await fixture()
unsupported.assets[0].tupleId = 'linux-riscv64-glibc'
await expect(verifySshRelayRuntimeAggregateInputs(unsupported)).rejects.toThrow(
/unsupported tuple/i
)
})
it('derives the archive name from tuple and content identity', async () => {
const input = await fixture()
input.assets[0].name = 'latest.tar.xz'
await expect(verifySshRelayRuntimeAggregateInputs(input)).rejects.toThrow(/archive name/i)
})
it('honors cancellation before reading an archive', async () => {
const input = await fixture()
const controller = new AbortController()
controller.abort(new Error('cancel aggregate'))
await expect(
verifySshRelayRuntimeAggregateInputs({ ...input, signal: controller.signal })
).rejects.toThrow(/cancel aggregate/i)
})
})
@@ -0,0 +1,256 @@
import { createHash } from 'node:crypto'
const API_VERSION = '2022-11-28'
const DIGEST_PATTERN = /^sha256:[0-9a-f]{64}$/u
const TAG_PATTERN = /^v\d+\.\d+\.\d+(?:-rc\.\d+(?:\.[0-9A-Za-z]+)?)?$/u
const REPOSITORY_PATTERN = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u
const ASSET_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,239}$/u
const MANAGED_ASSET_PREFIX = 'orca-ssh-relay-runtime-'
const RELEASE_ASSET_HOST = 'release-assets.githubusercontent.com'
const MAX_ASSET_BYTES = 100 * 1024 * 1024
const MAX_TOTAL_BYTES = 1024 * 1024 * 1024
const MAX_ASSETS = 26
const READBACK_TIMEOUT_MS = 15 * 60_000
const ASSET_FIELDS = ['name', 'sha256', 'size']
function assertObject(value, label) {
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
throw new Error(`SSH relay runtime draft read-back ${label} must be an object`)
}
}
function assertExactFields(value, fields, label) {
assertObject(value, label)
const actual = Object.keys(value).sort()
const expected = [...fields].sort()
if (JSON.stringify(actual) !== JSON.stringify(expected)) {
throw new Error(`SSH relay runtime draft read-back ${label} has unexpected or missing fields`)
}
}
function normalizeExpectedAssets(assets) {
if (!Array.isArray(assets) || assets.length === 0 || assets.length > MAX_ASSETS) {
throw new Error('SSH relay runtime draft read-back assets must be a bounded non-empty array')
}
const names = new Set()
let totalBytes = 0
const normalized = assets.map((asset, index) => {
assertExactFields(asset, ASSET_FIELDS, `expected asset ${index}`)
if (
typeof asset.name !== 'string' ||
!ASSET_NAME_PATTERN.test(asset.name) ||
!asset.name.startsWith(MANAGED_ASSET_PREFIX)
) {
throw new Error('SSH relay runtime draft read-back expected an invalid managed asset')
}
if (names.has(asset.name)) {
throw new Error(`SSH relay runtime draft read-back has a duplicate asset: ${asset.name}`)
}
names.add(asset.name)
if (typeof asset.sha256 !== 'string' || !DIGEST_PATTERN.test(asset.sha256)) {
throw new Error('SSH relay runtime draft read-back expected an invalid SHA-256')
}
if (!Number.isSafeInteger(asset.size) || asset.size <= 0 || asset.size > MAX_ASSET_BYTES) {
throw new Error('SSH relay runtime draft read-back expected an invalid size')
}
totalBytes += asset.size
return { ...asset }
})
if (!Number.isSafeInteger(totalBytes) || totalBytes > MAX_TOTAL_BYTES) {
throw new Error('SSH relay runtime draft read-back expected assets exceed the total size limit')
}
return normalized
}
function authenticatedHeaders(token, accept = 'application/vnd.github+json') {
return {
Accept: accept,
Authorization: `Bearer ${token}`,
'X-GitHub-Api-Version': API_VERSION
}
}
async function responseError(response) {
const body = await response.text().catch(() => '')
return new Error(
`SSH relay runtime GitHub request failed ${response.status} ${response.statusText}: ${body.slice(0, 300)}`
)
}
async function fetchRelease({ repo, releaseId, token, fetchImpl, signal }) {
const response = await fetchImpl(`https://api.github.com/repos/${repo}/releases/${releaseId}`, {
headers: authenticatedHeaders(token),
redirect: 'error',
signal
})
if (!response.ok) {
throw await responseError(response)
}
return response.json()
}
function validateRelease(release, releaseId, tag, expectedAssets) {
assertObject(release, 'release')
if (release.id !== releaseId || release.draft !== true) {
throw new Error('SSH relay runtime release must remain the requested draft during read-back')
}
if (release.tag_name !== tag) {
throw new Error('SSH relay runtime draft read-back tag does not match')
}
if (!Array.isArray(release.assets)) {
throw new Error('SSH relay runtime draft read-back release assets must be an array')
}
const expectedByName = new Map(expectedAssets.map((asset) => [asset.name, asset]))
const releaseByName = new Map()
for (const asset of release.assets) {
assertObject(asset, 'release asset')
if (typeof asset.name !== 'string' || releaseByName.has(asset.name)) {
throw new Error('SSH relay runtime draft read-back has a duplicate or invalid release asset')
}
releaseByName.set(asset.name, asset)
if (asset.name.startsWith(MANAGED_ASSET_PREFIX) && !expectedByName.has(asset.name)) {
throw new Error(`SSH relay runtime draft has an unexpected managed asset: ${asset.name}`)
}
}
for (const expected of expectedAssets) {
const actual = releaseByName.get(expected.name)
if (!actual) {
throw new Error(`SSH relay runtime draft is missing managed asset: ${expected.name}`)
}
if (!Number.isSafeInteger(actual.id) || actual.id <= 0) {
throw new Error(`SSH relay runtime draft asset has an invalid ID: ${expected.name}`)
}
if (actual.state !== 'uploaded') {
throw new Error(`SSH relay runtime draft asset is not uploaded: ${expected.name}`)
}
if (actual.size !== expected.size) {
throw new Error(`SSH relay runtime draft asset size disagrees: ${expected.name}`)
}
}
return releaseByName
}
function redirectedAssetUrl(response) {
const location = response.headers.get('location')
if (!location) {
throw new Error('SSH relay runtime draft read-back redirect is missing Location')
}
const url = new URL(location)
if (url.protocol !== 'https:') {
throw new Error('SSH relay runtime draft read-back redirect must use HTTPS')
}
if (url.hostname !== RELEASE_ASSET_HOST) {
throw new Error('SSH relay runtime draft read-back redirect has an unapproved origin')
}
return url.href
}
async function fetchAsset({ repo, assetId, token, fetchImpl, signal }) {
const response = await fetchImpl(
`https://api.github.com/repos/${repo}/releases/assets/${assetId}`,
{
headers: authenticatedHeaders(token, 'application/octet-stream'),
redirect: 'manual',
signal
}
)
if (response.status !== 302) {
// Why: partial or otherwise unusual successful responses cannot prove the exact release asset.
if (response.status !== 200) {
throw await responseError(response)
}
return response
}
const location = redirectedAssetUrl(response)
// Why: the API request is authenticated, but its signed CDN redirect must never receive the token.
const redirected = await fetchImpl(location, {
headers: { Accept: 'application/octet-stream' },
redirect: 'error',
signal
})
if (redirected.status !== 200) {
throw await responseError(redirected)
}
return redirected
}
async function hashResponse(response, expected, signal) {
const contentLength = response.headers.get('content-length')
if (contentLength !== null) {
const parsed = Number(contentLength)
if (!Number.isSafeInteger(parsed) || parsed !== expected.size) {
throw new Error(
`SSH relay runtime draft read-back Content-Length disagrees: ${expected.name}`
)
}
}
if (!response.body) {
throw new Error(`SSH relay runtime draft read-back body is missing: ${expected.name}`)
}
const hash = createHash('sha256')
let bytes = 0
for await (const chunk of response.body) {
signal?.throwIfAborted()
const buffer = Buffer.from(chunk)
bytes += buffer.length
if (bytes > expected.size || bytes > MAX_ASSET_BYTES) {
throw new Error(`SSH relay runtime draft read-back size exceeded: ${expected.name}`)
}
hash.update(buffer)
}
if (bytes !== expected.size) {
throw new Error(`SSH relay runtime draft read-back size mismatch: ${expected.name}`)
}
const digest = `sha256:${hash.digest('hex')}`
if (digest !== expected.sha256) {
throw new Error(`SSH relay runtime draft read-back SHA-256 mismatch: ${expected.name}`)
}
}
export async function verifySshRelayRuntimeDraftReadback({
repo,
releaseId,
tag,
token,
expectedAssets,
fetchImpl = fetch,
signal
}) {
const effectiveSignal = signal
? AbortSignal.any([signal, AbortSignal.timeout(READBACK_TIMEOUT_MS)])
: AbortSignal.timeout(READBACK_TIMEOUT_MS)
effectiveSignal.throwIfAborted()
if (typeof repo !== 'string' || !REPOSITORY_PATTERN.test(repo)) {
throw new Error('SSH relay runtime draft read-back repository is invalid')
}
if (!Number.isSafeInteger(releaseId) || releaseId <= 0) {
throw new Error('SSH relay runtime draft read-back release ID is invalid')
}
if (typeof tag !== 'string' || !TAG_PATTERN.test(tag)) {
throw new Error('SSH relay runtime draft read-back tag is invalid')
}
if (typeof token !== 'string' || token.length === 0) {
throw new Error('SSH relay runtime draft read-back token is required')
}
const expected = normalizeExpectedAssets(expectedAssets)
const release = await fetchRelease({
repo,
releaseId,
token,
fetchImpl,
signal: effectiveSignal
})
const releaseAssets = validateRelease(release, releaseId, tag, expected)
for (const asset of expected) {
effectiveSignal.throwIfAborted()
const response = await fetchAsset({
repo,
assetId: releaseAssets.get(asset.name).id,
token,
fetchImpl,
signal: effectiveSignal
})
await hashResponse(response, asset, effectiveSignal)
}
return { releaseId, tag, downloadedAssets: expected }
}
@@ -0,0 +1,212 @@
import { afterEach, describe, expect, it, vi } from 'vitest'
import { verifySshRelayRuntimeDraftReadback } from './ssh-relay-runtime-draft-readback.mjs'
const TAG = 'v1.4.140-rc.1'
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',
sha256: 'sha256:5396515749878bd28c5dae110040b4fbae1c33f59318b9c23f446319d68e236a',
size: bytes.length
}
function release(overrides = {}) {
return {
id: 42,
tag_name: TAG,
draft: true,
assets: [{ id: 101, name: expected.name, state: 'uploaded', size: expected.size }],
...overrides
}
}
function fetchFixture(assetResponse = new Response(bytes)) {
return vi
.fn()
.mockResolvedValueOnce(Response.json(release()))
.mockResolvedValueOnce(assetResponse)
}
afterEach(() => vi.restoreAllMocks())
describe('SSH relay runtime draft read-back', () => {
it('downloads and hashes every exact managed asset from the same draft', async () => {
const fetchImpl = fetchFixture()
await expect(
verifySshRelayRuntimeDraftReadback({
repo: REPO,
releaseId: 42,
tag: TAG,
token: TOKEN,
expectedAssets: [expected],
fetchImpl
})
).resolves.toEqual({ releaseId: 42, tag: TAG, downloadedAssets: [expected] })
})
it('follows only the approved asset redirect without forwarding authorization', async () => {
const location = 'https://release-assets.githubusercontent.com/example/runtime?sig=signed'
const fetchImpl = vi
.fn()
.mockResolvedValueOnce(Response.json(release()))
.mockResolvedValueOnce(new Response(null, { status: 302, headers: { location } }))
.mockResolvedValueOnce(new Response(bytes))
await verifySshRelayRuntimeDraftReadback({
repo: REPO,
releaseId: 42,
tag: TAG,
token: TOKEN,
expectedAssets: [expected],
fetchImpl
})
expect(fetchImpl.mock.calls[1][1].headers.Authorization).toBe(`Bearer ${TOKEN}`)
expect(fetchImpl.mock.calls[2][0]).toBe(location)
expect(fetchImpl.mock.calls[2][1].headers).not.toHaveProperty('Authorization')
})
it.each([
['http://release-assets.githubusercontent.com/runtime', 'HTTPS'],
['https://example.com/runtime', 'origin']
])('rejects an unsafe asset redirect %s', async (location, message) => {
const fetchImpl = vi
.fn()
.mockResolvedValueOnce(Response.json(release()))
.mockResolvedValueOnce(new Response(null, { status: 302, headers: { location } }))
await expect(
verifySshRelayRuntimeDraftReadback({
repo: REPO,
releaseId: 42,
tag: TAG,
token: TOKEN,
expectedAssets: [expected],
fetchImpl
})
).rejects.toThrow(new RegExp(message, 'i'))
})
it.each(['direct API response', 'redirected CDN response'])(
'rejects an unexpected successful status from the %s',
async (responseKind) => {
const partialResponse = new Response(bytes, {
status: 206,
headers: { 'content-range': `bytes 0-${bytes.length - 1}/${bytes.length}` }
})
const fetchImpl =
responseKind === 'direct API response'
? fetchFixture(partialResponse)
: vi
.fn()
.mockResolvedValueOnce(Response.json(release()))
.mockResolvedValueOnce(
new Response(null, {
status: 302,
headers: {
location: 'https://release-assets.githubusercontent.com/example/runtime'
}
})
)
.mockResolvedValueOnce(partialResponse)
await expect(
verifySshRelayRuntimeDraftReadback({
repo: REPO,
releaseId: 42,
tag: TAG,
token: TOKEN,
expectedAssets: [expected],
fetchImpl
})
).rejects.toThrow(/failed 206/i)
}
)
it('rejects changed, truncated, or oversized returned bytes', async () => {
for (const body of [
Buffer.from('changed release bytes'),
bytes.subarray(1),
Buffer.concat([bytes, bytes])
]) {
await expect(
verifySshRelayRuntimeDraftReadback({
repo: REPO,
releaseId: 42,
tag: TAG,
token: TOKEN,
expectedAssets: [expected],
fetchImpl: fetchFixture(new Response(body))
})
).rejects.toThrow(/size|sha-?256/i)
}
})
it('rejects a published, cross-tag, incomplete, or unexpected managed draft', async () => {
for (const changedRelease of [
release({ draft: false }),
release({ tag_name: 'v1.4.140-rc.2' }),
release({ assets: [] }),
release({
assets: [
...release().assets,
{ id: 102, name: 'orca-ssh-relay-runtime-extra.zip', state: 'uploaded', size: 1 }
]
})
]) {
const fetchImpl = vi.fn().mockResolvedValueOnce(Response.json(changedRelease))
await expect(
verifySshRelayRuntimeDraftReadback({
repo: REPO,
releaseId: 42,
tag: TAG,
token: TOKEN,
expectedAssets: [expected],
fetchImpl
})
).rejects.toThrow(/draft|tag|missing|unexpected/i)
}
})
it('rejects non-uploaded metadata or a mismatched declared size before download', async () => {
for (const asset of [
{ ...release().assets[0], state: 'new' },
{ ...release().assets[0], size: expected.size + 1 }
]) {
const fetchImpl = vi.fn().mockResolvedValueOnce(Response.json(release({ assets: [asset] })))
await expect(
verifySshRelayRuntimeDraftReadback({
repo: REPO,
releaseId: 42,
tag: TAG,
token: TOKEN,
expectedAssets: [expected],
fetchImpl
})
).rejects.toThrow(/uploaded|size/i)
expect(fetchImpl).toHaveBeenCalledTimes(1)
}
})
it('honors cancellation before any GitHub request', async () => {
const controller = new AbortController()
controller.abort(new Error('cancel read-back'))
const fetchImpl = vi.fn()
await expect(
verifySshRelayRuntimeDraftReadback({
repo: REPO,
releaseId: 42,
tag: TAG,
token: TOKEN,
expectedAssets: [expected],
fetchImpl,
signal: controller.signal
})
).rejects.toThrow(/cancel read-back/i)
expect(fetchImpl).not.toHaveBeenCalled()
})
})
@@ -98,7 +98,9 @@ describe('SSH relay runtime artifact workflow', () => {
for (const moduleName of [
'windows-source-signature-verification',
'release-stage-gate',
'draft-recovery'
'draft-recovery',
'aggregate-input',
'draft-readback'
]) {
const script = `ssh-relay-runtime-${moduleName}`
expect(source.split(`${script}.test.mjs`)).toHaveLength(5)
@@ -60,9 +60,12 @@ complete a box.
remain separately gated.
- Next external proof: kernel 4.18, macOS 13.5, Windows arm64 build 26100, and native signing/trust.
- No tuple is enabled; every SSH transfer/runtime and rollout cell remains open.
- [ ] **WP3 active implementation — Prove disconnected release/signing DAG behavior in exact-head
CI.** Local contracts pass at `6f13e94f8`, which is one commit ahead of PR #8741; no production
workflow, publication, desktop consumer, or tuple is connected.
- [ ] **WP3 active implementation — Add disconnected aggregate-input and authenticated draft
read-back verification.** Release-DAG contracts pass locally and on all six native build jobs in
exact-head run [29390079639](https://github.com/stablyai/orca/actions/runs/29390079639) under
`E-M4-RELEASE-DAG-CI-001`. Aggregate/read-back RED/GREEN, workflow, full SSH-relay, and static
gates pass locally under `E-M4-AGGREGATE-READBACK-LOCAL-001`; exact-head CI is next. No
production workflow, publication, desktop consumer, signing credential, or tuple is connected.
## Work packages, in required order
@@ -97,11 +100,12 @@ complete a box.
### WP3 — Release build and signing
- [ ] **In progress — 2026-07-15, Codex implementation owner:** add disconnected credential-free
fail-closed release/signing DAG contracts before production workflow wiring. Local red/green,
full SSH-relay, type, lint, formatting, and native-job wiring gates pass under
`E-M4-RELEASE-DAG-LOCAL-001` at local commit `6f13e94f8`; the commit is one ahead of the PR and
exact-head CI is next.
- [x] Release/signing DAG contracts pass locally and on all six native build jobs under
`E-M4-RELEASE-DAG-LOCAL-001` and `E-M4-RELEASE-DAG-CI-001`.
- [ ] **In progress — 2026-07-15, Codex implementation owner:** implement disconnected
aggregate-input and authenticated draft read-back verification before any production workflow,
publication, desktop consumer, or signing credential is connected. Local implementation and
verification pass under `E-M4-AGGREGATE-READBACK-LOCAL-001`; exact-head 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.
@@ -8,8 +8,8 @@ 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 release/signing DAG failure contracts — **In progress — 2026-07-15, Codex implementation owner**. Work Package 2's target-native Windows official-Node and preserved-upstream source-signature gate is closed under E-M3-WINDOWS-SOURCE-SIGNATURE-CI-001. Exact-floor gaps and real native signing/trust remain open external gates, so the active package is limited to disconnected fail-closed release-DAG contracts and tests; it may not publish, connect desktop consumers, 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** — local implementation commit `6f13e94f8a7a315ac3da6bb2067b99da8e02a803` is one commit ahead of the PR head and closes the disconnected release-stage and draft-recovery contracts locally under E-M4-RELEASE-DAG-LOCAL-001. Exact-head CI for that commit is the active gate; push and GitHub-runner evidence collection are now authorized. The current PR head remains `be32653a7`: artifact jobs 87267322867 and 87267322870 in run [29388734922](https://github.com/stablyai/orca/actions/runs/29388734922) passed target-native Windows source-signature verification under E-M3-WINDOWS-SOURCE-SIGNATURE-CI-001, while PR Checks [29388734935](https://github.com/stablyai/orca/actions/runs/29388734935) and Golden E2E [29388734914](https://github.com/stablyai/orca/actions/runs/29388734914) are green. The artifact run's only failure is the retained Windows arm64 build-26200-versus-26100 floor gate. Real Apple/SignPath signing, returned production signatures, Gatekeeper/notarization, Defender/WDAC, missing exact-floor snapshots, and native trust remain separately gated. Nothing is published or enabled, and legacy remains the production default.<br>
Current phase: Milestone 4 / Work Package 3 credential-free aggregate-input and draft read-back verification — **In progress — 2026-07-15, Codex implementation owner**. The disconnected release/signing DAG failure contracts are closed locally and on all six native build jobs under E-M4-RELEASE-DAG-LOCAL-001 and E-M4-RELEASE-DAG-CI-001. Exact-floor gaps and real native signing/trust remain open external gates, so the active package may validate only immutable aggregate inputs and authenticated draft bytes; it may not publish, connect desktop consumers, use 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 [29390079639](https://github.com/stablyai/orca/actions/runs/29390079639) executes the two release-DAG suites under Node 24 on all six target-native build jobs at `97164470c`; every build and supplemental userland job passes. The run remains red only because Windows arm64 runner build 26200 is not the required build 26100, after archive/tree/runtime smoke passes in 7,721.7682 ms with 48,504,832-byte RSS. Golden E2E [29390079632](https://github.com/stablyai/orca/actions/runs/29390079632) is green. PR Checks [29390079665](https://github.com/stablyai/orca/actions/runs/29390079665) attempt 1 passed lint, typecheck, Git compatibility, and tests, then hit a TCP reset downloading Electron; authorized attempt 2 job 87272898091 passes the complete verify/package/CLI-smoke job. The disconnected aggregate-input and authenticated draft read-back implementation now passes local RED/GREEN, workflow-wiring, full SSH-relay, type, lint, line-budget, formatting, and diff gates under E-M4-AGGREGATE-READBACK-LOCAL-RED-001 and E-M4-AGGREGATE-READBACK-LOCAL-001; exact-head native CI is next. Real Apple/SignPath signing, returned production signatures, Gatekeeper/notarization, Defender/WDAC, missing exact-floor snapshots, 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)
@@ -65,10 +65,11 @@ same change as the work it records.
[#8728](https://github.com/stablyai/orca/pull/8728), which is CI-green at current PR head
`0c299fe18`; implementation evidence remains anchored at `b9d80a4cb`. No deploy/resolver call site
is connected and no tuple is enabled.
- Active package: Work Package 3 credential-free release/signing DAG failure contracts. The package
must model fail-closed build, approval, signing, aggregate, upload, read-back, and recovered-draft
outcomes without credentials, production workflow wiring, publication, desktop consumers, or
tuple enablement. No Milestone 4 box is checked until an implemented contract and exact tests exist.
- Active package: Work Package 3 credential-free aggregate-input and authenticated draft read-back
verification. It must bind every input and returned byte to exact name, size, SHA-256, tuple,
content identity, and source release without credentials, publication, production workflow wiring,
desktop consumers, or tuple enablement. No Milestone 4 box is checked until the corresponding
implementation and exact tests exist.
- 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
@@ -1459,7 +1460,7 @@ Update status and evidence as work begins. Do not combine these into one large b
| 0. #8450 legacy fix | Coherent Node/npm selection and live repro | Fixes legacy selection only | Complete and CI-green in draft PR #8724 | E-M0-UNIT-002, E-M0-LIVE-002, E-M0-STATIC-002, E-M0-PR-001, E-M0-CI-001 |
| 1. Contract and selectors | Manifest schema, identity, platform/libc selection, hostile inputs | None | Complete and CI-green in draft PR #8728 | `b9d80a4cb`; E-M2-RED-001, E-M2-CONTRACT-001, E-M2-CI-001 |
| 2. Runtime builds | Per-tuple assembly, native smoke, SBOM/provenance/signing | None | Draft PR #8741; native build/source trust green; real signing/trust pending | `be32653a7`; E-M3-METADATA-CI-001, E-M3-WINDOWS-SOURCE-SIGNATURE-CI-001 |
| 3. Release publication | Prerequisite DAG, embedded manifest, draft upload/read-back gates | Asset-only | **In progress — 2026-07-15, Codex implementation owner** | E-M4-RELEASE-DAG-LOCAL-001; exact-head CI pending |
| 3. Release publication | Prerequisite DAG, embedded manifest, draft upload/read-back gates | Asset-only | **In progress — 2026-07-15, Codex implementation owner** | E-M4-RELEASE-DAG-LOCAL-001; E-M4-RELEASE-DAG-CI-001 |
| 4. Desktop resolver/cache | Verified download, extraction, cache, offline behavior | None/forced mode only | Not started | — |
| 5. Transfer/install | Bounded transports, structured sentinel, bundled launch behind per-target Beta/forced mode | Per-target opt-in only | Not started | — |
| 6. Fallback/diagnostics | Abort-and-join state machine, mode isolation, reason codes, target-mode configuration/UI | Per-target Beta only | Not started | — |
@@ -1527,6 +1528,8 @@ 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-release-stage-gate.test.mjs config/scripts/ssh-relay-runtime-draft-recovery.test.mjs` (E-M4-RELEASE-DAG-LOCAL-RED-001, E-M4-RELEASE-DAG-LOCAL-001; disconnected credential-free stage/recovery contract only)
- [x] `pnpm exec vitest run --config config/vitest.config.ts --maxWorkers=1 config/scripts/ssh-relay-runtime-release-stage-gate.test.mjs config/scripts/ssh-relay-runtime-draft-recovery.test.mjs config/scripts/ssh-relay-runtime-workflow.test.mjs` (E-M4-RELEASE-DAG-LOCAL-001; static native-job wiring only, no real release/signing execution)
- [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` (E-M4-AGGREGATE-READBACK-LOCAL-RED-001, E-M4-AGGREGATE-READBACK-LOCAL-001; local filesystem plus mocked GitHub responses only)
- [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)
### Commands/scripts that must be added or formally identified
@@ -8846,6 +8849,149 @@ diff --check`.
credential-free aggregate-input/read-back implementation without connecting publication or a
desktop consumer.
### E-M4-RELEASE-DAG-CI-001 — Release-DAG contracts pass all six native build jobs
- Date: 2026-07-15
- Owner: Codex implementation owner
- Source: exact PR head `97164470cb9abad670634b9d4f04424bcc8662b5`; implementation commit
`6f13e94f8a7a315ac3da6bb2067b99da8e02a803`; draft PR
[#8741](https://github.com/stablyai/orca/pull/8741).
- Runner/network: GitHub-hosted native runners with normal artifact-build egress and no SSH remote,
signing service, release credential, approval environment, draft upload, publication, or desktop
consumer. Exact jobs and resolved images:
- linux-x64-glibc job 87271365779: `ubuntu-24.04`, `ubuntu24` image `20260705.232.1`, X64,
04:53:59Z–04:58:13Z.
- linux-arm64-glibc job 87271365815: `ubuntu-24.04-arm`, `ubuntu24-arm64` image
`20260714.61.1`, ARM64, 04:54:03Z–04:59:11Z.
- darwin-x64 job 87271365782: `macos-15-intel`, `macos15` image `20260629.0276.1`, X64,
04:53:59Z–04:59:21Z.
- darwin-arm64 job 87271365773: `macos-15`, `macos15` image `20260706.0213.1`, ARM64,
04:53:59Z–04:57:05Z.
- win32-x64 job 87271365831: `windows-2022`, `win22` image `20260706.237.1`, X64,
04:53:59Z–04:59:34Z.
- win32-arm64 job 87271365776: `windows-11-arm`, `win11-arm64` image `20260706.102.1`, ARM64,
04:53:59Z–05:03:25Z.
- Command: the workflow's `Run runtime artifact contract tests` step syntax-checks both new modules
and tests, then includes
`ssh-relay-runtime-release-stage-gate.test.mjs` and
`ssh-relay-runtime-draft-recovery.test.mjs` in the purpose-named native Vitest command. Inspection
used `gh run view 29390079639 --repo stablyai/orca --job <job-id> --log` for every job.
- Result: PASS for all six target-native build jobs. Each runner passes the release-stage suite's 15
tests and draft-recovery suite's 6 tests under Node v24.18.0. The four POSIX jobs report 32 passing
contract files; the two Windows jobs report 33, including the Windows-only PE diagnostic suite.
Both Linux oldest-userland jobs and Windows x64 floor job also pass. Overall workflow conclusion is
the expected `failure` only because downstream Windows arm64 floor job 87272581856 observes build
26200 instead of required 26100 after the exact runtime passes archive/tree verification, bundled
Node, PTY, watcher, and resource settlement in 7,721.7682 ms with 48,504,832-byte RSS.
- Concurrent regression: Golden E2E run
[29390079632](https://github.com/stablyai/orca/actions/runs/29390079632) passes both macOS job
87271365717 and Linux job 87271365749. PR Checks run 29390079665 attempt 1 job 87271365846 passes
lint, typecheck, Git compatibility, and tests, then flakes during `Build unpacked app` when a
125-MB Electron GitHub asset download receives `read: connection reset by peer`. Authorized
attempt 2 job 87272898091 runs from 05:05:54Z to 05:21:00Z and passes the complete verify job,
including unpacked packaging and packaged CLI smoke.
- Oracle proved: the disconnected build → signing → aggregate → upload → read-back failure contract
and same-draft immutable recovery contract parse and execute identically on all six native runner
families, including Windows PowerShell workflow wiring. No platform can omit its required signing
stage, invent a Linux signing stage, exceed the bounded retry/time policy, or accept missing,
duplicate, drifted, failed, cancelled, approval-rejected, or recovered cross-release state.
- Does not prove: real Apple/SignPath signing or approval, target-native trust of returned Orca bytes,
aggregate/manifest generation, manifest signing, GitHub draft upload/read-back, packaged manifest
embedding, SSH transfer/install, fallback, performance, or an enabled tuple.
- Follow-up: implement disconnected aggregate-input and authenticated draft read-back verification,
then execute it on all six native job families. Retain every production/default and tuple state.
### E-M4-AGGREGATE-READBACK-LOCAL-RED-001 — Aggregate and draft byte verifiers are absent
- Date: 2026-07-15
- Owner: Codex implementation owner
- Source: exact implementation base `97164470cb9abad670634b9d4f04424bcc8662b5` plus the two new
uncommitted purpose-named test files.
- Command:
```sh
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
```
- Result: expected RED in 284 ms. Both suites fail before collecting tests with
`ERR_MODULE_NOT_FOUND` for `ssh-relay-runtime-aggregate-input.mjs` and
`ssh-relay-runtime-draft-readback.mjs`.
- Oracle proved: the exact head had only declarative stage/recovery contracts; it had no filesystem
implementation binding aggregate input declarations to stable archive bytes and no authenticated,
bounded draft asset read-back implementation.
- Does not prove: implementation, GitHub API behavior, actual release assets, native runners,
manifest generation/signing, publication, desktop embedding, SSH behavior, or an enabled tuple.
- Correction: implement both byte boundaries as disconnected modules with bounded streaming,
cancellation, exact identity/asset checks, and credential-safe redirect handling.
### E-M4-AGGREGATE-READBACK-LOCAL-001 — Immutable aggregate and draft read-back bytes pass locally
- Date: 2026-07-15
- Owner: Codex implementation owner
- Source: uncommitted implementation based on exact head
`97164470cb9abad670634b9d4f04424bcc8662b5`.
- Runner/network: local macOS 26.2 build 25C56 arm64, Node v26.0.0 and pnpm 10.24.0. Aggregate tests
use exclusive local temporary directories. Draft tests use injected WHATWG `Response` objects and
make no network, GitHub API, release, credential, signing-service, SSH, publication, or production
call. The repository emits its expected Node-24 engine warning.
- Commands:
```sh
node --check config/scripts/ssh-relay-runtime-aggregate-input.mjs
node --check config/scripts/ssh-relay-runtime-aggregate-input.test.mjs
node --check config/scripts/ssh-relay-runtime-draft-readback.mjs
node --check config/scripts/ssh-relay-runtime-draft-readback.test.mjs
/usr/bin/time -l 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
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
pnpm exec vitest run --config config/vitest.config.ts --maxWorkers=1 \
config/scripts/ssh-relay-*.test.mjs
pnpm run typecheck
pnpm run lint
pnpm run check:max-lines-ratchet
pnpm exec oxfmt --check <eight touched implementation/workflow/checklist files>
git diff --check
```
- Result: PASS. Four syntax checks pass. After exact-HTTP-200 hardening, the two purpose-named suites
pass 2 files/17 tests in 295 ms; `/usr/bin/time -l` records 0.89 seconds wall time,
132,104,192-byte maximum RSS, zero swaps, and 96,277,880-byte peak memory footprint.
Workflow-inclusive focus passes 3 files/23 tests in 410 ms. The complete SSH-relay suite passes 35
files/201 tests in 6.63 seconds. Typecheck, full
lint/reliability/localization/bundled-skill gates, max-lines (355 grandfathered suppressions and no
new bypass), focused formatting, and `git diff --check` all pass; lint emits only existing unrelated
warnings.
- Aggregate oracle: accepts at most eight declared supported tuples and derives each immutable
archive name from its tuple/content identity. The exclusive input directory must contain exactly
those regular files, with no extras or links; each file is streamed under a 100-MiB/file and
15-minute bound, and exact size, SHA-256, and stable pre/post file metadata must match before the
declared asset chain is returned. Duplicate tuple/name, unsupported tuple, malformed identity,
cancellation, missing/extra input, or byte drift fails closed.
- Draft read-back oracle: requires one exact draft ID and stable/RC/perf tag, exact managed asset
names, uploaded state, nonzero declared size, at most 100 MiB per asset/1 GiB total, and a 15-minute
bound. It manually handles the authenticated GitHub asset API redirect, accepts only HTTPS
`release-assets.githubusercontent.com`, never forwards authorization to the CDN, requires exact
HTTP 200 from either direct or redirected downloads, streams every body, and requires exact size
and SHA-256. Published/cross-tag/incomplete/unexpected drafts, unsafe redirects, unexpected 2xx
statuses, changed/truncated/oversized bytes, and cancellation fail closed.
- Workflow oracle: both POSIX and Windows artifact jobs syntax-check and execute the two new suites
under the same Node 24 native job families. The workflow retains read-only contents permission and
has no release, signing credential, or publication authority.
- Does not prove: a real GitHub API/CDN redirect, a real draft or full-size asset, aggregate manifest
generation, Ed25519 signing, native signing/trust, upload/recovery execution, desktop
prerequisites/embedding, SSH transfer/install, fallback, performance, or an enabled tuple. The
local symlink fixture is skipped on Windows, although the shared implementation rejects all
non-regular directory entries and exact-head Windows execution remains required.
- Follow-up: execute both suites on all six native jobs at the exact implementation head, then add
credential-free canonical manifest assembly/signature handoff without production credentials,
publication, or a desktop consumer.
## Accepted Gaps
No product gap is accepted merely because it appears in this list. Each entry requires explicit
@@ -8903,12 +9049,13 @@ The project is not complete until every applicable item below is checked with ev
## Next Required Action
Run the disconnected credential-free release/signing DAG and draft-recovery contracts on all six
native jobs at the exact implementation head. If green, implement the next artifact-only
aggregate-input/read-back capability without release publication or a desktop consumer. 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 run the disconnected aggregate-input and authenticated draft read-back verifiers on all
six native jobs at the exact implementation head. If green, record exact job evidence and implement
the next credential-free canonical-manifest assembly/signature-handoff slice without release
publication, production signing credentials, or a desktop consumer. 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