Fix runway chart collapse and ops cleanup
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
-- PolyWeather production remediation from Supabase MCP diagnostics.
|
||||
-- Intended for Supabase SQL Editor or a privileged database session.
|
||||
-- The Supabase MCP session available to Codex was read-only, so this file
|
||||
-- contains the exact write-side changes to run with project write access.
|
||||
|
||||
-- 1) Restrict SECURITY DEFINER functions from public RPC execution.
|
||||
-- These functions are used as event/row triggers and should not be callable
|
||||
-- directly by anon/authenticated clients unless intentionally exposed.
|
||||
revoke execute on function public.rls_auto_enable() from public, anon, authenticated;
|
||||
revoke execute on function public.sync_profile_from_auth() from public, anon, authenticated;
|
||||
|
||||
-- 2) Remove broad direct public-table privileges from client roles.
|
||||
-- RLS currently blocks row access because no policies exist, but these grants
|
||||
-- create a large blast radius if a permissive policy is added later.
|
||||
revoke all privileges on all tables in schema public from anon, authenticated;
|
||||
revoke all privileges on all sequences in schema public from anon, authenticated;
|
||||
|
||||
-- Keep future objects created by this role from inheriting broad access.
|
||||
alter default privileges in schema public revoke all on tables from anon, authenticated;
|
||||
alter default privileges in schema public revoke all on sequences from anon, authenticated;
|
||||
|
||||
-- 3) Add missing foreign-key helper indexes reported by Supabase advisor.
|
||||
create index if not exists idx_entitlement_events_user_id
|
||||
on public.entitlement_events(user_id);
|
||||
|
||||
create index if not exists idx_payments_user_id
|
||||
on public.payments(user_id);
|
||||
|
||||
create index if not exists idx_wallet_link_challenges_user_id
|
||||
on public.wallet_link_challenges(user_id);
|
||||
|
||||
-- 4) Normalize stale business state observed in read-only diagnostics.
|
||||
update public.subscriptions
|
||||
set status = 'expired',
|
||||
updated_at = now()
|
||||
where status = 'active'
|
||||
and expires_at <= now();
|
||||
|
||||
update public.payment_intents
|
||||
set status = 'expired',
|
||||
updated_at = now()
|
||||
where status in ('created', 'submitted')
|
||||
and expires_at <= now();
|
||||
|
||||
delete from public.wallet_link_challenges
|
||||
where consumed_at is null
|
||||
and expires_at <= now();
|
||||
|
||||
-- Backfill profiles for auth users created while the auth trigger was absent
|
||||
-- or failed. Existing profiles are not modified.
|
||||
insert into public.profiles (id, email)
|
||||
select u.id, coalesce(u.email, '')
|
||||
from auth.users u
|
||||
left join public.profiles p on p.id = u.id
|
||||
where p.id is null;
|
||||
|
||||
analyze public.entitlement_events;
|
||||
analyze public.payments;
|
||||
analyze public.wallet_link_challenges;
|
||||
analyze public.subscriptions;
|
||||
analyze public.payment_intents;
|
||||
analyze public.profiles;
|
||||
|
||||
-- 5) Verification queries. Expected after this script:
|
||||
-- - exposed_security_definer_functions = 0
|
||||
-- - public_client_table_grants = 0
|
||||
-- - missing_public_fk_indexes = 0
|
||||
-- - active_expired_subscriptions = 0
|
||||
-- - open_expired_payment_intents = 0
|
||||
-- - expired_unconsumed_wallet_challenges = 0
|
||||
-- - auth_users_without_profile = 0
|
||||
select 'exposed_security_definer_functions' as check_name,
|
||||
count(*)::bigint as count
|
||||
from pg_proc p
|
||||
join pg_namespace n on n.oid = p.pronamespace
|
||||
where n.nspname = 'public'
|
||||
and p.proname in ('rls_auto_enable', 'sync_profile_from_auth')
|
||||
and p.prosecdef
|
||||
and (
|
||||
has_function_privilege('anon', p.oid, 'execute')
|
||||
or has_function_privilege('authenticated', p.oid, 'execute')
|
||||
)
|
||||
union all
|
||||
select 'public_client_table_grants',
|
||||
count(*)::bigint
|
||||
from pg_class c
|
||||
join pg_namespace n on n.oid = c.relnamespace
|
||||
cross join lateral aclexplode(coalesce(c.relacl, acldefault('r', c.relowner))) a
|
||||
left join pg_roles grantee on grantee.oid = a.grantee
|
||||
where n.nspname = 'public'
|
||||
and c.relkind = 'r'
|
||||
and coalesce(grantee.rolname, 'PUBLIC') in ('anon', 'authenticated')
|
||||
union all
|
||||
select 'missing_public_fk_indexes',
|
||||
count(*)::bigint
|
||||
from (
|
||||
select con.conrelid, con.conkey
|
||||
from pg_constraint con
|
||||
join pg_namespace n on n.oid = con.connamespace
|
||||
where con.contype = 'f'
|
||||
and n.nspname = 'public'
|
||||
and not exists (
|
||||
select 1
|
||||
from pg_index i
|
||||
where i.indrelid = con.conrelid
|
||||
and i.indisvalid
|
||||
and i.indisready
|
||||
and (
|
||||
select array_agg(k order by ord)
|
||||
from unnest(i.indkey) with ordinality as x(k, ord)
|
||||
where ord <= array_length(con.conkey, 1)
|
||||
) = con.conkey
|
||||
)
|
||||
) missing_fks
|
||||
union all
|
||||
select 'active_expired_subscriptions',
|
||||
count(*)::bigint
|
||||
from public.subscriptions
|
||||
where status = 'active'
|
||||
and expires_at <= now()
|
||||
union all
|
||||
select 'open_expired_payment_intents',
|
||||
count(*)::bigint
|
||||
from public.payment_intents
|
||||
where status in ('created', 'submitted')
|
||||
and expires_at <= now()
|
||||
union all
|
||||
select 'expired_unconsumed_wallet_challenges',
|
||||
count(*)::bigint
|
||||
from public.wallet_link_challenges
|
||||
where consumed_at is null
|
||||
and expires_at <= now()
|
||||
union all
|
||||
select 'auth_users_without_profile',
|
||||
count(*)::bigint
|
||||
from auth.users u
|
||||
left join public.profiles p on p.id = u.id
|
||||
where p.id is null;
|
||||
Reference in New Issue
Block a user