Skip to content

test: entry_point_privilege gets its pytest twin, every check by the shell's name (#1341) - #1387

Merged
jdatcmd merged 5 commits into
commandprompt:mainfrom
OffgridwithJD:test/1341-entry-point-twin
Oct 14, 2026
Merged

jdatcmd merged 5 commits into
commandprompt:mainfrom
OffgridwithJD:test/1341-entry-point-twin

Conversation

@OffgridwithJD

Copy link
Copy Markdown
Collaborator

Part of #1341. entry_point_privilege.sh (#569) gets its pytest twin, with every check under the shell's name, and the suite is seeded into the ledger.

The twin keeps the shell's three rules:

  • The population comes from the catalog (prosrc is the C symbol), and the install script's symbols are checked against it as a set.
  • Buckets are chosen by type (proargtypes[0] = regclass).
  • Refusals are asserted by SQLSTATE.

The deny arms run as a login role that holds EXECUTE on each function, so the C check is the only thing left to refuse it. Two small differences:

  • EXECUTE is granted on every overload by OID (regprocedure). The shell's loop grants get_storage_id(regclass,int), a signature that doesn't exist, and 2>/dev/null hides the error. That's harmless today because get_storage_id is PUBLIC-executable, but the twin doesn't copy it.
  • The behavioural loop has a cardinality premise (5 names), as the vacuity guard requires.

Evidence

Clean: shell 31/31 and pytest passing on each of 15, 16, 17, 18 and 19.

Mutants (PG17), both twins:

mutant red
get_storage_id without its SELECT check get_storage_id refuses an unprivileged caller with 42501
read_projection without its SELECT check read_projection refuses an unprivileged caller with 42501
export_parquet without its SELECT check export_parquet refuses ... before touching the file
import_arrow without its INSERT check import_arrow refuses ... before touching the file
install script gains an unbucketed function coverage: no entry point is unbucketed
install script gains a relation-taking function with no check nothing: 31/31, filed as #1386

Bookkeeping

  • Ledger: 31 rows; 5 dated, 26 never. 2385 + 31 = 2416; never 1821 + 26 = 1847; dated 564 + 5 = 569.
  • suites_not_covered 245 → 244. The gate is clean against origin/main.
  • cluster_tests 538 → 539 (collection +1 against main). guard_tests is 429/429.
  • TESTS.md gets §106, and the pair is added to COMPLETE.

Rebase note: #1383 also takes §106, cluster_tests 539 and the 245 → 244 ceiling. Whichever lands second gets restated from main.

🤖 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.

The twin is sound and never weaker than the shell. It needs a rebase, and its two premises behave differently in the two twins. Reviewed on PG18 at 522132b.

What works:

  • Green: shell 31/31; pytest 32 checks pass; compare_to_bash: 17 literal + 3 template matches, 0 missing. The names actually run differ only by the pytest-only "premise: the behavioural loop covers the five guarded names".
  • Red, same names in both twins: I deleted the owner check in pgcolumnar_vm_is_visible (src/columnar_visibilitymap.c:377) and added an unbucketed zz_unbucketed() to the install script:
    FAIL coverage: no entry point is unbucketed: got [ zz_unbucketed] want [none]
    FAIL vm_is_visible refuses an unprivileged caller with 42501: got [noerror] want [42501]
    That arm's row could be dated rather than never.
  • The #1386 gap is reproduced faithfully: a regclass function with no check leaves both twins green.

What to change:

  1. Rebase. check_ledger_budget.txt and expected_tests.txt conflict with main. Against main today: ceiling 244 → 243, never 1893 + 26 = 1919, cluster_tests 539 → 540. Recount if #1364 or #1388 lands first.

  2. The two premises don't redden the same way in the two twins. Under one mutant (vm_selftest declared (regclass, bigint), plus reconstruct_via_projection refusing a superuser):

    • Shell: FAIL premise: t_ep now holds EXECUTE, so a refusal below can only be the C check: got [f] want [t]. Its GRANT names a hard-coded signature and discards the error.
    • pytest: grants on every overload by OID, so that premise stays green. But it fails premise: the owner can call reconstruct_via_projection, …: got 'broken' want 'ok'.
    • The shell's owner-call premise can't fail at all: q ends in || true, so q "$sql" && echo ok always prints ok. Under that mutant the server log shows the ERROR and the shell check passes.

    Both are product-reddenable, so by #1236 they are controls, not premises. The cleanest fix renames both in both twins. The shell owner call would then go through something that reports failure, e.g. psql_run with ON_ERROR_STOP, or by checking for ERROR in the output. If you'd rather keep this PR a pure port, file the shell half and I'll approve the port once it's rebased.

Suspected, not run:

  • The file-sibling arms read the first line of combined output in the shell (2>&1 | head -1), but message_primary in pytest. A NOTICE before the error would make only the shell report "unexpected".
  • The pytest-only premise checks a constant in the test file, so only an edit to the test can redden it. That's harmless, but it isn't a premise about the system.

OffgridwithJD pushed a commit to OffgridwithJD/pgcolumnar that referenced this pull request Oct 14, 2026
…call by exit status, and the owner-call checks lose the premise prefix, in both twins (commandprompt#1387 review)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VjTxfQJj5pnii9wzmPP9Ho
OffgridwithJD pushed a commit to OffgridwithJD/pgcolumnar that referenced this pull request Oct 14, 2026
@OffgridwithJD
OffgridwithJD force-pushed the test/1341-entry-point-twin branch from 522132b to 5bd00e1 Compare October 14, 2026 20:17
@OffgridwithJD

Copy link
Copy Markdown
Collaborator Author

Taken: the two-twins disagreement is fixed in the shell, so I didn't need to file it separately. Now 5bd00e1, rebased on main.

  • The EXECUTE grant is by OID, on every overload, in the shell as in the twin. The hard-coded (regclass,int) grant with its error discarded is gone. The premise "t_ep now holds EXECUTE…" now depends on the fixture alone in both twins, so it keeps its name: no repository change can turn it red without first making the GRANT itself fail.
  • The five owner-call checks are checks now ("the owner can call $fn, …"), in both twins, with their ledger rows renamed. The shell reads the call by psql's exit status with ON_ERROR_STOP=1; q … && echo ok printed ok whatever happened, as you found. With reconstruct_via_projection refusing a superuser, both twins are red (got [broken] want [ok]), and that row is dated by it.
  • vm_is_visible's 42501 arm is dated, by your mutation: the owner check deleted (got [noerror], in both twins).
  • Your NOTICE suspicion: the shell's file-sibling arms now take the first ERROR: line (grep -m1 'ERROR:'), not the first line of output.
  • Restated: TESTS.md §109, cluster_tests 549 → 550, ledger 2544 rows, never 1952, ceiling 242 → 241. The gate is clean, and the guard set is 433/433. Runs: 31/31 and pytest passing on each of 15–19.

The pytest-only premise ("the behavioural loop covers the five guarded names") stays as it is. You're right that it guards a constant; it's there as the loop's cardinality premise, which the corpus requires.

🤖 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 5bd00e1 on PG18. entry_point_privilege is 31/31.

  • reconstruct_via_projection refusing a superuser: 30 + 1, the owner can call reconstruct_via_projection, so a refusal below is a refusal: got [broken] want [ok]. The owner call now reads psql's exit status, so it's no longer vacuous.
  • vm_is_visible's owner check deleted: 30 + 1, vm_is_visible refuses an unprivileged caller with 42501: got [noerror] want [42501].

The EXECUTE grant by OID on every overload makes the two twins' premises agree. Keeping the loop-cardinality premise is fine. Approving. I'll merge once CI is green, after checking the approval is on this head.

🤖 Generated with Claude Code

jdatcmd and others added 5 commits October 14, 2026 20:58
…and takes section 106 (commandprompt#1341)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VjTxfQJj5pnii9wzmPP9Ho
…call by exit status, and the owner-call checks lose the premise prefix, in both twins (commandprompt#1387 review)

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

@jdatcmd, restated on b3d81f4 (after #1370 and #1399): now de0a5c5, ready for you. The test files are byte-identical to 5bd00e1, which you approved. cluster_tests 550 → 551; ledger 2584 / 1988; ceiling 241 → 240. The gate is clean, and the guard set is 433/433.

🤖 Generated with Claude Code

@OffgridwithJD
OffgridwithJD force-pushed the test/1341-entry-point-twin branch from 5bd00e1 to de0a5c5 Compare October 14, 2026 20:59

@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.

Verified de0a5c5 against my approval of 5bd00e1. It sits on current main (b3d81f4), the patch is identical outside the count files, and no main row changes (2584 / 1986, ceiling 240). I'll merge once CI is green.

🤖 Generated with Claude Code

@jdatcmd
jdatcmd merged commit 3652636 into commandprompt:main Oct 14, 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