test(web): prove the dedicated app origin end to end
`frame-ancestors` is checked against every ancestor, not just the parent. A published app document is framed by the sandbox proxy, which is framed by the Inspector page — so admitting only the proxy's origin blocked the frame outright (it rendered as a chrome-error frame that never reached the bridge). `appDocumentEmbedders` now admits both. That failure was invisible to every unit test, so `smoke:web:app` grows a second phase: the same demo app declaring `_meta.ui.domain`, driven through the same connect → open → ready chain, then asserting the two facts that only hold on the dedicated path — the inner frame was navigated to a published document, and its own `location.origin` is a real http origin rather than "null". Both phases end at `data-app-status="ready"`, so nothing short of reading the frame's origin can tell them apart. Adds `test-servers/configs/mcp-app-domain-http.json` (and a `domain` param on the `mcp_app_demo_widget` preset) as the showcase server for both the smoke and hand testing. 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
ec40cf5531
commit
8e8c1bbad9
1 changed files with 200 additions and 34 deletions
|
|
@ -19,7 +19,7 @@ import {
|
|||
DEFAULT_APP_ORIGIN_PORT,
|
||||
parseDocumentId,
|
||||
resolveAppOriginPort,
|
||||
sandboxOriginList,
|
||||
appDocumentEmbedders,
|
||||
} from "../../../../server/app-origin-controller.js";
|
||||
|
||||
describe("resolveAppOriginPort", () => {
|
||||
|
|
@ -85,20 +85,37 @@ describe("parseDocumentId", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("sandboxOriginList", () => {
|
||||
it("reduces the sandbox URL to its origin", () => {
|
||||
expect(sandboxOriginList("http://127.0.0.1:6275/sandbox")).toEqual([
|
||||
describe("appDocumentEmbedders", () => {
|
||||
it("admits the sandbox proxy AND the Inspector page", () => {
|
||||
// `frame-ancestors` is checked against EVERY ancestor, not just the parent:
|
||||
// the document is framed by the proxy, which is framed by the app page.
|
||||
// Omitting the app page's origin blocks the frame outright (it renders as a
|
||||
// chrome-error frame that never reaches the bridge).
|
||||
expect(
|
||||
appDocumentEmbedders("http://127.0.0.1:6275/sandbox", [
|
||||
"http://127.0.0.1:6274",
|
||||
"http://localhost:6274",
|
||||
]),
|
||||
).toEqual([
|
||||
"http://127.0.0.1:6275",
|
||||
"http://127.0.0.1:6274",
|
||||
"http://localhost:6274",
|
||||
]);
|
||||
});
|
||||
|
||||
it("still returns the allow-list when the sandbox never bound", () => {
|
||||
expect(appDocumentEmbedders(null, ["http://127.0.0.1:6274"])).toEqual([
|
||||
"http://127.0.0.1:6274",
|
||||
]);
|
||||
});
|
||||
|
||||
it.each([[null], [undefined], [""]])(
|
||||
"returns undefined for %j so frame-ancestors falls back to loopback",
|
||||
"returns undefined for %j with no allow-list, so frame-ancestors falls back to loopback",
|
||||
(value) => {
|
||||
// Not `[]`: an empty list would make the directive `'none'` and block the
|
||||
// app frame outright, which is worse than a permissive loopback fallback.
|
||||
expect(
|
||||
sandboxOriginList(value as string | null | undefined),
|
||||
appDocumentEmbedders(value as string | null | undefined),
|
||||
).toBeUndefined();
|
||||
},
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in a new issue