79edee659f
docs/SOVEREIGN.md (run Accounted on Swedish infrastructure: providers, self-hosted Supabase gotchas, backup/restore runbook, honest dependency list), scripts/self-host/backup.sh + restore.sh (pg_dump custom format, storage tar, SHA-256 manifest, S3-compatible upload; ACLs are preserved through the restore and re-verified against an acl-manifest including sequences; the resume hook always runs after a failed quiesce and the hooks must be configured as a pair), Vercel Speed Insights gated off for self-hosted, and stale self-host docs corrected (assistant Q&A and categorization run on BYO OpenAI-compatible models; SMTP via EMAIL_PROVIDER=smtp after #1746; connector subscription described as proposed only).
68 lines
3.4 KiB
SQL
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";
|