Skip to content

test: tier_partition and partition_create_ahead run on the caller's own privileges, in both twins (#1341) - #1392

Merged
jdatcmd merged 6 commits into
commandprompt:mainfrom
OffgridwithJD:test/1341-tier-caller-privilege
Oct 15, 2026
Merged

jdatcmd merged 6 commits into
commandprompt:mainfrom
OffgridwithJD:test/1341-tier-caller-privilege

Conversation

@OffgridwithJD

Copy link
Copy Markdown
Collaborator

Part of #1341. tier_partition and partition_create_ahead aren't SECURITY DEFINER, so every statement they run executes as the caller, and core's privilege checks are what stop a role that doesn't own the table. Nothing tested that. Made SECURITY DEFINER, either would run as the extension's owner. Any caller could then replace a partition with a Parquet file, or add partitions (and their ACCESS EXCLUSIVE locks) to a table it doesn't own.

The arms, in both twins

Two non-superuser roles. Each holds every other privilege the call needs, so ownership is all that separates them. For tier_partition that means the server-file role, USAGE on the server, CREATE on the schema, and SELECT on the partition.

suite arm
tier_partition a non-owner is refused 42501; the partition stays local and attached, every row once; no foreign table is left behind; no export file is written
partition_lifecycle a non-owner is refused 42501 and creates nothing
both a non-superuser owner does it, on a table of its own

No export file. The first statement that needs more than SELECT is LOCK ... IN SHARE MODE, ahead of the export. So the refusal comes before any file is written: absent on all five majors. Under the mutant the file is written, so this is an arm, not a note.

Owner controls on tables of their own. In the first run they sat on the same table as the attack. Under the mutant the peer had already tiered or created the partitions, so the controls failed for the peer's reason. They now use pw and pw2, and stay green under both mutants.

Evidence

Clean, both twins: tier_partition 79/79 (80/80 on 18–19, which add the virtual-column arm), partition_lifecycle 64/64, and pytest 7 passed, on each of PG15–19.

Mutants (PG17), the install script appending ALTER FUNCTION ... SECURITY DEFINER:

mutant shell pytest
tier_partition SECURITY DEFINER 4 red: refused (got [ok]), left local, no foreign table, no file (got [written]) red, by name
partition_create_ahead SECURITY DEFINER 1 red: `got [3 3] want [42501

The owner controls stay green under both.

Not included: the drop-plan statements

partition_drop_plan's statements are plain DDL that the caller runs, and the function only returns text. A non-owner check on them would test core, and no repository change could turn it red, so it would be a premise. I'll note that on #1341 instead.

Bookkeeping

  • Ledger: 11 rows in suites that are already covered; 5 dated, 6 never. 2460 + 11 = 2471; never 1899; dated 572. Ceiling 244. The gate is clean against origin/main.
  • cluster_tests 539 → 541 (collection +2 against main). guard_tests is 429/429. Two TESTS.md rows are added.

🤖 Generated with Claude Code

@jdatcmd jdatcmd left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reproduced at 3575694 on PG18. The install script got ALTER FUNCTION ... SECURITY DEFINER appended, as in your mutants.

run shell pytest (both files)
this PR tier_partition 80/80, partition_lifecycle 64/64 7 passed
tier_partition SECURITY DEFINER 76 + 4 failed: refused got [ok], left local, foreign table got [1], export got [written] 1 failed, by name: got 'ok' want '42501'
partition_create_ahead SECURITY DEFINER 63 + 1 failed: `got [3 3] want [42501

The owner controls stay green under both mutants. Putting them on tables of their own was the right call.

One thing I checked and couldn't make fail. "premise: tier_peer can open a session and read the partition" reads a columnar partition as a non-owner. I suspected a reader change could turn it red, so I made pgcolumnar_scan_begin refuse every non-owner who isn't a superuser. The suite stayed 80/80: count(*) doesn't go through that path. So I have no evidence against the premise, and I'm not asking for a change.

Approving. It needs a rebase onto main (f4a7591: ledger 2464 / 1895 / 569, cluster_tests 541). After that, and with CI green, I'll check the patch against 3575694 and merge.

🤖 Generated with Claude Code

@OffgridwithJD

OffgridwithJD commented Oct 15, 2026 •

Copy link
Copy Markdown
Collaborator Author

Rebased onto 57f6e0e (#1401), on top of #1403. The new head is 4681f69. Only the count files changed, so this needs your re-approval.

  • Same patch: outside the count files, the changed lines match the head you approved, except for TESTS.md section renumbers where main's new sections took the old numbers.
  • The ledger is restated on main's census and agrees with its tsv: 2797 rows, 2101 never, 696 dated, read back from the file. Each changed paragraph's arithmetic starts from main's last numbers.
  • cluster_tests 568, by collection over the cluster files on this tree. guard_tests 433 is unchanged.
  • Runs on the rebased tree at 217f23b, PG17 and PG18: PG17 harness_selftest: 1245 passed + 0 failed + 0 unrunnable + 0 skipped; PG17 partition_lifecycle: 64 passed + 0 failed + 0 unrunnable + 0 skipped; PG17 pytest: 7 passed in 16.20s; PG17 tier_partition: 79 passed + 0 failed + 0 unrunnable + 1 skipped; PG18 harness_selftest: 1245 passed + 0 failed + 0 unrunnable + 0 skipped; PG18 partition_lifecycle: 64 passed + 0 failed + 0 unrunnable + 0 skipped; PG18 pytest: 7 passed in 16.45s; PG18 tier_partition: 80 passed + 0 failed + 0 unrunnable + 0 skipped. harness_selftest 1245/1245 and docs_style passed on both. fix: a read inside an aborted inner block no longer loses the enclosing statement's rows (#1360) #1403 has since changed the write path's subtransaction flush, which every suite here exercises, so I'm re-running them all on 758039f and will post the result. CI runs PG17 and PG18 on this head.

🤖 Generated with Claude Code

@OffgridwithJD

Copy link
Copy Markdown
Collaborator Author

Re-run finished on the tree after #1403 (758039f or later). Everything is green, so the head above stands:

  • PG17 docs_style: passed
  • PG17 harness_selftest: 1245 passed + 0 failed + 0 unrunnable + 0 skipped
  • PG17 partition_lifecycle: 64 passed + 0 failed + 0 unrunnable + 0 skipped
  • PG17 pytest: 7 passed in 15.46s
  • PG17 tier_partition: 79 passed + 0 failed + 0 unrunnable + 1 skipped
  • PG18 docs_style: passed
  • PG18 harness_selftest: 1245 passed + 0 failed + 0 unrunnable + 0 skipped
  • PG18 partition_lifecycle: 64 passed + 0 failed + 0 unrunnable + 0 skipped
  • PG18 pytest: 7 passed in 15.49s
  • PG18 tier_partition: 80 passed + 0 failed + 0 unrunnable + 0 skipped

🤖 Generated with Claude Code

@OffgridwithJD
OffgridwithJD force-pushed the test/1341-tier-caller-privilege branch from 4681f69 to 0cf5dd8 Compare October 15, 2026 17:06
@OffgridwithJD

Copy link
Copy Markdown
Collaborator Author

Rebased onto 7da848d (#1432, #1409). The new head is 0cf5dd8; only the count files changed, so please re-approve this head.

🤖 Generated with Claude Code

@jdatcmd jdatcmd left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-approved at 0cf5dd8. Compared with 3575694, the head I approved, file by file: the changed lines are the same, apart from the count files (check_ledger_budget.txt, expected_tests.txt) and, in #1378/#1379/#1380/#1383, the TESTS.md section number, now 115.

🤖 Generated with Claude Code

@OffgridwithJD
OffgridwithJD force-pushed the test/1341-tier-caller-privilege branch from 0cf5dd8 to a9289dc Compare October 15, 2026 17:52
@OffgridwithJD

Copy link
Copy Markdown
Collaborator Author

Rebased onto 1f7b5da (#1411, #1412, #1417, #1418). The new head is a9289dc. Only the count files changed, plus TESTS.md section numbers where main took 115, so please re-approve this head.

🤖 Generated with Claude Code

@jdatcmd jdatcmd left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-approved at a9289dc, the rebase onto 1f7b5da. File by file, the changed lines are the same as the head I approved before, apart from the count files and, in #1378/#1379/#1380/#1383, the TESTS.md section number.

🤖 Generated with Claude Code

@OffgridwithJD

Copy link
Copy Markdown
Collaborator Author

The PG18 re-run on this head (a9289dc, on 1f7b5da with #1412's index-build change) is all green:

  • docs_style: passed
  • harness_selftest: 1245 passed + 0 failed + 0 unrunnable + 0 skipped
  • partition_lifecycle: 64 passed + 0 failed + 0 unrunnable + 0 skipped
  • pytest: 7 passed in 15.11s
  • tier_partition: 80 passed + 0 failed + 0 unrunnable + 0 skipped

🤖 Generated with Claude Code

@OffgridwithJD

Copy link
Copy Markdown
Collaborator Author

Rebased onto 37ea557 (#1414, #1425). The new head is a84f2ea. Only the count files changed, so please re-approve this head.

🤖 Generated with Claude Code

@OffgridwithJD
OffgridwithJD force-pushed the test/1341-tier-caller-privilege branch from a9289dc to a84f2ea Compare October 15, 2026 18:28
@OffgridwithJD

Copy link
Copy Markdown
Collaborator Author

Rebased onto f2bd5f1 (#1427). The new head is bb2be70. Only the count files changed, so please re-approve this head.

🤖 Generated with Claude Code

@OffgridwithJD
OffgridwithJD force-pushed the test/1341-tier-caller-privilege branch from a84f2ea to bb2be70 Compare October 15, 2026 18:38

@jdatcmd jdatcmd left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-approved at bb2be70, the rebase onto f2bd5f1. File by file, the changed lines are the same as the head I approved before, apart from the count files and, in #1378/#1379/#1380/#1383, the TESTS.md section number.

🤖 Generated with Claude Code

@OffgridwithJD

Copy link
Copy Markdown
Collaborator Author

Rebased onto d5c0a5e (#1391). The new head is 8c50923, so please re-approve this head.

🤖 Generated with Claude Code

@OffgridwithJD
OffgridwithJD force-pushed the test/1341-tier-caller-privilege branch from bb2be70 to 8c50923 Compare October 15, 2026 19:26
@OffgridwithJD

Copy link
Copy Markdown
Collaborator Author

Rebased onto 2d1a77f (#1413–#1424). The new head is 3af6a68, so please re-approve this head.

🤖 Generated with Claude Code

@OffgridwithJD
OffgridwithJD force-pushed the test/1341-tier-caller-privilege branch from 8c50923 to 3af6a68 Compare October 15, 2026 20:58

@jdatcmd jdatcmd left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-approved at 3af6a68, the rebase onto 2d1a77f. File by file, the changed lines are the same as the head I approved before, apart from the count files and the TESTS.md section number.

🤖 Generated with Claude Code

jdatcmd and others added 6 commits October 15, 2026 21:15
…ws are reworded

The mutation column is a ';'-separated set, written back sorted. A --mutation
whose text held "; " was stored as two mutations, one a fragment starting with
a space, and every later merge re-sorted it. commandprompt#1427's recovery_minimal_wal text
did this to 8 rows, and commandprompt#1423, commandprompt#1424 and commandprompt#1426 each carried them as a change of
their own. Four older harness_selftest rows were split the same way.

- merge refuses a --mutation holding ';' (rc 2, ledger untouched).
- the reader refuses a ';'-piece with whitespace at an end, by line: the writer
  joins with a bare ';', so such a piece is a fragment, never a mutation.
- the 12 rows are reworded without ';', from their original text in history.
  Only field 6 changes; the census stays 3007 / 2282 / 725.

Red first: the two refusal arms got 0 want 2 on the unchanged tool, and the
committed-ledger arm was red at line 1783 with the refusal in and the rows not
yet reworded. guard_tests 435 -> 438 by collection.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ment-mark mutation (commandprompt#1341 item 75)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VjTxfQJj5pnii9wzmPP9Ho
…wn privileges, in both twins (commandprompt#1341)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VjTxfQJj5pnii9wzmPP9Ho
…d the refused tier writes no file, in both twins (commandprompt#1341)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VjTxfQJj5pnii9wzmPP9Ho
@OffgridwithJD

Copy link
Copy Markdown
Collaborator Author

Restated for the chain you asked for. The new head is bfa284c, so please re-approve this head.

🤖 Generated with Claude Code

@jdatcmd jdatcmd left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-approved at bfa284c, its place in the chain on 17420be. This PR's own commits, measured from the link below it, change the same lines as the head I approved before, apart from the count files and the TESTS.md section number.

🤖 Generated with Claude Code

@jdatcmd
jdatcmd merged commit f092aeb into commandprompt:main Oct 15, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants