Initial commit of Descrybe v2 without local scratch artifacts.

Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
This commit is contained in:
2026-08-09 22:47:43 +02:00
commit 8580c996c3
1285 changed files with 325780 additions and 0 deletions
+96
View File
@@ -0,0 +1,96 @@
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import { contentSecurityPolicy, resolveApiOrigin } from "./csp.ts";
describe("resolveApiOrigin", () => {
it("returns null for empty or same-origin API URL", () => {
assert.equal(resolveApiOrigin("", "http://localhost:5174"), null);
assert.equal(resolveApiOrigin("http://localhost:5174", "http://localhost:5174"), null);
assert.equal(resolveApiOrigin("http://localhost:5174/", "http://localhost:5174"), null);
});
it("returns cross-origin API origin", () => {
assert.equal(
resolveApiOrigin("http://localhost:8080", "http://localhost:5174"),
"http://localhost:8080"
);
assert.equal(
resolveApiOrigin("https://api.example.com/v1", "https://app.example.com"),
"https://api.example.com"
);
});
it("returns null for invalid URLs", () => {
assert.equal(resolveApiOrigin("not a url", "http://localhost:5174"), null);
});
});
describe("contentSecurityPolicy", () => {
it("production policy omits Google hosts when GTM id is unset", () => {
const csp = contentSecurityPolicy({ dev: false });
assert.match(csp, /default-src 'self'/);
assert.match(csp, /frame-ancestors 'none'/);
assert.match(csp, /object-src 'none'/);
assert.match(csp, /script-src 'self' 'unsafe-inline'/);
assert.doesNotMatch(csp, /googletagmanager\.com/);
assert.doesNotMatch(csp, /google-analytics\.com/);
assert.doesNotMatch(csp, /analytics\.google\.com/);
assert.doesNotMatch(csp, /'unsafe-eval'/);
assert.doesNotMatch(csp, /\bws:/);
assert.match(csp, /connect-src 'self' blob:/);
assert.match(csp, /font-src 'self' data:/);
assert.doesNotMatch(csp, /scalar\.com/);
});
it("production policy allowlists Google hosts when GTM id is valid", () => {
const csp = contentSecurityPolicy({ dev: false, gtmId: "GTM-ABC123" });
assert.match(csp, /script-src 'self' 'unsafe-inline' https:\/\/www\.googletagmanager\.com/);
assert.match(csp, /https:\/\/www\.google-analytics\.com/);
assert.match(csp, /frame-src 'self' https:\/\/www\.googletagmanager\.com/);
assert.match(csp, /connect-src 'self' blob: https:\/\/www\.googletagmanager\.com/);
});
it("invalid or empty gtmId does not allowlist Google hosts", () => {
for (const gtmId of ["", " ", "G-XXXX", "gtm-bad!", null, undefined]) {
const csp = contentSecurityPolicy({ dev: false, gtmId });
assert.doesNotMatch(csp, /googletagmanager\.com/);
assert.doesNotMatch(csp, /google-analytics\.com/);
}
});
it("production connect-src includes cross-origin API without GTM hosts by default", () => {
const csp = contentSecurityPolicy({
dev: false,
apiOrigin: "http://localhost:8080"
});
assert.match(csp, /connect-src 'self' blob: http:\/\/localhost:8080/);
assert.doesNotMatch(csp, /googletagmanager\.com/);
assert.doesNotMatch(csp, /scalar\.com/);
});
it("production connect-src includes API and GTM hosts when gtmId is valid", () => {
const csp = contentSecurityPolicy({
dev: false,
apiOrigin: "http://localhost:8080",
gtmId: "GTM-ABC123"
});
assert.match(
csp,
/connect-src 'self' blob: https:\/\/www\.googletagmanager\.com .*http:\/\/localhost:8080/
);
assert.doesNotMatch(csp, /scalar\.com/);
});
it("development policy allows Vite HMR eval and websockets", () => {
const csp = contentSecurityPolicy({ dev: true });
assert.match(csp, /'unsafe-eval'/);
assert.match(csp, /\bws:/);
assert.match(csp, /\bwss:/);
assert.match(csp, /http:\/\/localhost:\*/);
assert.match(csp, /http:\/\/127\.0\.0\.1:\*/);
assert.match(csp, /connect-src 'self' blob:/);
assert.match(csp, /font-src 'self' data:/);
assert.doesNotMatch(csp, /googletagmanager\.com/);
assert.doesNotMatch(csp, /scalar\.com/);
});
});