Files
cobble/src/utils/graphic-headers.test.ts
T
tbenandClaude Opus 5.5 bea656ade8 Add bot graphics
Bots can now show a concept as a visual: create_graphic (with
update_graphic, read_graphic and list_graphics, on every run, no computer
needed) stores one HTML document in bot_graphics, per user like the
conversation, and the chat renders its [graphic:ID] ref as an inline card
sized to fit, with a large view and a page of its own (no rail).

Graphic HTML is treated as hostile: it is only served at /graphics/<id>
with a CSP sandbox allowing scripts under an origin of its own and no
network, loading only the vendored Chart.js and Mermaid from
/graphics-lib/. The document carries the app's theme vars and scrollbars,
reports its height to the thread, and a frame that navigates away is
closed.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-27 08:11:15 +01:00

30 lines
1.3 KiB
TypeScript

import { describe, expect, test } from "bun:test";
import graphicHeaders from "./graphic-headers";
describe("graphicHeaders", () => {
const csp = graphicHeaders({ origin: "https://app.test" })["Content-Security-Policy"]!;
const directives = csp.split("; ");
test("sandboxes scripts away from the app's origin", () => {
expect(directives).toContain("sandbox allow-scripts");
expect(csp).not.toContain("allow-same-origin");
expect(csp).not.toContain("allow-top-navigation");
expect(csp).not.toContain("allow-popups");
});
test("allows no network beyond the app's graphic libraries", () => {
expect(directives).toContain("default-src 'none'");
expect(directives).toContain("connect-src 'none'");
expect(directives).toContain("script-src 'unsafe-inline' https://app.test/graphics-lib/");
expect(directives).toContain("img-src data: blob:");
});
test("is only framed by the app and never cached", () => {
const headers = graphicHeaders({ origin: "https://app.test" });
expect(directives).toContain("frame-ancestors 'self'");
expect(headers["Cache-Control"]).toBe("private, no-store");
expect(headers["X-Content-Type-Options"]).toBe("nosniff");
});
});