Files
orca/src/main/ssh/ssh-relay-runtime-step-plan.ts
T
8afa1db50c feat(ssh): rung B glibc 2.17 compat runtime; gate remote vault on host node:sqlite (#24148)
* feat(ssh): wire rung B to the glibc 2.17 compat runtime; gate rung C vault on full node:sqlite

- COMPAT_RELAY_RUNTIMES lists linux-x64-glibc217; rung B plans the compat slot and compat
  pinned Node when glibc is below 2.28 or rung A refused with libc_floor/missing_lib.
- The relay version folds the compat runtime's executable hash; refusals are cached per runtime.
- The orcad template stages an optional linux-x64-glibc217 target (base package + compat
  node-pty slot + compat runtime marker); the verifier and materializer accept it.
- node-pty slot loader falls back to the compat slot when the default slot is missing or
  needs a newer glibc.
- Runtime store GC keeps the compat pin beside the default one on every relay connect.
- hasNodeSqliteReaderApi (DatabaseSync + backup) gates relay session search and the relay
  OpenCode reader, which now names the host Node version in its unavailable reason; the SSH
  vault reader installs the compat Node on old-glibc hosts and uploads nothing when no
  pinned Node can run.
- Rung D: a remembered noexec reports home_noexec and never advises installing Node.

* fix(ssh): re-prove a replayed noexec after rung D so allowing exec recovers the host

* fix(ssh): keep the rung B compat runtime pinned in the relay-connect store GC

* test(ssh): mock deployment-target facts in the Windows OpenCode runtime tests

* ci(ssh): build the glibc 2.17 compat slot for the hostile-host matrix; CentOS 7 lands on rung B

---------

Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-01 05:32:05 -07:00

124 lines
3.8 KiB
TypeScript

/** Turns one ladder step into a relay plan, or a classified refusal the ladder steps past. */
import type { SshConnection } from './ssh-connection'
import { planHostNodeAddonRelay, type PrebuiltRelayPlan } from './ssh-relay-host-node-addons'
import {
PinnedRelayFallbackError,
planPinnedNodeRelay,
resolvePinnedRelayTargetFacts
} from './ssh-relay-pinned-node'
import { rungBCompatRuntimeFor, type RelayRuntimeStep } from './ssh-relay-runtime-ladder'
import type { RelayRuntimeLadderRun } from './ssh-relay-runtime-resolution'
import type { RemoteHostPlatform } from './ssh-remote-platform'
import type { OrcadDeploymentTargetFacts } from './orcad-deployment-target'
type StepPlanOptions = {
conn: SshConnection
host: RemoteHostPlatform
baseVersion: string
step: RelayRuntimeStep
run: RelayRuntimeLadderRun
signal?: AbortSignal
}
/** Resolved once per ladder pass; every rung above legacy keys on the same answer. */
async function ladderTargetFacts(options: StepPlanOptions): Promise<OrcadDeploymentTargetFacts> {
const { run } = options
if (run.facts) {
return run.facts
}
const facts = await resolvePinnedRelayTargetFacts(options)
if ('kind' in facts) {
throw new PinnedRelayFallbackError(
facts.fallbackReason ?? 'target_unresolved',
'the host libc answer was not recognised'
)
}
run.facts = facts
return facts
}
/** Undefined for the host-npm path; throws `PinnedRelayFallbackError` when a rung cannot run. */
export async function planRelayRuntimeStep(
options: StepPlanOptions
): Promise<PrebuiltRelayPlan | undefined> {
const { conn, host, baseVersion, step, run, signal } = options
run.host = host
switch (step) {
case 'legacy':
return undefined
case 'A': {
const facts = await ladderTargetFacts(options)
const plan = await planPinnedNodeRelay({
conn,
host,
baseVersion,
targetId: run.targetId,
facts,
persistedRefusal: (known) => run.persistedPinnedRefusal(known),
signal
})
if (plan.kind === 'host-node') {
throw new PinnedRelayFallbackError(
plan.fallbackReason ?? 'artifacts_unavailable',
'Orca-managed Node cannot run here',
plan.remembered === true
)
}
return plan
}
case 'B': {
if (host.os === 'win32') {
throw new PinnedRelayFallbackError(
'runtime_unavailable',
'no compat runtime serves Windows'
)
}
const facts = await ladderTargetFacts(options)
// run.lastRefusal is rung A's: B is entered only by stepping down from A.
const compat = rungBCompatRuntimeFor(facts, run.lastRefusal)
if (!compat) {
throw new PinnedRelayFallbackError(
'runtime_unavailable',
'no compat runtime serves this host'
)
}
const plan = await planPinnedNodeRelay({
conn,
host,
baseVersion,
targetId: run.targetId,
facts,
compat: { target: compat.runtimeTarget, glibcFloor: compat.glibcFloor },
signal
})
if (plan.kind === 'host-node') {
throw new PinnedRelayFallbackError(
plan.fallbackReason ?? 'artifacts_unavailable',
`compat runtime ${compat.id} cannot run here`,
plan.remembered === true
)
}
return plan
}
case 'C': {
if (host.os === 'win32') {
throw new PinnedRelayFallbackError(
'windows_host_unsupported',
'Windows hosts have no host-Node addon relay'
)
}
const plan = await planHostNodeAddonRelay({
conn,
host,
facts: await ladderTargetFacts(options),
baseVersion,
signal
})
run.hostNode = plan.hostNode.version
return plan
}
case 'D':
throw new Error('Rung D has no relay to plan')
}
}