\set ON_ERROR_STOP on -- Run during the documented v1.2.1 downtime while connected as the installation's existing -- modelforge bootstrap superuser. This creates a separate retained administrator before demoting -- the schema owner. Secrets come from the psql process environment and are never stored here. \getenv admin_role MODELFORGE_POSTGRES_ADMIN_USER \getenv admin_password MODELFORGE_POSTGRES_ADMIN_PASSWORD \getenv owner_password MODELFORGE_MIGRATION_DB_PASSWORD \getenv runtime_password MODELFORGE_RUNTIME_DB_PASSWORD \getenv database_name MODELFORGE_POSTGRES_DB select pg_catalog.format( 'create role %I login password %L superuser createdb createrole inherit replication bypassrls', :'admin_role', :'admin_password' ) where not exists ( select 1 from pg_catalog.pg_roles where rolname = :'admin_role' ) \gexec select pg_catalog.format( 'alter role %I with login password %L superuser createdb createrole inherit replication bypassrls', :'admin_role', :'admin_password' ) \gexec select pg_catalog.format( 'create role modelforge_runtime login password %L nosuperuser nocreatedb nocreaterole noinherit noreplication nobypassrls', :'runtime_password' ) where not exists (select 1 from pg_catalog.pg_roles where rolname = 'modelforge_runtime') \gexec select pg_catalog.format( 'alter role modelforge_runtime with login password %L nosuperuser nocreatedb nocreaterole noinherit noreplication nobypassrls', :'runtime_password' ) \gexec -- NOINHERIT still permits SET ROLE. Purge stale memberships while this session still has the -- bootstrap superuser authority; after the next statement the retained owner is deliberately -- unable to grant or revoke roles. select pg_catalog.format('revoke %I from %I', granted.rolname, member.rolname) from pg_catalog.pg_auth_members as membership join pg_catalog.pg_roles as granted on granted.oid = membership.roleid join pg_catalog.pg_roles as member on member.oid = membership.member where member.rolname in ('modelforge', 'modelforge_runtime') \gexec -- Keep the existing role OID so every v1.2.1 table remains owned by the migration role. select pg_catalog.format( 'alter role modelforge with login password %L nosuperuser nocreatedb nocreaterole inherit noreplication nobypassrls', :'owner_password' ) \gexec select pg_catalog.format('revoke create, temporary on database %I from public', :'database_name') \gexec select pg_catalog.format('grant connect, create, temporary on database %I to modelforge', :'database_name') \gexec select pg_catalog.format('revoke all on database %I from modelforge_runtime', :'database_name') \gexec select pg_catalog.format('grant connect on database %I to modelforge_runtime', :'database_name') \gexec revoke create on schema public from public; grant usage, create on schema public to modelforge; grant usage on schema public to modelforge_runtime;