#!/usr/bin/env node /* * no-storage.test.mjs — the GEO-03 grep gate (zero persistence, source-introspection). * ----------------------------------------------------------------------------------- * Inverted form of bot/test/privacy.test.mjs (PG1 pins writes to carry TTLs; this * pin that web/src contains NO persistence surface at all — D-03 (memory-only * token) + D-07 (coordinates live in memory only)). * * The gate MUST strip comments before scanning: web/src/mock/telegram-mock.ts's * header documents the ban in prose, and prose is not a call site. Strip block * comments (/* … *​/) and line comments (// …), THEN assert none of the banned * tokens appear — code occurrences only. */ import { strict as assert } from "node:assert"; import { readFileSync, readdirSync, statSync } from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; import { test } from "./harness.mjs"; const SRC = path.join(path.dirname(fileURLToPath(new URL(import.meta.url))), "..", "src"); const BANNED = [ "localStorage", "sessionStorage", "indexedDB", "caches", "CacheStorage", "document.cookie", "WebApp.DeviceStorage", "WebApp.SecureStorage", "WebApp.CloudStorage", ]; /* path-scrape + comment strip (the plan's contract for this gate) */ function listFiles(dir, exts, acc = []) { for (const entry of readdirSync(dir)) { const full = path.join(dir, entry); if (statSync(full).isDirectory()) listFiles(full, exts, acc); else if (exts.some((e) => entry.endsWith(e))) acc.push(full); } return acc; } function stripComments(src) { return src .replace(/\/\*[\s\S]*?\*\//g, " ") // block comments .replace(/(^|[^:\\])\/\/[^\n]*/g, "$1"); // line comments (not URLs inside strings — benign over-stripping, gate is prefer-fail reading) } function codeText(file) { return stripComments(readFileSync(file, "utf8")); } /* ————— GEO3 — the mechanical gate over every web/src source ————— */ test("GEO3 no banned storage token appears in web/src code (comments stripped, all *.ts/*.html)", () => { const files = listFiles(SRC, [".ts", ".html"]); assert.ok(files.length >= 12, `scanned a real tree (found ${files.length} files)`); for (const file of files) { const code = codeText(file); for (const banned of BANNED) { assert.ok(!code.includes(banned), `${path.relative(process.cwd(), file)} references ${banned} — GEO-03 violated`); } } }); test("GEO3 the runtime-probe-preceding invariant: no service worker / registration call exists", () => { // Vite emits no SW by default; this pins the "and none was added" half (RESEARCH GEO-03 §). for (const file of listFiles(SRC, [".ts", ".html"])) { const code = codeText(file); for (const token of ["serviceWorker.register", "navigator.serviceWorker", "workbox"]) { assert.ok(!code.includes(token), `${path.relative(process.cwd(), file)} references ${token} — GEO-03 surface added`); } } }); test("GEO3 web/src/session/store.ts assigns nothing to any storage object (the D-03 half)", () => { const code = codeText(path.join(SRC, "session", "store.ts")); assert.ok(!/Storage\s*\.\s*setItem|Storage\s*\.\s*getItem/.test(code), "store.ts touches a Storage object"); assert.ok(!/indexedDB\s*\.\s*open/.test(code), "store.ts opens IndexedDB"); assert.ok(!/document\s*\.\s*cookie\s*=/.test(code), "store.ts writes a cookie"); assert.ok(!/caches\s*\.\s*open/.test(code), "store.ts opens a CacheStorage"); // ...and keeps the named TTL constant the client revalidates against (D-03). assert.ok(code.includes("SESSION_TTL_SECONDS = 900"), "the 900s TTL mirror by name is present"); });