import { describe, expect, it } from "vitest"; import { readdirSync, readFileSync, statSync } from "node:fs"; import path from "node:path"; /** * Static guard for the zero-retention promise. Fails the build if any source * file outside a short, reviewed allowlist: * - calls a filesystem write API (writeFile, appendFile, createWriteStream, …) * - logs with console.* (all logging must go through lib/log.ts, which only * accepts metadata fields) * - re-introduces an output-storage option or table * The allowlist is the place to look in review: every entry says why. */ const ROOTS = [path.resolve(__dirname, "../src"), path.resolve(__dirname, "../../../packages/renderer/src")]; const WRITE_ALLOW: Record = { "apps/web/src/lib/db/index.ts": "creates the local PGlite data directory in development (mkdirSync); no request data", "apps/web/src/lib/snippets.ts": "text of customer-facing code samples (their code saves the PDF on their machine); not executed here", "apps/web/src/app/(marketing)/guides/content.tsx": "text of code samples in the guides; not executed here", }; const CONSOLE_ALLOW: Record = { "apps/web/src/lib/log.ts": "the metadata-only logger itself", "apps/web/src/lib/dev-seed.ts": "prints the local dev account once, development only", "apps/web/src/app/(marketing)/guides/articles-trust.tsx": "text of a code sample (offline receipt check) shown in a guide; not executed here", "apps/web/src/lib/mail/log.ts": "MAIL_PROVIDER=log prints the email in development and tests only; in production it logs metadata through lib/log.ts", "apps/web/src/lib/verify-script.ts": "text of the receipt-check script customers run on their own machine (/verify); not executed here", "packages/renderer/src/server.ts": "startup line and one metadata line per request (path, status, ms, error code and class; never the URL)", }; function files(dir: string): string[] { return readdirSync(dir).flatMap((n) => { const p = path.join(dir, n); return statSync(p).isDirectory() ? files(p) : /\.(ts|tsx|mts)$/.test(n) ? [p] : []; }); } const rel = (p: string) => path.relative(path.resolve(__dirname, "../../.."), p).split(path.sep).join("/"); const all = ROOTS.flatMap(files).map((p) => ({ file: rel(p), src: readFileSync(p, "utf8") })); describe("no write paths for request content or output", () => { it("scans a meaningful amount of code", () => { expect(all.length).toBeGreaterThan(50); }); it("no filesystem writes outside the allowlist", () => { const re = /\b(writeFile|writeFileSync|appendFile|appendFileSync|createWriteStream|mkdtemp|mkdtempSync|copyFile|copyFileSync|rename|renameSync|mkdirSync|mkdir)\s*\(/; const offenders = all.filter((f) => re.test(f.src) && !WRITE_ALLOW[f.file]).map((f) => f.file); expect(offenders).toEqual([]); }); it("no console logging outside the metadata logger", () => { const offenders = all.filter((f) => /\bconsole\.(log|info|warn|error|debug|trace)\s*\(/.test(f.src) && !CONSOLE_ALLOW[f.file]).map((f) => f.file); expect(offenders).toEqual([]); }); it("logMeta is never handed request content", () => { // Fields that could carry content must never appear inside a logMeta({...}) call. const bad = /logMeta\(\{[^}]*\b(html|url|body|data|headerHtml|footerHtml|deliverTo|template|text|filename)\s*:/s; expect(all.filter((f) => bad.test(f.src)).map((f) => f.file)).toEqual([]); }); it("no output-storage option or table can come back unnoticed", () => { const re = /\b(temp_files|tempFiles|storeTempFile|log_request|logRequest)\b/; // comparison.ts quotes competitors' parameter names (e.g. PDFShift's log_request); it is data, not code. const QUOTES = new Set(["apps/web/src/lib/comparison.ts"]); expect(all.filter((f) => re.test(f.src) && !QUOTES.has(f.file)).map((f) => f.file)).toEqual([]); }); it("the renderer container is configured read-only with tmpfs only", () => { const compose = readFileSync(path.resolve(__dirname, "../../../docker-compose.yml"), "utf8"); const renderer = compose.slice(compose.indexOf("renderer:"), compose.indexOf("web:")); expect(renderer).toMatch(/read_only:\s*true/); expect(renderer).toMatch(/tmpfs:/); expect(renderer).not.toMatch(/volumes:/); }); });