One command produces a per-identity access report that flags a table anon can read.
Why the data matters
A generated test only proves something if its data matches the policy and the identity
Reverse-predicate seeding works from each policy to the rows that satisfy and violate it
"The owner can see their row" is checked against a row that is actually theirs
"Another tenant cannot" against a real, different tenant
Never emits a false-passing test
Runs against a local or throwaway database, never production
The report
One report per schema, dated and reproducible. Each table shows a row-level grid and a column-level security grid, side by side, so it reads like a permissions table.
Each table carries a row-level grid and a column-level security grid, side by side. Columns that a broader grant leaks past are flagged red.
Row level, a tick means the identity can act, a dot means blocked
A tick where a dot belongs is the security hole, flagged red
Column level security, the columns each role is granted and any a broader grant leaks past
A summary line counts tables, exposed tables, problems, enforced as declared, and bypass surfaces
service_role is shown for completeness; it bypasses RLS by design
A table with RLS off is flagged loud, with no row-level protection at all
Dated and reproducible, so a run stands as access-control evidence
--all-schemas writes one dashboard for the whole database, a schema picker beside each report
The two-membership user
Most suites test membership policies with users who belong to exactly one team. Real users belong to two, and that is where a class of bugs lives.
A scalar subquery keyed on auth.uid() errors the moment a user joins a second team
A LIMIT 1 "fix" silently shows one of their teams at random
An over-broad rewrite shows a user more than their memberships grant
rlsautotest seeds one identity in two tenants, probes what it sees, and pins the exact count as a test
Any later drift into those shapes turns the suite red in CI
lint flags the scalar-subquery shape statically, with the fix
Beyond the policies
Correct policies can still be undone by how the data is reached. rlsautotest maps that surface straight from the catalog and reports each object or role that can sidestep RLS.
Owner-rights (SECURITY DEFINER) views and functions a client can reach
Materialized views, a frozen owner-populated copy of their source
BYPASSRLS and superuser roles a client can become
Tables with RLS enabled but not FORCEd
Column grants a broader grant quietly widens past, named column by column
Each is a review flag with a severity and a reason, not a pass or fail
Two layers where tenant data leaks
A test at one layer says nothing about the other.
The policy layer, where Row-Level Security governs direct table access
The code layer, where SECURITY DEFINER functions, views and owner-run triggers bypass RLS by design
rlsautotest
Policy layer
Proves each RLS policy, per table, per command and per identity
Fails CI on a reachable table with no policy
Names every SECURITY DEFINER function, view and trigger as a suspect
It cannot judge the suspects; it sees that code bypasses RLS, not whether it leaks.
Start free with rlsautotest for the policies. Use seccover to cover both layers.
rlsautotest is a separate free, open-source tool for RLS policies
seccover tests the policies and the functions, views and triggers that bypass them
Get started
pip install rlsautotest
# quick check: write an access report, open it in your browser (nothing saved)
rlsautotest --db-url "$DATABASE_URL" --schema public --html rls-report.html
# or generate a pgTAP suite to commit and run in CI
rlsautotest --db-url "$DATABASE_URL" --schema public --emit supabase/
Native pgTAP: supabase test db, pg_prove or psql
Nothing to install on the database
Free and open source under Apache-2.0
Beta, validated on real Supabase schemas and a multi-tenant corpus
rlsautotest generates exactly the RLS proof PostgreSQL, Supabase and Neon tell you to have.
Supabase encourages automated pgTAP tests that RLS policies are correctly applied. rlsautotest writes them, with the seed data. Supabase, Testing your database →
Supabase documents Row Level Security as how you secure data in Postgres. rlsautotest proves each policy per identity. Supabase, Row Level Security →
Neon requires RLS on every table exposed through its Data API. rlsautotest fails CI on any table left unprotected. Neon, Row-Level Security →
PostgreSQL documents RLS policies per command and role. rlsautotest tests each, per table, command and identity. PostgreSQL, Row Security Policies →
Your privacy
We would like to log your visit to see how the site is used. That records the page, the site you came from, your IP address and browser, and a random id for this tab. We delete it once we no longer need it.