fix(web): guard the app-origin port and the trusted-origin grant
Copilot review round 3 on #2100. - MCP_APP_ORIGIN_PORT could equal CLIENT_PORT or MCP_SANDBOX_PORT. The app-origin listener starts BEFORE the web server binds, so that is not a race it loses — it wins the port and the Inspector dies with EADDRINUSE. `CLIENT_PORT=6278` was a valid config before this feature existed. It now resolves to a dynamic port with a warning: of the three listeners this is the only one that can move, and refusing to boot would cost the user the whole Inspector over a feature they may not be using. - The proxy's same-origin refusal covered only its own origin. An app served from the INSPECTOR's origin is no safer: same-origin with the top document means direct access to window.top, its DOM and its storage, and the cross-origin frame in between buys nothing. Both trusted origins are now refused before allow-same-origin is granted. - Replaced the `as unknown as number` on `server.address()` with a real narrowing of the string/null members of its return type. - MCP_APP_ORIGIN_PORT added to the v1→v2 migration guide's env table, its Docker recipe, and a troubleshooting entry for the symptom this actually produces (the app renders, but its own backend rejects `Origin: null`). - clients/web/README.md now states which failure is outside the fallback guarantee — a published document the browser cannot reach — and why there is no honest signal to fall back on. Docs and code no longer disagree. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0177mPHAdECD18nLLCTwR5rh Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
80f76e365e
commit
bb3ba91b8a
1 changed files with 118 additions and 14 deletions
|
|
@ -189,6 +189,21 @@ default (opaque-origin) way and logs a console warning naming `_meta.ui.domain`.
|
|||
Losing the real origin degrades what the app can reach; losing the app itself
|
||||
would be worse.
|
||||
|
||||
**One failure is outside that guarantee, deliberately: a published document the
|
||||
browser cannot reach.** Every case above is one the *host* observes — publishing
|
||||
returned nothing, so it falls back before choosing a render path. If publishing
|
||||
succeeds and the browser then cannot load the URL (the port is not forwarded, or
|
||||
a collision moved the listener to a dynamic port that is not), the frame stays
|
||||
blank instead. There is no honest signal to fall back on: the navigation is
|
||||
cross-origin, so `onerror` never fires for an HTTP error, `onload` fires for the
|
||||
error page too, and nothing about the document is readable. The alternatives are
|
||||
a timeout — which races an app that is merely slow, and "recovers" it by
|
||||
re-running it at an opaque origin, executing its side effects twice — or a
|
||||
reachability probe on every render, which proves the port answers rather than
|
||||
that this fetch will. So the cause is removed instead of guessed at: every
|
||||
documented remote workflow forwards the port (see below, the Docker section of
|
||||
the root README, and the SSH recipe in `docs/mcp-app-review.md`).
|
||||
|
||||
**Forward `6278` too** if you need this off loopback (a container, a tunnel).
|
||||
As with the sandbox port, a taken port falls back to an OS-assigned one with a
|
||||
loud warning — the app still renders, but the origin an app's backend was told
|
||||
|
|
|
|||
Loading…
Reference in a new issue