47 lines
3.6 KiB
TypeScript
47 lines
3.6 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { CachedVerifiedSurfaceDocumentResolver, parseBridgeMessage, parseReadyMessage, productionSurfaceDocument, surfaceDocument } from "@/runtime/surfaces/isolated-surface-host";
|
|
import { VerifiedSurfaceBundleCache, type SurfaceBundleDigest, type SurfaceManifestSignatureVerifier } from "@/runtime/surfaces/surface-bundle-cache";
|
|
|
|
describe("isolated Surface bridge contract", () => {
|
|
it("accepts only the exact minimal ready message", () => {
|
|
expect(parseReadyMessage({ v: 1, type: "lineup.surface.v1.ready", instance_id: "task:001" })).toEqual({ v: 1, type: "lineup.surface.v1.ready", instance_id: "task:001" });
|
|
expect(parseReadyMessage({ v: 1, type: "lineup.surface.v1.ready", instance_id: "task:001", state: {} })).toBeUndefined();
|
|
expect(parseReadyMessage({ v: 1, type: "lineup.surface.v1.event", instance_id: "task:001" })).toBeUndefined();
|
|
expect(parseReadyMessage({ v: 1, type: "lineup.surface.v1.ready", instance_id: "<script>" })).toBeUndefined();
|
|
});
|
|
|
|
it("builds a host-local opaque-sandbox document with a default-deny CSP", () => {
|
|
const document = surfaceDocument("task:001");
|
|
expect(document).toContain("default-src 'none'");
|
|
expect(document).toContain("connect-src 'none'");
|
|
expect(document).toContain("base-uri 'none'");
|
|
expect(document).toContain("lineup.surface.v1.ready");
|
|
expect(document).not.toContain("https://");
|
|
});
|
|
|
|
it("accepts the SDK camelCase reportProgress bridge method", () => {
|
|
expect(parseBridgeMessage({ v: 1, type: "lineup.miniapp.v1.request", instance_id: "task:001", request_id: "req_1", method: "tools.reportProgress", payload: { call_id: "call-1", progress: { percent: 10 } } })).toMatchObject({ method: "tools.reportProgress" });
|
|
});
|
|
|
|
it("wraps only an exact verified production bundle in the host default-deny CSP", async () => {
|
|
// Digest mismatch behavior belongs to the cache suite. This test isolates
|
|
// the resolver's exact-version lookup and Host-owned CSP wrapping.
|
|
const digest: SurfaceBundleDigest = { async sha256() { return "b".repeat(64); } };
|
|
const signatures: SurfaceManifestSignatureVerifier = { async verify() { return true; } };
|
|
const cache = new VerifiedSurfaceBundleCache(signatures, digest);
|
|
const bundle = new TextEncoder().encode("<main><script>window.ok=1<\/script></main>");
|
|
await cache.install({
|
|
v: 1, app_id: "lineup.task-dashboard", version: "1.0.0",
|
|
artifact: { artifact_id: "dashboard-prod", sha256: "b".repeat(64), size_bytes: bundle.length },
|
|
min_host_version: "0.1.0", permissions: ["surface.event.cancel"], key_id: "release-key", signature: "A".repeat(86),
|
|
}, bundle);
|
|
const resolver = new CachedVerifiedSurfaceDocumentResolver(cache);
|
|
const document = resolver.documentFor({ instance_id: "surface:001", conversation_id: "conversation", app_id: "lineup.task-dashboard", version: "1.0.0", state: {}, phase: "opening", opened_at: "2026-08-04T00:00:00.000Z", updated_at: "2026-08-04T00:00:00.000Z" });
|
|
expect(document).toContain("default-src 'none'");
|
|
expect(document).toContain("window.__LINEUP_SURFACE_INSTANCE__=\"surface:001\"");
|
|
expect(document).toContain("window.ok=1");
|
|
expect(resolver.documentFor({ instance_id: "surface:002", conversation_id: "conversation", app_id: "lineup.task-dashboard", version: "9.9.9", state: {}, phase: "opening", opened_at: "2026-08-04T00:00:00.000Z", updated_at: "2026-08-04T00:00:00.000Z" })).toBeUndefined();
|
|
expect(productionSurfaceDocument("surface:003", "<script src=\"https://attacker.invalid/x.js\"><\/script>")).toContain("script-src 'unsafe-inline'");
|
|
});
|
|
});
|