Repository navigation
feat(ssh): remote orcad primitives on the pinned Node runtime (#16741 T6-1) - #24419
Conversation
…T6-1) - orcad-remote-runtime-control: the one launch-and-poll-readiness loop that deployOrcad and rollbackOrcad now share, plus exec and recovery helpers. - orcad-remote-record-file: bounded, marker-delimited reads and atomic writes for host records. A read that returns no verifiable answer rejects instead of reading as "no record". - The activation record store reads through it (a lost read no longer becomes an empty record) and writeOrcadActivationRecord refuses to replace a record this client cannot read, such as a newer schema; deploy and rollback use it. - orcad-active-readiness: prove a recorded-active or relaunched slot against the activation gate, reporting exited / unverifiable / rejected. - orcad-remote-build-hash and orcad-remote-context (host, home, server target via orcad-deployment-target, activation record; POSIX-only). - Readiness reads are capped at 256 KiB, and a finished invalid JSON line is malformed rather than pending forever. Inert: nothing in the app calls managed orcad deploy yet. Ported from #16741 (a68b6f3) onto main's pinned-Node deploy core; the branch's Bun runtime, slot eligibility, target detection and bundle installation are superseded by main's orcad-remote-runtime, orcad-deployment-target and orcad-remote-install.
|
| orcadActivationPath(options.host, options.remoteHome), | ||
| ORCAD_ACTIVATION_RECORD_MAX_BYTES | ||
| ) | ||
| return read.state === 'absent' ? read : parseOrcadActivationRecord(read.raw) |
There was a problem hiding this comment.
Empty record appears absent When
orcad-active.json exists but is empty, the file read reports it as present, but parsing its contents turns it back into an absent record. Deploy can then proceed as though nothing is active, even if an installation is live, and lose its rollback target. An existing empty file needs to be treated as unreadable.
Knowledge Base Used: Remote connectivity and execution
| const existing = await readActivationRecordState(options) | ||
| if (existing.state === 'unreadable') { | ||
| throw new Error(`Refusing to overwrite this host's orcad activation record: ${existing.reason}`) | ||
| } | ||
| await writeAtomicOrcadRemoteRecord( |
There was a problem hiding this comment.
Concurrent writes replace records The schema check and the final rename happen in separate SSH commands. If another client writes a newer-schema record between them,
mv -f still replaces it. Two deployments can also overwrite each other's active version and rollback target using records read earlier. The check needs to remain valid through publication.
Knowledge Base Used: Remote connectivity and execution
| serializeOrcadActivationRecord(withRolledBackVersion(options.record, now())), | ||
| { signal: options.signal } | ||
| ) | ||
| await writeOrcadActivationRecord(options, withRolledBackVersion(options.record, now())) |
There was a problem hiding this comment.
Rollback can finish unrecorded This write now rereads the activation record after rollback has stopped the incumbent, restored its data, and launched the older build. If that read fails or finds an unreadable record, the function throws without recording the rollback or returning recovery guidance. The old build can be serving while the record still names the stopped build.
Knowledge Base Used: Remote connectivity and execution
| const readiness = parsed.state === 'ready' ? parsed.readiness : null | ||
| const verdict = evaluateOrcadActivation(readiness, expectation) | ||
| if (verdict.decision === 'reject') { | ||
| throw new OrcadActiveReadinessError( | ||
| 'rejected', | ||
| `${label} failed its readiness check: ${verdict.reason}` |
There was a problem hiding this comment.
Missing readiness appears rejected When the process is live but its readiness file has not answered, parsing returns
pending. Passing that as null to the activation gate labels the result rejected rather than unverifiable. This makes the new verdict less useful for recovery decisions because unavailable evidence looks like a failed build check.
Knowledge Base Used: Remote connectivity and execution
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. 🧰 Additional context used📚 Code guidelines (1)No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (12)
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 0 remain after this review. 📝 WalkthroughWalkthroughThe changes add bounded remote-record reads and atomic writes, remote context resolution, build-hash verification, and active readiness checks. Deployment and rollback now use shared launch-and-readiness handling and the activation-record store. Readiness reads have a size limit, and parsing distinguishes incomplete final output from completed invalid output. Priority: ➖ Normal Merge Risk: ⚪ Minimal · up to The change adds guarded atomic activation-record writes and bounded readiness handling without an established merge-blocking regression. It is mergeable subject to normal checks. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to The changes strengthen record handling and preserve existing launch and readiness controls. Current exposure is limited because managed deployment is not called by the application. One recovery gap remains: the new final record-read check can reject after the service has already changed, leaving the recorded and running versions inconsistent. Retained concerns
Security review detailsSecurity Blast Radius
Trust Boundaries and Controls
Resilience and Maintainability Implications
Hardening Proposals
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
ℹ️ No critical issues — one coverage gap and a minor cleanup note below.
Reviewed changes
- Shared launch/readiness loop — new
orcad-remote-runtime-control.tsextracts the one "launch a slot, then poll its readiness file" loop; deploy and rollback now delegate tolaunchOrcadAndAwaitReadiness, and the duplicated loops/READINESS_POLL_MScopies are gone. - Bounded marker-based record IO — new
orcad-remote-record-file.tsreads small host records behind explicitabsent/presentmarkers (withwc -csize cap andexit 65on not-regular/oversize), and writes them atomically via a unique partial +mv -f. - Activation store hardening — a failed record read now rejects instead of
.catch(() => '')reading it as absent;writeOrcadActivationRecordre-reads and refuses to overwrite a record the client cannot parse (e.g. a newer schema). Deploy and rollback write through it. - Readiness cap + malformed detection —
readOrcadReadinessCommandcaps reads at 256 KiB viahead -c; a finished invalid JSON line is nowmalformedimmediately instead of stayingpendinguntil timeout. - New primitives —
orcad-active-readiness.ts,orcad-remote-build-hash.ts,orcad-remote-context.ts(all inert; no production caller yet).
ℹ️ The new record shell commands have no real-shell coverage
readBoundedOrcadRemoteRecord and writeAtomicOrcadRemoteRecord build non-trivial shell strings — a marker/exit 65 read and a umask 077; printf %s … > partial && mv -f … write — but they are only exercised through a mocked execCommand. This repo maintains orcad-remote-shell-commands.integration.test.ts for exactly this reason: its header states command-text tests "stays green while the shell it produces does not work — a quoting slip, a case pattern that never matches." I ran both generated strings against a real /bin/sh (absent / present / oversize / directory / empty, plus quote-and-backslash content) and they behave correctly on Linux, so this is a guard against future regressions rather than a current bug.
Technical details
# Add real-shell coverage for the record read/write commands
## Affected sites
- `src/main/ssh/orcad-remote-record-file.ts:20` — `readBoundedOrcadRemoteRecord` marker/`wc -c`/`exit 65` shell string is never run by a real shell.
- `src/main/ssh/orcad-remote-record-file.ts:46` — `writeAtomicOrcadRemoteRecord` `umask 077; printf %s … > partial && mv -f` command is never run by a real shell.
- `src/main/ssh/orcad-remote-shell-commands.integration.test.ts` — the existing suite that runs generated POSIX commands through `/bin/sh`; does not import the record-file module.
## Required outcome
- The read command distinguishes a missing record (`absent`, exit 0) from a present one (`present` + raw bytes), and exits nonzero (never `absent`) for an oversize/not-regular/dangling-symlink target.
- The write command lands the exact byte content and is atomic (partial does not remain at the final path).
## Suggested approach (optional)
- Extend `orcad-remote-shell-commands.integration.test.ts` to `sh(...)` both command builders against a temp dir, covering: absent, present, oversize, directory, dangling symlink, and content containing a single quote/backslash/newline.ℹ️ Nitpicks
writeAtomicOrcadRemoteRecordkeeps its.partial.<pid>.<uuid>file on every timeout/abort (isUnconfirmedSshCommandTerminationis also true for the 30s timeout), and nothing sweeps~/.orca-remote/partials. Repeated aborted deploys accumulate uniquely named orphans; a periodic sweep (or reusing a stable partial name per target) would bound it.withoutAbortSignalinorcad-remote-runtime-control.ts:34is exported but has no caller or test in this PR — fine as an inert building block, just flagging that it is currently unreferenced.
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏
* Revert "feat(orcad): source-side dormant export of a relay-hosted SSH target (#16741 T6-8) (#24519)" This reverts commit 783101b. * Revert "feat(ssh): update, roll back, recover and stop a managed orcad server (#16741 T6-5 follow-up) (#24463)" This reverts commit 38c2d1d. * Revert "feat(ssh): deploy and pair an empty managed orcad server over SSH (#16741 T6-5) (#24453)" This reverts commit 8b76683. * Revert "fix(ssh): orcad GC honors the activation journal; readiness requires proven daemon coverage (#16741 T6 follow-up) (#24451)" This reverts commit d3f8c50. * Revert "feat(ssh): remote orcad stop by request file and journaled decommission (#16741 T6-4) (#24449)" This reverts commit 43d9b43. * Revert "feat(orcad): supervisable server: stop requests, managed stop receipts and a lifetime that keeps its lock on failed teardown (#16741 T6-3) (#24433)" This reverts commit b093d3a. * Revert "feat(ssh): crash-safe orcad activation, rollback and recovery (#16741 T6-2) (#24423)" This reverts commit 1a9ac0e. * Revert "feat(runtime): SSH access links for paired servers in a downgrade-safe sidecar (#16741 T5-1+T5-2) (#24420)" This reverts commit 99db2bf. * Revert "feat(relay): capability-gated owner reset with a durable preparation journal (#16741 T3 R1) (#24418)" This reverts commit 34a582b. * Revert "feat(ssh): track connection-manager drains, test probes and provider continuations (#16741 T2 P3+P8a) (#24407)" This reverts commit d53063d. * Revert "feat(daemon): idle retirement, session census and recovery-only provider (#16741 T2 P4b) (#24409)" This reverts commit ff212db. * Revert "feat(ssh): add pty.resumeClient and split SSH PTY process listing (#16741 T2 P5+P6) (#24414)" This reverts commit 92cb717. * Revert "feat(relay): await owned watcher and agent children on shutdown (#16741 T2 P1) (#24400)" This reverts commit 6b36e4f. * Revert "feat(session): retry failed renderer session writes and verify local folder PTYs (#16741 T2 P9) (#24406)" This reverts commit d23ecef. * Revert "feat(ssh): remote orcad primitives on the pinned Node runtime (#16741 T6-1) (#24419)" This reverts commit dd87ae5. * Revert "fix(runtime): fence runtime-environment subscriptions and status probes by identity (#16741 T5-3) (#24421)" This reverts commit ece9e4d. * Revert "feat(orcad): migration manifest and dormant-state contracts (#16741 T6-7) (#24422)" This reverts commit 3fbdaba. * Revert "feat(ssh): wire SshConnection through the work and transport close ledgers (#16741 T2 P2) (#24401)" This reverts commit 4e8edc8. * Revert "feat(profiles): carry markdown frontmatter visibility in project transfers (#16741 T2 P7) (#24405)" This reverts commit 60c9326. * Revert "fix(runtime): project the PTY incarnation onto mobile session tabs (#24413)" This reverts commit 99e0303. * Revert "feat(daemon): tag daemon stream data with the PTY incarnation id (#16741 T2 P4a) (#24402)" This reverts commit 817af76. * Revert "feat(ssh): port the SSH connection work ledger and transport close ledger (#16741 T2) (#24210)" This reverts commit c991893. * Revert "feat(relay): fence and drain file and git response streams on shutdown (#24185)" This reverts commit dc08ffe. * Revert "refactor(runtime-rpc): extract the Node WebSocket lifecycle; opt-in pinned port (#24186)" This reverts commit a789233. * Revert "feat(relay): route relay handlers through work admission; producer publication drain (#24181)" This reverts commit 0b812bd. * Revert "feat(relay): land the #16741 T1 seam (work drain, publication drain, release gate) (#24156)" This reverts commit 3aa2d3a. --------- Co-authored-by: m4air <m4air@Mac.localdomain>

ELI5
Orca can, in principle, install its server (orcad) on an SSH host and switch to it safely. The code for that already exists on main, but nothing in the app calls it yet. This PR adds the small building blocks the next steps need, and fixes a dangerous edge case in the existing code: a failed read of the host's "which version is active" record was treated as "no record". That could let a later deploy run over a live install.
This is slice T6-1 of the T6 exit-gate track (porting #16741: one remote server for SSH and paired transports). It is inert: nothing in the app calls managed orcad deploy yet.
What Changed
orcad-remote-runtime-control.ts(new): the one "launch a slot, then poll its readiness file" loop, plusexecOrcadRemoteandwithoutAbortSignal.deployOrcadandrollbackOrcadeach had their own copy of the loop; both now use this one.orcad-remote-record-file.ts(new): reads and writes of small records on the host.writeOrcadActivationRecordrefuses to replace a record this client can't read. A newer schema, for example, stays untouched. Deploy and rollback write through it.orcad-active-readiness.ts(new): proves that a recorded-active or relaunched slot is the expected build, using the existing activation gate (build hash and version). Failures say which of three it was:exited(the process is gone),unverifiable(the host couldn't say) orrejected(it answered with the wrong build).orcad-remote-build-hash.tsandorcad-remote-context.ts(new):orcad-deployment-target) and the activation record.assertPosixOrcadHoststays.malformedstraight away. Before, it stayedpendinguntil the deploy timed out. A half-written last line is stillpending.Why
.catch(() => ''), which turned a lost read into an empty record. An empty record means "nothing is active", which admits a fresh deploy over a live install and loses its rollback target. That's the "loss of contact is never death" rule fromdocs/reference/ssh-execution-boundary.md.orcad-remote-target-detection→ main'sorcad-deployment-target;orcad-slot-runtime-eligibility(Bun versus legacy Node) → main'sorcad-remote-runtimeslot marker;orcad-bundle-installation→ main'sorcad-remote-install.orcad-remote-host-supportdelta. It would removeOrcadRemoteLaunchUnsupportedErrorand therefuseUnverifiableliveness probe, which is a regression.orcad-remote-process-controldelta, which switches stop from SIGTERM to a stop-request file. It only works once orcad itself consumes that file, which is T6-3. Shipping it before then would mean stops never complete on current builds.ssh-upload-session-lifetime. It comes with feat(ssh): wire SshConnection through the work and transport close ledgers (#16741 T2 P2) #24401, and nothing here needs it.coverage: 'pty-spawn'from feat(daemon): idle retirement, session census and recovery-only provider (#16741 T2 P4b) #24409 is a follow-up once that merges.Linked Issue
Part of the Node runtime plan (Phase 3), T6 exit-gate track, porting #16741.
Visual Proof
N/A. There's no UI change, and this code has no production caller yet.
Testing
New
orcad-remote-primitives.test.ts:DEAD,UNKNOWNor empty maps to exited or unverifiable;Updated: the deploy and rollback test hosts, for the marker-delimited record read and the
head -creadiness read. Record writes are now checked throughwriteAtomicOrcadRemoteRecord.Regression: every
src/main/ssh/orcad-*,src/main/ssh/ssh-*andsrc/main/orcad/*test. 216 files: 214 passed, 2 skipped. 2900 tests passed, 22 skipped.Static checks:
node config/scripts/check-changed-code-quality.mjs origin/mainis clean.I manually tested these changes locally
Automated tests added/updated, or explained why not below
Agent skill upstream boundary
docs/reference/agent-skill-sharing-upstream-boundary.mdand copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.