forked from wangziqi/gongxue-base
103 lines
4.1 KiB
PL/PgSQL
103 lines
4.1 KiB
PL/PgSQL
-- Taro uses Supabase for Auth only. Business data is served by apps/api, so
|
|
-- public-schema Data API access must stay closed until a table/view/RPC has a
|
|
-- dedicated authorization model and an explicit grant migration.
|
|
revoke all privileges on all tables in schema public from public, anon, authenticated;
|
|
revoke all privileges on all sequences in schema public from public, anon, authenticated;
|
|
revoke all privileges on all functions in schema public from public, anon, authenticated;
|
|
revoke create on schema public from public, anon, authenticated;
|
|
|
|
-- A standard Supabase migration user cannot change ACLs on public extension
|
|
-- functions owned by supabase_admin. The privileged runtime-role bootstrap must
|
|
-- seal those base-image functions before migrations; never accept warning-only
|
|
-- REVOKE output as proof that the Data API RPC surface is closed.
|
|
do $$
|
|
begin
|
|
if exists (
|
|
select 1
|
|
from pg_proc function_row
|
|
join pg_namespace namespace on namespace.oid = function_row.pronamespace
|
|
cross join (values ('anon'), ('authenticated')) requested_role(role_name)
|
|
join pg_roles client_role on client_role.rolname = requested_role.role_name
|
|
where namespace.nspname = 'public'
|
|
and has_function_privilege(client_role.oid, function_row.oid, 'EXECUTE')
|
|
) then
|
|
raise exception
|
|
'public functions remain executable by anon/authenticated; run the privileged backend runtime role bootstrap before migrations';
|
|
end if;
|
|
end
|
|
$$;
|
|
|
|
do $$
|
|
declare
|
|
owner_name name;
|
|
begin
|
|
for owner_name in
|
|
select distinct owner_role.rolname
|
|
from (
|
|
select c.relowner as owner_oid
|
|
from pg_class c
|
|
join pg_namespace n on n.oid = c.relnamespace
|
|
where n.nspname = 'public'
|
|
and c.relkind in ('r', 'p', 'S', 'v', 'm', 'f')
|
|
union
|
|
select p.proowner as owner_oid
|
|
from pg_proc p
|
|
join pg_namespace n on n.oid = p.pronamespace
|
|
where n.nspname = 'public'
|
|
) owners
|
|
join pg_roles owner_role on owner_role.oid = owners.owner_oid
|
|
where owner_role.rolname = current_user
|
|
or pg_has_role(current_user, owner_role.oid, 'MEMBER')
|
|
loop
|
|
execute format(
|
|
'alter default privileges for role %I in schema public revoke all privileges on tables from public, anon, authenticated',
|
|
owner_name
|
|
);
|
|
execute format(
|
|
'alter default privileges for role %I in schema public revoke all privileges on sequences from public, anon, authenticated',
|
|
owner_name
|
|
);
|
|
-- PostgreSQL grants PUBLIC EXECUTE to new functions through the global
|
|
-- default ACL. A schema-local revoke cannot subtract that global default.
|
|
execute format(
|
|
'alter default privileges for role %I revoke execute on functions from public, anon, authenticated',
|
|
owner_name
|
|
);
|
|
end loop;
|
|
end $$;
|
|
|
|
-- A platform role claim can outlive a staff-status change. Resolve platform
|
|
-- authority from the active database identity on every RLS evaluation instead.
|
|
create or replace function app.is_platform_admin()
|
|
returns boolean
|
|
language sql
|
|
stable
|
|
security definer
|
|
set search_path = ''
|
|
as $$
|
|
select app.current_role() = 'service_role'
|
|
or exists (
|
|
select 1
|
|
from public.platform_users u
|
|
where u.auth_user_id = (select auth.uid())
|
|
and u.primary_role = 'platform_admin'
|
|
and u.status = 'active'
|
|
)
|
|
$$;
|
|
|
|
revoke all on function app.is_platform_admin() from public, anon, authenticated;
|
|
grant execute on function app.is_platform_admin() to anon, authenticated, service_role;
|
|
|
|
-- The original FOR ALL owner policy allowed a signed-in user to update their
|
|
-- own role, status and platform_permissions. Keep only a future-safe self-read
|
|
-- policy; no client table grant is provided by this migration.
|
|
drop policy if exists platform_admin_platform_users on public.platform_users;
|
|
drop policy if exists platform_users_self_read on public.platform_users;
|
|
create policy platform_users_self_read on public.platform_users
|
|
for select
|
|
to authenticated
|
|
using (auth_user_id = (select auth.uid()));
|
|
|
|
comment on policy platform_users_self_read on public.platform_users is
|
|
'Self-read policy only. anon/authenticated have no table grant; privileged updates must use apps/api.';
|