import assert from "node:assert/strict"; import { readFile } from "node:fs/promises"; import test from "node:test"; import { CONTROL_PLANE_EXCLUSIONS, DATA_INVENTORY, INVENTORIED_TABLES, } from "../app/privacy/data-inventory.ts"; test("keeps the public data inventory complete against the D1 schema", async () => { const schema = await readFile(new URL("../db/schema.ts", import.meta.url), "utf8"); const schemaTables = [...schema.matchAll(/sqliteTable\(\s*["']([^"']+)["']/g)] .map((match) => match[1]) .sort(); const inventoryTables = [...INVENTORIED_TABLES].sort(); assert.equal(new Set(schemaTables).size, schemaTables.length, "schema table names must be unique"); assert.equal(new Set(inventoryTables).size, inventoryTables.length, "inventory table names must be unique"); assert.deepEqual(inventoryTables, schemaTables); }); test("publishes purpose, retention boundary, and user control for every data group", () => { assert.ok(DATA_INVENTORY.length >= 7); for (const group of DATA_INVENTORY) { assert.ok(group.summary.length > 10, `${group.id} needs a summary`); assert.ok(group.purpose.length > 10, `${group.id} needs a purpose`); assert.ok(group.retention.length > 10, `${group.id} needs a retention boundary`); assert.ok(group.userControl.length > 10, `${group.id} needs a user control statement`); assert.ok(group.examples.length > 0, `${group.id} needs examples`); assert.ok(group.tables.length > 0, `${group.id} needs table coverage`); } const dormant = DATA_INVENTORY.find((group) => group.id === "dormant-billing"); assert.equal(dormant?.status, "dormant"); assert.match(dormant?.purpose ?? "", /服务端拒绝写入/); assert.ok(CONTROL_PLANE_EXCLUSIONS.some((entry) => entry.item === "项目文件和任意磁盘目录内容")); assert.match( CONTROL_PLANE_EXCLUSIONS.find((entry) => entry.item.includes("明文配对码"))?.boundary ?? "", /短暂处理,不持久化到 D1/, ); }); test("keeps the public privacy page honest about unfinished deletion and compliance work", async () => { const [page, shell, readiness, docs, plan] = await Promise.all([ readFile(new URL("../app/privacy/page.tsx", import.meta.url), "utf8"), readFile(new URL("../app/components/Shells.tsx", import.meta.url), "utf8"), readFile(new URL("../app/readiness/page.tsx", import.meta.url), "utf8"), readFile(new URL("../docs/data-inventory.md", import.meta.url), "utf8"), readFile(new URL("../docs/implementation-plan.md", import.meta.url), "utf8"), ]); assert.match(page, /这不是一份拿模板拼出的最终隐私政策/); assert.match(page, /隐私门禁还没有通过/); assert.match(page, /不会宣称“已经合规”/); assert.match(page, /DATA_INVENTORY\.map/); assert.match(shell, /href="\/privacy"/); assert.match(readiness, /查看公测数据说明/); assert.match(docs, /以上项目完成前.*P0 门禁继续保持阻止/); assert.match(plan, /\[x\].*D1 schema 完整对齐的控制平面数据清单/); assert.doesNotMatch(`${page}\n${docs}`, /隐私门禁已经通过|已经完成合规/); }); test("documents retention facts that are enforced by the current pairing code", async () => { const repository = await readFile(new URL("../db/repository.ts", import.meta.url), "utf8"); assert.match(repository, /const expiresAt = isoAfterMinutes\(10\)/); assert.match(repository, /pairing_claim_rate_limits WHERE window_start < \?/); assert.match(repository, /nowMilliseconds - 24 \* 60 \* 60_000/); assert.match(repository, /pairing_claim_attempts WHERE created_at < \?/); assert.match(repository, /nowMilliseconds - 30 \* 24 \* 60 \* 60_000/); });