zone1-data-integrity.test.ts43 lines · main
1import { readFileSync } from 'node:fs';
2import { fileURLToPath } from 'node:url';
3
4import { describe, expect, test } from 'bun:test';
5
6/**
7 * Zone-1 data-integrity regression guards.
8 *
9 * The two fixes below live inside raw `sql` templates that only execute
10 * against a live Postgres control plane (the full behaviour is covered by
11 * account-deletion.integration.test.ts, which gates on a real DB). These
12 * lightweight source guards lock in the exact predicates so a future edit
13 * can't silently reintroduce the original bugs without a DB to hand.
14 */
15
16function readSrc(rel: string): string {
17 return readFileSync(fileURLToPath(new URL(rel, import.meta.url)), 'utf8');
18}
19
20describe('hardDeleteExpiredAccounts GC predicate', () => {
21 const src = readSrc('./account-deletion.ts');
22
23 test('selects orgs to purge via org_members owner role (mirrors isSoleOwner)', () => {
24 // The org purge must qualify orgs by OWNERSHIP, not organizations.created_by
25 // alone — created_by is nulled by the 0042/0044 FK SET NULL sweep, so a
26 // created_by-only predicate leaves zombie soft-deleted orgs that block the
27 // user DELETE forever (the original account-deletion incident).
28 expect(src).toContain('FROM org_members m');
29 expect(src).toContain("m.role = 'owner'");
30 expect(src).toContain('m.user_id IN (');
31 });
32});
33
34describe('admin abuse-report rollup', () => {
35 const src = readSrc('./admin.ts');
36
37 test("counts open + triaged reports, never the non-existent 'investigating' status", () => {
38 // abuseStatus enum is ['open','triaged','resolved'] — 'investigating' is not
39 // a member, so the old predicate silently under-counted the operator queue.
40 expect(src).toContain("status IN ('open', 'triaged')");
41 expect(src).not.toContain('investigating');
42 });
43});