perf(rls): wrap auth.uid()/current_setting() in (select …) for per-statement evaluation - #3121
perf(rls): wrap auth.uid()/current_setting() in (select …) for per-statement evaluation#3121dmitrymaranik wants to merge 2 commits into
Conversation
|
@dmitrymaranik is attempting to deploy a commit to the Onlook Team on Vercel. A member of the Team first needs to authorize it. |
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
📝 WalkthroughWalkthroughA new Supabase migration rewrites RLS policies on storage and public tables by replacing direct ChangesRLS InitPlan Performance Migration
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
apps/backend/supabase/migrations/0020_wrap_rls_perf_initplan.sql (1)
8-9: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winWrap the
auth.uid()inside theEXISTStoo. Line 9 still callsauth.uid()directly in the correlated subquery (WHERE users.id = auth.uid()), so that part can still be evaluated per row. Change it to(SELECT auth.uid())as well for the same InitPlan caching used elsewhere here.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/backend/supabase/migrations/0020_wrap_rls_perf_initplan.sql` around lines 8 - 9, The project_invitations_delete_policy still calls auth.uid() directly inside the correlated EXISTS subquery, so update that predicate to use the same InitPlan-wrapped form as the rest of the policy. In the ALTER POLICY statement for project_invitations_delete_policy, change the users.id comparison inside the EXISTS clause to compare against (SELECT auth.uid()) instead of auth.uid(), keeping the rest of the USING expression unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/backend/supabase/migrations/0020_wrap_rls_perf_initplan.sql`:
- Around line 1-72: The migration is missing the same InitPlan optimization for
the project_invitations read/update policies. Update the ALTER POLICY statements
for project_invitations_select_policy and project_invitations_update_policy to
wrap auth.uid() in a (select ...) just like the other PERF001 fixes, including
inside the auth.users subquery, so the predicates stay equivalent while enabling
statement-level caching.
---
Nitpick comments:
In `@apps/backend/supabase/migrations/0020_wrap_rls_perf_initplan.sql`:
- Around line 8-9: The project_invitations_delete_policy still calls auth.uid()
directly inside the correlated EXISTS subquery, so update that predicate to use
the same InitPlan-wrapped form as the rest of the policy. In the ALTER POLICY
statement for project_invitations_delete_policy, change the users.id comparison
inside the EXISTS clause to compare against (SELECT auth.uid()) instead of
auth.uid(), keeping the rest of the USING expression unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b2d84b8c-3a35-444f-aca4-5de6a54af4cc
📒 Files selected for processing (1)
apps/backend/supabase/migrations/0020_wrap_rls_perf_initplan.sql
|
Good catch — you're right that the EXISTS-nested |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
apps/backend/supabase/migrations/0020_wrap_rls_perf_initplan.sql (1)
41-45: 🚀 Performance & Scalability | 🔵 TrivialInitPlan benefit is partially negated by
user_has_project_access, which still calls bareauth.uid()per row.The direct
(select auth.uid())wrapping here is correct, but theseORbranches also calluser_has_project_access(...), aSECURITY DEFINERplpgsql function defined in0006_rls.sqlthat invokesauth.uid()once per call — and the function is evaluated per row. So PERF001 on the policy predicate is resolved, but the per-rowauth.uid()cost remains inside the helper. If the perf goal is end-to-end, consider stabilizing the function (e.g. passing the uid in, or wrapping its internal lookup) in a follow-up. Out of scope for this migration.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/backend/supabase/migrations/0020_wrap_rls_perf_initplan.sql` around lines 41 - 45, The policy changes correctly wrap auth.uid() in an InitPlan, but user_has_project_access still evaluates a bare auth.uid() per row inside the SECURITY DEFINER helper defined in 0006_rls.sql. To complete the perf improvement, update user_has_project_access to avoid calling auth.uid() internally on every invocation, for example by passing the caller uid into the function or by caching the lookup once inside the function, and then keep the user_projects_delete_policy and user_projects_select_policy predicates using that stabilized helper.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@apps/backend/supabase/migrations/0020_wrap_rls_perf_initplan.sql`:
- Around line 41-45: The policy changes correctly wrap auth.uid() in an
InitPlan, but user_has_project_access still evaluates a bare auth.uid() per row
inside the SECURITY DEFINER helper defined in 0006_rls.sql. To complete the perf
improvement, update user_has_project_access to avoid calling auth.uid()
internally on every invocation, for example by passing the caller uid into the
function or by caching the lookup once inside the function, and then keep the
user_projects_delete_policy and user_projects_select_policy predicates using
that stabilized helper.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 23b9a0d8-2c99-4394-9a75-e617e6035349
📒 Files selected for processing (1)
apps/backend/supabase/migrations/0020_wrap_rls_perf_initplan.sql
|
Good catch, and agreed it's out of scope for this migration (as the bot notes). This change wraps the policy predicates' direct The |
Postgres re-evaluates a bare
auth.uid()/current_setting(…)in an RLS policy once per row. Wrapping it in a scalar subquery —(select auth.uid())— makes it an InitPlan the planner evaluates once per statement and caches. It's predicate-equivalent (row visibility unchanged) and the optimization Supabase documents for RLS.This adds a migration that wraps the 16 affected per-user policies:
USINGandWITH CHECK(the write path runs per inserted/updated row too).pgrls fix --rule PERF001output, added as a new migration (0020_wrap_rls_perf_initplan.sql).Happy to adjust the migration filename/placement to your conventions.
Summary by CodeRabbit