test(security): non-superuser installer invariant - #349
Conversation
Prove the partition-keys SECURITY DEFINER co-ownership invariant (SPEC section 6, T-security) against an install owned by a non-superuser, non-pgque_admin role -- the first test to exercise it unmasked by superuser privilege. Shell harness: role bootstrap needs a superuser, but the install itself runs under set role as the plain installer. Includes a negative control: reassigning receive_partitioned's owner (with every other needed privilege granted) breaks the reader flow with 42501 on get_batch_cursor, proving co-ownership is load-bearing and the harness detects its absence. Standalone via PGQUE_TEST_SUPERUSER_DSN; not wired into run_all.sql (CI wiring is a follow-up). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
samorev Code Review Report
REVIEW FINDINGS (10)HIGH
HIGH [bugs] On PG16+ against a cluster where the
MEDIUM [bugs] Cleanup leaks cluster-wide state and the leak is only a warning, so the run still exits 0.
MEDIUM [tests] Nothing in this PR executes the harness. It is not in
MEDIUM [tests] Every assertion in the harness except the two explicit
MEDIUM [bugs] Any failure of the install step is reported as a product finding against
LOW [bugs] The negative control's post-flip phase re-claims a slot that phase A claimed and never released, and discards the return value without asserting it.
LOW [bugs] The bootstrap's conditional block guards on
LOW [tests] The negative control hard-codes the exact privilege set
LOW [tests] The ownership sanity check runs only against
Summary
Note:
Review metadatasamorev-assisted review (AI analysis by Tanya301/samorev) |
What invariant
The partition-keys SECURITY DEFINER co-ownership invariant (
blueprints/partition-keys/SPEC.md§6, T-security in §9):receive_partitionedreaches the admin-onlypgque.get_batch_cursor(4)trusted-SQL hook not via any grant but because both functions share an OWNER — the role that randevel/sql/pgque.sql. The invariant is "installed by the pgque install owner", explicitly NOT requiring superuser orpgque_admin. Every existing test runs against a superuser-owned install, where superuser privilege masks ownership — this is the first test to exercise the invariant as designed. (SPEC §9 marks T-security; the spec file is being edited on the PR-336 branch, so this PR deliberately makes no spec edit — a one-line "implemented" note can ride that branch.)Why a shell harness
Role and database bootstrap needs a superuser, but the point of the test is that the install itself must not: the harness (superuser DSN) creates a
pgque_nsu_installer_*role (CREATEROLE, no superuser, no pgque_admin) plus bare reader/writer app roles and two installer-owned databases, then runs\i devel/sql/pgque.sqlunderset roleas the installer —set roleapplies that role's privileges to every permission/ownership check, so the install runs with genuinely non-superuser rights and the harness needs no passwords. That bootstrap/step split doesn't fittests/run_all.sql(one database, one role), hence a standalonetests/security_nonsuperuser_install.shmirroringtests/two_session_slot_claim.sh.What it asserts, in order:
devel/sql/pgque.sqlinstalls cleanly as a non-superuser owner (no findings — it does, including the conditional role-membership grants).get_batch_cursorco-owned by the installer.sends; reader doessubscribe_slot→claim_slot→receive_partitioned→ack_partitionedover n=2, with hash-routing and per-key single-slot assertions.get_batch_cursordirectly still fails42501(both overloads, mirroringtests/test_security_get_batch_cursor.sql).partition_consumer/partition_slotunreadable by reader and writer (42501).The negative control (the "red" that proves teeth)
In a second, identical install: after proving the reader flow works, the superuser reassigns
receive_partitioned's OWNER to a foreign role that is deliberately given every other privilege the function body needs (pgque_readermembership fornext_batch, EXECUTE on_slot_guard/_slot_batch/_slot_name) — everything except co-ownership. The previously-working reader flow must then fail with42501specifically onget_batch_cursor(asserted on sqlstate and message). If the flow still worked, the harness raisesNEGATIVE CONTROL HAS NO TEETHand fails. Co-ownership is load-bearing, and this harness detects its absence.CI wiring — follow-up
Not wired into
tests/run_all.sql(needs the superuser bootstrap + throwaway databases + cluster roles). Follow-up: a dedicated CI job invoking the harness withPGQUE_TEST_SUPERUSER_DSNacross PG 14–18.Verification (local, PG 18.3)
shellcheck: clean. Cleanup verified: no leftover
pgque_nsu_*roles or databases.🤖 Generated with Claude Code