import { describe, expect, it } from "@effect/vitest"; import { SealedBundleError, executeSealedBundle } from "@executor-js/runtime-quickjs"; import * as Effect from "effect/Effect"; import harnessBundle from "./smoke-harness-bundle.gen"; import { smokeRenderArtifact, stubSealedBundle } from "./smoke-render"; import type { SmokeRenderResult } from "./smoke-render-result"; // The create-time render check. Each case is a shape a model actually writes; // the assertion is what the model would be told back. describe("smokeRenderArtifact", () => { it("passes a plain component", async () => { expect((await smokeRenderArtifact("function App(){ return
hello
; }")).status).toBe( "ok", ); }); it("catches the chart primitive rendered outside its ChartContainer", async () => { // The exact failure that motivated this: it saved fine and died on the page. const result = await smokeRenderArtifact( "function App(){ return ; }", ); expect(result.status).toBe("failed"); // The real error, verbatim, so the model can act on it without a translation. expect(result.status === "failed" ? result.message : "").toContain( "useChart must be used within a ", ); }); it("passes the same chart once a ChartContainer wraps it", async () => { const result = await smokeRenderArtifact( [ "function App(){", " return (", ' ', " ", ' ', " } />", ' ', " ", " ", " );", "}", ].join("\n"), ); expect(result.status).toBe("ok"); }); it("renders the loading branch: every query is pending, nothing is fetched", async () => { const result = await smokeRenderArtifact( [ "function App(){", " const q = useQuery(tools.vercel.getDomains.queryOptions({ limit: 10 }));", " if (q.isLoading) return ;", " return
{q.data?.length}
;", "}", ].join("\n"), ); expect(result.status).toBe("ok"); }); it("catches a component that dereferences pending query data without a guard", async () => { // `data` IS undefined while a query is pending, so this crashes for real on // the user's first paint. Catching it here is the feature, not a false // positive. const result = await smokeRenderArtifact( [ "function App(){", " const q = useQuery(tools.vercel.getDomains.queryOptions({}));", " return
{q.data.domains.length}
;", "}", ].join("\n"), ); expect(result.status).toBe("failed"); expect(result.status === "failed" ? result.message : "").toMatch(/undefined/i); }); it("passes the same component when it guards the pending state", async () => { const result = await smokeRenderArtifact( [ "function App(){", " const q = useQuery(tools.vercel.getDomains.queryOptions({}));", " return
{q.data?.domains?.length ?? 0}
;", "}", ].join("\n"), ); expect(result.status).toBe("ok"); }); it("passes an infinite query's loading state", async () => { const result = await smokeRenderArtifact( [ "function App(){", " const q = useInfiniteQuery(", " tools.vercel.getDomains.infiniteQueryOptions(", " { limit: 100 },", ' { cursorKey: "since", getNextPageParam: (page) => page?.next ?? undefined },', " ),", " );", " const rows = (q.data?.pages ?? []).flatMap((page) => page?.domains ?? []);", " return
{rows.length}
;", "}", ].join("\n"), ); expect(result.status).toBe("ok"); }); it("passes a mutation, which is inert until something calls it", async () => { const result = await smokeRenderArtifact( [ "function App(){", " const m = useMutation(tools.vercel.addDomain.mutationOptions({}));", " return ;", "}", ].join("\n"), ); expect(result.status).toBe("ok"); }); it("passes rather than blocks when the sandbox cannot answer", async () => { // FAIL OPEN, the contract this check lives under. A sandbox that fails to // start, a harness bundle missing from a partial build, a deadline — none // of them say anything about the artifact, so a create must go through // rather than be refused with an error about code the model did not write. // Simulated at the seam the host actually depends on: the sealed-bundle // call that would carry the answer back. const failing = Effect.fail(new SealedBundleError({ message: "sandbox unavailable" })); using _sandbox = stubSealedBundle(() => failing); // Code that certainly would NOT render, so a pass can only come from the // fail-open path and not from the artifact being fine. expect( (await smokeRenderArtifact("function App(){ return ; }")).status, ).toBe("ok"); }); // ------------------------------------------------------------------ // The security property this check exists inside a sandbox for. // // These are attempted escapes, written the way a compromised or careless // model would write them, asserting the sandbox DENIES each one. They are // not testing the ~280-name scope — shadowing an identifier is not a // boundary, since `globalThis.process` never mentions the shadowed name. // They are testing that the host's process is genuinely not reachable from // where this code runs. Every one of them would have read real host state // back when the render ran in-process. // // A denied escape surfaces as a render failure (the reference throws), which // is exactly right: the sandbox has no `process` to find, so looking for one // is a ReferenceError like any other. // ------------------------------------------------------------------ describe("sandbox containment", () => { const renderExpression = (expression: string): Promise => smokeRenderArtifact(`function App(){ return
{String(${expression})}
; }`); it("has no process to reach", async () => { // `typeof` cannot throw, so this reads back what the sandbox actually // has: "undefined". If a host process leaked in, it would say "object". const result = await renderExpression("typeof process"); expect(result.status).toBe("ok"); }); it("denies globalThis.process", async () => { const result = await renderExpression("globalThis.process.env.EXECUTOR_SECRET"); expect(result.status).toBe("failed"); }); it("denies the Function constructor route to process", async () => { // The classic scope-shadowing bypass: build a function whose body is // evaluated in global scope, so no shadowed binding is in the way. const result = await renderExpression('Function("return process")()'); expect(result.status).toBe("failed"); expect(result.status === "failed" ? result.message : "").toContain("process"); }); it("denies dynamic import", async () => { // Asserted against the sandbox directly rather than through a component. // `import()` REJECTS rather than throwing, and its rejection lands after // the one-shot server render has finished (effects never run during SSR), // so no artifact could observe it — the render would pass while proving // nothing. What matters is that the module genuinely does not load: the // sandbox has no loader behind `import` and no host module graph to reach. const probe = await Effect.runPromise( executeSealedBundle({ bundle: harnessBundle ?? "", call: `(async () => { try { await import('node:fs'); return 'RESOLVED'; } catch (e) { return 'REJECTED:' + (e && e.message ? e.message : String(e)); } })()`, timeoutMs: 30_000, }), ); expect(probe).toContain("REJECTED:"); expect(probe).toContain("could not load module"); }, 60_000); it("has no host globals to reach at all", async () => { // The complement of the shadowing tests: not "is the name shadowed" but // "does the sandbox's global object contain any of this". Asked of the // sandbox itself, so no component scope is involved. const probe = await Effect.runPromise( executeSealedBundle({ bundle: harnessBundle ?? "", call: `Promise.resolve(JSON.stringify({ process: typeof globalThis.process, fetch: typeof globalThis.fetch, require: typeof globalThis.require, XMLHttpRequest: typeof globalThis.XMLHttpRequest, WebSocket: typeof globalThis.WebSocket, }))`, timeoutMs: 30_000, }), ); expect(JSON.parse(probe)).toEqual({ process: "undefined", fetch: "undefined", require: "undefined", XMLHttpRequest: "undefined", WebSocket: "undefined", }); }, 60_000); it("denies require of a host module", async () => { const result = await smokeRenderArtifact( "function App(){ require('node:child_process'); return
; }", ); expect(result.status).toBe("failed"); }); it("denies network access", async () => { const result = await smokeRenderArtifact( "function App(){ fetch('https://example.com'); return
; }", ); expect(result.status).toBe("failed"); }); it("stops a component that spins forever", async () => { // In-process this could not be done — no timeout interrupts a spinning // host thread, so such an artifact hung the request until the host's own // timeout. The sandbox's interrupt handler preempts the interpreter. // Inconclusive, so `ok` by the fail-open contract, but BOUNDED. const result = await smokeRenderArtifact("function App(){ while (true) {} return
; }"); expect(result.status).toBe("ok"); }, 60_000); }); it("reports a syntax error as a failure rather than throwing", async () => { const result = await smokeRenderArtifact("function App(){ return
; }"); expect(result.status).toBe("failed"); }); // The same render that validates the artifact also produces the gallery's // layout preview. These pin the markup half of the contract. describe("layout markup", () => { it("returns the markup the component rendered", async () => { const result = await smokeRenderArtifact( 'function App(){ return

Revenue

; }', ); expect(result.status).toBe("ok"); const markup = result.status === "ok" ? (result.markup ?? "") : ""; // The classes are the whole visual layer, so they have to survive. expect(markup).toContain('class="p-4"'); expect(markup).toContain("Revenue"); }); it("returns the LOADING composition for a component that queries", async () => { // Every tool call hangs by design, so this is the state the user sees // first — and the state that is safe to store, since nothing was fetched. const result = await smokeRenderArtifact( [ "function App(){", " const q = useQuery(tools.github.issues.list.queryOptions({}));", " if (q.isPending) return ;", " return
{String(q.data)}
;", "}", ].join("\n"), ); expect(result.status).toBe("ok"); const markup = result.status === "ok" ? (result.markup ?? "") : ""; expect(markup).toContain("artifact-loading"); expect(markup).not.toContain("undefined"); }); it("omits markup when the render fails", async () => { // A failed verdict has no preview to offer, and the type says so. const result = await smokeRenderArtifact("function App(){ return ; }"); expect(result.status).toBe("failed"); expect("markup" in result).toBe(false); }); it("omits markup for a component that renders nothing", async () => { // Empty is not a preview, and the caller must not read "" as one. const result = await smokeRenderArtifact("function App(){ return null; }"); expect(result.status).toBe("ok"); expect(result.status === "ok" ? result.markup : "unused").toBeUndefined(); }); it("drops the markup rather than returning a partial tree when it is huge", async () => { // Past the harness's cap the render is still driven to completion — that // is how a late throw is observed — but nothing is kept, because half a // DOM tree is not a picture of anything. const result = await smokeRenderArtifact( [ "function App(){", " return (", "
", " {Array.from({ length: 4000 }, (_, i) => (", '
', " Row number {i} with enough text to add up quickly", "
", " ))}", "
", " );", "}", ].join("\n"), ); expect(result.status).toBe("ok"); expect(result.status === "ok" ? result.markup : "unused").toBeUndefined(); }, 60_000); }); it("reports code with no App component", async () => { const result = await smokeRenderArtifact("const x = 1;"); expect(result.status).toBe("failed"); expect(result.status === "failed" ? result.message : "").toContain("App"); }); it("carries a component stack when React reports one", async () => { const result = await smokeRenderArtifact( [ "function Inner(){ throw new Error('boom'); }", "function App(){ return ; }", ].join("\n"), ); expect(result.status).toBe("failed"); expect(result.status === "failed" ? result.message : "").toContain("boom"); expect(result.status === "failed" ? result.componentStack : undefined).toContain("Inner"); }); it("renders the shadcn components that need their own provider from the shell", async () => { // TooltipProvider is supplied by the harness exactly as the inner renderer // supplies it, so a bare Tooltip must not be reported as broken. const result = await smokeRenderArtifact( [ "function App(){", " return (", " ", " ?", " Help", " ", " );", "}", ].join("\n"), ); expect(result.status).toBe("ok"); }); it("renders a representative dashboard: cards, table, badges, icons", async () => { const result = await smokeRenderArtifact( [ "function App(){", " const q = useQuery(tools.vercel.getDomains.queryOptions({}));", " const rows = q.data?.domains ?? [];", " if (q.isLoading) return ;", " if (q.error) return ;", " if (!rows.length) return ;", " return (", " ", " Domains", " ", " ", " {rows.map((row) => (", " ", " {row.name}", " {row.status}", " ", " ))}", "
", "
", "
", " );", "}", ].join("\n"), ); expect(result.status).toBe("ok"); }); });