Skip to content

add migration for pg_create_subscription grant #1514

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion ansible/files/admin_api_scripts/pg_upgrade_scripts/complete.sh
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,21 @@ EOF
)
run_sql -c "$REENCRYPT_VAULT_SECRETS_QUERY"

run_sql -c "grant pg_read_all_data, pg_signal_backend to postgres"
GRANT_PREDEFINED_ROLES_TO_POSTGRES_QUERY=$(cat <<EOF
DO \$\$
DECLARE
major_version INT;
BEGIN
SELECT current_setting('server_version_num')::INT / 10000 INTO major_version;
IF major_version >= 16 THEN
GRANT pg_create_subscription TO postgres;
END IF;
GRANT pg_monitor, pg_read_all_data, pg_signal_backend TO postgres;
END
\$\$;
EOF
)
run_sql -c "$GRANT_PREDEFINED_ROLES_TO_POSTGRES_QUERY"
}

function complete_pg_upgrade {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
-- migrate:up
DO $$
DECLARE
major_version INT;
BEGIN
SELECT current_setting('server_version_num')::INT / 10000 INTO major_version;

IF major_version >= 16 THEN
GRANT pg_create_subscription TO postgres;
END IF;
END $$;

-- migrate:down
77 changes: 30 additions & 47 deletions nix/tests/expected/roles.out
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
-- Some predefined roles don't exist in earlier versions of Postgres, so we
-- exclude them in this test file. They're tested in version-specific test files
-- (z_<ver>_roles.sql).
--
-- Currently those roles are:
-- pg_create_subscription, pg_maintain, pg_use_reserved_connections
-- all roles and attributes
select
rolname,
Expand All @@ -11,7 +17,6 @@ select
rolbypassrls ,
rolvaliduntil
from pg_roles r
-- TODO: this exclusion is to maintain compat with pg17, we should cover it
where rolname not in ('pg_create_subscription', 'pg_maintain', 'pg_use_reserved_connections')
order by rolname;
rolname | rolcreaterole | rolcanlogin | rolsuper | rolinherit | rolcreatedb | rolreplication | rolconnlimit | rolbypassrls | rolvaliduntil
Expand Down Expand Up @@ -51,7 +56,6 @@ select
rolname,
rolconfig
from pg_roles r
-- TODO: this exclusion is to maintain compat with pg17, we should cover it
where rolname not in ('pg_create_subscription', 'pg_maintain', 'pg_use_reserved_connections')
order by rolname;
rolname | rolconfig
Expand Down Expand Up @@ -98,53 +102,31 @@ left join
pg_auth_members m on r.oid = m.member
left join
pg_roles g on m.roleid = g.oid
-- TODO: this exclusion is to maintain compat with pg17, we should cover it
where r.rolname not in ('pg_create_subscription', 'pg_maintain', 'pg_use_reserved_connections')
and g.rolname not in ('pg_create_subscription', 'pg_maintain', 'pg_use_reserved_connections')
order by
r.rolname, g.rolname;
member | member_of (can become) | admin_option
----------------------------+------------------------+--------------
anon | |
authenticated | |
authenticator | anon | f
authenticator | authenticated | f
authenticator | service_role | f
dashboard_user | |
pg_checkpoint | |
pg_database_owner | |
pg_execute_server_program | |
pg_monitor | pg_read_all_settings | f
pg_monitor | pg_read_all_stats | f
pg_monitor | pg_stat_scan_tables | f
pg_read_all_data | |
pg_read_all_settings | |
pg_read_all_stats | |
pg_read_server_files | |
pg_signal_backend | |
pg_stat_scan_tables | |
pg_write_all_data | |
pg_write_server_files | |
pgbouncer | |
pgsodium_keyholder | pgsodium_keyiduser | f
pgsodium_keyiduser | |
pgsodium_keymaker | pgsodium_keyholder | f
pgsodium_keymaker | pgsodium_keyiduser | f
pgtle_admin | |
postgres | anon | f
postgres | authenticated | f
postgres | pg_monitor | f
postgres | pg_read_all_data | f
postgres | pg_signal_backend | f
postgres | pgtle_admin | f
postgres | service_role | f
service_role | |
supabase_admin | |
supabase_auth_admin | |
supabase_functions_admin | |
supabase_read_only_user | pg_read_all_data | f
supabase_replication_admin | |
supabase_storage_admin | authenticator | f
(40 rows)
member | member_of (can become) | admin_option
-------------------------+------------------------+--------------
authenticator | anon | f
authenticator | authenticated | f
authenticator | service_role | f
pg_monitor | pg_read_all_settings | f
pg_monitor | pg_read_all_stats | f
pg_monitor | pg_stat_scan_tables | f
pgsodium_keyholder | pgsodium_keyiduser | f
pgsodium_keymaker | pgsodium_keyholder | f
pgsodium_keymaker | pgsodium_keyiduser | f
postgres | anon | f
postgres | authenticated | f
postgres | pg_monitor | f
postgres | pg_read_all_data | f
postgres | pg_signal_backend | f
postgres | pgtle_admin | f
postgres | service_role | f
supabase_read_only_user | pg_read_all_data | f
supabase_storage_admin | authenticator | f
(18 rows)

-- Check all privileges of the roles on the schemas
select schema_name, privilege_type, grantee, default_for
Expand All @@ -164,7 +146,8 @@ from (
join
pg_roles r on a.grantee = r.oid
where
a.privilege_type != 'MAINTAIN' -- TODO: this is to maintain compat with pg17, we should cover it
-- PG17+, handled in version-specific test files
a.privilege_type != 'MAINTAIN'
union all
-- explicit grant usage and create on the schemas
select
Expand Down
111 changes: 111 additions & 0 deletions nix/tests/expected/z_17_roles.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
-- version-specific roles and attributes
select
rolname,
rolcreaterole ,
rolcanlogin ,
rolsuper ,
rolinherit ,
rolcreatedb ,
rolreplication ,
rolconnlimit ,
rolbypassrls ,
rolvaliduntil
from pg_roles r
where rolname in ('pg_create_subscription', 'pg_maintain', 'pg_use_reserved_connections')
order by rolname;
rolname | rolcreaterole | rolcanlogin | rolsuper | rolinherit | rolcreatedb | rolreplication | rolconnlimit | rolbypassrls | rolvaliduntil
-----------------------------+---------------+-------------+----------+------------+-------------+----------------+--------------+--------------+---------------
pg_create_subscription | f | f | f | t | f | f | -1 | f |
pg_maintain | f | f | f | t | f | f | -1 | f |
pg_use_reserved_connections | f | f | f | t | f | f | -1 | f |
(3 rows)

select
rolname,
rolconfig
from pg_roles r
where rolname in ('pg_create_subscription', 'pg_maintain', 'pg_use_reserved_connections')
order by rolname;
rolname | rolconfig
-----------------------------+-----------
pg_create_subscription |
pg_maintain |
pg_use_reserved_connections |
(3 rows)

-- version-specific role memberships
select
r.rolname as member,
g.rolname as "member_of (can become)",
m.admin_option
from
pg_roles r
left join
pg_auth_members m on r.oid = m.member
left join
pg_roles g on m.roleid = g.oid
where r.rolname in ('pg_create_subscription', 'pg_maintain', 'pg_use_reserved_connections')
or g.rolname in ('pg_create_subscription', 'pg_maintain', 'pg_use_reserved_connections')
order by
r.rolname, g.rolname;
member | member_of (can become) | admin_option
-----------------------------+------------------------+--------------
pg_create_subscription | |
pg_maintain | |
pg_use_reserved_connections | |
postgres | pg_create_subscription | f
(4 rows)

-- Check version-specific privileges of the roles on the schemas
select schema_name, privilege_type, grantee, default_for
from (
-- ALTER DEFAULT privileges on schemas
select
n.nspname as schema_name,
a.privilege_type,
r.rolname as grantee,
d.defaclrole::regrole as default_for,
case when n.nspname = 'public' then 0 else 1 end as schema_order
from
pg_default_acl d
join
pg_namespace n on d.defaclnamespace = n.oid
cross join lateral aclexplode(d.defaclacl) as a
join
pg_roles r on a.grantee = r.oid
where
a.privilege_type = 'MAINTAIN'
) sub
order by schema_order, schema_name, privilege_type, grantee, default_for;
schema_name | privilege_type | grantee | default_for
----------------+----------------+--------------------+---------------------
public | MAINTAIN | anon | supabase_admin
public | MAINTAIN | anon | postgres
public | MAINTAIN | authenticated | supabase_admin
public | MAINTAIN | authenticated | postgres
public | MAINTAIN | postgres | supabase_admin
public | MAINTAIN | postgres | postgres
public | MAINTAIN | service_role | supabase_admin
public | MAINTAIN | service_role | postgres
auth | MAINTAIN | dashboard_user | supabase_auth_admin
auth | MAINTAIN | postgres | supabase_auth_admin
extensions | MAINTAIN | postgres | supabase_admin
graphql | MAINTAIN | anon | supabase_admin
graphql | MAINTAIN | authenticated | supabase_admin
graphql | MAINTAIN | postgres | supabase_admin
graphql | MAINTAIN | service_role | supabase_admin
graphql_public | MAINTAIN | anon | supabase_admin
graphql_public | MAINTAIN | authenticated | supabase_admin
graphql_public | MAINTAIN | postgres | supabase_admin
graphql_public | MAINTAIN | service_role | supabase_admin
pgsodium | MAINTAIN | pgsodium_keyholder | supabase_admin
pgsodium_masks | MAINTAIN | pgsodium_keyiduser | supabase_admin
realtime | MAINTAIN | dashboard_user | supabase_admin
realtime | MAINTAIN | postgres | supabase_admin
repack | MAINTAIN | postgres | supabase_admin
storage | MAINTAIN | anon | postgres
storage | MAINTAIN | authenticated | postgres
storage | MAINTAIN | postgres | postgres
storage | MAINTAIN | service_role | postgres
(28 rows)

14 changes: 10 additions & 4 deletions nix/tests/sql/roles.sql
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
-- Some predefined roles don't exist in earlier versions of Postgres, so we
-- exclude them in this test file. They're tested in version-specific test files
-- (z_<ver>_roles.sql).
--
-- Currently those roles are:
-- pg_create_subscription, pg_maintain, pg_use_reserved_connections

-- all roles and attributes
select
rolname,
Expand All @@ -11,15 +18,13 @@ select
rolbypassrls ,
rolvaliduntil
from pg_roles r
-- TODO: this exclusion is to maintain compat with pg17, we should cover it
where rolname not in ('pg_create_subscription', 'pg_maintain', 'pg_use_reserved_connections')
order by rolname;

select
rolname,
rolconfig
from pg_roles r
-- TODO: this exclusion is to maintain compat with pg17, we should cover it
where rolname not in ('pg_create_subscription', 'pg_maintain', 'pg_use_reserved_connections')
order by rolname;

Expand All @@ -34,8 +39,8 @@ left join
pg_auth_members m on r.oid = m.member
left join
pg_roles g on m.roleid = g.oid
-- TODO: this exclusion is to maintain compat with pg17, we should cover it
where r.rolname not in ('pg_create_subscription', 'pg_maintain', 'pg_use_reserved_connections')
and g.rolname not in ('pg_create_subscription', 'pg_maintain', 'pg_use_reserved_connections')
order by
r.rolname, g.rolname;

Expand All @@ -57,7 +62,8 @@ from (
join
pg_roles r on a.grantee = r.oid
where
a.privilege_type != 'MAINTAIN' -- TODO: this is to maintain compat with pg17, we should cover it
-- PG17+, handled in version-specific test files
a.privilege_type != 'MAINTAIN'
union all
-- explicit grant usage and create on the schemas
select
Expand Down
60 changes: 60 additions & 0 deletions nix/tests/sql/z_17_roles.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
-- version-specific roles and attributes
select
rolname,
rolcreaterole ,
rolcanlogin ,
rolsuper ,
rolinherit ,
rolcreatedb ,
rolreplication ,
rolconnlimit ,
rolbypassrls ,
rolvaliduntil
from pg_roles r
where rolname in ('pg_create_subscription', 'pg_maintain', 'pg_use_reserved_connections')
order by rolname;

select
rolname,
rolconfig
from pg_roles r
where rolname in ('pg_create_subscription', 'pg_maintain', 'pg_use_reserved_connections')
order by rolname;

-- version-specific role memberships
select
r.rolname as member,
g.rolname as "member_of (can become)",
m.admin_option
from
pg_roles r
left join
pg_auth_members m on r.oid = m.member
left join
pg_roles g on m.roleid = g.oid
where r.rolname in ('pg_create_subscription', 'pg_maintain', 'pg_use_reserved_connections')
or g.rolname in ('pg_create_subscription', 'pg_maintain', 'pg_use_reserved_connections')
order by
r.rolname, g.rolname;

-- Check version-specific privileges of the roles on the schemas
select schema_name, privilege_type, grantee, default_for
from (
-- ALTER DEFAULT privileges on schemas
select
n.nspname as schema_name,
a.privilege_type,
r.rolname as grantee,
d.defaclrole::regrole as default_for,
case when n.nspname = 'public' then 0 else 1 end as schema_order
from
pg_default_acl d
join
pg_namespace n on d.defaclnamespace = n.oid
cross join lateral aclexplode(d.defaclacl) as a
join
pg_roles r on a.grantee = r.oid
where
a.privilege_type = 'MAINTAIN'
) sub
order by schema_order, schema_name, privilege_type, grantee, default_for;