Repository navigation
test(db): cover RLS on the nine tables that had no pgTAP tests - #80
Conversation
shared_items, user_roles, admin_grants, api_keys, source_files, rate_limits, global_prompts, webhook_events and user_data_clear_markers all had row-level security enabled, but no test asserted their policies. The new tests check that: - a user cannot grant themselves admin, demote an admin, or lift their own ban; - shares can be read only through get_shared_item(code), and clients cannot read or write the table directly; - users can manage their own API keys and source files but cannot read, plant, move or delete anyone else's; - only admins read the grant log, users see only their own and global rate limits, and no client role can write grants, limits or prompts; - clients see no webhook events or clear markers and cannot write them. Denied UPDATE and DELETE statements must change zero rows, whether the table lacks the privilege or RLS filters the rows out. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
@coderabbitai full review |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Free Run ID: 📒 Files selected for processing (5)
Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review. 📝 WalkthroughWalkthroughThe pull request adds five transactional pgTAP suites. They test role-specific access, write restrictions, and seeded-record preservation for administrative tables, server-only tables, owner-scoped records, shared items, and user roles. ChangesSupabase RLS test coverage
Estimated code review effort: 3 (Moderate) | ~25 minutes
Note 🎁 Summarized by CodeRabbit FreeYour organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Essentials by visiting https://app.coderabbit.ai/settings/billing. Comment |
|
has_table_privilege returns true when the role holds any privilege in a comma-separated list. The service-role checks for shared_items, webhook_events and user_data_clear_markers still passed after INSERT, UPDATE and DELETE were revoked, as long as SELECT remained. They now require every privilege. Revoking INSERT from service_role makes both checks fail. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Notes on the first head (
|
|
@coderabbitai full review |
✅ Action performedFull review finished. |
|
Locked gate result at
CI at CodeRabbit ran a full review of all five files at |
Summary
Nine public tables had row-level security enabled, but nothing in
supabase/tests/asserted their policies. This PR adds five pgTAP files that cover them. It changes no schema, policy or application code.user_roles_rls_test.sql. A user cannot promote themselves to admin through an update or an upsert. They cannot create an admin row for themselves or for anyone else. They cannot demote or delete an admin, and a banned user cannot delete or change their ban. After these attempts,get_active_rate_limits()still rejects the user.shared_items_rls_test.sql. Clients have no direct table privileges. Anonymous and signed-in callers read a share only throughget_shared_item(code). That function matches the code exactly, skips expired shares, does not returncreated_by, and changes nothing exceptview_count.owner_scoped_tables_rls_test.sql(api_keys,source_files). A user can read, create, update and delete their own rows. They cannot read, plant, replace, reassign or delete another user's rows. Anonymous callers see nothing.admin_tables_rls_test.sql(admin_grants,rate_limits,global_prompts). Only admins can read the grant log, and grantees cannot read it either. Users see their own rate limits and the global ones, but not other users' limits. No client role, admins included, can write grants, limits or prompts, because those writes go through the admin Edge Function.server_only_tables_rls_test.sql(webhook_events,user_data_clear_markers).anonandauthenticatedhold no privileges, see zero rows, and cannot insert, update or delete.Under RLS, a denied
UPDATEorDELETEcan either raise a privilege error or match no rows. The tests count changed rows and treat a privilege error as zero, so they still pass if a later migration revokes a grant.Differences from the task description
shared_itemsas "public read only through the share code, owner-only write". Since20260819000000_security_hardening.sql, owners cannot write shares directly. Only theshareEdge Function writes them, using the service role. The tests assert that current model.api_keysandsource_filesare owner-scoped CRUD tables, not deny-all, so their tests check owner isolation.Open findings, not fixed here
global_prompts_select_allletsanonand every signed-in user read every global system prompt. Only Edge Functions read this table. The tests leave reads unasserted so they don't lock this behavior in.rate_limits_select_ownalso exposes global rows (user_id IS NULL) toanon.anonandauthenticatedholdTRUNCATE,TRIGGERandREFERENCESonuser_roles,admin_grants,rate_limits,global_prompts,api_keysandsource_files, from Supabase's default privileges. RLS does not apply toTRUNCATE. PostgREST does not expose it, so clients cannot reach it today. I did not check production grants.Verification
npm run docs:checkpasses../.superset/db-gate.sh: see the comment below for the locked gate result at this head.🤖 Generated with Claude Code
Summary by CodeRabbit