-
Notifications
You must be signed in to change notification settings - Fork 1
Give the test role schema rights only, never a database-level grant #64
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
Changes from all commits
cd1c0fc
ef3cfb0
1f4cdee
7f2f3c8
8c8677c
76a0c2f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,8 @@ | ||
| # Claude Code Instructions for pg_count_nulls | ||
|
|
||
| See [`../ai/CLAUDE.md`](../ai/CLAUDE.md) (or | ||
| https://github.com/Postgres-Extensions/ai/blob/main/CLAUDE.md if that path | ||
| doesn't exist locally — clone it to `../ai/` per its own first instruction) | ||
| for CI-monitoring conventions, including handling of `claude-code-review` | ||
| findings. | ||
| @../ai/CLAUDE.md | ||
|
|
||
| If `../ai/CLAUDE.md` doesn't exist locally (see | ||
| https://github.com/Postgres-Extensions/ai), clone it now per its own | ||
| first instruction, then re-read it — do not rely on the import above | ||
| alone to have picked it up in that case. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,13 @@ | ||
| /* | ||
| * Defines, but does not call, the functions that find-and-drop leftover test | ||
| * schemas and install count_nulls into a fresh one. Split from calling them, | ||
| * and from each other, so test/install/load.sql can decide server-side | ||
| * whether to install at all, and so every caller can run cleanup before | ||
| * switching to the test user (test/helpers/use_test_user.sql) while | ||
| * installing after - a leftover schema can belong to any role, and only the | ||
| * connecting one is sure to be able to drop it. | ||
| * schemas, produce the schema count_nulls goes into, and install it there. | ||
| * Split from calling them, and from each other, so test/install/load.sql can | ||
| * decide server-side whether to install at all, and so every caller can run | ||
| * the first two as the connecting role and only the install as the test user | ||
| * (test/helpers/use_test_user.sql). Cleanup has to be the connecting role's | ||
| * because a leftover schema can belong to any role; the schema creation has | ||
| * to be, because the whole point is that the test user holds nothing but | ||
| * what it was granted on that one schema. | ||
| */ | ||
| CREATE OR REPLACE FUNCTION pg_temp.count_nulls_cleanup_test_schemas( | ||
| p_mode text | ||
|
|
@@ -25,7 +27,7 @@ BEGIN | |
| /* | ||
| * A run that died before its own teardown leaves a schema nothing else | ||
| * knows the name of, so match the prefix (see | ||
| * count_nulls_install_extension()'s c_prefix below) and drop whatever's | ||
| * count_nulls_prepare_test_schema()'s c_prefix below) and drop whatever's | ||
| * there. | ||
| */ | ||
| FOR r IN SELECT nspname FROM pg_namespace WHERE nspname LIKE 'count_nulls test schema %' LOOP | ||
|
|
@@ -34,8 +36,16 @@ BEGIN | |
| END | ||
| $body$; | ||
|
|
||
| CREATE OR REPLACE FUNCTION pg_temp.count_nulls_install_extension( | ||
| p_version text | ||
| /* | ||
| * Names the schema count_nulls is about to be installed into, creating it as | ||
| * the connecting role. 'existing' instead finds the schema a prior, separate | ||
| * prepare-old run installed into: that installation is the thing the mode | ||
| * exists to test, so creating a second schema here would both destroy the | ||
| * one-schema invariant test/helpers/find_test_schema.sql relies on and leave | ||
| * the real one untested. | ||
| */ | ||
| CREATE OR REPLACE FUNCTION pg_temp.count_nulls_prepare_test_schema( | ||
| p_mode text | ||
| ) RETURNS name LANGUAGE plpgsql AS $body$ | ||
| DECLARE | ||
| /* | ||
|
|
@@ -46,6 +56,48 @@ DECLARE | |
| */ | ||
| c_prefix CONSTANT text := 'count_nulls test schema '; | ||
| v_schema name; | ||
| BEGIN | ||
| IF p_mode NOT IN ('fresh', 'update', 'existing') THEN | ||
| RAISE EXCEPTION USING | ||
| MESSAGE = format('invalid value for parameter "count_nulls.test_load_mode": %L', p_mode) | ||
| , HINT = 'Valid values are ''fresh'', ''update'', and ''existing''.' | ||
| , ERRCODE = 'invalid_parameter_value' | ||
| ; | ||
| END IF; | ||
|
Comment on lines
+60
to
+66
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor consistency nit: this validates the same value (
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Claude here — correct, and already discussed on this PR: load.sql's check pre-dates this PR (see the reply on 3961370056) and is deliberately out of scope here per the maintainer - not brought in line with the new style in this PR. |
||
|
|
||
| IF p_mode = 'existing' THEN | ||
| SELECT nspname INTO v_schema | ||
| FROM pg_namespace n JOIN pg_extension x ON n.oid = x.extnamespace | ||
| WHERE extname = 'count_nulls' | ||
| ; | ||
|
|
||
| IF v_schema IS NULL THEN | ||
| RAISE EXCEPTION | ||
| 'count_nulls is not installed, so mode ''%'' has no test schema to find' | ||
| , p_mode | ||
| ; | ||
| END IF; | ||
|
|
||
| RETURN v_schema; | ||
| END IF; | ||
|
jnasbyupgrade marked this conversation as resolved.
|
||
|
|
||
| v_schema := c_prefix || substr(md5(random()::text), 1, 12); | ||
| EXECUTE format('CREATE SCHEMA %I', v_schema); | ||
|
|
||
| RETURN v_schema; | ||
| END | ||
| $body$; | ||
|
|
||
| /* | ||
| * Runs as the test user, on a schema the connecting role made and granted it | ||
| * rights on (test/helpers/use_test_user.sql) - which is what makes a | ||
| * successful install prove count_nulls needs no privilege on the database | ||
| * itself, only on its target schema. | ||
| */ | ||
| CREATE OR REPLACE FUNCTION pg_temp.count_nulls_install_extension( | ||
| p_schema name | ||
| , p_version text | ||
| ) RETURNS void LANGUAGE plpgsql AS $body$ | ||
| BEGIN | ||
| /* | ||
| * 'current' means whatever the control file's default_version is, matching | ||
|
|
@@ -56,9 +108,6 @@ BEGIN | |
| RAISE EXCEPTION $$p_version must be set explicitly, or 'current'$$; | ||
| END IF; | ||
|
|
||
| v_schema := c_prefix || substr(md5(random()::text), 1, 12); | ||
| EXECUTE format('CREATE SCHEMA %I', v_schema); | ||
|
|
||
| /* | ||
| * WITH SCHEMA rather than arranging search_path first: this way a | ||
| * successful install proves the install script doesn't depend on | ||
|
|
@@ -67,11 +116,29 @@ BEGIN | |
| */ | ||
| EXECUTE format( | ||
| 'CREATE EXTENSION count_nulls WITH SCHEMA %I%s' | ||
| , v_schema | ||
| , p_schema | ||
| , CASE WHEN p_version = 'current' THEN '' ELSE format(' VERSION %L', p_version) END | ||
| ); | ||
|
|
||
| RETURN v_schema; | ||
| /* | ||
| * CREATE EXTENSION runs the install script with search_path set to | ||
| * "<target>, pg_temp", and search_path silently drops a schema the role | ||
| * lacks USAGE on - so a role holding only CREATE builds the entire | ||
| * extension in pg_temp, where it disappears at disconnect, and CREATE | ||
| * EXTENSION still reports success. pg_extension.extnamespace says the | ||
| * target either way, so the only way to tell is to look for the objects. | ||
| */ | ||
| IF NOT EXISTS( | ||
| SELECT 1 | ||
| FROM pg_depend d | ||
| JOIN pg_proc p ON p.oid = d.objid AND d.classid = 'pg_proc'::regclass | ||
| JOIN pg_namespace n ON n.oid = p.pronamespace | ||
| WHERE d.deptype = 'e' | ||
| AND d.refobjid = (SELECT oid FROM pg_extension WHERE extname = 'count_nulls') | ||
| AND n.nspname = p_schema | ||
| ) THEN | ||
| RAISE EXCEPTION 'count_nulls installed no functions into schema %', p_schema; | ||
| END IF; | ||
| END | ||
| $body$; | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.