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:
@@ -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/);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user