diff --git a/.github/workflows/ssh-relay-runtime-artifacts.yml b/.github/workflows/ssh-relay-runtime-artifacts.yml
index 52e7101ccc0..e82c629d64b 100644
--- a/.github/workflows/ssh-relay-runtime-artifacts.yml
+++ b/.github/workflows/ssh-relay-runtime-artifacts.yml
@@ -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 `
diff --git a/.github/workflows/ssh-relay-runtime-manifest-signing.yml b/.github/workflows/ssh-relay-runtime-manifest-signing.yml
new file mode 100644
index 00000000000..1e6fc5f292e
--- /dev/null
+++ b/.github/workflows/ssh-relay-runtime-manifest-signing.yml
@@ -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
diff --git a/config/scripts/ssh-relay-runtime-manifest-signing-workflow.test.mjs b/config/scripts/ssh-relay-runtime-manifest-signing-workflow.test.mjs
new file mode 100644
index 00000000000..6d2431a1cbd
--- /dev/null
+++ b/config/scripts/ssh-relay-runtime-manifest-signing-workflow.test.mjs
@@ -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')
+ }
+ })
+})
diff --git a/docs/reference/plans/2026-07-14-ssh-relay-github-release-implementation-checklist-summary.md b/docs/reference/plans/2026-07-14-ssh-relay-github-release-implementation-checklist-summary.md
index 6fb74adf9c0..7f49e6744df 100644
--- a/docs/reference/plans/2026-07-14-ssh-relay-github-release-implementation-checklist-summary.md
+++ b/docs/reference/plans/2026-07-14-ssh-relay-github-release-implementation-checklist-summary.md
@@ -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.
diff --git a/docs/reference/plans/2026-07-14-ssh-relay-github-release-implementation-checklist.md b/docs/reference/plans/2026-07-14-ssh-relay-github-release-implementation-checklist.md
index 2986ee50794..338749d382b 100644
--- a/docs/reference/plans/2026-07-14-ssh-relay-github-release-implementation-checklist.md
+++ b/docs/reference/plans/2026-07-14-ssh-relay-github-release-implementation-checklist.md
@@ -9,7 +9,7 @@ work; keep exact commands, runner identities, hashes, metrics, and residual gaps
Date created: 2026-07-14
Last updated: 2026-07-15
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.
-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.
+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.
Primary design: [SSH relay GitHub Release plan](./2026-07-14-ssh-relay-github-release-plan.html)
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.