import { describe, expect, it } from "vitest";
import { markdownRoot, resolveMarkdownAttachments, sanitizedSvgUrl, staticOutputDocument } from "./security";
const parse = (html: string) => new DOMParser().parseFromString(html, "text/html");
describe("static notebook output sanitization", () => {
it("retains table content while removing executable, navigation and external-resource surfaces", () => {
const document = parse(
staticOutputDocument(`
link
safe text
`),
);
expect(document.querySelector("tbody tr")?.textContent).toBe("alpha42");
expect(document.querySelector("script,base,form,input,button,iframe,object")).toBeNull();
expect(document.querySelector("meta[http-equiv=refresh]")).toBeNull();
expect(document.querySelector("[href],[target],[srcset],[onerror],[ping]")).toBeNull();
expect(document.querySelector("img")?.hasAttribute("src")).toBe(false);
expect(document.querySelector("body div")?.hasAttribute("style")).toBe(false);
});
it("retains safe SVG chart paint, local definitions and raster images but removes active/external SVG", () => {
const url = sanitizedSvgUrl(``);
const xml = decodeURIComponent(url.slice(url.indexOf(",") + 1));
const document = new DOMParser().parseFromString(xml, "image/svg+xml");
expect(document.querySelector("script,foreignObject,animate,style")).toBeNull();
expect(document.querySelector('[href^="https:"],[href^="http:"]')).toBeNull();
expect(document.querySelector("#chart")?.getAttribute("stroke")).toBe("#123456");
expect(document.querySelector("#chart")?.getAttribute("fill")).toBe("none");
expect(document.querySelector("rect")?.getAttribute("fill")).toBe("url(#paint)");
expect(document.querySelector("#local-marker")?.getAttribute("href")).toBe("#chart");
expect(document.querySelector("#external")?.hasAttribute("fill")).toBe(false);
expect(document.querySelector("image")?.getAttribute("href")).toBe("data:image/png;base64,aGVsbG8=");
expect(document.querySelector("[onclick],[style]")).toBeNull();
});
it("resolves only embedded image attachments and makes Markdown file links editor-controlled", () => {
const root = resolveMarkdownAttachments(
markdownRoot(
`\n\n\n\n[local](./other.py#L8)\n\ntext
`,
),
{
"chart.png": { "image/png": "aGVsbG8=" },
},
);
const images = root.querySelectorAll("img");
expect(images[0]?.getAttribute("src")).toBe("data:image/png;base64,aGVsbG8=");
expect(images[1]?.hasAttribute("src")).toBe(false);
const link = root.querySelector("a");
expect(link?.hasAttribute("href")).toBe(false);
expect(link?.getAttribute("data-notebook-href")).toBe("./other.py#L8");
expect(root.querySelector("script,[style]")).toBeNull();
});
});