44deeab35d
The bootstrap SQL ended with:
GRANT audit_owner, audit_writer, audit_reader, audit_archiver TO portal;
which assumed POSTGRES_USER is `portal`. The compose file (and the
.env.example) document POSTGRES_USER as overridable — anyone who
changed it to something else (e.g. `apf_portal`) hit:
ERROR: role "portal" does not exist
psql: .../01-init.sql:48: ERROR: role "portal" does not exist
`current_user` resolves at script execution to whoever is running
the init SQL — that is, the superuser Postgres just created from
POSTGRES_USER, regardless of its name. Use it instead of hard-coding
`portal`.
Recovery for anyone hit by the original bug:
cd infra/local
docker compose -f dev.compose.yml down -v # wipes the
# half-initialised
# postgres-data volume
docker compose -f dev.compose.yml up -d # bootstrap re-runs
# cleanly
58 lines
2.7 KiB
SQL
58 lines
2.7 KiB
SQL
-- Bootstrap SQL for local-dev Postgres, applied on FIRST boot only
|
|
-- (Postgres image runs files in /docker-entrypoint-initdb.d once,
|
|
-- when the data volume is empty).
|
|
--
|
|
-- Implements the role + schema layout from ADR-0013 (Audit trail,
|
|
-- separated Postgres schema, append-only by Postgres role grants).
|
|
-- Production deployment manifests (future infrastructure ADR) will
|
|
-- replicate the same layout with real service accounts; in dev the
|
|
-- default `portal` user (created automatically from POSTGRES_USER)
|
|
-- is the schema owner, and the audit roles are granted to it for
|
|
-- testing role-based access patterns locally.
|
|
|
|
-- ---------------------------------------------------------------- Audit roles
|
|
-- NOLOGIN: these are permission containers, not login users. The BFF
|
|
-- connects as a login user that has been GRANTed the role.
|
|
CREATE ROLE audit_owner NOLOGIN;
|
|
CREATE ROLE audit_writer NOLOGIN;
|
|
CREATE ROLE audit_reader NOLOGIN;
|
|
CREATE ROLE audit_archiver NOLOGIN;
|
|
|
|
-- ---------------------------------------------------------------- Audit schema
|
|
-- Owned by audit_owner so DEFAULT PRIVILEGES below take effect for
|
|
-- every future table created under the schema (Prisma migration etc.).
|
|
CREATE SCHEMA audit AUTHORIZATION audit_owner;
|
|
|
|
GRANT USAGE ON SCHEMA audit TO audit_writer, audit_reader, audit_archiver;
|
|
|
|
-- ---------------------------------------------------------------- Append-only contract
|
|
-- ADR-0013 §"Append-only by role grants":
|
|
-- audit_writer → INSERT only
|
|
-- audit_reader → SELECT only
|
|
-- audit_archiver → DELETE only (used to prune past retention)
|
|
-- nobody → UPDATE, TRUNCATE
|
|
ALTER DEFAULT PRIVILEGES FOR ROLE audit_owner IN SCHEMA audit
|
|
GRANT INSERT ON TABLES TO audit_writer;
|
|
|
|
ALTER DEFAULT PRIVILEGES FOR ROLE audit_owner IN SCHEMA audit
|
|
GRANT SELECT ON TABLES TO audit_reader;
|
|
|
|
ALTER DEFAULT PRIVILEGES FOR ROLE audit_owner IN SCHEMA audit
|
|
GRANT DELETE ON TABLES TO audit_archiver;
|
|
|
|
-- ---------------------------------------------------------------- Dev convenience
|
|
-- The dev superuser (created by Postgres from POSTGRES_USER, default
|
|
-- `portal` but overridable in infra/local/.env) bypasses these grants
|
|
-- anyway, but granting the audit roles explicitly lets us test
|
|
-- role-based access with `SET ROLE audit_writer;` etc. from a psql
|
|
-- session against the dev DB.
|
|
--
|
|
-- `current_user` resolves at script execution time to whoever is
|
|
-- running the init SQL — i.e. the superuser created from POSTGRES_USER,
|
|
-- whatever its name happens to be. Hard-coding `portal` here was
|
|
-- wrong: it broke any setup where the contributor changed
|
|
-- POSTGRES_USER in their .env.
|
|
--
|
|
-- Production never grants all four roles to one user.
|
|
GRANT audit_owner, audit_writer, audit_reader, audit_archiver TO current_user;
|