d3ro-voice/server/supabase/tests/drop-legacy-admin-write-policies.integration.sql

261 lines
9.4 KiB
PL/PgSQL

\set ON_ERROR_STOP on
-- Regression: staff access tokens must not write subscriptions or other users'
-- profiles directly through PostgREST. Back-office mutations go only through the
-- audited service-role RPCs (admin_mutate_subscription_v1 and friends).
-- Before 20260929000006 the JWT-role policies admin_write_subscriptions,
-- manager_update_subscriptions and admin_update_profiles let a manager copy
-- another customer's payple_payer_id onto a row (so payple-renew charged the
-- wrong card) or raise tier/overage_credits with no audit_log row.
BEGIN;
INSERT INTO auth.users (
id, aud, role, email, encrypted_password, email_confirmed_at,
raw_app_meta_data, raw_user_meta_data, created_at, updated_at
) VALUES
(
'42600000-0000-4000-8000-000000000001', 'authenticated', 'authenticated',
'legacy-policy-manager@example.invalid', crypt('fixture-password', gen_salt('bf')), now(),
'{"provider":"email","providers":["email"],"role":"manager"}'::jsonb, '{}'::jsonb, now(), now()
),
(
'42600000-0000-4000-8000-000000000002', 'authenticated', 'authenticated',
'legacy-policy-admin@example.invalid', crypt('fixture-password', gen_salt('bf')), now(),
'{"provider":"email","providers":["email"],"role":"admin"}'::jsonb, '{}'::jsonb, now(), now()
),
(
'42600000-0000-4000-8000-000000000003', 'authenticated', 'authenticated',
'legacy-policy-payer@example.invalid', crypt('fixture-password', gen_salt('bf')), now(),
'{"provider":"email","providers":["email"]}'::jsonb, '{}'::jsonb, now(), now()
),
(
'42600000-0000-4000-8000-000000000004', 'authenticated', 'authenticated',
'legacy-policy-target@example.invalid', crypt('fixture-password', gen_salt('bf')), now(),
'{"provider":"email","providers":["email"]}'::jsonb, '{}'::jsonb, now(), now()
),
(
'42600000-0000-4000-8000-000000000005', 'authenticated', 'authenticated',
'legacy-policy-unsubscribed@example.invalid', crypt('fixture-password', gen_salt('bf')), now(),
'{"provider":"email","providers":["email"]}'::jsonb, '{}'::jsonb, now(), now()
);
UPDATE public.profiles SET role = 'manager' WHERE id = '42600000-0000-4000-8000-000000000001';
UPDATE public.profiles SET role = 'admin' WHERE id = '42600000-0000-4000-8000-000000000002';
UPDATE public.profiles SET name = 'Original Target' WHERE id = '42600000-0000-4000-8000-000000000004';
INSERT INTO public.subscriptions (user_id, tier, status, provider, payment_provider)
VALUES
('42600000-0000-4000-8000-000000000003', 'free', 'active', 'none', 'none'),
('42600000-0000-4000-8000-000000000004', 'free', 'active', 'none', 'none')
ON CONFLICT (user_id) DO NOTHING;
UPDATE public.subscriptions
SET payple_payer_id = 'legacy-policy-victim-payer',
overage_credits = 0
WHERE user_id = '42600000-0000-4000-8000-000000000003';
UPDATE public.subscriptions
SET tier = 'free', status = 'active', payple_payer_id = NULL, overage_credits = 0
WHERE user_id = '42600000-0000-4000-8000-000000000004';
DELETE FROM public.subscriptions WHERE user_id = '42600000-0000-4000-8000-000000000005';
-- Catalog: only read policies remain on subscriptions, and the client roles hold
-- no table-level write privilege on it.
DO $$
DECLARE
v_policy text;
BEGIN
SELECT string_agg(policyname || ':' || cmd, ', ') INTO v_policy
FROM pg_policies
WHERE schemaname = 'public' AND tablename = 'subscriptions' AND cmd <> 'SELECT';
IF v_policy IS NOT NULL THEN
RAISE EXCEPTION 'assertion_failed: write policies remain on subscriptions: %', v_policy;
END IF;
IF EXISTS (
SELECT 1 FROM pg_policies
WHERE schemaname = 'public' AND tablename = 'profiles' AND policyname = 'admin_update_profiles'
) THEN
RAISE EXCEPTION 'assertion_failed: admin_update_profiles still exists';
END IF;
IF has_table_privilege('authenticated', 'public.subscriptions', 'INSERT')
OR has_table_privilege('authenticated', 'public.subscriptions', 'UPDATE')
OR has_table_privilege('authenticated', 'public.subscriptions', 'DELETE')
OR has_table_privilege('authenticated', 'public.subscriptions', 'TRUNCATE')
OR has_table_privilege('anon', 'public.subscriptions', 'UPDATE') THEN
RAISE EXCEPTION 'assertion_failed: client roles still hold write privileges on subscriptions';
END IF;
END;
$$;
-- Manager token: may read every subscription, may not write any.
SET LOCAL ROLE authenticated;
SELECT set_config('request.jwt.claim.sub', '42600000-0000-4000-8000-000000000001', true);
SELECT set_config(
'request.jwt.claims',
'{"sub":"42600000-0000-4000-8000-000000000001","role":"authenticated","app_metadata":{"role":"manager"}}',
true
);
DO $$
DECLARE
v_rows integer;
v_payer text;
BEGIN
SELECT payple_payer_id INTO v_payer
FROM public.subscriptions WHERE user_id = '42600000-0000-4000-8000-000000000003';
IF v_payer IS DISTINCT FROM 'legacy-policy-victim-payer' THEN
RAISE EXCEPTION 'assertion_failed: manager lost read access to subscriptions (got %)', v_payer;
END IF;
BEGIN
UPDATE public.subscriptions
SET payple_payer_id = v_payer, tier = 'pro_plus', overage_credits = 1000000
WHERE user_id = '42600000-0000-4000-8000-000000000004';
GET DIAGNOSTICS v_rows = ROW_COUNT;
IF v_rows <> 0 THEN
RAISE EXCEPTION 'assertion_failed: manager direct UPDATE changed % subscription row(s)', v_rows;
END IF;
EXCEPTION WHEN insufficient_privilege THEN
NULL;
END;
END;
$$;
-- Admin token: no direct UPDATE, INSERT or DELETE on subscriptions, and no
-- UPDATE of another user's profile.
SELECT set_config('request.jwt.claim.sub', '42600000-0000-4000-8000-000000000002', true);
SELECT set_config(
'request.jwt.claims',
'{"sub":"42600000-0000-4000-8000-000000000002","role":"authenticated","app_metadata":{"role":"admin"}}',
true
);
DO $$
DECLARE
v_rows integer;
BEGIN
BEGIN
UPDATE public.subscriptions
SET tier = 'pro_plus', overage_credits = 1000000
WHERE user_id = '42600000-0000-4000-8000-000000000004';
GET DIAGNOSTICS v_rows = ROW_COUNT;
IF v_rows <> 0 THEN
RAISE EXCEPTION 'assertion_failed: admin direct UPDATE changed % subscription row(s)', v_rows;
END IF;
EXCEPTION WHEN insufficient_privilege THEN
NULL;
END;
BEGIN
DELETE FROM public.subscriptions WHERE user_id = '42600000-0000-4000-8000-000000000004';
GET DIAGNOSTICS v_rows = ROW_COUNT;
IF v_rows <> 0 THEN
RAISE EXCEPTION 'assertion_failed: admin direct DELETE removed % subscription row(s)', v_rows;
END IF;
EXCEPTION WHEN insufficient_privilege THEN
NULL;
END;
BEGIN
INSERT INTO public.subscriptions (user_id, tier, status, provider, payment_provider)
VALUES ('42600000-0000-4000-8000-000000000005', 'pro_plus', 'active', 'none', 'none');
RAISE EXCEPTION 'assertion_failed: admin direct INSERT created a subscription row';
EXCEPTION WHEN insufficient_privilege THEN
NULL;
END;
BEGIN
UPDATE public.profiles
SET name = 'Renamed By Admin'
WHERE id = '42600000-0000-4000-8000-000000000004';
GET DIAGNOSTICS v_rows = ROW_COUNT;
IF v_rows <> 0 THEN
RAISE EXCEPTION 'assertion_failed: admin direct UPDATE changed % other profile row(s)', v_rows;
END IF;
EXCEPTION WHEN insufficient_privilege THEN
NULL;
END;
END;
$$;
-- Ordinary user token: own-profile edits (profiles_update_own) still work.
SELECT set_config('request.jwt.claim.sub', '42600000-0000-4000-8000-000000000004', true);
SELECT set_config(
'request.jwt.claims',
'{"sub":"42600000-0000-4000-8000-000000000004","role":"authenticated","app_metadata":{}}',
true
);
DO $$
DECLARE
v_rows integer;
BEGIN
UPDATE public.profiles SET name = 'Self Renamed' WHERE id = '42600000-0000-4000-8000-000000000004';
GET DIAGNOSTICS v_rows = ROW_COUNT;
IF v_rows <> 1 THEN
RAISE EXCEPTION 'assertion_failed: user could not update own profile (% rows)', v_rows;
END IF;
IF NOT EXISTS (
SELECT 1 FROM public.subscriptions WHERE user_id = '42600000-0000-4000-8000-000000000004'
) THEN
RAISE EXCEPTION 'assertion_failed: user lost read access to own subscription';
END IF;
END;
$$;
RESET ROLE;
-- The service-role client (edge functions, payple-renew) still writes directly.
SET LOCAL ROLE service_role;
DO $$
DECLARE
v_rows integer;
BEGIN
UPDATE public.subscriptions
SET admin_note = 'service-role write'
WHERE user_id = '42600000-0000-4000-8000-000000000004';
GET DIAGNOSTICS v_rows = ROW_COUNT;
IF v_rows <> 1 THEN
RAISE EXCEPTION 'assertion_failed: service_role direct UPDATE changed % rows', v_rows;
END IF;
END;
$$;
RESET ROLE;
-- Nothing the staff tokens attempted reached the rows.
DO $$
DECLARE
v_row public.subscriptions%ROWTYPE;
BEGIN
SELECT * INTO v_row FROM public.subscriptions WHERE user_id = '42600000-0000-4000-8000-000000000004';
IF v_row.user_id IS NULL THEN
RAISE EXCEPTION 'assertion_failed: target subscription was deleted';
END IF;
IF v_row.tier <> 'free'
OR v_row.overage_credits <> 0
OR v_row.payple_payer_id IS NOT NULL THEN
RAISE EXCEPTION 'assertion_failed: target subscription changed: %/%/%',
v_row.tier, v_row.overage_credits, v_row.payple_payer_id;
END IF;
IF EXISTS (
SELECT 1 FROM public.subscriptions WHERE user_id = '42600000-0000-4000-8000-000000000005'
) THEN
RAISE EXCEPTION 'assertion_failed: admin INSERT created a subscription';
END IF;
IF (SELECT name FROM public.profiles WHERE id = '42600000-0000-4000-8000-000000000004')
IS DISTINCT FROM 'Self Renamed' THEN
RAISE EXCEPTION 'assertion_failed: target profile name unexpected';
END IF;
END;
$$;
ROLLBACK;