diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index f322fcd1..d85ee659 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -129,18 +129,17 @@ jobs: psql "$DB_URL" -v ON_ERROR_STOP=1 -f "$m" >/dev/null 2>&1 \ || echo "::warning::migration returned a non-zero status (already applied?): $m" done - # 3) schema.sql revokes client grants (anon/authenticated) on purpose, but - # assumes a HOSTED Supabase where service_role already holds full table - # access. On a fresh CLI stack loaded via psql, service_role gets no grants - # on the new public tables, so the backend — which queries exclusively as - # service_role (lib/supabase.ts) — 500s with "permission denied for table - # user_profiles" on the first write. Grant AFTER migrations so the tables - # they add are covered too. + # 3) schema.sql now grants service_role its narrowed data privileges + # itself, but those GRANT ... ON ALL statements only cover tables that + # exist when schema.sql runs — tables created by the migrations above + # are not covered, and the backend (which queries exclusively as + # service_role, lib/supabase.ts) 500s with "permission denied" on them. + # Re-grant AFTER migrations with the SAME privilege set as schema.sql — + # deliberately not ALL, so e2e cannot pass on a privilege prod lacks. psql "$DB_URL" -v ON_ERROR_STOP=1 <<'SQL' GRANT USAGE ON SCHEMA public TO service_role; - GRANT ALL ON ALL TABLES IN SCHEMA public TO service_role; - GRANT ALL ON ALL SEQUENCES IN SCHEMA public TO service_role; - GRANT ALL ON ALL FUNCTIONS IN SCHEMA public TO service_role; + GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO service_role; + GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO service_role; SQL # 4) PostgREST cached its schema when `supabase start` booted it (before # the DDL above). Tell it to reload so the new tables/grants are visible. diff --git a/docs/e2e-ci.md b/docs/e2e-ci.md index ed6f60a9..bb2ab934 100644 --- a/docs/e2e-ci.md +++ b/docs/e2e-ci.md @@ -17,10 +17,11 @@ and on manual `workflow_dispatch`, the `e2e / playwright` job: `backend/schema.sql`, then applies every dated migration in `backend/migrations/` on top. `schema.sql` is meant to be the latest shape but in practice lags the migrations (e.g. it is missing `workflow_open_source_submissions`, which - `GET /workflows/:id` queries — a 500 without the migrations). It also grants - `service_role` full access to the `public` tables afterward, because - `schema.sql` revokes client grants assuming a hosted Supabase where - `service_role` is already privileged; + `GET /workflows/:id` queries — a 500 without the migrations). After the + migrations it re-grants `service_role` the same narrowed data privileges + `schema.sql` grants (`SELECT/INSERT/UPDATE/DELETE` on tables, `USAGE/SELECT` + on sequences): the schema's own `GRANT ... ON ALL` statements only cover + tables that existed when the schema loaded, not ones the migrations create; 4. writes `backend/.env` and `frontend/.env.local` from the live Supabase values; 5. **builds** the web app (`next build`) and serves it with `next start` — a production build, not `next dev`, so there is no on-demand compilation (which diff --git a/scripts/e2e-local-stack.sh b/scripts/e2e-local-stack.sh index 19bdcbb7..ba767d4f 100755 --- a/scripts/e2e-local-stack.sh +++ b/scripts/e2e-local-stack.sh @@ -2,10 +2,10 @@ # Boot the full local e2e stack and run the Playwright suite. # # Local-machine mirror of .github/workflows/e2e.yml: starts the Supabase CLI -# stack (Docker), loads backend/schema.sql + backend/migrations/ + the -# service_role grants (schema.sql assumes a hosted project where service_role -# is already privileged — see docs/e2e-ci.md), points backend/.env and -# frontend/.env.local at the local stack, then runs `npx playwright test`. +# stack (Docker), loads backend/schema.sql + backend/migrations/ (re-granting +# service_role's narrowed privileges afterwards for migration-created tables — +# see docs/e2e-ci.md), points backend/.env and frontend/.env.local at the +# local stack, then runs `npx playwright test`. # # Usage, from the repo root: # npm run test:e2e:local # whole suite @@ -62,11 +62,12 @@ for m in migrations/*.sql; do psql "$DB_URL" -q -f "$m" >/dev/null 2>&1 || echo "warning: migration returned non-zero (already applied?): $m" done +# schema.sql grants these itself, but only for tables that existed when it +# ran — re-grant after migrations, with the same narrowed set (not ALL). psql "$DB_URL" -v ON_ERROR_STOP=1 -q <<'SQL' GRANT USAGE ON SCHEMA public TO service_role; -GRANT ALL ON ALL TABLES IN SCHEMA public TO service_role; -GRANT ALL ON ALL SEQUENCES IN SCHEMA public TO service_role; -GRANT ALL ON ALL FUNCTIONS IN SCHEMA public TO service_role; +GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO service_role; +GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO service_role; NOTIFY pgrst, 'reload schema'; SQL