Make cross-machine pairing recoverable when the host advertises loopback - #11083
Make cross-machine pairing recoverable when the host advertises loopback#11083puze8681 wants to merge 3 commits into
Conversation
A pairing offer embeds whatever address the host advertised. "Share this Orca server" defaults its address picker to 127.0.0.1, so a link minted for a LAN or Tailscale peer routinely carries a loopback endpoint that the receiving machine dials against itself. The credentials are fine — only the address is wrong — but the CLI had no way to correct it, leaving hand-editing the base64 offer as the only path. `environment add --endpoint <host>` redirects the offer while keeping the deviceToken and pinned public key the host issued. Resolution reuses resolveAdvertisedPairingEndpoint, so the flag accepts the same host, host:port, and ws(s):// forms as the address field that produced the link, inherits the port from the pairing code when omitted, and rejects wildcard bind addresses no client can dial. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The address picker under "Share this Orca server" defaults to 127.0.0.1, and its hint rendered as static muted copy that read the same whichever address was selected. Nothing distinguished the one selection that produces a link no other device can open, so pairing a second machine tended to fail only after the link had been copied and pasted. Make the hint track the selection: loopback gets warning emphasis, any other address states which host the peer has to reach. Generated links carry their own warning, keyed to the address the link was actually minted for rather than the current picker value, so moving the picker afterwards cannot make the warning lie. Loopback detection lives in shared/network so the picker and the link row agree; it covers 127.x, localhost, ::1, and ws(s):// forms. The warning uses typography and an icon rather than a new color, since a loopback address is a valid choice and the palette reserves color for selection, destructive, and git decorations. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (5)
🚧 Files skipped from review as they are similar to previous changes (5)
📝 WalkthroughWalkthroughThe CLI environment add command now accepts an optional endpoint override, validates it, and stores the resolved endpoint with the paired environment. CLI specifications, help text, compilation inputs, and tests were updated. Shared networking code adds loopback address detection. Runtime pairing generation tracks the address used for generated links and displays reachability or loopback warnings using new localized strings. 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
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.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/renderer/src/components/settings/RuntimePairingGeneratorForm.tsx (1)
192-202: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winRedundant warning when selection and generated address are both loopback.
When
selectedAddresshasn't changed since generating (the common path: pick "This computer", then Generate), bothselectionIsLoopback(lines 157-164) andgeneratedForLoopback(this block) are true, so the user sees two near-identical loopback warnings stacked in the same card. Consider suppressing this banner whenselectionIsLoopbackis already showing the same message.♻️ Proposed fix to avoid double messaging
- {generatedForLoopback && (webClientUrl || runtimePairingUrl) ? ( + {generatedForLoopback && !selectionIsLoopback && (webClientUrl || runtimePairingUrl) ? ( <p className="flex items-start gap-1.5 text-xs text-foreground"> <AlertTriangle className="mt-0.5 size-3.5 shrink-0" /> {translate( 'auto.components.settings.RuntimePairingUrlGenerator.generated-loopback-warning', 'These links were generated for {{address}}, so only this computer can open them. Pick a reachable address above and generate again to pair another device.', { address: generatedAddress ?? '' } )} </p> ) : null}
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 5e5e50c4-f6dc-453c-87cc-203463ff8d11
📒 Files selected for processing (17)
config/tsconfig.cli.jsonsrc/cli/handlers/environment.tssrc/cli/help.tssrc/cli/runtime/environments.test.tssrc/cli/runtime/environments.tssrc/cli/specs/environment.test.tssrc/cli/specs/environment.tssrc/renderer/src/components/settings/RuntimePairingGeneratorForm.tsxsrc/renderer/src/components/settings/RuntimePairingUrlGenerator.tsxsrc/renderer/src/i18n/locales/en.jsonsrc/renderer/src/i18n/locales/es.jsonsrc/renderer/src/i18n/locales/ja.jsonsrc/renderer/src/i18n/locales/ko.jsonsrc/renderer/src/i18n/locales/zh.jsonsrc/shared/network/server-share-address.test.tssrc/shared/network/server-share-address.tssrc/shared/runtime-environment-store.ts
resolveAdvertisedPairingEndpoint reads a blank advertised address as "none given" and defaults to 127.0.0.1. That fallback is right for `orca serve` with no --pairing-address, but on the override path it inverted the flag's purpose: `--endpoint " "` rewrote a reachable ws://10.0.0.5:6768 offer into loopback, silently causing the failure the flag exists to repair. Guard both layers. getOptionalStringFlag now measures the trimmed value, and addEnvironmentFromPairingCode tests endpointAddress for provided-ness rather than truthiness so an empty string is rejected as invalid instead of passing as "no override" — direct callers get the same protection as the CLI. Also drop the generated-link warning when the picker still sits on the address the link was minted for; the hint above the picker already says the same thing, and stacking both read as two separate problems. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Both CodeRabbit comments addressed in f16062f. 1. Blank 2. Redundant stacked warning ( One correction to my own test in this round: I first asserted that Re-verified: typecheck (node/cli/web) clean, 1438 tests passed / 170 files (+4), oxlint and oxfmt clean, localization and max-lines gates pass, and the four CLI cases re-run against the rebuilt binary — blank rejected, valid override applied, omitted flag still a no-op. |
Problem
Pairing a second machine goes through Settings → Runtime Environments → Share this Orca server. Its address picker defaults to
127.0.0.1, and the hint below it renders as static muted copy that reads identically whichever address is selected. Nothing marks the one selection that produces a link no other device can open.The result is a link whose credentials are correct but whose endpoint points at the receiving machine's own loopback. Recovering from it meant base64-decoding the offer, rewriting
endpoint, and re-encoding by hand —environment addaccepted only--nameand--pairing-code.Two commits: one makes the mistake recoverable, one makes it less likely.
environment add --endpoint <host>Redirects a pairing offer to a reachable address while keeping the
deviceTokenand pinned public key the host issued.Resolution reuses
resolveAdvertisedPairingEndpoint, so the flag accepts exactly the forms the "Share this Orca server" address field accepts, and rejects wildcard bind addresses no client can dial. No second address grammar was introduced.src/clireaching intosrc/mainfollows the existing pattern (handlers/agent-hooks.ts→main/agent-hooks/…); the module is added to the explicit allowlist inconfig/tsconfig.cli.json.Selection-aware loopback warning
isLoopbackShareAddress()lives inshared/networkso the picker and the link row agree:127.x,localhost,::1,[::1], andws(s)://forms.The warning uses typography and an icon rather than a new color. A loopback address is a valid choice, not an error, and STYLEGUIDE reserves color for selection, destructive, and git decorations — there is no warning token to reach for.
Verification
typecheck(node / cli / web) — cleanvitestacrosssrc/cli,src/shared/network,src/shared/runtime-environment-store,src/renderer/src/components/settings— 1434 passed / 170 filesoxlinton changed files — clean;oxfmt --check— cleanverify-localization-catalog+audit-localization-coverage— pass (2 new keys synced across all 5 locales)check-max-lines-ratchet— passORCA_USER_DATA_PATH(the four cases above)12 new tests: endpoint override (port inheritance,
host:port/ws(s)://forms, credential preservation, wildcard rejection, no-op when omitted), loopback detection, and command-spec coverage asserting--endpointis accepted onaddand rejected onlist/show/rm.Not run:
lint:react-doctor:changed. In my checkoutoxlint-plugin-react-doctorresolves to 0.2.10 whilepackage.jsonpins 0.9.1, soconfig/oxlint-react-doctor.jsonfails to parse — identically on files this PR does not touch. Unrelated to these changes, but flagging it since the pre-commit hook depends on it.🤖 Generated with Claude Code