A wrong RLS policy doesn't throw an error, it just returns the wrong rows, so it ships untested and you find out when data leaks. rlsautotest generates the pgTAP tests and the seed data straight from your policies, so you can catch it. Free and open-source.
The problem: RLS fails quietly
Row-Level Security is what keeps one tenant's data from another's.
When it's wrong, it doesn't error. It returns the wrong rows.
- Too strict → empty results → your app looks broken.
- Too loose → rows the user shouldn't see → your app leaks.
Neither raises an exception. You find out from a confused user, or a security report.
And "it works in the SQL editor" proves nothing. The SQL editor bypasses RLS, so your policies were never exercised.
Why nobody tests it
Supabase's own docs admit writing pgTAP tests for RLS is "inaccessible to most web developers."
To test one policy by hand you have to:
- create a few users (owner, other user, anon, role-holder)
- insert rows owned by different users
- become each identity (set JWT claims + role)
- run SELECT / INSERT / UPDATE / DELETE as each
- assert exactly which rows each can and can't touch
Per table. Per policy.
And the seed data matters as much as the test. Assert "the owner sees their row" against an empty table and it passes while proving nothing.
Most teams take one look and skip it. So the actual security boundary ships untested.
What a real RLS test checks
From each identity's point of view:
owner → sees and changes their own row
other user / tenant → can't see it at all
anon **→ blocked
**role-holder → exactly the access the role grants
All against a row really owned by the identity under test.
And "denied" has two flavors a good test keeps apart:
row-level filtering → zero rows
missing grant → permission error
That's a lot of careful setup, for every policy.
Generate it instead
I got tired of doing this by hand, so I built rlsautotest **(open-source, Apache-2.0).
**Repo:
SOCIAL SHARE CARD GENERATOR