Skip to content
Open
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
17 changes: 17 additions & 0 deletions sql/test_factory--0.5.0.sql
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,23 @@ EXCEPTION
END
$body$;

/*
* As of PG16, CREATE ROLE no longer grants the creating role a SET-enabled
* membership in the new role, so SET ROLE test_factory__owner below fails
* unless the current role is a superuser (which bypasses the check). Grant it
* explicitly WITH SET so a non-superuser install works too. Runs
* unconditionally, even when the role already existed and CREATE ROLE was a
* no-op. Gated on PG16+, where the WITH SET syntax exists; pre-16 GRANT ... TO
* already confers the ability to SET ROLE.
*/
DO $body$
BEGIN
IF current_setting('server_version_num')::int >= 160000 THEN
EXECUTE format('GRANT test_factory__owner TO %I WITH SET TRUE', current_user);
END IF;
END
$body$;

CREATE SCHEMA tf AUTHORIZATION test_factory__owner;
COMMENT ON SCHEMA tf IS $$Test factory. Tools for maintaining test data.$$;
GRANT USAGE ON SCHEMA tf TO public;
Expand Down
17 changes: 17 additions & 0 deletions sql/test_factory.sql
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,23 @@ EXCEPTION
END
$body$;

/*
* As of PG16, CREATE ROLE no longer grants the creating role a SET-enabled
* membership in the new role, so SET ROLE test_factory__owner below fails
* unless the current role is a superuser (which bypasses the check). Grant it
* explicitly WITH SET so a non-superuser install works too. Runs
* unconditionally, even when the role already existed and CREATE ROLE was a
* no-op. Gated on PG16+, where the WITH SET syntax exists; pre-16 GRANT ... TO
* already confers the ability to SET ROLE.
*/
DO $body$
BEGIN
IF current_setting('server_version_num')::int >= 160000 THEN
EXECUTE format('GRANT test_factory__owner TO %I WITH SET TRUE', current_user);
END IF;
END
$body$;

CREATE SCHEMA tf AUTHORIZATION test_factory__owner;
COMMENT ON SCHEMA tf IS $$Test factory. Tools for maintaining test data.$$;
GRANT USAGE ON SCHEMA tf TO public;
Expand Down
45 changes: 23 additions & 22 deletions test/expected/base.out
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
\set ECHO none
Creating extension test_factory
ok 1 - Register test customers
ok 2 - Create function customer__add
ok 3 - Register test invoices
ok 4 - Ensure original_role temp table was dropped
ok 5 - Ensure role is put back after install
ok 6 - Security definer function _tf.schema__getsert has search_path=pg_catalog
ok 7 - Security definer function _tf.test_factory__get has search_path=pg_catalog
ok 8 - Security definer function _tf.test_factory__set has search_path=pg_catalog
ok 9 - Security definer function _tf.table_create has search_path=pg_catalog
ok 10 - Security definer function _tf.get has search_path=pg_catalog
ok 11 - customer table is empty
ok 12 - invoice table is empty
ok 13 - invoice factory output
ok 14 - invoice table content
ok 15 - customer table content
ok 16 - invoice factory second call
ok 17 - invoice table content stayed constant
ok 18 - customer table content stayed constant
ok 19 - Test function factory
ok 20 - customer table has new row
ok 21 - truncate invoice
ok 22 - invoice factory get remains the same after truncate
ok 1 - Installing role has SET-enabled membership in test_factory__owner (issue #14)
ok 2 - Register test customers
ok 3 - Create function customer__add
ok 4 - Register test invoices
ok 5 - Ensure original_role temp table was dropped
ok 6 - Ensure role is put back after install
ok 7 - Security definer function _tf.schema__getsert has search_path=pg_catalog
ok 8 - Security definer function _tf.test_factory__get has search_path=pg_catalog
ok 9 - Security definer function _tf.test_factory__set has search_path=pg_catalog
ok 10 - Security definer function _tf.table_create has search_path=pg_catalog
ok 11 - Security definer function _tf.get has search_path=pg_catalog
ok 12 - customer table is empty
ok 13 - invoice table is empty
ok 14 - invoice factory output
ok 15 - invoice table content
ok 16 - customer table content
ok 17 - invoice factory second call
ok 18 - invoice table content stayed constant
ok 19 - customer table content stayed constant
ok 20 - Test function factory
ok 21 - customer table has new row
ok 22 - truncate invoice
ok 23 - invoice factory get remains the same after truncate
30 changes: 30 additions & 0 deletions test/sql/base.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,36 @@
\set extension_name test_factory
\i test/helpers/create_extension.sql

/*
* Regression test for issue #14. On PostgreSQL 16+, CREATE ROLE no longer
* grants the creating role a SET-enabled membership in the new role, so the
* install must GRANT test_factory__owner ... WITH SET TRUE or the SET ROLE
* performed during install fails for non-superuser installs (RDS/Aurora). A
* real superuser bypasses the SET ROLE check, so a plain install here cannot
* reproduce the failure; instead assert the SET-enabled membership the fix
* establishes. pg_auth_members.set_option only exists on PG16+, so the check is
* skipped (with identical TAP output) on older versions, where a plain
* GRANT ... TO already confers the ability to SET ROLE.
*/
SELECT (current_setting('server_version_num')::int >= 160000) AS pg16plus \gset
\if :pg16plus
SELECT ok(
EXISTS(
SELECT 1
FROM pg_auth_members
WHERE roleid = 'test_factory__owner'::regrole
AND member = current_user::regrole
AND set_option
)
, 'Installing role has SET-enabled membership in test_factory__owner (issue #14)'
);
\else
SELECT ok(
true
, 'Installing role has SET-enabled membership in test_factory__owner (issue #14)'
);
\endif

-- NOTE: This runs some tests itself
\i test/helpers/create.sql

Expand Down
Loading