test(ssh): prove full-size POSIX system transfer

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
Jinwoo-H
2026-07-16 14:33:23 -04:00
co-authored by Orca
parent 3fbf2339ba
commit a56dded6ff
5 changed files with 632 additions and 7 deletions
@@ -632,6 +632,96 @@ jobs:
pnpm exec vitest run --config config/vitest.config.ts --maxWorkers=1 --reporter=verbose \
src/main/ssh/ssh-relay-runtime-sftp-openssh-full-size.test.ts
- name: Start restricted loopback OpenSSH POSIX system-SSH fixture
if: runner.os == 'Linux'
shell: bash
run: |
set -euo pipefail
fixture="$RUNNER_TEMP/orca-live-sftp"
test -x /usr/sbin/sshd
test -s "$fixture/client-key"
test -s "$fixture/host-key"
system_fixture="$fixture/system-ssh"
primitives="$system_fixture/primitives"
mkdir -p "$primitives"
ln -s "$(command -v mkdir)" "$primitives/mkdir"
ln -s "$(command -v chmod)" "$primitives/chmod"
ln -s "$(command -v cat)" "$primitives/cat"
ln -s "$(command -v rm)" "$primitives/rm"
wrapper="$system_fixture/restricted-command"
printf '%s\n' \
'#!/bin/sh' \
'PATH="${0%/*}/primitives"' \
'export PATH' \
'exec /bin/sh -c "$SSH_ORIGINAL_COMMAND"' > "$wrapper"
chmod 755 "$wrapper"
port=22223
known_hosts="$HOME/.ssh/known_hosts"
printf '[127.0.0.1]:%s %s\n' "$port" "$(cat "$fixture/host-key.pub")" >> "$known_hosts"
chmod 600 "$known_hosts"
config="$system_fixture/sshd_config"
printf '%s\n' \
"Port $port" \
'ListenAddress 127.0.0.1' \
"HostKey $fixture/host-key" \
"PidFile $system_fixture/sshd.pid" \
"AuthorizedKeysFile $HOME/.ssh/authorized_keys" \
"AllowUsers $USER" \
'PasswordAuthentication no' \
'KbdInteractiveAuthentication no' \
'ChallengeResponseAuthentication no' \
'UsePAM no' \
'StrictModes yes' \
'LogLevel VERBOSE' \
"ForceCommand $wrapper" > "$config"
sudo /usr/sbin/sshd -f "$config" -E "$system_fixture/sshd.log"
for attempt in {1..20}; do
if ssh -F /dev/null -i "$fixture/client-key" -p "$port" \
-o BatchMode=yes -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes \
-o UserKnownHostsFile="$known_hosts" "$USER@127.0.0.1" true; then
break
fi
if test "$attempt" = 20; then
sudo tail -200 "$system_fixture/sshd.log"
exit 1
fi
sleep 0.25
done
server_version=$(/usr/sbin/sshd -V 2>&1 | head -1)
{
printf 'ORCA_SSH_RELAY_LIVE_SYSTEM_SSH_HOST=127.0.0.1\n'
printf 'ORCA_SSH_RELAY_LIVE_SYSTEM_SSH_PORT=%s\n' "$port"
printf 'ORCA_SSH_RELAY_LIVE_SYSTEM_SSH_USER=%s\n' "$USER"
printf 'ORCA_SSH_RELAY_LIVE_SYSTEM_SSH_IDENTITY=%s\n' "$fixture/client-key"
printf 'ORCA_SSH_RELAY_LIVE_SYSTEM_SSH_REMOTE_ROOT=%s\n' "$fixture/remote"
printf 'ORCA_SSH_RELAY_LIVE_SYSTEM_SSH_SERVER_VERSION=%s\n' "$server_version"
} >> "$GITHUB_ENV"
- name: Measure exact full-size runtime over POSIX system SSH
if: runner.os == 'Linux'
shell: bash
run: |
set -euo pipefail
first_output="$RUNNER_TEMP/ssh-relay-runtime/${{ matrix.tuple }}/first"
ORCA_SSH_FORCE_SYSTEM_TRANSPORT=1 \
ORCA_SSH_RELAY_FULL_SIZE_RUNTIME_ROOT="$first_output/runtime" \
ORCA_SSH_RELAY_FULL_SIZE_IDENTITY="$first_output/orca-ssh-relay-runtime-${{ matrix.tuple }}.identity.json" \
pnpm exec vitest run --config config/vitest.config.ts --maxWorkers=1 --reporter=verbose \
src/main/ssh/ssh-relay-runtime-posix-system-ssh-openssh-full-size.test.ts
- name: Stop restricted loopback OpenSSH POSIX system-SSH fixture
if: always() && runner.os == 'Linux'
shell: bash
run: |
set -euo pipefail
system_fixture="$RUNNER_TEMP/orca-live-sftp/system-ssh"
if test -s "$system_fixture/sshd.pid"; then
sudo kill "$(cat "$system_fixture/sshd.pid")" || true
fi
if test -f "$system_fixture/sshd.log"; then
sudo tail -200 "$system_fixture/sshd.log"
fi
- name: Stop loopback OpenSSH SFTP fixture
if: always() && runner.os == 'Linux'
shell: bash
@@ -104,6 +104,42 @@ describe('SSH relay runtime artifact workflow', () => {
expect(stop.if).toBe("always() && runner.os == 'Linux'")
})
it('runs full-size POSIX system SSH against loopback OpenSSH with restricted primitives', async () => {
const workflow = parse(await readFile(workflowUrl, 'utf8'))
const steps = workflow.jobs['build-posix-runtime'].steps
const start = steps.find(
(step) => step.name === 'Start restricted loopback OpenSSH POSIX system-SSH fixture'
)
const measure = steps.find(
(step) => step.name === 'Measure exact full-size runtime over POSIX system SSH'
)
const stop = steps.find(
(step) => step.name === 'Stop restricted loopback OpenSSH POSIX system-SSH fixture'
)
expect(start).toBeDefined()
expect(measure).toBeDefined()
expect(stop).toBeDefined()
expect(start.if).toBe("runner.os == 'Linux'")
expect(start.run).toContain('ListenAddress 127.0.0.1')
expect(start.run).toContain('ForceCommand $wrapper')
expect(start.run).toContain('PasswordAuthentication no')
expect(start.run).toContain('StrictModes yes')
expect(start.run).toContain('known_hosts')
expect(start.run).toContain('StrictHostKeyChecking=yes')
for (const primitive of ['mkdir', 'chmod', 'cat', 'rm']) {
expect(start.run).toContain(`command -v ${primitive}`)
}
for (const forbidden of ['node', 'python', 'perl', 'tar', 'base64', 'sha256sum', 'shasum']) {
expect(start.run).not.toContain(`command -v ${forbidden}`)
}
expect(measure.if).toBe("runner.os == 'Linux'")
expect(measure.run).toContain('ORCA_SSH_FORCE_SYSTEM_TRANSPORT=1')
expect(measure.run).toContain('ssh-relay-runtime-posix-system-ssh-openssh-full-size.test.ts')
expect(measure.run).toContain('first_output/runtime')
expect(stop.if).toBe("always() && runner.os == 'Linux'")
})
it('uploads only the first output after two clean builds verify and compare', async () => {
const source = await readFile(workflowUrl, 'utf8')
const workflow = parse(source)
@@ -43,6 +43,19 @@ immediate SIGTERM listener.
No direct spawn, legacy uploader change, live claim, or product path is included. Audit only a
disconnected live/full-size POSIX system-SSH proof next; legacy remains the only production/default
path and SignPath remains deferred.
`E-M6-POSIX-SYSTEM-SSH-TREE-LIVE-AUDIT-001` limits that proof to a second loopback-only stock
`sshd` on Linux x64/arm64 artifact runners, exact generated host-key trust, public-key auth, and a
forced remote `PATH` containing only `mkdir`, `chmod`, `cat`, and `rm` plus absolute `/bin/sh`.
It adds only a purpose-named full-size test and workflow/oracle wiring; no production module changes.
`E-M6-POSIX-SYSTEM-SSH-TREE-LIVE-LOCAL-RED-001` proves the live suite skips without its seven CI
inputs while the independent workflow oracle fails only because the audited start/measure/stop
steps are absent. That bounded fixture wiring now passes the local 9/9 workflow oracle while the
purpose suite remains honestly skipped without CI inputs; broad regression gates and exact-head
Linux x64/arm64 live evidence remain required.
`E-M6-POSIX-SYSTEM-SSH-TREE-LIVE-LOCAL-001` records that bounded package locally green: 9/9 workflow
oracle, 220 focused, 656 broad relay, 282 release-contract, typecheck, lint, 355-entry max-lines,
formatting, diff, protected-resolver, and no-product-consumer gates pass. The live case is explicitly
skipped locally and earns no proof; exact-head Linux x64/arm64 live evidence is still required.
`E-M6-POSIX-SYSTEM-SSH-FILE-LOCAL-001` records 25/25 purpose, 628 broad relay, 281/281 release, and all
static/isolation gates.
`E-M6-POSIX-SYSTEM-SSH-FILE-CI-001` proves the 25 cases on all six primary native clients; both Linux
@@ -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 6 / Work Package 5 bounded runtime transfer — **In progress — 2026-07-15, Codex implementation owner: disconnected POSIX system-SSH/no-tar transfer composition**. Keep every capability disconnected from every production/default SSH path. Real Apple/SignPath rehearsals remain an explicit late gate and are not on this package's critical path.<br>
Session checkpoint: **POSIX SYSTEM-SSH TREE/ROOT EXACT-HEAD GREEN / LIVE FULL-SIZE AUDIT NEXT — 2026-07-15, Codex implementation owner** — `E-M6-POSIX-SYSTEM-SSH-TREE-CI-001` proves the 15-case disconnected composition on all six primary Node 24 native clients at exact head `ec51e36b7`; Linux supplements, Windows x64 floor, PR Checks, computer-use, and Golden E2E pass. The artifact run remains red only for the declared Windows arm64 hosted build 26200 versus required 26100 floor mismatch after complete runtime verification. Audit only a purpose-named live/full-size loopback OpenSSH proof next; do not connect production behavior. Merging to `main` remains prohibited, SignPath is deferred, and legacy remains the production default.<br>
Session checkpoint: **POSIX SYSTEM-SSH LIVE FULL-SIZE LOCAL PACKAGE GREEN / COMMIT AND EXACT-HEAD CI NEXT — 2026-07-15, Codex implementation owner** — `E-M6-POSIX-SYSTEM-SSH-TREE-LIVE-LOCAL-001` records the bounded workflow oracle, focused/broad/release suites, typecheck, lint, max-lines, formatting, diff, protected-resolver, and no-product-consumer gates green. The purpose suite remains honestly skipped without its seven CI inputs and earns no live proof locally. Commit and push only this test/workflow/docs package, then require exact-head Linux x64/arm64 live metrics and all-six adjacent regression cells. Merging to `main` remains prohibited, SignPath is deferred, 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)
@@ -17879,8 +17879,8 @@ config/scripts/ssh-relay-runtime-workflow.test.mjs`.
separate five-second abort controller. Runtime-invalid staging-root input was corrected before
final GREEN so validation cannot throw an incidental `.split` type error.
- Purpose command: `/usr/bin/time -l pnpm exec vitest run --config config/vitest.config.ts
--maxWorkers=1 src/main/ssh/ssh-relay-runtime-posix-control-command.test.ts
src/main/ssh/ssh-relay-runtime-posix-tree-transfer.test.ts`. Result: 2 files and 15/15 cases pass;
--maxWorkers=1 src/main/ssh/ssh-relay-runtime-posix-control-command.test.ts
src/main/ssh/ssh-relay-runtime-posix-tree-transfer.test.ts`. Result: 2 files and 15/15 cases pass;
Vitest 1.95 seconds, 2.96 seconds real, 139,640,832-byte maximum RSS, 95,851,848-byte peak memory
footprint, zero swaps and block I/O. Cases cover exact/no-input success, nonzero/error, pre/mid
abort, timeout, graceful/forced settlement and joined failures; invalid OS/path/concurrency before
@@ -17888,7 +17888,7 @@ config/scripts/ssh-relay-runtime-workflow.test.mjs`.
progress, default-one/four-channel bounds, collision ownership, cancellation settlement, and
cleanup failure/timeout joining.
- Focused composition command: `/usr/bin/time -l pnpm exec vitest run --config
config/vitest.config.ts --maxWorkers=1` with the two new purpose suites plus
config/vitest.config.ts --maxWorkers=1` with the two new purpose suites plus
`ssh-relay-runtime-posix-file-destination.test.ts`,
`ssh-relay-runtime-system-ssh-file-channel.test.ts`, the source-tree/scan/stream suites,
`ssh-system-fallback.test.ts`, `ssh-connection.test.ts`, and
@@ -17898,13 +17898,13 @@ config/scripts/ssh-relay-runtime-workflow.test.mjs`.
lease, retained-buffer/no-later-write, missing process/false kill, diagnostic, child settlement,
and exact native-workflow-family contracts inherited from the composed boundaries.
- Broad relay command: `/usr/bin/time -l pnpm exec vitest run --config config/vitest.config.ts
--maxWorkers=1 src/main/ssh/ssh-relay-*.test.ts`. Result: 50 files passed, four files skipped;
--maxWorkers=1 src/main/ssh/ssh-relay-*.test.ts`. Result: 50 files passed, four files skipped;
656 passed and six declared skips out of 662. Vitest 55.58 seconds, 58.05 seconds real,
254,115,840-byte maximum RSS, 96,458,248-byte peak memory footprint, zero swaps and block I/O.
Skips remain the declared case-fold/full-size/live SSH cells and are not treated as this package's
evidence.
- Release-contract command: `/usr/bin/time -l pnpm exec vitest run --config
config/vitest.config.ts --maxWorkers=1 config/scripts/ssh-relay-runtime-*.test.mjs`. Result: 50
config/vitest.config.ts --maxWorkers=1 config/scripts/ssh-relay-runtime-*.test.mjs`. Result: 50
files and 281/281 cases pass; Vitest 37.74 seconds, 41.85 seconds real, 190,676,992-byte maximum
RSS, 97,195,384-byte peak memory footprint, zero swaps and block I/O.
- Static commands/results: `/usr/bin/time -l pnpm typecheck` passes in 8.38 seconds real with
@@ -17917,7 +17917,7 @@ config/scripts/ssh-relay-runtime-workflow.test.mjs`.
`pnpm check:max-lines-ratchet` command; no checklist box was credited to the failed spelling.
- Isolation evidence: `git diff --check` and no-index whitespace checks for all four new files are
clean. `git diff --exit-code HEAD -- src/main/ssh/ssh-remote-node-resolution.ts
src/main/ssh/ssh-remote-node-resolution.test.ts` is empty, preserving the protected Milestone 0
src/main/ssh/ssh-remote-node-resolution.test.ts` is empty, preserving the protected Milestone 0
resolver. The only implementation references to the exported tree owner are its definition and
purpose test; the control owner is consumed only by that disconnected tree owner and its test.
No product, settings, legacy uploader, fallback, tuple, publication, or default-path importer
@@ -17971,6 +17971,115 @@ config/scripts/ssh-relay-runtime-workflow.test.mjs`.
publish/launch, product/Beta/fallback/default wiring, tuple enablement, release publication, and
SignPath remain absent.
### E-M6-POSIX-SYSTEM-SSH-TREE-LIVE-AUDIT-001 — restricted-primitive full-size OpenSSH proof
- Date/owner/base: 2026-07-15, Codex implementation owner; exact clean evidence base
`3fbf2339badb7bab0308a6daadb80e7d5444e280` after recording the disconnected tree package's
exact-head evidence.
- Existing-boundary audit: the exact tree owner already composes production `SshConnection.exec`,
the system-SSH child/channel adapter, exclusive POSIX destinations, the scanned lease-backed
source stream, and bounded owned-root cleanup. No production change is necessary for live proof.
The existing live SFTP fixture cannot force a restricted command environment because its
`internal-sftp` subsystem shares the daemon, so do not alter or weaken it.
- Live fixture: on only the Linux x64/arm64 target-native artifact jobs, start a second stock
loopback-only `sshd` on its own port/PID/log with the already-generated ephemeral Ed25519 client
and host keys. Pin the generated public host key into the runner user's `known_hosts`; retain
`StrictModes yes`, disable password/keyboard-interactive authentication, and never expose a
non-loopback listener. `ForceCommand` invokes a fixed fixture-owned POSIX wrapper whose remote
`PATH` contains symlinks only for `mkdir`, `chmod`, `cat`, and `rm`; `/bin/sh` is absolute. This
proves transfer without remote Node, Python, Perl, tar, base64, `sha256sum`, or `shasum`, while
preserving normal production system-SSH argument/channel behavior and authenticated transport.
- Purpose suite: build a scanned source tree from the exact full-size runtime identity produced in
the same native job, force the existing `SshConnection` into system transport only for the test,
and call `transferSshRelayRuntimeTreeViaPosixSystemSsh` directly. Measure serial/default-one and
explicit-four transfers; validate every remote path, byte, SHA-256, mode, file count, and total;
prove a root collision cannot alter the complete tree; cancel after the first transferred bytes,
require no later progress and owned-root removal after settlement; and prove the connection remains
usable. Record tuple/content/server/runner, bytes/files, elapsed time, peak progress concurrency,
incremental RSS, cancellation delay, and residual gaps. Enforce the existing 80 MiB incremental
RSS and 10-second cancellation ceilings under the workflow's 20-minute job budget.
- Evidence sequence: add only the skipped-without-input purpose suite plus workflow oracle first and
accept RED only when the oracle reports the three missing start/measure/stop steps. Then add the
bounded workflow fixture/wiring, require local skip/oracle GREEN plus broad/static/isolation gates,
commit, and require exact-head Linux x64/arm64 live metrics and all-six adjacent regression cells.
- Explicit residual boundary: no high-RTT host, `MaxSessions=1`, cross-client/remote family matrix,
network interruption/disk/quota/inode/noexec/AV fault injection, semantic probe/cache, optional tar
fast path, Windows transfer, remote bundled-Node verification/install/publish/launch, product/Beta/
settings/fallback/default behavior, tuple enablement, publication, or SignPath is included. Legacy
remains the only production/default path.
### E-M6-POSIX-SYSTEM-SSH-TREE-LIVE-LOCAL-RED-001 — audited workflow fixture is absent
- Date/owner/base: 2026-07-15, Codex implementation owner; audit, purpose suite, and workflow-oracle-
only diff atop exact clean evidence base `3fbf2339badb7bab0308a6daadb80e7d5444e280`.
- Command: `/usr/bin/time -l pnpm exec vitest run --config config/vitest.config.ts --maxWorkers=1
src/main/ssh/ssh-relay-runtime-posix-system-ssh-openssh-full-size.test.ts
config/scripts/ssh-relay-runtime-workflow.test.mjs`.
- Result: expected RED, exit 1. The purpose-named live suite declares its single case skipped because
the seven full-size/OpenSSH inputs are absent locally and earns no transfer evidence. The workflow
oracle passes 8/9 existing cases and its only failure is `expected undefined to be defined` for
the audited restricted POSIX system-SSH start step; measure and stop are consequently absent too.
- Resource evidence: Vitest 1.50 seconds, 3.73 seconds real, 143,818,752-byte maximum RSS,
96,146,808-byte peak memory footprint, zero swaps and block I/O.
- Disposition: RED is causal and accepted. Add only the second loopback daemon, restricted primitive
wrapper, exact known-host pin, purpose measurement, and always-run cleanup steps. No production,
product/default, fallback, tuple, publication, tar optimization, Windows transfer, or SignPath
change is authorized by this evidence.
### E-M6-POSIX-SYSTEM-SSH-TREE-LIVE-LOCAL-001 — bounded live fixture package is locally green
- Date/owner/base/runner: 2026-07-15, Codex implementation owner; uncommitted test/workflow/docs
package atop exact base `3fbf2339badb7bab0308a6daadb80e7d5444e280` on Apple arm64, macOS 26.2
build 25C56, Node 26.0.0, pnpm 10.24.0. The local Node version is newer than the repository's Node
24 contract, so exact-head native workflow evidence remains mandatory.
- Package: add one purpose-named live/full-size test and three audited Linux-only artifact-workflow
steps. The fixture starts a second stock loopback `sshd`, pins the generated host key, permits only
public-key authentication, and forces a wrapper whose `PATH` contains only `mkdir`, `chmod`, `cat`,
and `rm` while invoking absolute `/bin/sh`. The test uses the exact native runtime tree and existing
production system-SSH composition to measure default-one and explicit-four transfer, exact tree
bytes/hashes/modes/paths/counts, exclusive-root collision preservation, cancellation settlement,
no later progress, owned-root cleanup, post-cancellation connection usability, latency, RSS, and
active-file count. No production module changes.
- Targeted command: `pnpm exec oxfmt --check` for the new test, workflow oracle, and artifact workflow;
`pnpm exec oxlint` for the new test and oracle; then `/usr/bin/time -l pnpm exec vitest run --config
config/vitest.config.ts --maxWorkers=1 src/main/ssh/ssh-relay-runtime-posix-system-ssh-openssh-full-size.test.ts
config/scripts/ssh-relay-runtime-workflow.test.mjs`. Result: formatting/lint pass; the workflow
oracle passes 9/9 while the one live case is explicitly skipped because its seven CI inputs are
absent. Vitest 12.53 seconds; 25.90 seconds real; 131,907,584-byte maximum RSS; 96,146,904-byte
peak footprint; zero swaps and block I/O. The skip earns no live/full-size transfer evidence.
- Focused composition command: `/usr/bin/time -l pnpm exec vitest run --config
config/vitest.config.ts --maxWorkers=1` with the control/tree/file-destination/system-channel,
source-tree/scan/stream, system-fallback, connection, and workflow-oracle suites. Result: 10 files,
220 passed and one declared platform skip; Vitest 13.07 seconds; 14.67 seconds real;
178,061,312-byte maximum RSS; 96,277,904-byte peak footprint; zero swaps and block I/O.
- Broad relay command: `/usr/bin/time -l pnpm exec vitest run --config config/vitest.config.ts
--maxWorkers=1 src/main/ssh/ssh-relay-*.test.ts`. Result: 50 files passed, five files skipped; 656
passed and seven declared skips out of 663. Vitest 59.16 seconds; 64.28 seconds real;
269,565,952-byte maximum RSS; 96,114,160-byte peak footprint; zero swaps and block I/O. The new
live case is one of the declared skips and is not counted as proof.
- Release-contract command: `/usr/bin/time -l pnpm exec vitest run --config
config/vitest.config.ts --maxWorkers=1 config/scripts/ssh-relay-runtime-*.test.mjs`. Result: 50 files
and 282/282 cases pass; Vitest 35.69 seconds; 39.36 seconds real; 190,201,856-byte maximum RSS;
96,638,376-byte peak footprint; zero swaps and block I/O.
- Static evidence: `/usr/bin/time -l pnpm typecheck` passes in 6.13 seconds real with
1,241,317,376-byte maximum RSS and 96,163,192-byte peak footprint. `/usr/bin/time -l pnpm lint`
passes in 36.12 seconds real with 2,111,471,616-byte maximum RSS and 95,868,232-byte peak footprint;
its 26 warnings are pre-existing outside this diff. Full lint proves switch exhaustiveness, 41
reliability gates, the 355-entry max-lines ratchet with no new bypass, bundled guides, and all
localization checks. Standalone max-lines and targeted formatting pass after formatting this
ledger entry; the new test is 377 lines with no suppression.
- Isolation evidence: `git diff --check` passes; `git diff --exit-code HEAD --
src/main/ssh/ssh-remote-node-resolution.ts src/main/ssh/ssh-remote-node-resolution.test.ts` is empty.
An asserted non-test reference search finds the tree-transfer export only in its owning production
module; this package adds no product importer. The intended diff is limited to the live test,
artifact workflow, workflow oracle, and both checklist documents. No settings, Beta, legacy
uploader, fallback, tuple, publication, default-path, or signing behavior changes.
- Residual boundary: local execution does not supply a Linux OpenSSH daemon or the exact full-size
native runtime, so exact-head Linux x64/arm64 live metrics and all-six adjacent native regression
cells remain required. High RTT, `MaxSessions=1`, cross-family remotes, Windows transfer, primitive
probe/cache, remote bundled-Node verification/install/publish/launch, product/Beta/fallback/default
wiring, tuple enablement, publication, Apple signing, and SignPath remain absent.
## Accepted Gaps
No product gap is accepted merely because it appears in this list. Each entry requires explicit
@@ -0,0 +1,377 @@
import { createHash } from 'node:crypto'
import { lstat, open, opendir, readFile, rm } from 'node:fs/promises'
import { join } from 'node:path'
import { performance } from 'node:perf_hooks'
import { describe, expect, it, vi } from 'vitest'
vi.mock('electron', () => ({ app: { getAppPath: () => process.cwd() } }))
import type { SshTarget } from '../../shared/ssh-types'
import { SshConnection } from './ssh-connection'
import { runSshRelayRuntimePosixControlCommand } from './ssh-relay-runtime-posix-control-command'
import { transferSshRelayRuntimeTreeViaPosixSystemSsh } from './ssh-relay-runtime-posix-tree-transfer'
import {
scanSshRelayRuntimeSourceTree,
type SshRelayRuntimeScannedSourceTree
} from './ssh-relay-runtime-source-scan'
import type { SshRelayRuntimeSourceTree } from './ssh-relay-runtime-source-tree'
import {
SSH_RELAY_RUNTIME_SOURCE_STREAM_LIMITS,
type SshRelayRuntimeSourceStreamProgress
} from './ssh-relay-runtime-source-stream'
import { openSshRelayRuntimeSystemSshFileChannel } from './ssh-relay-runtime-system-ssh-file-channel'
type MeasurementIdentity = Pick<
SshRelayRuntimeSourceTree,
'tupleId' | 'contentId' | 'os' | 'architecture'
> & {
entries: (
| { path: string; type: 'directory'; mode: 0o755 }
| {
path: string
type: 'file'
role: SshRelayRuntimeSourceTree['files'][number]['role']
size: number
mode: 0o644 | 0o755
sha256: SshRelayRuntimeSourceTree['files'][number]['sha256']
}
)[]
archive: { expandedSize: number; fileCount: number }
}
type Measurement<T> = {
result: T
elapsedMs: number
baselineRss: number
peakRss: number
incrementalRssBytes: number
}
const host = process.env.ORCA_SSH_RELAY_LIVE_SYSTEM_SSH_HOST
const user = process.env.ORCA_SSH_RELAY_LIVE_SYSTEM_SSH_USER
const identityFile = process.env.ORCA_SSH_RELAY_LIVE_SYSTEM_SSH_IDENTITY
const remoteRoot = process.env.ORCA_SSH_RELAY_LIVE_SYSTEM_SSH_REMOTE_ROOT
const runtimeRoot = process.env.ORCA_SSH_RELAY_FULL_SIZE_RUNTIME_ROOT
const identityPath = process.env.ORCA_SSH_RELAY_FULL_SIZE_IDENTITY
const port = Number.parseInt(process.env.ORCA_SSH_RELAY_LIVE_SYSTEM_SSH_PORT ?? '', 10)
const hasLiveInput = Boolean(
host &&
user &&
identityFile &&
remoteRoot &&
runtimeRoot &&
identityPath &&
Number.isInteger(port)
)
function parseIdentity(value: unknown): MeasurementIdentity {
if (
typeof value !== 'object' ||
value === null ||
!('entries' in value) ||
!Array.isArray(value.entries) ||
!('archive' in value) ||
typeof value.archive !== 'object' ||
value.archive === null
) {
throw new Error('Live POSIX system-SSH measurement identity is incomplete')
}
return value as MeasurementIdentity
}
function sourceTree(identity: MeasurementIdentity): SshRelayRuntimeSourceTree {
const directories = identity.entries
.filter((entry) => entry.type === 'directory')
.map((entry) => ({
...entry,
localPath: join(runtimeRoot as string, ...entry.path.split('/'))
}))
const files = identity.entries
.filter((entry) => entry.type === 'file')
.map((entry) => ({
...entry,
localPath: join(runtimeRoot as string, ...entry.path.split('/'))
}))
return Object.freeze({
tupleId: identity.tupleId,
contentId: identity.contentId,
releaseTag: 'measurement-only',
os: identity.os,
architecture: identity.architecture,
runtimeRoot: runtimeRoot as string,
directories,
files,
fileCount: identity.archive.fileCount,
expandedBytes: identity.archive.expandedSize,
assertLeaseOwned: async () => {}
})
}
async function measure<T>(operation: () => Promise<T>): Promise<Measurement<T>> {
const baselineRss = process.memoryUsage().rss
let peakRss = baselineRss
const sample = (): void => {
peakRss = Math.max(peakRss, process.memoryUsage().rss)
}
const sampler = setInterval(sample, 1)
const startedAt = performance.now()
try {
const result = await operation()
sample()
return {
result,
elapsedMs: performance.now() - startedAt,
baselineRss,
peakRss,
incrementalRssBytes: Math.max(0, peakRss - baselineRss)
}
} finally {
clearInterval(sampler)
}
}
async function hashFile(path: string): Promise<string> {
const handle = await open(path, 'r')
const digest = createHash('sha256')
const buffer = Buffer.allocUnsafe(64 * 1024)
let position = 0
try {
while (true) {
const { bytesRead } = await handle.read(buffer, 0, buffer.length, position)
if (bytesRead === 0) {
break
}
digest.update(buffer.subarray(0, bytesRead))
position += bytesRead
}
} finally {
await handle.close()
}
return `sha256:${digest.digest('hex')}`
}
async function collectRemotePaths(root: string): Promise<string[]> {
const paths: string[] = []
const pending = [{ localPath: root, relativePath: '' }]
while (pending.length > 0) {
const current = pending.pop()!
const directory = await opendir(current.localPath)
for await (const entry of directory) {
const relativePath = current.relativePath
? `${current.relativePath}/${entry.name}`
: entry.name
paths.push(relativePath)
if (entry.isDirectory()) {
pending.push({ localPath: join(current.localPath, entry.name), relativePath })
}
}
}
return paths.sort()
}
async function validateTransferredTree(
tree: SshRelayRuntimeScannedSourceTree,
stage: string
): Promise<void> {
const expectedPaths = [...tree.directories, ...tree.files].map((entry) => entry.path).sort()
// Why: the loopback runner can inspect sshd's filesystem without adding another proof channel.
expect(await collectRemotePaths(stage)).toEqual(expectedPaths)
for (const directory of tree.directories) {
const metadata = await lstat(join(stage, ...directory.path.split('/')))
expect(metadata.isDirectory()).toBe(true)
expect(metadata.mode & 0o777).toBe(directory.mode)
}
for (const file of tree.files) {
const path = join(stage, ...file.path.split('/'))
const metadata = await lstat(path)
expect(metadata.isFile()).toBe(true)
expect(metadata.size).toBe(file.size)
expect(metadata.mode & 0o777).toBe(file.mode)
expect(await hashFile(path)).toBe(file.sha256)
}
}
function stagePath(name: string, identity: MeasurementIdentity): string {
return join(remoteRoot as string, `${name}-${identity.contentId.slice('sha256:'.length, 23)}`)
}
function createProgressRecorder(): {
record: (progress: SshRelayRuntimeSourceStreamProgress) => void
snapshot: () => { bytes: number; updates: number; peakActiveFiles: number }
} {
let bytes = 0
let updates = 0
let peakActiveFiles = 0
return {
record: (progress) => {
bytes = progress.bytesTransferred
updates += 1
peakActiveFiles = Math.max(peakActiveFiles, progress.activeFiles)
},
snapshot: () => ({ bytes, updates, peakActiveFiles })
}
}
async function transfer(
connection: SshConnection,
tree: SshRelayRuntimeScannedSourceTree,
stage: string,
signal: AbortSignal,
onProgress: (progress: SshRelayRuntimeSourceStreamProgress) => void,
maximumConcurrency?: number
) {
return transferSshRelayRuntimeTreeViaPosixSystemSsh({
connection,
tree,
remoteStagingRoot: stage,
signal,
onProgress,
...(maximumConcurrency === undefined ? {} : { maximumConcurrency })
})
}
describe.skipIf(!hasLiveInput)(
'SSH relay full-size POSIX system-SSH transfer through restricted OpenSSH',
() => {
it(
'preserves exact bytes and modes with bounded serial, concurrent, and cancellation behavior',
{ timeout: 20 * 60_000 },
async () => {
expect(process.platform).toBe('linux')
expect(process.env.ORCA_SSH_FORCE_SYSTEM_TRANSPORT).toBe('1')
const identity = parseIdentity(JSON.parse(await readFile(identityPath as string, 'utf8')))
expect(identity.os).toBe('linux')
const tree = await scanSshRelayRuntimeSourceTree(
sourceTree(identity),
new AbortController().signal
)
const target: SshTarget = {
id: 'live-posix-system-ssh-measurement',
label: 'live-posix-system-ssh-measurement',
host: host as string,
port,
username: user as string,
identityFile: identityFile as string,
identitiesOnly: true,
systemSshConnectionReuse: true,
source: 'manual'
}
const connection = new SshConnection(target, { onStateChange: () => {} })
const serialStage = stagePath('system-serial', identity)
const concurrentStage = stagePath('system-concurrent', identity)
const cancelledStage = stagePath('system-cancelled', identity)
const stages = [serialStage, concurrentStage, cancelledStage]
await Promise.all(stages.map((stage) => rm(stage, { recursive: true, force: true })))
try {
await connection.connect()
expect(connection.usesSystemSshTransport()).toBe(true)
const serialProgress = createProgressRecorder()
const serial = await measure(() =>
transfer(
connection,
tree,
serialStage,
new AbortController().signal,
serialProgress.record
)
)
await validateTransferredTree(tree, serialStage)
expect(serialProgress.snapshot().peakActiveFiles).toBe(1)
const concurrentProgress = createProgressRecorder()
const concurrent = await measure(() =>
transfer(
connection,
tree,
concurrentStage,
new AbortController().signal,
concurrentProgress.record,
4
)
)
await validateTransferredTree(tree, concurrentStage)
expect(concurrentProgress.snapshot().peakActiveFiles).toBeGreaterThan(1)
expect(concurrentProgress.snapshot().peakActiveFiles).toBeLessThanOrEqual(4)
await expect(
transfer(connection, tree, concurrentStage, new AbortController().signal, () => {})
).rejects.toBeTruthy()
await validateTransferredTree(tree, concurrentStage)
const controller = new AbortController()
const cancelledProgress = createProgressRecorder()
let abortRequestedAt = 0
const cancelled = await measure(async () => {
const outcome = transfer(
connection,
tree,
cancelledStage,
controller.signal,
(progress) => {
cancelledProgress.record(progress)
if (progress.bytesTransferred > 0 && !controller.signal.aborted) {
abortRequestedAt = performance.now()
controller.abort(new Error('live POSIX system-SSH cancellation'))
}
},
4
)
await expect(outcome).rejects.toThrow('live POSIX system-SSH cancellation')
return performance.now() - abortRequestedAt
})
const updatesAfterSettlement = cancelledProgress.snapshot().updates
await expect(lstat(cancelledStage)).rejects.toMatchObject({ code: 'ENOENT' })
await new Promise((resolve) => setTimeout(resolve, 500))
await expect(lstat(cancelledStage)).rejects.toMatchObject({ code: 'ENOENT' })
expect(cancelledProgress.snapshot().updates).toBe(updatesAfterSettlement)
await runSshRelayRuntimePosixControlCommand({
command: 'true',
signal: new AbortController().signal,
openChannel: (command, signal) =>
openSshRelayRuntimeSystemSshFileChannel(connection, command, signal)
})
expect(connection.getState().status).toBe('connected')
const metrics = {
tupleId: identity.tupleId,
contentId: identity.contentId,
files: tree.fileCount,
bytes: tree.expandedBytes,
serverVersion: process.env.ORCA_SSH_RELAY_LIVE_SYSTEM_SSH_SERVER_VERSION,
runnerImage: process.env.ImageOS,
runnerVersion: process.env.ImageVersion,
runnerArchitecture: process.env.RUNNER_ARCH,
remotePrimitives: ['/bin/sh', 'mkdir', 'chmod', 'cat', 'rm'],
serialElapsedMs: serial.elapsedMs,
serialIncrementalRssBytes: serial.incrementalRssBytes,
serialPeakActiveFiles: serialProgress.snapshot().peakActiveFiles,
concurrentElapsedMs: concurrent.elapsedMs,
concurrentIncrementalRssBytes: concurrent.incrementalRssBytes,
concurrentPeakActiveFiles: concurrentProgress.snapshot().peakActiveFiles,
cancellationSettlementMs: cancelled.result,
cancellationIncrementalRssBytes: cancelled.incrementalRssBytes,
cancellationProgressUpdates: cancelledProgress.snapshot().updates
}
console.log(`ssh_relay_live_posix_system_ssh=${JSON.stringify(metrics)}`)
expect(serial.result.bytesTransferred).toBe(tree.expandedBytes)
expect(concurrent.result.bytesTransferred).toBe(tree.expandedBytes)
expect(serialProgress.snapshot().bytes).toBe(tree.expandedBytes)
expect(concurrentProgress.snapshot().bytes).toBe(tree.expandedBytes)
expect(serial.incrementalRssBytes).toBeLessThanOrEqual(
SSH_RELAY_RUNTIME_SOURCE_STREAM_LIMITS.maximumIncrementalMemoryBytes
)
expect(concurrent.incrementalRssBytes).toBeLessThanOrEqual(
SSH_RELAY_RUNTIME_SOURCE_STREAM_LIMITS.maximumIncrementalMemoryBytes
)
expect(cancelled.result).toBeLessThan(10_000)
} finally {
await connection.disconnect()
await Promise.all(stages.map((stage) => rm(stage, { recursive: true, force: true })))
}
}
)
}
)