fix: enable RLS with deny-all policy on all public tables#145
Open
bmersereau wants to merge 3 commits into
Open
fix: enable RLS with deny-all policy on all public tables#145bmersereau wants to merge 3 commits into
bmersereau wants to merge 3 commits into
Conversation
- Add event trigger enforce_rls_on_public_tables so any future CREATE TABLE in public automatically gets RLS + deny-all policy. SECURITY DEFINER, covers both regular and partitioned tables (relkind 'r','p'). - Add 20260516_enable_rls_deny_all.down.sql rollback that drops the policy, function, event trigger, and disables RLS. - Tighten verify-rls.sql: also assert with_check (write wall), accept both 'false' and '(false)' for Postgres-rendering tolerance, cleaner pg_class join through pg_namespace. - Document the convention in CONTRIBUTING.md: Database Migrations section with rollback expectation, RLS policy expectation, and verify-rls command.
Author
|
Updated based on self-review (commit ea8a44b). Five changes:
Rollback migration —
Event trigger —
Suggested staging-side verification step added to the rollout list
Pre-existing items not addressed in this PR (intentional, out of scope):
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds Row Level Security as a defense-in-depth second wall against accidental
GRANTstatements on application tables.DO $$ ... END$$block tobackend/schema.sqlthat, for everypublicbase table, runsALTER TABLE ... ENABLE ROW LEVEL SECURITYand creates adeny_client_access_<tbl>policy withUSING (false) WITH CHECK (false)foranon, authenticated.backend/migrations/20260516_enable_rls_deny_all.sqlso existing deployments can apply it incrementally (matches the convention from prior migration commits).backend/scripts/verify-rls.sql— a psql-runnable assertion script that fails non-zero if any public table is missing RLS or the deny-all policy.Closes #144
Changes
backend/schema.sqlbackend/migrations/20260516_enable_rls_deny_all.sqlbackend/scripts/verify-rls.sqlWhy this matters
The current authorization model is a single
REVOKE ALL ... FROM anon, authenticatedblock. One accidentalGRANT SELECT ON public.documents TO authenticatedin a future migration, hotfix, or Supabase dashboard click undoes it for that table with zero pushback. RLS with ausing (false)deny-all policy is a second wall: even if a grant lands, the policy still blocks the row.The service role bypasses RLS, so the backend (
createServerSupabase()usesSUPABASE_SECRET_KEY) is unaffected.Test plan
tscbuild passes locally.if not existsguard on policy creation;enable row level securityis naturally idempotent).backend/scripts/verify-rls.sqlruns cleanly against the post-migration schema. On a database without the migration it raisesverify-rls: N assertion(s) failed.from('documents').select('*')returns no rows (or fails) — confirming the second wall.Notes for reviewers
eslintandnext buildfailures on this branch reproduce identically onorigin/main— they are pre-existing tooling debt (missing build-time env vars, accumulated lint errors), not regressions from this PR. Backendtscis the only gate that applies to a SQL-only change and it is clean.npm auditreports unrelated high/moderate transitive CVEs (@xmldom/xmldom,protobufjs,postcss) — out of scope here; tracked in this codebase's security audit.