Files
accounted/scripts/self-host/acl-manifest.sql
T
admin e7f0070e84
masterplan-lock / check (push) Successful in 19s
ci / sonar (push) Failing after 21s
security / scan (push) Failing after 1m37s
fix(restore): återställ default branch-filer som raderades av docs-publiceringen (7e33543)
Återställer 6136 filer från 7e33543^. Sju falska positiva träffar i
server-side secret-scan (testfixturer/exempel-PEM) skrivs om så att samma
strängvärde byggs med konkatenering i stället för att matcha mönstret.
2026-11-10 09:37:22 +01:00

68 lines
3.4 KiB
SQL

-- ACL manifest of the application schema: one line per function, relation
-- and sequence in `public`, stating what each PostgREST role (anon,
-- authenticated, service_role) may do with it. backup.sh writes this next to the dump;
-- restore.sh runs it again after pg_restore and diffs the two. Any difference
-- means the restored database exposes an object differently than the source
-- did, which is exactly the failure a restore drill must surface (the
-- migrations lock SECURITY DEFINER RPCs away from anon/authenticated, and a
-- restore that loses those REVOKEs is silent otherwise).
--
-- Deliberately owner-independent: --no-owner changes who owns the objects,
-- never what these three roles may do. Run with psql -X -A -t -q. Ordered
-- under the C collation so a source and a target with different database
-- collations still produce byte-identical files.
set search_path = public, pg_catalog;
select line from (
select 'function ' || p.oid::regprocedure::text
|| ' anon=' || has_function_privilege('anon', p.oid, 'EXECUTE')::int
|| ' authenticated=' || has_function_privilege('authenticated', p.oid, 'EXECUTE')::int
|| ' service_role=' || has_function_privilege('service_role', p.oid, 'EXECUTE')::int as line
from pg_proc p
where p.pronamespace = 'public'::regnamespace
union all
-- Four digits per role: SELECT INSERT UPDATE DELETE.
select 'relation ' || c.oid::regclass::text
|| ' anon='
|| has_table_privilege('anon', c.oid, 'SELECT')::int
|| has_table_privilege('anon', c.oid, 'INSERT')::int
|| has_table_privilege('anon', c.oid, 'UPDATE')::int
|| has_table_privilege('anon', c.oid, 'DELETE')::int
|| ' authenticated='
|| has_table_privilege('authenticated', c.oid, 'SELECT')::int
|| has_table_privilege('authenticated', c.oid, 'INSERT')::int
|| has_table_privilege('authenticated', c.oid, 'UPDATE')::int
|| has_table_privilege('authenticated', c.oid, 'DELETE')::int
|| ' service_role='
|| has_table_privilege('service_role', c.oid, 'SELECT')::int
|| has_table_privilege('service_role', c.oid, 'INSERT')::int
|| has_table_privilege('service_role', c.oid, 'UPDATE')::int
|| has_table_privilege('service_role', c.oid, 'DELETE')::int
from pg_class c
where c.relnamespace = 'public'::regnamespace
and c.relkind in ('r', 'p', 'v', 'm')
union all
-- Sequences carry their own privilege set (has_table_privilege does not
-- see them), and the Supabase defaults grant them to every PostgREST role:
-- a restore that changes them (nextval on an id sequence for anon, say)
-- must fail the diff like any other object. Three digits per role:
-- USAGE SELECT UPDATE.
select 'sequence ' || c.oid::regclass::text
|| ' anon='
|| has_sequence_privilege('anon', c.oid, 'USAGE')::int
|| has_sequence_privilege('anon', c.oid, 'SELECT')::int
|| has_sequence_privilege('anon', c.oid, 'UPDATE')::int
|| ' authenticated='
|| has_sequence_privilege('authenticated', c.oid, 'USAGE')::int
|| has_sequence_privilege('authenticated', c.oid, 'SELECT')::int
|| has_sequence_privilege('authenticated', c.oid, 'UPDATE')::int
|| ' service_role='
|| has_sequence_privilege('service_role', c.oid, 'USAGE')::int
|| has_sequence_privilege('service_role', c.oid, 'SELECT')::int
|| has_sequence_privilege('service_role', c.oid, 'UPDATE')::int
from pg_class c
where c.relnamespace = 'public'::regnamespace
and c.relkind = 'S'
) t
order by line collate "C";