Repository navigation
fix(ssh): a cancelled or revoked host's browser command stops on the desktop - #30630
Conversation
…desktop orcad now tells a cancel-capable desktop when the CLI gave up on a forwarded browser command, and a running host command on the desktop checks revocation before every side-effecting step (each helper CDP message and each direct input dispatch).
…lper on its proxy
…ck still lets go of the button
…what a revoked command left held
… go of the page; release held input with a lease, synced pointer state and the focus guard
…e they land, and a revoked helper is retired at once with its routes kept
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Priority: ➖ Normal Merge Risk: ⚪ Minimal · up to
|
ELI5
When an SSH host's
orcaCLI drives a browser page on the desktop, the user (or orcad) can cancel the command, or the desktop can stop sharing its browser with that host. Before this change, neither one actually stopped the page action. A click waiting in the desktop's queue still ran after it was cancelled, and a click already running still finished after access was revoked. Now a cancelled or revoked host's page actions stop where they are.What Changed
Before: cancelling an
orca browser clickon the host only made orcad stop waiting. The desktop never heard about it, so the queued click ran later anyway. Revoking a host's access was only checked when a command started. A command that was already running (its helper process, the CDP proxy, native key input) kept driving the page.After:
cancelevent for that request. The desktop aborts that request's signal, so a queued command never starts and a running one is revoked.Wire compatibility:
cancelis gated on a new client capability,browser.desktopBridge.cancel.v1. orcad sends it only to desktops that declare that capability, because an older desktop drops its whole bridge attachment on an event type it can't parse. A new desktop paired with an old orcad never receivescancel. It still gets revocation enforcement locally, and timeouts and detach still abort as before.Why
Cancellation has to reach the side that executes the action, and revocation has to be checked where actions are sent, not only when they are admitted. Checking at each command's call sites kept missing paths (helper steps through the proxy, deferred input, edit commands). Gating the few sinks every page action passes through covers all of them, including future commands. Releasing held input from the desktop after revocation was simpler than exempting releases at the gates. Exempting them would have let a revoked host keep sending mouseup and keyup events, and it broke frame routing.
ref-oss check: compared with how VS Code remote and Zed propagate cancellation over their remote protocols. The standard model is an optional per-request cancel message that the executing side honours (as in LSP's
$/cancelRequest), with new message types negotiated as capabilities so older peers never receive them. This PR uses the same design: an optional per-requestcancelevent, sent only to desktops that declarebrowser.desktopBridge.cancel.v1, with revocation enforced at the choke points where page actions are sent. The approach didn't change after the check. The later review rounds hardened the choke points: the scope leak, held-input cleanup, retiring the helper daemon, and deferred proxy input.Linked Issue
Fixes finding #6 of the SSH hardening Codex review 4 ("Canceled or revoked remote browser actions can still execute", introduced in #29384). That finding has no GitHub issue.
Visual Proof
N/A. No UI changes. The behaviour change is that a cancelled or revoked host's browser action no longer reaches the page.
Testing
New tests, each confirmed failing before its fix and passing after:
cancelemission, gated on the capabilityRan the full static-analysis job locally (all steps of "static analysis and typecheck", including the ratchets), plus the
src/main/browserand desktop-browser-bridge test folders single-worker.Verified in unit tests only. Not exercised live against a real SSH host.
I manually tested these changes locally
Automated tests added/updated, or explained why not below
Review
Agent skill upstream boundary
Notes
guest-direct-key-input.tsintoguest-key-event-plan.ts, unchanged, to stay under max-lines.Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)