feat: compose SSH relay host evidence

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
Jinwoo-H
2026-07-16 07:07:51 -04:00
co-authored by Orca
parent cfe56d0fdb
commit a7fd19de5f
6 changed files with 458 additions and 14 deletions
@@ -264,6 +264,7 @@ jobs:
src/main/ssh/ssh-relay-artifact-selector.test.ts \
src/main/ssh/ssh-relay-libc-detection.test.ts \
src/main/ssh/ssh-relay-linux-kernel-detection.test.ts \
src/main/ssh/ssh-relay-host-evidence-detection.test.ts \
src/main/ssh/ssh-relay-darwin-version-detection.test.ts \
src/main/ssh/ssh-relay-darwin-translation-detection.test.ts \
src/main/ssh/ssh-relay-linux-libstdcxx-detection.test.ts \
@@ -815,6 +816,7 @@ jobs:
src/main/ssh/ssh-relay-artifact-selector.test.ts `
src/main/ssh/ssh-relay-libc-detection.test.ts `
src/main/ssh/ssh-relay-linux-kernel-detection.test.ts `
src/main/ssh/ssh-relay-host-evidence-detection.test.ts `
src/main/ssh/ssh-relay-darwin-version-detection.test.ts `
src/main/ssh/ssh-relay-darwin-translation-detection.test.ts `
src/main/ssh/ssh-relay-linux-libstdcxx-detection.test.ts `
@@ -122,6 +122,7 @@ describe('SSH relay runtime artifact workflow', () => {
'ssh-relay-artifact-selector.test.ts',
'ssh-relay-libc-detection.test.ts',
'ssh-relay-linux-kernel-detection.test.ts',
'ssh-relay-host-evidence-detection.test.ts',
'ssh-relay-darwin-version-detection.test.ts',
'ssh-relay-darwin-translation-detection.test.ts',
'ssh-relay-linux-libstdcxx-detection.test.ts',
@@ -9,9 +9,9 @@ keeps commands, hashes, runner identities, timings, and failure details.
A checked box means the work has evidence in the detailed ledger. Design approval alone does not
complete a box.
Active checkpoint: **Milestone 5 / Work Package 4 desktop resolver/cache — audit the smallest
disconnected full host-evidence composition boundary after native acceptance of every individual
compatibility detector, 2026-07-15, Codex implementation owner.**
Active checkpoint: **Milestone 5 / Work Package 4 desktop resolver/cache — disconnected host-
evidence composition is locally green; exact-head all-six native CI is next, 2026-07-15, Codex
implementation owner.**
`E-M5-ARTIFACT-CACHE-RESOLUTION-CI-001` closes warm-cache commit
`22031fa68` on all six native clients, both Linux supplements, Windows x64 baseline, PR Checks,
Golden E2E, and computer-use; Windows arm64 remains the expected build-26200 rejection against 26100. `E-M5-ARTIFACT-CACHE-RESOLUTION-LOCAL-001` passes 9/9 purpose tests,
@@ -269,6 +269,25 @@ format, max-lines, diff, and protected-resolver gates pass; replacement native C
clients, both Linux supplements, Windows x64 baseline, PR Checks, Golden E2E, and computer-use pass.
Both Windows architectures pass all 32 detector cases under native Windows PowerShell. Windows
arm64 completes full runtime proof and retains only the declared hosted build-26200 rejection against 26100. No live SSH, composer, product caller, setting/fallback, tuple, publication, or default exists.
`E-M5-HOST-EVIDENCE-COMPOSITION-AUDIT-001` fixes the next disconnected boundary: consume an explicit
canonical detected platform, SSH connection, and signal; run only that OS family's already-proven
detectors with at most three concurrent bounded channels; and return frozen selector-shaped evidence.
Darwin translation unknown returns no evidence rather than inventing native/translated state.
Inconsistent platform identity, product/startup callers, selector changes, live SSH, settings,
fallback, transfer/install, tuple enablement, publication, defaults, and SignPath stay absent.
RED is recorded before implementation: the purpose suite exits 1 because its module is absent
(0 tests, 316 ms, 132,235,264-byte max RSS), and the workflow oracle exits 1 because the suite has
only its POSIX native-family occurrence (6 passed/1 failed, 409 ms, 131,743,744-byte max RSS).
Pre-RED diff and protected-resolver checks pass.
`E-M5-HOST-EVIDENCE-COMPOSITION-LOCAL-001` is green: 20/20 purpose and 193/193 focused assertions,
512/512 broader relay assertions, 280/280 release-script assertions, typecheck, lint, format,
max-lines, diff, no-product-import, and protected-resolver gates pass. The disconnected composer
validates canonical platform identity before probes; invokes only Linux's three, Darwin's two, or
Windows' one accepted bounded detector; runs multi-probe families concurrently; preserves
conservative unknowns; refuses unknown Darwin translation; propagates cancellation/errors; and
deeply freezes evidence. It is required in both native workflow families. Exact-head all-six Node 24
client proof remains mandatory; no live SSH, product caller, settings/fallback, transfer/install,
tuple, publication, default, or SignPath work is included.
`E-M5-ARTIFACT-CACHE-ROOT-CI-001` closes the pure cache-root contract at exact head `aefcaa9a9`:
all six primary native Node 24 jobs, both Linux supplements, Windows x64 baseline, PR Checks, Golden
E2E, and computer-use pass; Windows arm64 build 26200 remains correctly gated against 26100. The
@@ -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 5 / Work Package 4 desktop resolver/cache — **In progress — 2026-07-15, Codex implementation owner: audit the smallest disconnected full host-evidence composition boundary after native acceptance of every individual detector**. 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: **WINDOWS COMPATIBILITY CI CLOSED / HOST COMPOSITION AUDIT NEXT — 2026-07-15, Codex implementation owner** — `E-M5-WINDOWS-COMPATIBILITY-DETECTION-CI-001` proves both native Windows architectures pass the strict detector, all six primary clients and both Linux supplements pass, Windows x64 baseline passes, and Windows arm64 retains only the declared build-26200/26100 runner mismatch after full runtime proof. Audit only the next disconnected composition boundary; do not add a product caller, settings/fallback wiring, tuple enablement, publication, or default behavior. Merging to `main` remains prohibited, SignPath is deferred, and legacy remains the production default.<br>
Current phase: Milestone 5 / Work Package 4 desktop resolver/cache — **In progress — 2026-07-15, Codex implementation owner: disconnected host-evidence composition is locally green; exact-head native CI is the next gate**. 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: **HOST COMPOSITION LOCAL GREEN / NATIVE CI NEXT — 2026-07-15, Codex implementation owner** — `E-M5-HOST-EVIDENCE-COMPOSITION-LOCAL-001` proves canonical six-tuple mapping, conservative unknowns, Darwin translation policy, bounded concurrency, cancellation/error propagation, deep freezing, workflow-family inclusion, and all local static/broad/release gates. Commit and push this isolated package, then require exact-head all-six native client proof before accepting it or opening another package. Do not add a product caller, settings/fallback wiring, tuple enablement, publication, or default behavior. 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)
@@ -147,11 +147,10 @@ same change as the work it records.
local gates, and all-six native Node 24 proof are green under
E-M5-ARTIFACT-CACHE-ROOT-LOCAL-RED-001, E-M5-ARTIFACT-CACHE-ROOT-LOCAL-001, and
E-M5-ARTIFACT-CACHE-ROOT-CI-001. No Electron or product caller exists.
- Active package: **In progress — 2026-07-15, Codex implementation owner** — audit the smallest
disconnected full host-evidence composition boundary after
E-M5-WINDOWS-COMPATIBILITY-DETECTION-CI-001 closes every individual detector on native clients.
Keep live SSH, transfer/install, settings, fallback wiring, tuple enablement, publication,
defaults, and SignPath separately gated.
- Active package: **In progress — 2026-07-15, Codex implementation owner** — disconnected full host-
evidence composition is locally green under E-M5-HOST-EVIDENCE-COMPOSITION-LOCAL-001. Exact-head
all-six native client proof is the next acceptance gate. Keep live SSH, transfer/install,
settings, fallback wiring, tuple enablement, publication, defaults, and SignPath separately gated.
- 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
@@ -15926,6 +15925,108 @@ config/scripts/ssh-relay-runtime-workflow.test.mjs` — PASS, two files, 38 pass
tuple enablement, release publication, defaults, and SignPath remain absent. Legacy remains the
sole production/default path and every tuple stays disabled.
### E-M5-HOST-EVIDENCE-COMPOSITION-AUDIT-001 — disconnected platform-specific evidence composition
- Date/owner: 2026-07-15, Codex implementation owner.
- Audit: complete reads of the canonical remote-platform type/detector and tests, all six accepted
platform-specific compatibility detectors and purpose suites, selector host-evidence union and
conservative legacy classifications, native workflow commands/oracle, and the current production-
caller graph. The detector functions remain imported only by purpose tests and no host composer
exists. The existing platform detector has no cancellation input and must remain unchanged here.
- Finding: add one purpose-named `ssh-relay-host-evidence-detection` module consuming an explicit
already-detected `RemoteHostPlatform`, SSH connection, and optional cancellation signal. First
require the platform object's relay-platform identity to agree with its canonical OS/architecture;
inconsistent input returns undefined without a probe. Then invoke only the accepted detector family:
Linux kernel/libc/libstdc++ concurrently (at most three channels), Darwin version/translation
concurrently (at most two), or the single Windows compatibility detector. Return a deeply frozen
`SshRelayHostEvidence` object with canonical OS/architecture.
- Conservative mapping: Linux and Windows are not subject to the reviewed Darwin/Rosetta process-
translation policy, so their composed `processTranslated` value is false. Linux preserves
`{ family: 'unknown' }` and missing optional fields for later selector classification. A missing
complete Windows segment yields Windows evidence with all optional compatibility fields absent so
selection remains legacy. Darwin preserves explicit true/false translation and optional version;
unknown translation returns no host evidence because inventing either boolean could select a native
artifact or misdiagnose a translated process. No selector/type change is needed.
- Failure/concurrency contract: pass the exact signal to every invoked detector. Pre-abort and
`AbortError` propagate; unexpected detector rejection propagates unchanged rather than becoming
fallback eligibility. Ordinary probe failures retain each accepted detector's existing unknown
return. All OS-specific calls start before composition awaits their results, bounding the composed
probe to the slowest existing 15-second detector instead of their sum. No unsupported detector,
platform re-probe, retry, network/download, Node, or filesystem operation is introduced.
- Required RED/green proof: canonical Linux/Darwin/Windows x64 and arm64 mapping; exact detector
family/call count; complete and missing/unknown fields; native/translated/unknown Darwin behavior;
inconsistent platform rejection with zero probes; deep freezing; all relevant calls starting
concurrently; exact signal forwarding; cancellation/unexpected rejection propagation; absence of
production imports; and both native workflow families requiring the purpose suite.
- Deliberately absent: platform-detection modification, full startup/official-manifest/cache
orchestration, live SSH/remote cells, semantic transfer capability, transfer/install, settings,
fallback classification/wiring, Electron, `ORCA_RELAY_PATH`, tuple enablement, publication,
defaults, and SignPath. Legacy remains the sole production/default path and every tuple stays
disabled.
- RED evidence, 2026-07-15:
- `/usr/bin/time -l pnpm exec vitest run --config config/vitest.config.ts --maxWorkers=1
src/main/ssh/ssh-relay-host-evidence-detection.test.ts` — EXPECTED FAIL, exit 1: purpose suite
could not import absent `ssh-relay-host-evidence-detection`; zero tests collected in 316 ms,
1.76 s wall time, 132,235,264-byte maximum RSS, 96,490,992-byte peak memory footprint.
- `/usr/bin/time -l pnpm exec vitest run --config config/vitest.config.ts --maxWorkers=1
config/scripts/ssh-relay-runtime-workflow.test.mjs` — EXPECTED FAIL, exit 1: 6 passed and the
native-family inclusion oracle failed because the purpose suite had only the POSIX workflow
occurrence (`source.split(...)` length 2 instead of 3); 409 ms suite duration, 1.84 s wall time,
131,743,744-byte maximum RSS, 95,851,800-byte peak memory footprint.
- Scope check before RED: `git diff --check` passed; protected
`ssh-remote-node-resolution.ts` and `.test.ts` diff remained empty. No implementation or product
caller existed.
### E-M5-HOST-EVIDENCE-COMPOSITION-LOCAL-001 — bounded immutable host evidence is locally green
- Date/owner/environment: 2026-07-15, Codex implementation owner; local macOS arm64, Node 26.0.0,
pnpm 10.24.0, atop pushed head `cfe56d0fd` plus this isolated uncommitted package. The expected
Node-24 engine warning means exact Node 24 remains a native CI gate.
- Implementation: the new 92-line `ssh-relay-host-evidence-detection.ts` accepts only an explicit
already-detected platform, connection, and optional signal. It rejects canonical OS/architecture
inconsistency before any probe; starts only the selected OS family's accepted bounded detectors;
runs Linux's three and Darwin's two probes concurrently; preserves Linux/Windows unknowns for
conservative legacy selection; refuses to invent Darwin translation; propagates cancellation and
unexpected rejection; and returns deeply frozen selector-shaped evidence. It has no production
import or caller.
- Purpose command: `/usr/bin/time -l pnpm exec vitest run --config config/vitest.config.ts
--maxWorkers=1 src/main/ssh/ssh-relay-host-evidence-detection.test.ts` — PASS, one file / 20 tests in
337 ms Vitest, 1.69 seconds wall, 132,431,872-byte maximum RSS, zero swaps. It covers all six
canonical tuples and exact family call counts, full/unknown/missing mapping, native/translated/
unknown Darwin behavior, inconsistent input with zero probes, deep freezing, concurrency, exact
signal forwarding, cancellation, and unexpected rejection.
- Workflow-oracle command: `/usr/bin/time -l pnpm exec vitest run --config config/vitest.config.ts
--maxWorkers=1 config/scripts/ssh-relay-runtime-workflow.test.mjs` — PASS, one file / seven tests in
384 ms Vitest, 1.73 seconds wall, 132,972,544-byte maximum RSS, zero swaps. The purpose suite now
occurs exactly once in both POSIX and PowerShell native contract commands.
- Post-format focused command: `/usr/bin/time -l pnpm exec vitest run --config
config/vitest.config.ts --maxWorkers=1` plus the composer, Windows compatibility, libc, kernel,
Darwin version/translation, libstdc++, selector, platform detection, and workflow-oracle suites —
PASS, 10 files / 193 passed / one declared native-Windows skip in 4.66 seconds Vitest, 7.18 seconds
wall, 138,493,952-byte maximum RSS, zero swaps.
- Broader relay command: `/usr/bin/time -l pnpm exec vitest run --config config/vitest.config.ts
--maxWorkers=1 --silent=true src/main/ssh/ssh-relay-*.test.ts` — PASS, 39 files passed / three
declared skipped files, 512 tests passed / four declared platform skips in 25.68 seconds Vitest,
27.42 seconds wall, 281,608,192-byte maximum RSS, zero swaps. Only the established stale-lock
diagnostic and local Node 26 `module.register()` deprecation warning appear.
- Release-script command: `/usr/bin/time -l pnpm exec vitest run --config config/vitest.config.ts
--maxWorkers=1 --silent=true config/scripts/ssh-relay-runtime-*.test.mjs` — PASS, 50 files / 280 tests
in 24.51 seconds Vitest, 27.61 seconds wall, 188,825,600-byte maximum RSS, zero swaps.
- Static gates: `/usr/bin/time -l pnpm typecheck` passes in 5.81 seconds wall with
1,262,075,904-byte maximum RSS. `/usr/bin/time -l pnpm lint` passes in 27.03 seconds wall with
2,034,597,888-byte maximum RSS; all switch-exhaustiveness, 41 reliability, 355-entry max-lines,
bundled-skill, 9,837 localization-reference, locale-parity, and zero-candidate localization gates
pass, with the existing 26 warnings only in untouched files. Explicit max-lines, targeted
`oxlint`, targeted `oxfmt --check`, `git diff --check`, no-production-import, and protected-
resolver empty-diff checks pass. The 92-line implementation and 229-line purpose suite add no
max-lines suppression or vague module.
- Boundary/residual gaps: this is local mock/composition proof, not live SSH or native detector
execution. Exact-head all-six Node 24 client proof is mandatory next. Platform detection,
manifest/cache startup composition, live SSH/remote cells, semantic transfer capability,
transfer/install, Electron/settings, fallback classification/wiring, `ORCA_RELAY_PATH`, tuple
enablement, publication, defaults, and SignPath remain absent. Legacy remains the sole production/
default path and every tuple stays disabled.
## Accepted Gaps
No product gap is accepted merely because it appears in this list. Each entry requires explicit
@@ -15984,10 +16085,10 @@ The project is not complete until every applicable item below is checked with ev
## Next Required Action
Audit only the smallest disconnected Windows compatibility-evidence boundary for the already-reviewed
OS build, OpenSSH for Windows, Windows PowerShell, and .NET Framework selector fields. Record the
exact acquisition/parsing/failure contract before adding purpose tests or implementation. Do not
compose full host evidence, provision production secrets or environments, add an Electron/startup
Commit and push only the locally green disconnected host-evidence composition package under
E-M5-HOST-EVIDENCE-COMPOSITION-LOCAL-001, then require exact-head all-six Node 24 native client proof
and adjacent PR checks before accepting it or auditing the next package. Do not modify platform
detection or selectors, provision production secrets or environments, add an Electron/startup
consumer, embed unreviewed keys or manifest bytes, add SSH transfer/install, mode wiring, fallback,
tuple enablement, release publication, or default behavior.
Keep Node upstream `.tar.xz` inputs, Windows ZIP, `ORCA_RELAY_PATH`, existing desktop required-assets
@@ -0,0 +1,229 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
import type { SshConnection } from './ssh-connection'
import { detectSshRelayHostEvidence } from './ssh-relay-host-evidence-detection'
import { getRemoteHostPlatform, type RemoteHostPlatform } from './ssh-remote-platform'
const detectorMocks = vi.hoisted(() => ({
kernel: vi.fn(),
libc: vi.fn(),
libstdcxx: vi.fn(),
darwinVersion: vi.fn(),
darwinTranslation: vi.fn(),
windowsCompatibility: vi.fn()
}))
vi.mock('./ssh-relay-linux-kernel-detection', () => ({
detectSshRelayLinuxKernelRelease: detectorMocks.kernel
}))
vi.mock('./ssh-relay-libc-detection', () => ({
detectSshRelayLinuxLibc: detectorMocks.libc
}))
vi.mock('./ssh-relay-linux-libstdcxx-detection', () => ({
detectSshRelayLinuxLibstdcxx: detectorMocks.libstdcxx
}))
vi.mock('./ssh-relay-darwin-version-detection', () => ({
detectSshRelayDarwinVersion: detectorMocks.darwinVersion
}))
vi.mock('./ssh-relay-darwin-translation-detection', () => ({
detectSshRelayDarwinProcessTranslation: detectorMocks.darwinTranslation
}))
vi.mock('./ssh-relay-windows-compatibility-detection', () => ({
detectSshRelayWindowsCompatibility: detectorMocks.windowsCompatibility
}))
const connection = {} as SshConnection
beforeEach(() => {
vi.resetAllMocks()
detectorMocks.kernel.mockResolvedValue('6.8.0-63-generic')
detectorMocks.libc.mockResolvedValue({ family: 'glibc', version: '2.39' })
detectorMocks.libstdcxx.mockResolvedValue({
libstdcxxVersion: '6.0.33',
glibcxxVersion: '3.4.33'
})
detectorMocks.darwinVersion.mockResolvedValue('15.5')
detectorMocks.darwinTranslation.mockResolvedValue(false)
detectorMocks.windowsCompatibility.mockResolvedValue({
build: 26100,
openSshVersion: '9.8p1',
powerShellVersion: '5.1',
dotNetFrameworkRelease: 533325
})
})
function allDetectorCallCounts(): number[] {
return Object.values(detectorMocks).map((mock) => mock.mock.calls.length)
}
describe('SSH relay host evidence detection', () => {
it.each([
['linux-x64', 'linux', 'x64', [1, 1, 1, 0, 0, 0]],
['linux-arm64', 'linux', 'arm64', [1, 1, 1, 0, 0, 0]],
['darwin-x64', 'darwin', 'x64', [0, 0, 0, 1, 1, 0]],
['darwin-arm64', 'darwin', 'arm64', [0, 0, 0, 1, 1, 0]],
['win32-x64', 'win32', 'x64', [0, 0, 0, 0, 0, 1]],
['win32-arm64', 'win32', 'arm64', [0, 0, 0, 0, 0, 1]]
] as const)(
'maps canonical %s and invokes only its detector family',
async (relayPlatform, os, architecture, expectedCalls) => {
const result = await detectSshRelayHostEvidence(
getRemoteHostPlatform(relayPlatform),
connection
)
expect(result).toMatchObject({ os, architecture, processTranslated: false })
expect(allDetectorCallCounts()).toEqual(expectedCalls)
}
)
it('composes complete Linux evidence and deeply freezes owned values', async () => {
const result = await detectSshRelayHostEvidence(getRemoteHostPlatform('linux-x64'), connection)
expect(result).toEqual({
os: 'linux',
architecture: 'x64',
processTranslated: false,
kernelVersion: '6.8.0-63-generic',
libc: { family: 'glibc', version: '2.39' },
libstdcxxVersion: '6.0.33',
glibcxxVersion: '3.4.33'
})
expect(Object.isFrozen(result)).toBe(true)
expect(result?.os === 'linux' && Object.isFrozen(result.libc)).toBe(true)
})
it('preserves unknown Linux libc and missing optional detector evidence', async () => {
detectorMocks.kernel.mockResolvedValue(undefined)
detectorMocks.libc.mockResolvedValue({ family: 'unknown' })
detectorMocks.libstdcxx.mockResolvedValue(undefined)
await expect(
detectSshRelayHostEvidence(getRemoteHostPlatform('linux-arm64'), connection)
).resolves.toEqual({
os: 'linux',
architecture: 'arm64',
processTranslated: false,
libc: { family: 'unknown' }
})
})
it.each([false, true])('preserves Darwin process translation %s', async (translated) => {
detectorMocks.darwinTranslation.mockResolvedValue(translated)
await expect(
detectSshRelayHostEvidence(getRemoteHostPlatform('darwin-arm64'), connection)
).resolves.toEqual({
os: 'darwin',
architecture: 'arm64',
processTranslated: translated,
version: '15.5'
})
})
it('keeps a known Darwin translation result when the version is unavailable', async () => {
detectorMocks.darwinVersion.mockResolvedValue(undefined)
await expect(
detectSshRelayHostEvidence(getRemoteHostPlatform('darwin-x64'), connection)
).resolves.toEqual({
os: 'darwin',
architecture: 'x64',
processTranslated: false
})
})
it('returns no Darwin evidence when process translation is unknown', async () => {
detectorMocks.darwinTranslation.mockResolvedValue(undefined)
await expect(
detectSshRelayHostEvidence(getRemoteHostPlatform('darwin-arm64'), connection)
).resolves.toBeUndefined()
})
it('preserves complete Windows compatibility evidence', async () => {
await expect(
detectSshRelayHostEvidence(getRemoteHostPlatform('win32-arm64'), connection)
).resolves.toEqual({
os: 'win32',
architecture: 'arm64',
processTranslated: false,
build: 26100,
openSshVersion: '9.8p1',
powerShellVersion: '5.1',
dotNetFrameworkRelease: 533325
})
})
it('returns conservative Windows evidence when compatibility detection is unavailable', async () => {
detectorMocks.windowsCompatibility.mockResolvedValue(undefined)
await expect(
detectSshRelayHostEvidence(getRemoteHostPlatform('win32-x64'), connection)
).resolves.toEqual({
os: 'win32',
architecture: 'x64',
processTranslated: false
})
})
it('rejects inconsistent platform identity without starting any detector', async () => {
const inconsistent = {
...getRemoteHostPlatform('linux-x64'),
os: 'win32'
} as RemoteHostPlatform
await expect(detectSshRelayHostEvidence(inconsistent, connection)).resolves.toBeUndefined()
expect(allDetectorCallCounts()).toEqual([0, 0, 0, 0, 0, 0])
})
it.each([
['linux-x64', ['kernel', 'libc', 'libstdcxx']],
['darwin-x64', ['darwinVersion', 'darwinTranslation']]
] as const)(
'starts all %s family probes before awaiting a result',
async (relayPlatform, names) => {
const settlements = names.map(() => Promise.withResolvers<unknown>())
names.forEach((name, index) =>
detectorMocks[name].mockReturnValue(settlements[index].promise)
)
const pending = detectSshRelayHostEvidence(getRemoteHostPlatform(relayPlatform), connection)
expect(names.map((name) => detectorMocks[name].mock.calls.length)).toEqual(names.map(() => 1))
settlements.forEach((settlement) => settlement.resolve(undefined))
await pending
}
)
it('forwards the exact signal to every selected detector', async () => {
const controller = new AbortController()
await detectSshRelayHostEvidence(getRemoteHostPlatform('linux-x64'), connection, {
signal: controller.signal
})
for (const mock of [detectorMocks.kernel, detectorMocks.libc, detectorMocks.libstdcxx]) {
expect(mock).toHaveBeenCalledWith(connection, { signal: controller.signal })
}
})
it('propagates cancellation without converting it to host evidence', async () => {
const abortError = new Error('cancel host evidence')
abortError.name = 'AbortError'
detectorMocks.windowsCompatibility.mockRejectedValue(abortError)
await expect(
detectSshRelayHostEvidence(getRemoteHostPlatform('win32-x64'), connection)
).rejects.toBe(abortError)
})
it('propagates unexpected detector rejection unchanged', async () => {
const failure = new Error('unexpected kernel detector failure')
detectorMocks.kernel.mockRejectedValue(failure)
await expect(
detectSshRelayHostEvidence(getRemoteHostPlatform('linux-x64'), connection)
).rejects.toBe(failure)
})
})
@@ -0,0 +1,92 @@
import type { SshConnection } from './ssh-connection'
import { detectSshRelayDarwinProcessTranslation } from './ssh-relay-darwin-translation-detection'
import { detectSshRelayDarwinVersion } from './ssh-relay-darwin-version-detection'
import { detectSshRelayLinuxLibc } from './ssh-relay-libc-detection'
import { detectSshRelayLinuxKernelRelease } from './ssh-relay-linux-kernel-detection'
import { detectSshRelayLinuxLibstdcxx } from './ssh-relay-linux-libstdcxx-detection'
import { detectSshRelayWindowsCompatibility } from './ssh-relay-windows-compatibility-detection'
import type { SshRelayHostEvidence } from './ssh-relay-artifact-selector'
import { getRemoteHostPlatform, type RemoteHostPlatform } from './ssh-remote-platform'
type DetectionOptions = { signal?: AbortSignal }
function isCanonicalPlatform(platform: RemoteHostPlatform): boolean {
const canonical = getRemoteHostPlatform(platform.relayPlatform)
return canonical.os === platform.os && canonical.arch === platform.arch
}
async function detectLinuxHostEvidence(
platform: RemoteHostPlatform,
connection: SshConnection,
options: DetectionOptions
): Promise<SshRelayHostEvidence> {
// Why: independent bounded probes run together so composition adds no serial bootstrap latency.
const [kernelVersion, libc, libstdcxx] = await Promise.all([
detectSshRelayLinuxKernelRelease(connection, options),
detectSshRelayLinuxLibc(connection, options),
detectSshRelayLinuxLibstdcxx(connection, options)
])
const frozenLibc = Object.freeze({ ...libc })
return Object.freeze({
os: 'linux',
architecture: platform.arch,
processTranslated: false,
...(kernelVersion === undefined ? {} : { kernelVersion }),
libc: frozenLibc,
...(libstdcxx === undefined ? {} : libstdcxx)
})
}
async function detectDarwinHostEvidence(
platform: RemoteHostPlatform,
connection: SshConnection,
options: DetectionOptions
): Promise<SshRelayHostEvidence | undefined> {
const [version, processTranslated] = await Promise.all([
detectSshRelayDarwinVersion(connection, options),
detectSshRelayDarwinProcessTranslation(connection, options)
])
// Why: guessing native or translated could select incompatible executable bytes.
if (processTranslated === undefined) {
return undefined
}
return Object.freeze({
os: 'darwin',
architecture: platform.arch,
processTranslated,
...(version === undefined ? {} : { version })
})
}
async function detectWindowsHostEvidence(
platform: RemoteHostPlatform,
connection: SshConnection,
options: DetectionOptions
): Promise<SshRelayHostEvidence> {
const compatibility = await detectSshRelayWindowsCompatibility(connection, options)
return Object.freeze({
os: 'win32',
architecture: platform.arch,
processTranslated: false,
...compatibility
})
}
export async function detectSshRelayHostEvidence(
platform: RemoteHostPlatform,
connection: SshConnection,
options: DetectionOptions = {}
): Promise<SshRelayHostEvidence | undefined> {
// Why: inconsistent caller evidence must not start probes or select a runtime for another tuple.
if (!isCanonicalPlatform(platform)) {
return undefined
}
if (platform.os === 'linux') {
return detectLinuxHostEvidence(platform, connection, options)
}
if (platform.os === 'darwin') {
return detectDarwinHostEvidence(platform, connection, options)
}
return detectWindowsHostEvidence(platform, connection, options)
}