Home / RLS / RLS in CI: fail the build

Supabase RLS · CI

RLS in CI: fail the build when a table ships exposed

GitHub Actions · Postgres✓ code tested against a real database
TL;DR

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.

◆ FREE · MIT · npm + GitHub Action

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.

npx airlock-rls

Or start from nextjs-supabase-starter — auth + a table with RLS + an isolation test, so a fresh table is safe by default.

FREE PDF

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.