import { existsSync, readFileSync } from "node:fs"; import { resolve } from "node:path"; import { describe, expect, it } from "vitest"; type WebAccessibleResource = { matches: string[]; resources: string[]; use_dynamic_url?: boolean; }; type ExtensionManifest = { web_accessible_resources?: WebAccessibleResource[]; }; // dist-chrome/ and dist-firefox/ are kohignored build outputs, so a clean // checkout has no manifest to read. scripts/ci.ts builds both targets before // the test step; with no artifacts present these suites skip instead of // throwing ENOENT and passing/failing on nothing. function manifestPath(target: "chrome" | "firefox"): string { return resolve(process.cwd(), `dist-${target}`, "manifest.json"); } function readManifest(target: "chrome" | "firefox"): ExtensionManifest { return JSON.parse( readFileSync(manifestPath(target), "utf8"), ) as ExtensionManifest; } const HASHED_ASSET = /^assets\/[^/]+-[A-Za-z0-9_-]+\.(?:js|css)$/; describe.skipIf(!existsSync(manifestPath("chrome")))( "shipped Chrome web-accessible resources", () => { it("scopes page-reachable resources to content-hashed asset chunks", () => { const resources = readManifest("chrome").web_accessible_resources ?? []; expect(resources).toHaveLength(1); expect(resources[0]?.matches).toEqual([""]); expect(resources[0]?.resources.length).toBeGreaterThan(0); expect( resources[0]?.resources.every((file) => HASHED_ASSET.test(file)), ).toBe(true); }); // PB-26-314 is OPEN, not accepted. use_dynamic_url was enabled once and // reverted at v5.0.100 (save e1c5043e4311) because Chrome then denied the // dependent content-script chunks from page contexts, breaking the form // icons. This stays an expected failure so that enabling the flag turns // the suite red instead of silently shipping the finding. it.fails( "PB-26-314 (OPEN): Chrome serves web-accessible resources from a per-install dynamic URL", () => { const resources = readManifest("chrome").web_accessible_resources ?? []; expect(resources[0]?.use_dynamic_url).toBe(true); }, ); }, ); describe.skipIf(!existsSync(manifestPath("firefox")))( "shipped Firefox web-accessible resources", () => { it("keeps Firefox resources limited to content-script chunks with content hashes", () => { const resources = readManifest("firefox").web_accessible_resources ?? []; const files = resources.flatMap((entry) => entry.resources); expect(files.length).toBeGreaterThan(0); expect(files.every((file) => HASHED_ASSET.test(file))).toBe(true); expect(files.every((file) => !file.includes(""))).toBe( true, ); }); }, );