Repository navigation
test(backend): fail the unit suite when an e2e spec bypasses the database guard - #111
Conversation
…base guard Add test/e2e-db-guard-scan.ts and its spec, which run in the unit suite and parse every .ts file under packages/backend/test with the TypeScript AST. They fail when a file: - wipes the database (dropSchema not literally false, DROP SCHEMA or DROP DATABASE SQL, .dropDatabase(), .synchronize(true)) without calling resolveE2eDatabaseUrl() or createTestApp(); - falls back from process.env.DATABASE_URL with ?? or ||; - has a string naming localhost:5432 or mydatabase (e2e-db-guard.spec.ts is exempt, since it proves the guard refuses those URLs). Fixtures under test/fixtures/e2e-db-guard (*.fixture, outside the scan and outside Jest) reproduce the legacy migration-spec pattern from #52, #60 and #66, a raw DROP SCHEMA reset, and the accepted guarded pattern. A temp-dir tree scan proves that adding the legacy spec fails the check. Closes #108 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of #111: test(backend): fail the unit suite when an e2e spec bypasses the database guardI reviewed SummaryNothing blocks this PR. I have one should-fix and four nits. The PR is not high risk. It doesn't touch auth, crypto or key handling, has no migration, doesn't affect tenant isolation, and doesn't change governance files, Does it meet issue #108?
Should-fixS1. Failure scenario: a new migration spec opens its own Fix: also push a drop when Nits (no need to fix before merge)N1.
N2.
N3.
When the fallback names N4.
Probe results (
|
| Source | Result |
|---|---|
spread { ...opts } with opts = { dropSchema: true }, dropSchema: undefined, !false, tagged template sql`DROP SCHEMA ...`, synchronize( true ), locally defined but uncalled createTestApp |
unguarded-drop (caught) |
qr.dropSchema('public', true, true) |
none (S1) |
createTestApp() plus a second DataSource with dropSchema: true; local createTestApp that drops |
none (N1) |
'DROP ' + 'SCHEMA', `DROP ${'SCHEMA'}`, TRUNCATE, DROP TABLE, DROP OWNED |
none (N2) |
??=, ||=, ternary, destructuring default, env alias, process?.env?. |
none (N3) |
/DROP SCHEMA/ regex literal, /* DROP SCHEMA */ comment |
none (correct) |
'postgresql://u:p@127.0.0.1:5432/postgres' |
none (out of scope; the issue names localhost:5432) |
Tests
- PR report: the PR lists shared build, backend
tsc --noEmit, stricttscon the new files, backend lint, prettier, backend unit (473 suites, 9066 tests) andtest:e2e:docker(70 suites, 592 tests), all passing. - CI on
527978f: every check-run issuccess: Lint, Unit (backend/frontend/shared/cli), Backend e2e (PostgreSQL 16), Compose smoke test, install.sh end-to-end, CodeQL and dependency-review. - My local runs in the review worktree:
npx jest test/e2e-db-guard: 2 suites, 53 tests passed;npx tsc --noEmit --strict --target es2022on the two new files: clean;npx prettier --checkon the two new files: clean.
qa-docker: not needed. This is a test-only change.
Docs
The new section of docs/dev/manifest-guide.md is in English. That is consistent with the rest of that inherited guide, including the #67 section right above it. It describes the rules and exemptions accurately.
Merge condition
Under aprovado, S1 must be fixed in this PR or tracked in an issue whose link is recorded in the PR before merge. N1-N4 are optional.
Head revisado: 527978f
Veredito: aprovado
… guard scan Refs #108 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Re-review of #111 at c1a95faThis re-review covers the delta S1: fixed
New findingN5 (nit): the change isn't described in the header comment or the guide. N1-N4 from the previous review stay optional and unaddressed, as agreed. Nothing blocks the PR, and no should-fix is left open. The PR is still not high risk. The change is test-only: no auth, crypto, migration, isolation, governance, workflow or release files, and no outbound calls. Tests
Head revisado: c1a95fa |
Closes #108
What
A unit-suite check that no backend e2e spec can wipe a database without going through the #67 guard.
packages/backend/test/e2e-db-guard-scan.ts: parses every.tsfile underpackages/backend/testwith the TypeScript AST, so comments never count, and reports three rules:unguarded-drop: the file wipes the database without callingresolveE2eDatabaseUrl()orcreateTestApp(). Wiping meansdropSchemaset to anything but a literalfalse(shorthand included),DROP SCHEMA/DROP DATABASEin a string or template,.dropDatabase()or.synchronize(true). A call is required; an import alone does not count.database-url-fallback:process.env.DATABASE_URL ?? ...or|| ....default-database: a string naminglocalhost:5432ormydatabase.e2e-db-guard.spec.tsis exempt, since it feeds those URLs to the guard to prove they are refused.packages/backend/test/e2e-db-guard-scan.spec.ts: runs in the unit suite (npm test, the jestrootsalready includetest/). It does three things:packages/backend/test/fixtures/e2e-db-guard/*.fixtureholds three fixtures:?? 'postgresql://...localhost:5432/mydatabase'fallback plusdropSchema: true;DROP SCHEMAreset;Their
.fixtureextension keeps them out of the scan, out of Jest and out oftsc.docs/dev/manifest-guide.md: the "Backend e2e database safety" section now describes the check.The current tree passes with no exemption other than the guard's own spec.
Tests
npm run build --workspace=packages/sharednpx tsc --noEmit -p tsconfig.json(backend)npx tsc --noEmit --strict ... test/e2e-db-guard-scan.ts test/e2e-db-guard-scan.spec.ts(test dir is outside the backend tsconfig)npm run lint --workspace=packages/backendsrc/, unchanged)npx prettier --checkon the new filesnpx jest(backend unit)TZ=UTC npm run test:e2e:docker --workspace=packages/backendTest-only change. No runtime behavior changes, so
qa-dockeris not needed.🤖 Generated with Claude Code