fix(supabase): drop legacy JWT-role admin write policies on subscriptions

This commit is contained in:
Yun Chan 2026-09-28 02:16:24 +09:00
parent 824ee42f1e
commit 80538c0f23
2 changed files with 293 additions and 0 deletions

View file

@ -0,0 +1,32 @@
-- Back-office writes go only through the audited service-role RPCs.
--
-- 20260413000005_add_manager_role.sql created three JWT-role write policies:
-- * subscriptions.admin_write_subscriptions FOR ALL (admin, super_admin)
-- * subscriptions.manager_update_subscriptions FOR UPDATE (manager)
-- * profiles.admin_update_profiles FOR UPDATE (admin, super_admin)
-- They key only on auth.jwt() -> app_metadata.role and restrict no columns.
-- 20260821000023_atomic_admin_management.sql moved every back-office mutation to
-- service-role RPCs (admin_mutate_subscription_v1 and friends) that validate
-- input, use an idempotency ledger and write audit_log. The admin web app and
-- the admin-* edge functions only use the service-role client, so these
-- policies serve no legitimate path.
--
-- Left in place they let any staff access token PATCH /rest/v1/subscriptions
-- directly: set tier='pro_plus' or overage_credits to an arbitrary value, or
-- copy another customer's payple_payer_id onto a row so payple-renew charges
-- the wrong card. None of that writes an audit_log row or goes through the RPC
-- whitelist and bounds checks.
--
-- The read policies (admin_read_all_*, *_read_own) and profiles_update_own are
-- kept. All subscription writers (handle_new_user, quota, payment-provider and
-- admin RPCs) are SECURITY DEFINER or run as service_role, so revoking the
-- write privileges from the client roles does not affect them.
DROP POLICY IF EXISTS admin_write_subscriptions ON public.subscriptions;
DROP POLICY IF EXISTS manager_update_subscriptions ON public.subscriptions;
DROP POLICY IF EXISTS admin_update_profiles ON public.profiles;
-- Defense in depth: without any write policy RLS already denies these rows, but
-- the client roles should not hold table-level write privileges at all. TRUNCATE
-- is included because it is not subject to RLS.
REVOKE INSERT, UPDATE, DELETE, TRUNCATE ON TABLE public.subscriptions FROM anon, authenticated;