fix(db): speed up usage credit ledger RLS#2074
Conversation
📝 WalkthroughWalkthroughThis PR adds ChangesUsage Credit RLS Performance Optimization
Sequence Diagram(s)sequenceDiagram
participant Client
participant RLS_Policy
participant Helper
participant Table
Client->>RLS_Policy: SELECT usage_credit rows
RLS_Policy->>Helper: usage_credit_readable_org_ids()
Helper-->>RLS_Policy: uuid[] of allowed org_ids
RLS_Policy->>Table: check row.org_id IN uuid[]
Table-->>Client: return authorized rows
🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4d5cab9436
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| IF v_user_id IS NULL THEN | ||
| SELECT public.get_apikey_header() INTO v_api_key_text; |
There was a problem hiding this comment.
Preserve API-key RBAC access in mixed-auth requests
usage_credit_readable_org_ids() only parses capgkey inside IF v_user_id IS NULL, so when a request has both a JWT and an API key, v_api_key remains null and API-key principals are never added to candidate_orgs. The previous policy path still let check_min_rights(...) evaluate API-key RBAC bindings even with an authenticated user, so this change can newly deny usage-credit rows for clients that rely on API-key-only org permissions while also sending a user session token.
Useful? React with 👍 / 👎.
4d5cab9 to
c1ff285
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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 `@supabase/migrations/20260507165636_fast_usage_credit_rls_policies.sql`:
- Around line 125-175: Add explicit deny policies for INSERT, UPDATE, and DELETE
on each of the four tables (usage_overage_events, usage_credit_consumptions,
usage_credit_grants, usage_credit_transactions) instead of relying on implicit
deny: for each table create policies named e.g. "Deny insert for org members",
"Deny update for org members", and "Deny delete for org members" using the
pattern AS RESTRICTIVE FOR INSERT/UPDATE/DELETE TO "anon", "authenticated" WITH
CHECK (false) so anon/authenticated roles are explicitly forbidden from writing
to those tables.
- Around line 33-45: The issue is that for RBAC-only API keys (where
v_api_key.mode is NULL), v_check_user_id remains NULL due to the condition in
the assignment, causing access checks to fail downstream. To fix it, modify the
condition that assigns v_check_user_id so that it also sets v_check_user_id to
v_user_id when v_api_key.mode is NULL, thus passing the RBAC API key's user ID
through to the permission checks like in the legacy mode. This ensures RBAC-only
API keys have their user ID correctly used in the check_min_rights call.
🪄 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: c038df2d-d3b2-4938-9703-5b00d1759768
📒 Files selected for processing (2)
supabase/migrations/20260507165636_fast_usage_credit_rls_policies.sqlsupabase/tests/54_test_usage_credit_rls_performance.sql
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@supabase/tests/54_test_usage_credit_rls_performance.sql`:
- Around line 53-70: The current assertion only checks that pg_policies.qual
mentions usage_credit_readable_org_ids, which would allow a direct per-row call;
update the check on pg_policies.qual to enforce the initPlan/subselect form.
Modify the WHERE clause that references pg_policies.qual to require a pattern
that includes a subselect wrapping the helper (e.g. qual LIKE
'%(SELECT%usage_credit_readable_org_ids%') or use a regex match to ensure the
policy contains a SELECT subquery calling usage_credit_readable_org_ids, so the
test only passes when the initPlan-style readable-org helper is used.
🪄 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: 0e42731a-7556-477e-90d0-3e5b19fc3b43
📒 Files selected for processing (2)
supabase/migrations/20260507165636_fast_usage_credit_rls_policies.sqlsupabase/tests/54_test_usage_credit_rls_performance.sql
✅ Files skipped from review due to trivial changes (1)
- supabase/migrations/20260507165636_fast_usage_credit_rls_policies.sql
|



Summary (AI generated)
usage_overage_events,usage_credit_consumptions,usage_credit_grants, andusage_credit_transactionssousage_credit_ledgerno longer runs expensive per-row identity resolution.get_identity_org_allowed()checks.Motivation (AI generated)
Production CPU stayed elevated after the bundle-list fix because
usage_credit_ledgerqueries were still spending about 1.2-1.5 seconds in RLS checks. The slow path started around the same incident window and came from per-row permission checks on usage-credit base tables, not from new ledger data volume.Business Impact (AI generated)
This reduces database CPU on billing/usage-credit ledger reads while keeping access gated by Capgo's existing legacy/RBAC, 2FA, password-policy, API-key expiration, and API-key org-scope checks. It protects the console from another expensive RLS scan without weakening billing-data access.
Test Plan (AI generated)
bun lintbun lint:backendbun run cli:build && vue-tsc --noEmitPGSSLMODE=disable bunx supabase test db supabase/tests/54_test_usage_credit_rls_performance.sql --db-url postgresql://postgres:postgres@127.0.0.1:56882/postgresusage_credit_ledgerpurchase query drops to about 110 ms from about 1.2-1.5 sGenerated with AI
Summary by CodeRabbit
Security
Tests