fix(cli): validate --via-tab before connecting, like the request URL - #210
Conversation
`runFetch` checks the request URL against the profile up front, so a typo is exit 1 with guidance. `--via-tab` skipped that, so the same class of mistake reached the server guard instead and came back as exit 2 — a "bridge error" for what is plainly a usage error, after making the user wait on a connection to be told so. Both now fail the same way, before `listen()`: $ fpx get https://api.x.com/v1 -p x --via-tab 'not a url' # exit 1 $ fpx get https://api.x.com/v1 -p x --via-tab https://evil.example/ # exit 1 Also corrects the `viaTab` doc comment. It said API hosts "serve no HTML app", which is imprecise and does not explain why the extension's own advice for the failure ("refresh the page to inject the content script") is unactionable. The real mechanism, confirmed by inspecting such a tab: the host 404s at `/`, so Chrome renders its own document at `chrome-error://chromewebdata/`, and Chrome never injects content scripts into `chrome-error://` pages. `chrome.tabs.query` still reports the tab's URL as the requested https one — hence "1 URL match, none responded" — and no amount of reloading changes it. Closes #209 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012o2nXwu7tov6j7ciBEpigo
|
Claude finished @chrischall's task in 2m 10s —— View job Review complete
Posted a full summary review: #210 (comment) Summary: The fix correctly moves Verdict: pass |
ReviewReviewed the diff against
No correctness, convention, or test-coverage issues found. I was not able to execute Verdict: pass |
|
✅ Auto-review verdict: pass — PR correctly validates --via-tab against the profile's domains before connecting, reusing the existing assertUrlOnProfile helper; tests properly assert no bridge connection occurs on rejection, and the ws-server.ts change is a pure doc-comment correction with no logic changes. |
🤖 I have created a release *beep* *boop* --- ## [2.0.0](v1.11.0...v2.0.0) (2026-08-06) ### ⚠ BREAKING CHANGES * **protocol:** bind the ephemeral key into the ready signature ([#222](#222)) ### Features * **protocol:** add write_cookies, the one verb that can repair a rotated session ([#211](#211)) ([b2557c2](b2557c2)) * **protocol:** bind the ephemeral key into the ready signature ([#222](#222)) ([c13aeed](c13aeed)) * **server:** let a request name the tab that relays it ([#207](#207)) ([c5d3f4d](c5d3f4d)) * **server:** pin the extension's identity, and verify it on the peer path ([#213](#213)) ([0eeced7](0eeced7)) ### Bug Fixes * **cli:** let a real filesystem error be itself, not "no extension pin" ([#221](#221)) ([c87a864](c87a864)), closes [#220](#220) * **cli:** validate --via-tab before connecting, like the request URL ([#210](#210)) ([959fcc5](959fcc5)) * **extension:** reattach the write_cookies doc block, and name the writable cookies as writable ([#215](#215)) ([2730c4a](2730c4a)) * **extension:** use the guarded caps local for the cookie heading ([#217](#217)) ([f95c832](f95c832)) * **server:** release only our own extension claim, and stop guessing scoped names ([#219](#219)) ([3d90a64](3d90a64)), closes [#218](#218) * **server:** type no-tab rejections so they stop reading as version mismatches ([#205](#205)) ([dc30bd9](dc30bd9)) ### Refactor * **server:** drop the concatBytes imports the signature change orphaned ([#224](#224)) ([4985ba7](4985ba7)), closes [#223](#223) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Closes #209 — the nit auto-review raised on #207.
The inconsistency
runFetchvalidates the request URL against the profile before connecting, so a typo is exit 1 with guidance.--via-tabskipped that, so the same class of mistake travelled to the server guard and came back as exit 2 ("bridge error") — after making the user wait on a connection to be told their flag was malformed.Both now fail identically, before
listen():Verified by exit code, and the tests assert
listen()was never called — a typo shouldn't cost a bridge round-trip.The server-side guard stays. It's the real boundary for library callers; this just stops the CLI from routing a usage error through it.
Also: corrects the
viaTabdoc comment#207 said API hosts "serve no HTML app". That's imprecise, and it doesn't explain why the extension's own advice for the failure — "Refresh the page in your browser to inject the content script" — can't work.
The actual mechanism, confirmed by opening such a tab and inspecting it:
{"url":"chrome-error://chromewebdata/", "bodyStart":"This api.creditkarma.com page can't be found…"}The host 404s at
/, so Chrome renders its own document atchrome-error://chromewebdata/, and Chrome never injects content scripts intochrome-error://pages regardless of the<all_urls>match.chrome.tabs.querystill reports the tab's URL as the requested https one — which is exactly why the failure reads "1 URL match, none responded". No amount of reloading fixes it.Full reproduction and the missing control are in the correction comment on #207. Short version: my original evidence for that PR was weaker than it looked — one success with no matching failure run, and a motivation I'd asserted rather than tested. The conclusion held, but I should have run the control before opening it.
Tests
1157 pass (up from 1154). Three new CLI tests: malformed relay tab, off-domain relay tab, and the accepted case — the first two also asserting no connection attempt.
🤖 Generated with Claude Code
https://claude.ai/code/session_012o2nXwu7tov6j7ciBEpigo