Verify the correctness of your RLS policies with the RLS tester
Important
We've decided to pause development of this feature preview while we re-evaluate its direction. A big thank you to everyone who were testing out this feature preview! 🙏🙂 Do let us know nonetheless any feedback or thoughts if any!"
Verifying the correctness of your RLS policies set up has always been a gap, as highlighted by a number of GitHub discussions like here and here. As such, we're piloting a dedicated UI for RLS testing (using role impersonation as the base), in which you'll be able to
- Run a SQL query as a user (not logged in / logged in - this is the role impersonation part)
- See which RLS policies are being evaluated as part of the query
- And hopefully be able to debug which policies are not set up correctly
- (Side note) We also added partial support for testing client library code instead of just SQL
- This is powered by the AI Assistant which will then infer the code into SQL
- e.g
const { data } = await client.from('colors').select('*') - Given that this is by AI, as always do verify the output!
Note: Only SELECT queries are supported for now to simplify things. Testing mutation queries (INSERT, UPDATE, DELETE) could trigger side effects such as triggering a database trigger, especially if it involves an external request such as an edge function or HTTP call - we're keeping them out of this preview while we work out a safe way to support them.
Changes are currently set as a feature preview which you can access by clicking on your Profile picture in the top navigation bar . We'll iterate as we get feedback from everyone so please do let us know what you think! 🙂🙏
Related PR: #45121
What we'd like to know from you
- Any bugs or issues that you might have run into while using the RLS tester
- Any ideas or suggestions that you reckon will improve the DX based on how you currently verify the correctness of your RLS policies
- Feel free to leave any feedback in this thread too! (Both good and bad!) 🙂🙏
Test crashes when I try to select an authenticated user:
- Click on
<test> - Write a valid query
- Test as anonymous. Works.
- Click on Test as: Authenticated user
- Open the select "Select which user to test as". Application crashes with:
Error: No QueryClient set, use QueryClientProvider to set one
at 0hq~gtr2cbnwx.js?dpl=dpl_9D9x4ig8vetYJtbF6fN7ZSLNXRpD:2:4638
at f (0hq~gtr2cbnwx.js?dpl=dpl_9D9x4ig8vetYJtbF6fN7ZSLNXRpD:4:18967)
at 0hq~gtr2cbnwx.js?dpl=dpl_9D9x4ig8vetYJtbF6fN7ZSLNXRpD:4:20174
at 07dtdym5ff416.js?dpl=dpl_9D9x4ig8vetYJtbF6fN7ZSLNXRpD:2:18247
at 07dtdym5ff416.js?dpl=dpl_9D9x4ig8vetYJtbF6fN7ZSLNXRpD:2:18435
at tr (09b~999wv0opm.js?dpl=dpl_9D9x4ig8vetYJtbF6fN7ZSLNXRpD:2:31018)
at ad (0i8wy8tbht2ow.js?dpl=dpl_9D9x4ig8vetYJtbF6fN7ZSLNXRpD:2:62359)
at i (0i8wy8tbht2ow.js?dpl=dpl_9D9x4ig8vetYJtbF6fN7ZSLNXRpD:2:123211)
at oD (0i8wy8tbht2ow.js?dpl=dpl_9D9x4ig8vetYJtbF6fN7ZSLNXRpD:2:102892)
at oR (0i8wy8tbht2ow.js?dpl=dpl_9D9x4ig8vetYJtbF6fN7ZSLNXRpD:2:102762)
at ox (0i8wy8tbht2ow.js?dpl=dpl_9D9x4ig8vetYJtbF6fN7ZSLNXRpD:2:99533)
at o_ (0i8wy8tbht2ow.js?dpl=dpl_9D9x4ig8vetYJtbF6fN7ZSLNXRpD:2:99922)
at r8 (0i8wy8tbht2ow.js?dpl=dpl_9D9x4ig8vetYJtbF6fN7ZSLNXRpD:2:48766)
at 0i8wy8tbht2ow.js?dpl=dpl_9D9x4ig8vetYJtbF6fN7ZSLNXRpD:2:97447
Windows 11, Chrome Version 144.0.7559.134 (Official Build) (64-bit)
1 reply
Thanks for previewing this feature couple of findings from me:
- Can't really test functions that we have defined on the database, nothing gets returned or displayed. e.g.
select try_consume_period_counter(auth.uid(), 'place_adds_used_this_period', 999); - Would be great to be able to test
UPDATEstatements (without it of course affecting the production table) - this would be the most useful feature as updates are the critical abuse pattern that others can use for a misconfigured RLS. (I understand you are looking into this)
0 replies
0 replies
Since this is paused pending a direction call, I spent some time on where I'd take it and built it out: https://ishwaryasuresh.github.io/deny-by-default/
Short version: I think the tester was the right capability in the wrong place. A separate verification surface is one you have to remember to visit, and the moment you most need it is the moment you don't know you need it, because a too-strict policy looks exactly like no data. Moving the same capability inside the policy editor, so that seeing the result is on the default path to saving, gets the value without asking anyone to change a habit.
The prototype on that page runs a real RLS interpreter over sample data (grants → role → permissive OR → restrictive AND), so you can drive it rather than take my word for it. Worth trying: set the caller to a logged-out visitor and note that it distinguishes "no policy reached you" from "a policy reached you and matched nothing". Those are opposite bugs that look identical in production, and they're the largest pattern in the 438 discussions I coded (34.2%).
On the two pieces of feedback already in this thread:
- @MoAfshar's ask for UPDATE testing looks solvable with impersonation inside a transaction that rolls back. The real exception is tables whose triggers make external calls, and those are detectable ahead of time, so the honest move is to disable the write preview on those specific tables rather than withhold write testing everywhere.
- Worth noting for scoping: per the docs, writes already fail loudly. A missing grant and a
with checkviolation both raise42501. Only ausingfilter is silent. So a write tester is arguably less urgent than a read one, which is the opposite of where I started.
Longer write-up and the coded research are in a Feature Requests thread so it's somewhere upvotable rather than buried in a comment.
0 replies