Repository navigation
fix(runtime): refuse SSH hosts in project setup instead of acting locally - #10799
Conversation
…ally projectHostSetup.clone and .setupExistingFolder threaded executionHostId all the way down but never used it for routing: cloneRepo runs a local mkdir plus a local gitSpawn, and addRepo probes the path with existsSync/statSync. An `ssh:` host therefore cloned and validated on the *local* machine and then registered the result as living on the SSH host. It only failed loudly here because the remote path did not exist locally. With a plausible destination the clone succeeds and writes a setup record pointing at the wrong machine. Nothing legitimate sends `ssh:` to these RPCs: the renderer maps every ssh host (including ephemeral-VM `ssh:runtime-ssh-*`) to the desktop IPC path, which dispatches to addRemoteRepoFromPath/cloneRemoteRepo, and the IPC handler symmetrically rejects `runtime:`. Only the CLI can reach here with `ssh:`. Fail closed until the RPC learns to route through the SSH providers.
📝 WalkthroughWalkthroughThe runtime adds an SSH-host validation helper before project repository setup and cloning. SSH configurations now reject with an error directing setup through the Orca desktop app. CLI guidance documents this behavior. A runtime test covers both setup flows and verifies that no git operation occurs and no repository is recorded. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 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 |
The test asserted `gitSpawn` was never called and no repo was registered, but neither assertion could fail. `/home/brennan` is unwritable on macOS, so the pre-guard clone died at `mkdir` before reaching `gitSpawn`, and `/home/brennan/orca` failed `isGitRepo` before reaching `addRepo` — the exact side effects under test were unreachable either way. `rejects.toThrow` also aborted the test before those lines ran. Use a real temp destination and a real temp git repo, await both calls via `.catch`, and assert the side effects before the wording. With the guard disabled the test now fails on `gitSpawn` being called once with a real `git clone`, and on a repo registered stamped `executionHostId: 'ssh:openclaw'` — the silent local-clone-recorded-as-remote defect itself. `gitSpawn` is stubbed so a regression records the call instead of hitting the network. Also document the SSH restriction on `project setup-existing-folder`, which the guard now rejects. `setup-clone` already carried that note; its sibling did not.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/main/runtime/orca-runtime.test.ts (1)
7163-7166: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueMulti-line "Why" comments exceed the one-line guideline.
These explanatory comments span 2-3 lines each. As per coding guidelines,
**/*.{ts,tsx,js,jsx}: "Comments must be concise, limited to non-obvious information, and preferably one line; do not explain obvious code or walk through implementation details." Consider condensing to a single line each.Also applies to: 7170-7177, 7206-7208
Source: Coding guidelines
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 9031dd35-ae53-4ab1-9f98-f15ef704c632
📒 Files selected for processing (2)
src/cli/specs/project.tssrc/main/runtime/orca-runtime.test.ts
…ally (stablyai#10799) * fix(runtime): refuse SSH hosts in project setup instead of acting locally projectHostSetup.clone and .setupExistingFolder threaded executionHostId all the way down but never used it for routing: cloneRepo runs a local mkdir plus a local gitSpawn, and addRepo probes the path with existsSync/statSync. An `ssh:` host therefore cloned and validated on the *local* machine and then registered the result as living on the SSH host. It only failed loudly here because the remote path did not exist locally. With a plausible destination the clone succeeds and writes a setup record pointing at the wrong machine. Nothing legitimate sends `ssh:` to these RPCs: the renderer maps every ssh host (including ephemeral-VM `ssh:runtime-ssh-*`) to the desktop IPC path, which dispatches to addRemoteRepoFromPath/cloneRemoteRepo, and the IPC handler symmetrically rejects `runtime:`. Only the CLI can reach here with `ssh:`. Fail closed until the RPC learns to route through the SSH providers. * test(runtime): make the SSH guard test observe the corruption it names The test asserted `gitSpawn` was never called and no repo was registered, but neither assertion could fail. `/home/brennan` is unwritable on macOS, so the pre-guard clone died at `mkdir` before reaching `gitSpawn`, and `/home/brennan/orca` failed `isGitRepo` before reaching `addRepo` — the exact side effects under test were unreachable either way. `rejects.toThrow` also aborted the test before those lines ran. Use a real temp destination and a real temp git repo, await both calls via `.catch`, and assert the side effects before the wording. With the guard disabled the test now fails on `gitSpawn` being called once with a real `git clone`, and on a repo registered stamped `executionHostId: 'ssh:openclaw'` — the silent local-clone-recorded-as-remote defect itself. `gitSpawn` is stubbed so a regression records the call instead of hitting the network. Also document the SSH restriction on `project setup-existing-folder`, which the guard now rejects. `setup-clone` already carried that note; its sibling did not.
Before / After
Before — the loud failure. Setting up a project on an SSH host from the CLI fails with an error about a path on the local machine:
Nothing on
openclawwas ever contacted — a target that doesn't exist at all (--host ssh:this-target-does-not-exist-xyz) produces the identical error.Before — the quiet failure, which is the real problem. Pick a destination that happens to exist locally and the same command succeeds:
Orca reports the project as set up on
openclawand shows it there. But nothing was ever put onopenclaw— the checkout is on the local Mac, and every later operation on that project keeps running on the Mac while the UI attributes it to the SSH host. The user is never told. There is no error to search for and nothing in the output looks wrong unless you notice the local path sitting under a remote host.After. The command refuses immediately and says where to go instead:
Exit code 1. Nothing is cloned, nothing is registered, no misattributed project is left behind.
orca project setup-existing-folder --host ssh:...behaves the same way, and both commands now say so in--help.Unchanged. Setting up projects on SSH hosts from the Orca desktop app works exactly as before — that path always did the real remote work and is where users are pointed.
--host localand--host runtime:<env>are untouched.Problem
projectHostSetup.cloneandprojectHostSetup.setupExistingFolderaccept anexecutionHostIdand thread it all the way down, but never use it for routing:cloneRepoAfterPathLockruns an unconditional localmkdirand a localgitSpawn(['clone', ...]).executionHostIdis used in exactly one place —runtimeRepoMatchesExecutionHostat the existing-repo lookup — never to pick a transport.addRepovalidates withisGitRepo(path), which isexistsSync/statSyncon the local box.So
--host ssh:<target>clones and probes on the local machine, then registers the result as living on the SSH host.Found while setting up a real SSH host from the CLI:
A deliberately fake target (
--host ssh:this-target-does-not-exist-xyz) produces the identical error, confirming the SSH target is never resolved.That only failed loudly because
/home/brennandoesn't exist on macOS. With a plausible local destination the clone succeeds and writes aProjectHostSetuprecord claiming a local checkout lives on the remote — silent state corruption rather than an error.Why fail closed rather than route it
The two layers are complementary today, and the split is deliberate:
local,ssh:addLocalRepoFromPath/addRemoteRepoFromPath,cloneRemoteReporuntime:The renderer's
getProjectSetupRuntimeTargetmaps onlyruntime:to the runtime RPC; everyssh:variant — including ephemeral-VMssh:runtime-ssh-*— goes to IPC. The IPC handler symmetrically rejectsruntime:with "Runtime hosts must be set up through the runtime projectHostSetup.setupExistingFolder RPC."So no legitimate caller sends
ssh:here; only the CLI can, and it is always wrong. This PR makes that explicit instead of silently doing local work.Routing these RPCs through the SSH providers is a follow-up —
SshGitProvider.clone()andaddRemoteRepoFromPathalready exist and are what the desktop calls, so the capability is there; it just isn't wired to the RPC.Test
refuses SSH hosts instead of setting the project up on the local machineasserts both entry points reject, and — the part that matters — thatgitSpawnwas never called and no repo was registered. Verified it fails without the guard, with the sameENOENT ... mkdirseen in production.Validation
orca-runtime.test.ts: 880/880 passtypecheck:tsc:node: cleanoxlinton both files: cleancheck:max-lines-ratchet: OK, no new bypasses