Unscoped queries fail the build

A static check scans every hand-written database query in the codebase and fails the build when a new one forgets to filter by account.

What it is

A script that walks the API and library source, finds every direct query against an account-scoped table, and flags any whose statement and near context never mention org_id. Known pre-existing hits live in a baseline file so the check fails only on NEW violations; the baseline is meant to be burned down, never added to without review.

Also called: tenant isolation test · CI check · forgot the org filter · scoping baseline

See it
Unscoped queries fail the build
Area
Platform & Admin
Group
Tenancy & isolation
System
Multi-Tenancy & Identity
Solves
2 named problems
01Every .ts/.tsx file under the API and library directories is scanned.
02A query against an account-scoped table is flagged if neither its chain (up to the terminating semicolon) nor the five lines above it mention org_id.
03The central data proxy is excluded because it enforces scoping itself.
Terminal output of the check listing file, line and table for a new violation, with a red FAIL summary. scripts/check-org-scoping.mjs. Sample data — no customer information appears here.
How it works
  1. 1Every .ts/.tsx file under the API and library directories is scanned.
  2. 2A query against an account-scoped table is flagged if neither its chain (up to the terminating semicolon) nor the five lines above it mention org_id.
  3. 3The central data proxy is excluded because it enforces scoping itself.
  4. 4Results are compared against scripts/org-scoping-baseline.json; only new entries fail.
  5. 5Flags support printing everything or regenerating the baseline deliberately.
Why we built it

The header states the reason bluntly: 'tenant isolation is app-enforced only (RLS policies are allow-all and the service key bypasses them regardless). The generic /api/db proxy stamps org_id centrally, but ~40 dedicated routes + server libs hand-write .from("table")… chains. One forgotten .eq("org_id", …) is a silent cross-tenant read/write with no DB backstop. This script is the tripwire.' It is explicitly described as a heuristic, not a proof — which is also why the audit-log helper keeps its org_id adjacent to the insert: 'burying org_id 20 lines down reads to it (correctly, in general) as an unscoped write.'

The problem
  • A single forgotten filter in a new endpoint is invisible in review and has no database-level backstop.
  • Existing known gaps would otherwise make a strict check unusable on day one.
Sound familiar?
What you get
New unscoped queries are caught before they reach production.
The list of known exceptions is explicit and shrinking rather than assumed.
Reviewers get a mechanical check instead of relying on remembering the rule.

See it on your own jobs

Twenty minutes, your numbers, no slide deck. We’ll build one of your real buildings in front of you and send you the estimate link at the end — yours to keep either way.

or keep browsing features →