Home / RLS / RLS in CI: fail the build
Supabase RLS · CI
RLS in CI: fail the build when a table ships exposed
Add a CI step that scans for tables with RLS off or USING (true) and exits non-zero. The fastest way is npx airlock-rls as a GitHub Action; a raw SQL check is below if you'd rather roll your own.
01 Why a gate, not a checklist
Every RLS leak in production started as a table someone forgot to protect. A human checklist misses it eventually; a build that goes red does not. The goal: a new table with RLS off, or a policy with USING (true), fails the pull request before it can merge.
02 The gate (airlock-rls)
airlock-rls is a free CI gate that does exactly this — it checks your project for exposed tables and permissive policies and exits non-zero when it finds one.
.github/workflows/rls.yml
jobs:
rls:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Gate RLS
run: npx airlock-rls
# exits 1 if any table ships with RLS off or a permissive policy
env:
SUPABASE_DB_URL: ${{ secrets.SUPABASE_DB_URL }}
03 Or the raw SQL check
Prefer to own it? Run this against your migration database and fail if it returns any rows:
ci-check.sql
-- any public table with RLS off = fail select t.tablename from pg_tables t join pg_class c on c.relname = t.tablename where t.schemaname = 'public' and c.relrowsecurity = false union all -- any permissive policy = fail select tablename from pg_policies where schemaname = 'public' and (qual = 'true' or with_check = 'true');
Wrap it so a non-empty result exits 1. This catches the coarse failures (RLS off, permissive) — pair it with an isolation test for the behavioral proof that policies actually isolate tenants.
Catch this before it ships
airlock-rls is a CI gate that fails your build when a table ships exposed or a policy is permissive — the same class of bug, caught on the pull request instead of in prod.
Or start from nextjs-supabase-starter — auth + a table with RLS + an isolation test, so a fresh table is safe by default.
Grab the Supabase RLS cheat sheet
The golden rules, the footguns that leak in prod, correct policy snippets, and the isolation test — on one page.
FAQ
Does the gate need production credentials?
No — point it at your migration/CI database (a branch database or a local supabase start), the same schema that will ship. It checks structure (RLS flags and policies), not production data.
Is the SQL check enough on its own?
It catches the coarse failures — RLS off and permissive policies. It can't tell whether a scoped policy is actually correct; only a behavioral isolation test does that. Run both: the gate for structure, the test for behavior.