ci: add protected relay manifest workflow

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
Jinwoo-H
2026-07-15 11:00:10 -04:00
co-authored by Orca
parent 8cf80a0228
commit 4979bc26c9
5 changed files with 447 additions and 9 deletions
@@ -171,6 +171,7 @@ jobs:
node --check config/scripts/ssh-relay-runtime-manifest-artifact-collection.mjs
node --check config/scripts/ssh-relay-runtime-manifest-aggregate-command.mjs
node --check config/scripts/ssh-relay-runtime-manifest-aggregate-command.test.mjs
node --check config/scripts/ssh-relay-runtime-manifest-signing-workflow.test.mjs
node --check config/scripts/ssh-relay-runtime-manifest-aggregate.mjs
node --check config/scripts/ssh-relay-runtime-manifest-aggregate.test.mjs
node --check config/scripts/ssh-relay-runtime-manifest-tuple.mjs
@@ -219,6 +220,7 @@ jobs:
config/scripts/ssh-relay-runtime-manifest-signing-handoff.test.mjs \
config/scripts/ssh-relay-runtime-manifest-seed-signing.test.mjs \
config/scripts/ssh-relay-runtime-manifest-aggregate-command.test.mjs \
config/scripts/ssh-relay-runtime-manifest-signing-workflow.test.mjs \
config/scripts/ssh-relay-runtime-manifest-aggregate.test.mjs \
config/scripts/ssh-relay-runtime-manifest-tuple.test.mjs \
config/scripts/ssh-relay-runtime-post-sign-metadata.test.mjs \
@@ -595,6 +597,8 @@ jobs:
if ($LASTEXITCODE -ne 0) { throw 'runtime manifest aggregate command syntax check failed' }
node --check config/scripts/ssh-relay-runtime-manifest-aggregate-command.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime manifest aggregate command test syntax check failed' }
node --check config/scripts/ssh-relay-runtime-manifest-signing-workflow.test.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime manifest signing workflow test syntax check failed' }
node --check config/scripts/ssh-relay-runtime-manifest-aggregate.mjs
if ($LASTEXITCODE -ne 0) { throw 'runtime manifest aggregate syntax check failed' }
node --check config/scripts/ssh-relay-runtime-manifest-aggregate.test.mjs
@@ -661,6 +665,7 @@ jobs:
config/scripts/ssh-relay-runtime-manifest-signing-handoff.test.mjs `
config/scripts/ssh-relay-runtime-manifest-seed-signing.test.mjs `
config/scripts/ssh-relay-runtime-manifest-aggregate-command.test.mjs `
config/scripts/ssh-relay-runtime-manifest-signing-workflow.test.mjs `
config/scripts/ssh-relay-runtime-manifest-aggregate.test.mjs `
config/scripts/ssh-relay-runtime-manifest-tuple.test.mjs `
config/scripts/ssh-relay-runtime-post-sign-metadata.test.mjs `
@@ -0,0 +1,257 @@
name: SSH Relay Runtime Manifest Signing
on:
workflow_call:
inputs:
source-sha:
required: true
type: string
release-tag:
required: true
type: string
created-at:
required: true
type: string
relay-protocol-version:
required: true
type: number
secrets:
SSH_RELAY_RUNTIME_MANIFEST_SEED:
required: true
permissions:
actions: read
contents: read
jobs:
prepare-manifest:
runs-on: ubuntu-24.04
timeout-minutes: 15
steps:
- name: Checkout exact source revision
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
ref: ${{ inputs.source-sha }}
- name: Setup pnpm
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6
with:
run_install: false
- name: Setup Node 24.18.0
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: 24.18.0
cache: pnpm
- name: Install credential-free dependencies
run: pnpm install --frozen-lockfile --ignore-scripts
- name: Download linux-x64-glibc artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: ssh-relay-runtime-linux-x64-glibc
path: ${{ runner.temp }}/relay-manifest-inputs/ssh-relay-runtime-linux-x64-glibc
- name: Download linux-arm64-glibc artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: ssh-relay-runtime-linux-arm64-glibc
path: ${{ runner.temp }}/relay-manifest-inputs/ssh-relay-runtime-linux-arm64-glibc
- name: Download signed darwin-x64 artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: ssh-relay-runtime-signed-darwin-x64
path: ${{ runner.temp }}/relay-manifest-inputs/ssh-relay-runtime-signed-darwin-x64
- name: Download signed darwin-arm64 artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: ssh-relay-runtime-signed-darwin-arm64
path: ${{ runner.temp }}/relay-manifest-inputs/ssh-relay-runtime-signed-darwin-arm64
- name: Download signed win32-x64 artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: ssh-relay-runtime-signed-win32-x64
path: ${{ runner.temp }}/relay-manifest-inputs/ssh-relay-runtime-signed-win32-x64
- name: Download signed win32-arm64 artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: ssh-relay-runtime-signed-win32-arm64
path: ${{ runner.temp }}/relay-manifest-inputs/ssh-relay-runtime-signed-win32-arm64
- name: Prepare canonical manifest request
run: |
set -euo pipefail
# Why: missing reviewed production keys must stop before signer bytes are exposed.
node config/scripts/ssh-relay-runtime-manifest-aggregate-command.mjs prepare \
--artifacts-directory '${{ runner.temp }}/relay-manifest-inputs' \
--accepted-keys config/ssh-relay-runtime-manifest-accepted-keys.json \
--output-directory '${{ runner.temp }}/relay-manifest-prepared' \
--source-sha '${{ inputs.source-sha }}' \
--release-tag '${{ inputs.release-tag }}' \
--created-at '${{ inputs.created-at }}' \
--relay-protocol-version '${{ inputs.relay-protocol-version }}'
- name: Upload canonical signing request
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: ssh-relay-runtime-manifest-signing-request
path: ${{ runner.temp }}/relay-manifest-prepared/signing-request.json
if-no-files-found: error
retention-days: 1
- name: Upload credential-free prepared receipt
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: ssh-relay-runtime-manifest-prepared
path: ${{ runner.temp }}/relay-manifest-prepared/prepared-aggregate.json
if-no-files-found: error
retention-days: 1
sign-manifest:
needs: prepare-manifest
runs-on: ubuntu-24.04
timeout-minutes: 5
environment: relay-runtime-manifest-signing
steps:
- name: Checkout exact source revision
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
ref: ${{ inputs.source-sha }}
- name: Setup pnpm
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6
with:
run_install: false
- name: Setup Node 24.18.0
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: 24.18.0
cache: pnpm
- name: Install signer dependencies
run: pnpm install --frozen-lockfile --ignore-scripts
- name: Download canonical signing request only
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: ssh-relay-runtime-manifest-signing-request
path: ${{ runner.temp }}/relay-manifest-signing-request
- name: Sign exact canonical bytes
env:
SSH_RELAY_RUNTIME_MANIFEST_SEED: ${{ secrets.SSH_RELAY_RUNTIME_MANIFEST_SEED }}
run: |
set -euo pipefail
node config/scripts/ssh-relay-runtime-manifest-seed-signing.mjs \
--request '${{ runner.temp }}/relay-manifest-signing-request/signing-request.json' \
--output-directory '${{ runner.temp }}/relay-manifest-signing-result'
- name: Upload signature-only result
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: ssh-relay-runtime-manifest-signing-result
path: ${{ runner.temp }}/relay-manifest-signing-result/signing-result.json
if-no-files-found: error
retention-days: 1
finalize-manifest:
needs: [prepare-manifest, sign-manifest]
runs-on: ubuntu-24.04
timeout-minutes: 15
steps:
- name: Checkout exact source revision
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
ref: ${{ inputs.source-sha }}
- name: Setup pnpm
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6
with:
run_install: false
- name: Setup Node 24.18.0
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: 24.18.0
cache: pnpm
- name: Install credential-free dependencies
run: pnpm install --frozen-lockfile --ignore-scripts
- name: Download linux-x64-glibc artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: ssh-relay-runtime-linux-x64-glibc
path: ${{ runner.temp }}/relay-manifest-inputs/ssh-relay-runtime-linux-x64-glibc
- name: Download linux-arm64-glibc artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: ssh-relay-runtime-linux-arm64-glibc
path: ${{ runner.temp }}/relay-manifest-inputs/ssh-relay-runtime-linux-arm64-glibc
- name: Download signed darwin-x64 artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: ssh-relay-runtime-signed-darwin-x64
path: ${{ runner.temp }}/relay-manifest-inputs/ssh-relay-runtime-signed-darwin-x64
- name: Download signed darwin-arm64 artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: ssh-relay-runtime-signed-darwin-arm64
path: ${{ runner.temp }}/relay-manifest-inputs/ssh-relay-runtime-signed-darwin-arm64
- name: Download signed win32-x64 artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: ssh-relay-runtime-signed-win32-x64
path: ${{ runner.temp }}/relay-manifest-inputs/ssh-relay-runtime-signed-win32-x64
- name: Download signed win32-arm64 artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: ssh-relay-runtime-signed-win32-arm64
path: ${{ runner.temp }}/relay-manifest-inputs/ssh-relay-runtime-signed-win32-arm64
- name: Download credential-free prepared receipt
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: ssh-relay-runtime-manifest-prepared
path: ${{ runner.temp }}/relay-manifest-prepared
- name: Download signature-only result
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: ssh-relay-runtime-manifest-signing-result
path: ${{ runner.temp }}/relay-manifest-signing-result
- name: Independently reconstruct and verify final manifest
run: |
set -euo pipefail
node config/scripts/ssh-relay-runtime-manifest-aggregate-command.mjs finalize \
--artifacts-directory '${{ runner.temp }}/relay-manifest-inputs' \
--accepted-keys config/ssh-relay-runtime-manifest-accepted-keys.json \
--prepared-directory '${{ runner.temp }}/relay-manifest-prepared' \
--signing-result '${{ runner.temp }}/relay-manifest-signing-result/signing-result.json' \
--output-directory '${{ runner.temp }}/relay-manifest-final' \
--source-sha '${{ inputs.source-sha }}' \
--release-tag '${{ inputs.release-tag }}' \
--created-at '${{ inputs.created-at }}' \
--relay-protocol-version '${{ inputs.relay-protocol-version }}'
- name: Upload verified manifest output
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: ssh-relay-runtime-signed-manifest
path: |
${{ runner.temp }}/relay-manifest-final/assets/
${{ runner.temp }}/relay-manifest-final/evidence/
if-no-files-found: error
retention-days: 7
@@ -0,0 +1,106 @@
import { access, readFile } from 'node:fs/promises'
import { parse } from 'yaml'
import { describe, expect, it } from 'vitest'
const workflowUrl = new URL(
'../../.github/workflows/ssh-relay-runtime-manifest-signing.yml',
import.meta.url
)
const releaseCutUrl = new URL('../../.github/workflows/release-cut.yml', import.meta.url)
const releaseMacUrl = new URL('../../.github/workflows/release-mac-build.yml', import.meta.url)
const rehearsalUrl = new URL(
'../../.github/workflows/ssh-relay-runtime-native-signing-rehearsal.yml',
import.meta.url
)
const acceptedKeysUrl = new URL('../ssh-relay-runtime-manifest-accepted-keys.json', import.meta.url)
const EXPECTED_INPUTS = {
'source-sha': { required: true, type: 'string' },
'release-tag': { required: true, type: 'string' },
'created-at': { required: true, type: 'string' },
'relay-protocol-version': { required: true, type: 'number' }
}
const EXPECTED_ARTIFACTS = [
'ssh-relay-runtime-linux-x64-glibc',
'ssh-relay-runtime-linux-arm64-glibc',
'ssh-relay-runtime-signed-darwin-x64',
'ssh-relay-runtime-signed-darwin-arm64',
'ssh-relay-runtime-signed-win32-x64',
'ssh-relay-runtime-signed-win32-arm64'
]
function actionRefs(source) {
return [...source.matchAll(/^\s*uses:\s+[^\s#]+@([^\s#]+)/gmu)].map((match) => match[1])
}
describe('SSH relay runtime protected manifest-signing workflow', () => {
it('isolates the seed between credential-free reconstruction stages and stays disconnected', async () => {
const [source, releaseCut, releaseMac, rehearsal] = await Promise.all([
readFile(workflowUrl, 'utf8'),
readFile(releaseCutUrl, 'utf8'),
readFile(releaseMacUrl, 'utf8'),
readFile(rehearsalUrl, 'utf8')
])
const workflow = parse(source)
expect(Object.keys(workflow.on)).toEqual(['workflow_call'])
expect(workflow.on.workflow_call.inputs).toEqual(EXPECTED_INPUTS)
expect(workflow.on.workflow_call.secrets).toEqual({
SSH_RELAY_RUNTIME_MANIFEST_SEED: { required: true }
})
expect(workflow.permissions).toEqual({ actions: 'read', contents: 'read' })
expect(Object.keys(workflow.jobs)).toEqual([
'prepare-manifest',
'sign-manifest',
'finalize-manifest'
])
const prepare = workflow.jobs['prepare-manifest']
const sign = workflow.jobs['sign-manifest']
const finalize = workflow.jobs['finalize-manifest']
expect(prepare).toMatchObject({ 'runs-on': 'ubuntu-24.04', 'timeout-minutes': 15 })
expect(sign).toMatchObject({
needs: 'prepare-manifest',
'runs-on': 'ubuntu-24.04',
'timeout-minutes': 5,
environment: 'relay-runtime-manifest-signing'
})
expect(finalize).toMatchObject({
needs: ['prepare-manifest', 'sign-manifest'],
'runs-on': 'ubuntu-24.04',
'timeout-minutes': 15
})
for (const artifact of EXPECTED_ARTIFACTS) {
expect(source.match(new RegExp(`name: ${artifact}$`, 'gmu'))).toHaveLength(2)
expect(JSON.stringify(sign)).not.toContain(artifact)
}
expect(source).not.toContain('pattern: ssh-relay-runtime-')
expect(source).not.toContain('merge-multiple: true')
expect(source.match(/ssh-relay-runtime-manifest-aggregate-command\.mjs prepare/g)).toHaveLength(
1
)
expect(source.match(/ssh-relay-runtime-manifest-seed-signing\.mjs/g)).toHaveLength(1)
expect(
source.match(/ssh-relay-runtime-manifest-aggregate-command\.mjs finalize/g)
).toHaveLength(1)
const seedReferences = source.match(/secrets\.SSH_RELAY_RUNTIME_MANIFEST_SEED/g) ?? []
expect(seedReferences).toHaveLength(1)
expect(JSON.stringify(sign)).toContain('secrets.SSH_RELAY_RUNTIME_MANIFEST_SEED')
expect(JSON.stringify(prepare)).not.toContain('secrets.')
expect(JSON.stringify(finalize)).not.toContain('secrets.')
expect(actionRefs(source).every((ref) => /^[0-9a-f]{40}$/u.test(ref))).toBe(true)
expect(source).not.toContain('continue-on-error')
expect(source).not.toMatch(/contents:\s*write|gh\s+release|upload-release-asset/u)
expect(source.match(/config\/ssh-relay-runtime-manifest-accepted-keys\.json/g)).toHaveLength(2)
// Why: a placeholder key would make an unreviewed trust root look provisioned.
await expect(access(acceptedKeysUrl)).rejects.toMatchObject({ code: 'ENOENT' })
// Why: this capability must remain inert until release/publication and desktop gates are reviewed.
for (const consumer of [releaseCut, releaseMac, rehearsal]) {
expect(consumer).not.toContain('ssh-relay-runtime-manifest-signing.yml')
}
})
})
@@ -245,8 +245,11 @@ complete a box.
`E-M4-PROTECTED-MANIFEST-SEED-LOCAL-001` and all-six exact-head CI is closed by
`E-M4-PROTECTED-MANIFEST-SEED-CI-001`. The filesystem prepare/finalize command is locally
green under `E-M4-MANIFEST-AGGREGATE-COMMAND-LOCAL-RED-001` and
`E-M4-MANIFEST-AGGREGATE-COMMAND-LOCAL-001`; exact-head CI and the callable workflow remain
open.
`E-M4-MANIFEST-AGGREGATE-COMMAND-LOCAL-001`, with all-six exact-head CI closed by
`E-M4-MANIFEST-AGGREGATE-COMMAND-CI-001`. The callable workflow remains open.
Its disconnected three-job source contract is locally green under
`E-M4-PROTECTED-MANIFEST-WORKFLOW-LOCAL-001`, but exact-head CI and live protected signing
remain open; no accepted production key, environment, or seed is provisioned.
- [ ] Embed the exact signed manifest and accepted keys in each desktop build.
- [ ] Upload to a draft release, read back, re-hash, and execute the downloaded archives.
- [ ] Test timeouts, retries, approval denial, signing failure, partial output, and draft recovery.
@@ -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 disconnected aggregate and protected manifest-signing workflow contract — **In progress — 2026-07-15, Codex implementation owner**. Linux aggregate-ready finalization is closed locally and on exact-head native x64/arm64 runners under E-M4-LINUX-FINALIZATION-LOCAL-RED-001, E-M4-LINUX-FINALIZATION-LOCAL-001, and E-M4-LINUX-FINALIZATION-CI-001. The active package must consume only the six exact aggregate-ready outputs, prepare canonical bytes credential-free, expose only those bytes to the tag-restricted `relay-runtime-manifest-signing` environment, accept only key ID plus Ed25519 signature, reconstruct and verify before final output, and fail closed on missing/extra/mutated inputs, approval/secret/signing failure, timeout, or partial output. It remains callable and disconnected. Release-cut, desktop builds, publication, and every tuple stay disconnected; production/default behavior is unchanged.<br>
Session checkpoint: **In progress — 2026-07-15, Codex implementation owner** — protected seed-signer exact-head CI is closed by E-M4-PROTECTED-MANIFEST-SEED-CI-001 at pushed head `4180e04ac4e732f082dc576af69364325a678d2b`: all six native build jobs, PR Checks, and Golden E2E pass, with the artifact workflow red only for the retained Windows arm64 build-floor mismatch. The exclusive six-artifact filesystem command is locally green under E-M4-MANIFEST-AGGREGATE-COMMAND-LOCAL-RED-001 and E-M4-MANIFEST-AGGREGATE-COMMAND-LOCAL-001. Exact-head CI for that command is the next checkpoint, after which the still-red callable workflow may be implemented. No signing credential, aggregate workflow, release consumer, publication path, desktop consumer, tuple enablement, or production/default change is connected. Legacy remains the production default, and merge to `main` remains prohibited.<br>
Session checkpoint: **In progress — 2026-07-15, Codex implementation owner** — the exclusive six-artifact filesystem command is closed locally and on all six exact-head native families under E-M4-MANIFEST-AGGREGATE-COMMAND-LOCAL-RED-001, E-M4-MANIFEST-AGGREGATE-COMMAND-LOCAL-001, and E-M4-MANIFEST-AGGREGATE-COMMAND-CI-001 at pushed head `8cf80a0228ffa095beceec018a0de2e237b89e2d`. The callable three-job workflow is locally green under E-M4-PROTECTED-MANIFEST-WORKFLOW-LOCAL-001 and is the active exact-head CI checkpoint. It stays disconnected and deliberately fails closed before signer exposure because no accepted production key exists. No signing credential, protected environment, release consumer, publication path, desktop consumer, tuple enablement, or production/default change is connected. Legacy remains the production default, and merge to `main` remains prohibited.<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)
@@ -10866,6 +10866,73 @@ config/scripts/ssh-relay-runtime-manifest-aggregate-command.test.mjs` — PASS,
- Follow-up: checkpoint and push this command, require it on all six exact-head native jobs, then
implement the still-red callable workflow without connecting release or product consumers.
### E-M4-MANIFEST-AGGREGATE-COMMAND-CI-001 — Filesystem aggregation passes all native families
- Date: 2026-07-15
- Owner: Codex implementation owner
- Source: exact pushed head `8cf80a0228ffa095beceec018a0de2e237b89e2d`; draft PR #8741.
- Workflow: [SSH Relay Runtime Artifacts run 29424084956](https://github.com/stablyai/orca/actions/runs/29424084956),
14:33:33Z–14:53:05Z. The expected workflow failure is solely Windows arm64 baseline job
87385641582: runtime verification passes in 8,318.1202 ms with 6,107.7828 ms smoke and
49,930,240-byte RSS, then the exact floor gate rejects observed build 26200 versus required 26100.
- Native jobs: macOS x64 87381843694, Linux arm64 87381843705, macOS arm64 87381843796, Linux x64
87381843825, Windows x64 87381843853, and Windows arm64 87381844294 all pass complete artifact
construction. POSIX reports 49 files / 256 tests. Windows reports 50 files / 250 passed and ten
skipped of 260; only the POSIX-only symlink case is skipped by the new command suite on Windows.
- Supplemental jobs: Linux arm64 87383766220, Linux x64 87383766265, and Windows x64 87385641378
pass. The sole Windows arm64 failure is the retained exact-build mismatch described above.
- Adjacent regressions: [PR Checks 29424084938](https://github.com/stablyai/orca/actions/runs/29424084938)
job 87381832092 passes 14:33:36Z–14:48:09Z. [Golden E2E 29424085004](https://github.com/stablyai/orca/actions/runs/29424085004)
passes macOS job 87381832460 and Linux job 87381832629.
- Oracle proved: every target-native Node 24 family executes the exact six-artifact collection,
accepted-key, canonical request, independent reconstruction, signature verification, hostile
input, cancellation, and cleanup suite without regressing runtime construction or adjacent CI.
- Does not prove: real downloaded signed macOS/Windows outputs, a provisioned accepted production
key, protected environment/seed/reviewer approval, live workflow execution, native trust, exact
oldest floors, publication, desktop embedding, SSH behavior, or an enabled tuple.
- Follow-up: implement the callable three-job workflow contract. Keep it disconnected and fail
closed while accepted production keys, the environment, and seed remain unprovisioned.
### E-M4-PROTECTED-MANIFEST-WORKFLOW-LOCAL-001 — Disconnected protected workflow contract passes locally
- Date: 2026-07-15
- Owner: Codex implementation owner
- Source: local implementation atop pushed head
`8cf80a0228ffa095beceec018a0de2e237b89e2d`; draft PR #8741.
- Runner/remote/network: local macOS 26.2 arm64, Node v26.0.0 and pnpm 10.24.0. Static workflow
parsing only; no Actions runner, artifact download, accepted production key, GitHub Environment,
seed, approval, release, desktop consumer, SSH host, publication, or enabled tuple.
- Focused command: `pnpm exec vitest run --config config/vitest.config.ts --maxWorkers=1
config/scripts/ssh-relay-runtime-manifest-signing-workflow.test.mjs` — PASS, 1 file / 1 test in
159 ms on the final contract/static-gate rerun (the first green implementation run passed in 169
ms).
- Broad release command: `/usr/bin/time -l sh -c "rg --files config/scripts | rg
'/ssh-relay.*[.]test[.]mjs$' | xargs pnpm exec vitest run --config config/vitest.config.ts
--maxWorkers=1"` — PASS, 51 files / 261 tests in 10.23 seconds Vitest / 11.41 seconds wall,
188,825,600-byte maximum RSS, zero swaps.
- Desktop parity/static results: manifest schema/signature/release-asset parity passes 3 files / 48
tests; typecheck, `node --check`, and workflow/source formatting pass. Full lint passes all 41
reliability gates, the 355-entry max-lines ratchet, bundled-skill, and localization gates; all 26
warnings remain in untouched existing files.
- Oracle proved: the reusable interface has only the exact source SHA, tag, timestamp, and protocol
inputs plus one required seed secret. Preparation and finalization are credential-free, download
six exact artifacts separately, and use 15-minute bounds. The sole five-minute protected job sees
no runtime artifacts, references the seed exactly once, and returns only key ID/signature. Final
reconstruction independently recollects all six inputs. Actions are SHA-pinned, permissions are
read-only, no wildcard merge/continue-on-error/write publication exists, and no release,
desktop, or rehearsal workflow calls it.
- Fail-closed provisioning gate: both credential-free stages reference the absent
`config/ssh-relay-runtime-manifest-accepted-keys.json`; the purpose test requires that absence so
no placeholder trust root can look provisioned. Consequently the workflow cannot expose a
signing request or reach the protected environment until a separately reviewed accepted key is
committed. The environment/seed/reviewer restrictions remain external and unprovisioned.
- Does not prove: GitHub accepts/executes the YAML, actual artifact downloads, accepted-key
provisioning, environment/tag policy, secret isolation at runtime, approval denial/timeout,
signature generation, final output, native trust, publication, desktop embedding, SSH behavior,
or an enabled tuple.
- Follow-up: checkpoint and push the workflow contract, require exact-head PR/native CI, and keep
live signing BLOCKED until accepted keys and the protected environment receive separate review.
## Accepted Gaps
No product gap is accepted merely because it appears in this list. Each entry requires explicit
@@ -10924,12 +10991,12 @@ The project is not complete until every applicable item below is checked with ev
## Next Required Action
Checkpoint the locally proven filesystem prepare/finalize command and require its purpose suite on
all six exact-head native test families. After that CI evidence is green, implement the still-red
callable workflow so only canonical request bytes and the base64 32-byte seed enter the
tag-restricted `relay-runtime-manifest-signing` environment, while credential-free preparation and
final reconstruction independently download the six exact artifacts. The environment, accepted
production keys, and secret remain unprovisioned, so live signing evidence must stay BLOCKED. Keep
Checkpoint and push the locally green callable workflow, then require its purpose contract on all
six exact-head native test families plus PR Checks and Golden E2E. Only canonical request bytes and
the base64 32-byte seed may enter the tag-restricted `relay-runtime-manifest-signing` environment,
while credential-free preparation and final reconstruction independently download the six exact
artifacts. The environment, accepted production keys, and secret remain unprovisioned, so live
signing evidence must stay BLOCKED. Keep
Windows arm64 build 26100, macOS 13.5, Linux kernel 4.18, release-cut, desktop builds, publication,
and every tuple separately gated. Do not merge to `main`; retain every production/default gate.