From 3d6d498892243cdc047dbc13f2b4d31ec1591b70 Mon Sep 17 00:00:00 2001 From: Jesse_Chen Date: Sat, 18 Jul 2026 22:34:58 +0800 Subject: [PATCH] fix: grant account upsert read columns --- ...les_service_role_account_upsert_selects.sql | 9 +++++++++ frontend/tests/profile-persistence.test.ts | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 frontend/supabase/migrations/20260718080000_profiles_service_role_account_upsert_selects.sql diff --git a/frontend/supabase/migrations/20260718080000_profiles_service_role_account_upsert_selects.sql b/frontend/supabase/migrations/20260718080000_profiles_service_role_account_upsert_selects.sql new file mode 100644 index 00000000..b84d4994 --- /dev/null +++ b/frontend/supabase/migrations/20260718080000_profiles_service_role_account_upsert_selects.sql @@ -0,0 +1,9 @@ +begin; + +-- Existing-row upserts must read every submitted column to resolve the result. +grant select ( + district_code, + updated_at +) on table public.profiles to service_role; + +commit; diff --git a/frontend/tests/profile-persistence.test.ts b/frontend/tests/profile-persistence.test.ts index 6694a689..8fbd5007 100644 --- a/frontend/tests/profile-persistence.test.ts +++ b/frontend/tests/profile-persistence.test.ts @@ -19,3 +19,21 @@ test("account route can fall back when coordinate columns are not deployed", () assert.match(source, /withoutCoordinates/); assert.match(source, /PGRST204|42703|schema cache|column/i); }); + +test("service role can read every column used by account profile upserts", () => { + // Given: the least-privilege grant omitted two columns submitted by /api/account. + const migration = readFileSync( + new URL( + "../supabase/migrations/20260718080000_profiles_service_role_account_upsert_selects.sql", + import.meta.url, + ), + "utf8", + ); + + // When: the corrective migration defines the account-upsert read grant. + // Then: PostgREST can read both submitted columns while resolving existing rows. + assert.match( + migration, + /grant\s+select\s*\(\s*district_code\s*,\s*updated_at\s*\)\s*on\s+table\s+public\.profiles\s+to\s+service_role/is, + ); +});