From 1a11c12740d19076d8fad040311fb729061b99a9 Mon Sep 17 00:00:00 2001 From: Simple Analytics Codex Date: Thu, 15 Oct 2026 17:08:17 +0200 Subject: [PATCH 1/2] Accept current and legacy script deployment headers Requested: make issue #107 ready to merge. Fix the proven mismatch between compile.js output and deployment header validation while retaining older pinned header support. Add tests against the real deployment manifest, legacy and malformed headers, and run the lightweight deployment suite in CI. All 15 deployment tests, type checking, and diff checks pass. Visitor-facing scripts are unchanged. Refs #107 --- .github/workflows/browserstack.yml | 2 +- deploy.mts | 4 ++-- test/deploy.test.mts | 37 ++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/.github/workflows/browserstack.yml b/.github/workflows/browserstack.yml index 5b0047c..91651ce 100644 --- a/.github/workflows/browserstack.yml +++ b/.github/workflows/browserstack.yml @@ -55,7 +55,7 @@ jobs: run: pnpm run test:matrix - name: Run unit tests - run: pnpm run build && pnpm run test:unit + run: pnpm run build && pnpm run test:unit && pnpm run test:deploy - name: Prettier check (report only, no writes or commits) if: always() diff --git a/deploy.mts b/deploy.mts index b595327..956fb90 100644 --- a/deploy.mts +++ b/deploy.mts @@ -71,8 +71,8 @@ const CDN_PUBLIC_ROOT = "https://scripts.simpleanalyticscdn.com"; const CDN_STORAGE_ROOT = "https://storage.bunnycdn.com/sa-cdn"; const CDN_PURGE_URL = "https://api.bunny.net/purge?url=https://simpleanalyticscdn.b-cdn.net/*"; -const HEADER_PATTERN = - /^\/\* Simple Analytics - Privacy friendly analytics \(docs\.simpleanalytics\.com\/[^;]+; \d{4}-\d{2}-\d{2}; [0-9a-f]{4}(?:; SRI-version)?(?:; v\d+)?\) \*\/$/; +export const HEADER_PATTERN = + /^\/\* Simple Analytics - Privacy(?: friendly|-first) analytics \(docs\.simpleanalytics\.com\/[^;]+; \d{4}-\d{2}-\d{2}; [0-9a-f]{4}(?:; SRI-version)?(?:; v\d+)?\) \*\/$/; const ansi = { bold: (value: string) => color("1", value), diff --git a/test/deploy.test.mts b/test/deploy.test.mts index 3ae7408..c25f260 100644 --- a/test/deploy.test.mts +++ b/test/deploy.test.mts @@ -1,10 +1,12 @@ import assert from "node:assert/strict"; +import { readFile } from "node:fs/promises"; import { describe, it } from "node:test"; import { classifyContent, createManifest, firstLine, + HEADER_PATTERN, latestVersionFromNames, repositoryPolicy, summarize, @@ -13,6 +15,41 @@ import { type PreviewFile, } from "../deploy.mts"; +describe("deployment headers", () => { + it("accepts every generated JavaScript header in the current manifest", async () => { + const files = createManifest( + { + destinations: ["cdn", "custom"], + scripts: ["default", "auto-events"], + variants: ["latest", "sri", "light", "proxy"], + }, + 12 + ); + for (const file of files.filter((file) => file.kind === "javascript")) { + const content = await readFile( + new URL("../" + file.localPath, import.meta.url) + ); + assert.match(firstLine(content), HEADER_PATTERN, file.localPath); + } + }); + + it("keeps accepting legacy headers", () => { + assert.match( + "/* Simple Analytics - Privacy friendly analytics (docs.simpleanalytics.com/script; 2024-01-01; abcd; SRI-version; v11) */", + HEADER_PATTERN + ); + }); + + it("rejects malformed or unrelated headers", () => { + for (const header of [ + "/* unrelated script */", + "/* Simple Analytics - Privacy-first analytics (docs.simpleanalytics.com/script; 2026-10-15; not-a-hash; v12) */", + ]) { + assert.doesNotMatch(header, HEADER_PATTERN); + } + }); +}); + describe("deployment manifest", () => { it("maps latest and its legacy companions to both destinations", () => { const files = createManifest({ From 2719289e6ef71d27b616564e8783d7e70477b75f Mon Sep 17 00:00:00 2001 From: Simple Analytics Codex Date: Thu, 15 Oct 2026 17:25:32 +0200 Subject: [PATCH 2/2] Check headers for the current SRI version in deployment tests Requested: make issue #107 mergeable and address review on #117. Reuse latestVersionFromNames with the dist directory so the manifest regression follows the current SRI version rather than only v12. All 15 deployment tests and type checking pass. Refs #107 --- test/deploy.test.mts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/deploy.test.mts b/test/deploy.test.mts index c25f260..5bf7727 100644 --- a/test/deploy.test.mts +++ b/test/deploy.test.mts @@ -1,5 +1,5 @@ import assert from "node:assert/strict"; -import { readFile } from "node:fs/promises"; +import { readFile, readdir } from "node:fs/promises"; import { describe, it } from "node:test"; import { @@ -17,13 +17,17 @@ import { describe("deployment headers", () => { it("accepts every generated JavaScript header in the current manifest", async () => { + const version = latestVersionFromNames( + await readdir(new URL("../dist", import.meta.url)) + ); + assert.ok(version !== undefined, "dist has no versioned SRI directory"); const files = createManifest( { destinations: ["cdn", "custom"], scripts: ["default", "auto-events"], variants: ["latest", "sri", "light", "proxy"], }, - 12 + version ); for (const file of files.filter((file) => file.kind === "javascript")) { const content = await readFile(