diff --git a/supabase/migrations/20260927000000_grant_table_privileges.sql b/supabase/migrations/20260927000000_grant_table_privileges.sql new file mode 100644 index 0000000..340740a --- /dev/null +++ b/supabase/migrations/20260927000000_grant_table_privileges.sql @@ -0,0 +1,31 @@ +-- Fixes a production-only bug: every table in this schema was created with +-- RLS policies but no Postgres-level GRANTs, which local self-hosted +-- Supabase's Docker bootstrap happens to pre-grant broadly on the `public` +-- schema — masking the gap in every local dev/test session so far — but a +-- fresh Supabase Cloud project does not. Confirmed against Supabase's own +-- docs (supabase.com/docs/guides/auth/managing-user-data): RLS policies +-- only ever narrow access an underlying GRANT already allows; with no +-- GRANT, every request from the `anon`/`authenticated` roles fails at the +-- Postgres level before RLS is even evaluated ("permission denied for +-- table ..."), regardless of how permissive the policy is. First surfaced +-- as CompleteProfileScreen's username-save failing after Google sign-in on +-- app.diagrav.com. +-- +-- `authenticated`/`service_role` get full CRUD per table — RLS (already +-- written and unchanged by this migration) is what actually narrows each +-- operation to the right rows. `anon` gets SELECT only, matching Supabase's +-- own least-privilege example; nothing in this app reads `public` schema +-- tables before sign-in today, but it's a harmless, RLS-gated default to +-- have in place rather than an under-grant that surfaces as another opaque +-- "permission denied" later. +-- +-- The `alter default privileges` statements make this automatic for tables +-- any future migration creates, so this class of bug can't recur. + +grant usage on schema public to anon, authenticated, service_role; + +grant select on all tables in schema public to anon; +grant select, insert, update, delete on all tables in schema public to authenticated, service_role; + +alter default privileges in schema public grant select on tables to anon; +alter default privileges in schema public grant select, insert, update, delete on tables to authenticated, service_role;