-- 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;