Skip to content

Commit

Permalink
feat: PG16 support
Browse files Browse the repository at this point in the history
  • Loading branch information
soedirgo committed Aug 27, 2024
1 parent 6d2c6e0 commit ad6e41e
Show file tree
Hide file tree
Showing 14 changed files with 488 additions and 23 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
pg-version: ['13', '14', '15']
pg-version: ['13', '14', '15', '16']

steps:
- uses: actions/checkout@v3
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
matrix:
extension_name:
- supautils
postgres: [13, 14, 15]
postgres: [13, 14, 15, 16]
box:
- { runner: ubuntu-20.04, arch: amd64 }
- { runner: arm-runner, arch: arm64 }
Expand Down
10 changes: 8 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,18 @@ endif
MODULE_big = supautils
OBJS = src/supautils.o src/privileged_extensions.o src/constrained_extensions.o src/extensions_parameter_overrides.o src/policy_grants.o src/utils.o

PG_VERSION = $(strip $(shell $(PG_CONFIG) --version | $(GREP) -oP '(?<=PostgreSQL )[0-9]+'))
PG_GE16 = $(shell test $(PG_VERSION) -ge 16; echo $$?)
SYSTEM = $(shell uname -s)

TESTS := $(wildcard test/sql/*.sql)
ifneq ($(SYSTEM), Linux)
TESTS = $(filter-out test/sql/ge13_%.sql, $(wildcard test/sql/*.sql))
TESTS := $(filter-out test/sql/linux_%.sql, $(TESTS))
endif
ifneq ($(PG_GE16), 0)
TESTS := $(filter-out test/sql/ge16_%.sql, $(TESTS))
else
TESTS = $(wildcard test/sql/*.sql)
TESTS := $(filter-out test/sql/lt16_%.sql, $(TESTS))
endif

REGRESS = $(patsubst test/sql/%.sql,%,$(TESTS))
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Supautils is an extension that secures a PostgreSQL cluster on a cloud environme

It doesn't require creating database objects. It's a shared library that modifies PostgreSQL behavior through "hooks", not through tables or functions.

It's tested to work on PostgreSQL 13, 14 and 15.
It's tested to work on PostgreSQL 13, 14, 15, and 16.

## Installation

Expand Down
14 changes: 14 additions & 0 deletions src/supautils.c
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,19 @@ supautils_hook(PROCESS_UTILITY_PARAMS)
if (hasrolemembers)
confirm_reserved_memberships(created_role);

// We don't want to switch to superuser on PG16+ because the
// creating role is implicitly granted ADMIN on the new
// role:
// https://www.postgresql.org/docs/16/runtime-config-client.html#GUC-CREATEROLE-SELF-GRANT
//
// This ADMIN will be missing if we switch to superuser
// since the creating role becomes the superuser.
//
// We also no longer need superuser to grant BYPASSRLS &
// REPLICATION anyway.
#if PG16_GTE
run_process_utility_hook(prev_hook);
#else
if (is_current_role_privileged()) {
bool already_switched_to_superuser = false;

Expand All @@ -479,6 +492,7 @@ supautils_hook(PROCESS_UTILITY_PARAMS)
} else {
run_process_utility_hook(prev_hook);
}
#endif

return;
}
Expand Down
246 changes: 246 additions & 0 deletions test/expected/ge16_privileged_role.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
-- non-superuser privileged role
set role privileged_role;
\echo

-- can set privileged_role_allowed_configs
set session_replication_role to 'replica';
begin;
set local session_replication_role to 'origin';
commit;
reset session_replication_role;
\echo

-- non-superuser non-privileged role cannot set privileged_role_allowed_configs
set role rolecreator;
set session_replication_role to 'replica';
ERROR: permission denied to set parameter "session_replication_role"
begin;
set local session_replication_role to 'origin';
ERROR: permission denied to set parameter "session_replication_role"
commit;
reset session_replication_role;
ERROR: permission denied to set parameter "session_replication_role"
set role privileged_role;
\echo

-- superuser can set privileged_role_allowed_configs
set role postgres;
set session_replication_role to 'replica';
begin;
set local session_replication_role to 'origin';
commit;
reset session_replication_role;
set role privileged_role;
\echo

-- can set privileged_role_allowed_configs for a role
create role r;
alter role r set session_replication_role to 'replica';
drop role r;
\echo

-- can manage bypassrls role attribute
create role r bypassrls;
select rolbypassrls from pg_roles where rolname = 'r';
rolbypassrls
--------------
t
(1 row)

alter role r nobypassrls;
select rolbypassrls from pg_roles where rolname = 'r';
rolbypassrls
--------------
f
(1 row)

alter role r bypassrls;
select rolbypassrls from pg_roles where rolname = 'r';
rolbypassrls
--------------
t
(1 row)

drop role r;
\echo

-- can manage replication role attribute
create role r replication;
select rolreplication from pg_roles where rolname = 'r';
rolreplication
----------------
t
(1 row)

alter role r noreplication;
select rolreplication from pg_roles where rolname = 'r';
rolreplication
----------------
f
(1 row)

alter role r replication;
select rolreplication from pg_roles where rolname = 'r';
rolreplication
----------------
t
(1 row)

drop role r;
\echo

-- can manage foreign data wrappers
create extension postgres_fdw;
create foreign data wrapper new_fdw
handler postgres_fdw_handler
validator postgres_fdw_validator;
drop extension postgres_fdw cascade;
NOTICE: drop cascades to foreign-data wrapper new_fdw
\echo

-- non-superuser non-privileged role cannot manage bypassrls role attribute
set role rolecreator;
\echo

-- the error message changed in PG14
do $$
begin
create role r bypassrls;
exception when insufficient_privilege then null;
end;
$$ language plpgsql;
create role r;
alter role r nobypassrls;
ERROR: permission denied to alter role
DETAIL: Only roles with the BYPASSRLS attribute may change the BYPASSRLS attribute.
alter role r bypassrls;
ERROR: permission denied to alter role
DETAIL: Only roles with the BYPASSRLS attribute may change the BYPASSRLS attribute.
drop role r;
set role privileged_role;
\echo

-- superuser can manage bypassrls role attribute
set role postgres;
create role r bypassrls;
select rolbypassrls from pg_roles where rolname = 'r';
rolbypassrls
--------------
t
(1 row)

alter role r nobypassrls;
select rolbypassrls from pg_roles where rolname = 'r';
rolbypassrls
--------------
f
(1 row)

alter role r bypassrls;
select rolbypassrls from pg_roles where rolname = 'r';
rolbypassrls
--------------
t
(1 row)

drop role r;
set role privileged_role;
\echo

-- regression: https://github.com/supabase/supautils/issues/34
create role tmp;
alter role tmp;
\echo

-- privileged_role can modify reserved roles GUCs
set role privileged_role;
alter role authenticator set search_path to public;
alter role authenticator set statement_timeout = '15s';
\echo

-- privileged_role can do GRANT <role> to <reserved_role>
grant testme to authenticator;
\echo

-- privileged_role can set wildcard privileged_role_allowed_configs
alter role authenticator set pgrst.db_plan_enabled to true;
alter role authenticator set pgrst.db_prepared_statements to false;
alter role authenticator set other.nested.foo to true;
alter role authenticator set other.nested.bar to true;
\echo

-- privileged_role cannot drop, rename or nologin reserved role
drop role authenticator;
ERROR: "authenticator" is a reserved role, only superusers can modify it
alter role authenticator rename to authorized;
ERROR: "authenticator" is a reserved role, only superusers can modify it
alter role authenticator nologin;
ERROR: "authenticator" is a reserved role, only superusers can modify it
\echo

-- privileged_role can create nosuperuser
create role r nosuperuser;
drop role r;
\echo

-- privileged_role cannot create superuser or alter [no]superuser
create role r superuser;
ERROR: permission denied to create role
DETAIL: Only roles with the SUPERUSER attribute may create roles with the SUPERUSER attribute.
create role r;
alter role r superuser;
ERROR: permission denied to alter role
DETAIL: Only roles with the SUPERUSER attribute may alter roles with the SUPERUSER attribute.
alter role r nosuperuser;
ERROR: permission denied to alter role
DETAIL: Only roles with the SUPERUSER attribute may alter roles with the SUPERUSER attribute.
drop role r;
\echo

-- member of privileged_role can do privileged role stuff
set role privileged_role_member;
grant testme to authenticator;
NOTICE: role "authenticator" has already been granted membership in role "testme" by role "privileged_role"
set role privileged_role;
\echo

-- privileged_role can manage publications
create publication p for all tables;
drop publication p;
-- not testing `create publication ... for tables in schema ...` because it's PG15+
\echo

-- privileged_role can manage policies on tables in allowlist
set role postgres;
create schema allow_policies;
create table allow_policies.my_table ();
grant usage on schema allow_policies to privileged_role;
set role privileged_role;
create policy p on allow_policies.my_table for select using (true);
alter policy p on allow_policies.my_table using (false);
drop policy p on allow_policies.my_table;
set role postgres;
drop schema allow_policies cascade;
NOTICE: drop cascades to table allow_policies.my_table
set role privileged_role;
\echo

-- privileged_role cannot manage policies on tables not in allowlist
set role postgres;
create schema deny_policies;
create table deny_policies.my_table ();
create policy p1 on deny_policies.my_table for select using (true);
grant usage on schema deny_policies to privileged_role;
set role privileged_role;
create policy p2 on deny_policies.my_table for select using (true);
ERROR: must be owner of table my_table
alter policy p1 on deny_policies.my_table using (false);
ERROR: must be owner of table my_table
drop policy p1 on deny_policies.my_table;
ERROR: must be owner of relation my_table
set role postgres;
drop schema deny_policies cascade;
NOTICE: drop cascades to table deny_policies.my_table
set role privileged_role;
\echo

Original file line number Diff line number Diff line change
Expand Up @@ -186,15 +186,12 @@ create role r superuser;
ERROR: permission denied to create role
DETAIL: Only roles with the SUPERUSER attribute may create roles with the SUPERUSER attribute.
create role r;
alter role r nosuperuser;
ERROR: permission denied to alter role
DETAIL: Only roles with the SUPERUSER attribute may alter roles with the SUPERUSER attribute.
alter role r superuser;
ERROR: permission denied to alter role
DETAIL: Only roles with the SUPERUSER attribute may alter roles with the SUPERUSER attribute.
alter role postgres nosuperuser;
alter role r nosuperuser;
ERROR: permission denied to alter role
DETAIL: Only superusers can alter privileged roles.
DETAIL: Only roles with the SUPERUSER attribute may alter roles with the SUPERUSER attribute.
drop role r;
\echo

Expand Down
11 changes: 7 additions & 4 deletions test/expected/reserved_roles.out
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ set role rolecreator;
\echo

-- cannot rename an existing role to a reserved role
alter role fake rename to reserved_but_not_yet_created;
create role r;
alter role r rename to reserved_but_not_yet_created;
ERROR: "reserved_but_not_yet_created" is a reserved role, only superusers can modify it
drop role r;
\echo

-- cannot rename a reserved role
Expand Down Expand Up @@ -56,9 +58,10 @@ ERROR: "reserved_but_not_yet_created" is a reserved role, only superusers can m
create role anon;
ERROR: role "anon" already exists
-- ensure our hooks don't mess regular non-reserved roles functionality
alter role fake rename to new_fake;
alter role new_fake createrole createdb;
drop role new_fake;
create role r;
alter role r rename to new_r;
alter role new_r createrole createdb;
drop role new_r;
create role non_reserved;
\echo

Expand Down
11 changes: 8 additions & 3 deletions test/fixtures.sql
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@ create role supabase_storage_admin noinherit;
create role anon noinherit;

-- login role
create user rolecreator createrole noinherit nosuperuser;
grant anon to rolecreator;
create user rolecreator createrole createdb noinherit nosuperuser;
grant anon to rolecreator with admin option;
grant pg_monitor to rolecreator with admin option;
grant pg_read_all_settings to rolecreator with admin option;
grant pg_read_all_stats to rolecreator with admin option;
grant supabase_storage_admin to rolecreator;

-- other roles
create role fake noinherit;
create role privileged_role login createrole;
create role privileged_role login createrole bypassrls replication;
create role privileged_role_member login createrole in role privileged_role;
create role testme noinherit;
grant testme to privileged_role with admin option;
create role authenticator login noinherit;
grant authenticator to privileged_role with admin option;
grant all on database postgres to privileged_role;
Loading

0 comments on commit ad6e41e

Please sign in to comment.