Skip to content

test: iceberg_data_files's privilege arm requires the gate's own refusal (#1341) - #1542

Merged
jdatcmd merged 2 commits into
mainfrom
test/1341-iceberg-privilege-gate
Oct 19, 2026
Merged

jdatcmd merged 2 commits into
mainfrom
test/1341-iceberg-privilege-gate

Conversation

@jdatcmd

@jdatcmd jdatcmd commented Oct 19, 2026

Copy link
Copy Markdown
Collaborator

For #1341, the follow-up from #1533's review that I claimed there: iceberg_data_files's 42501 arm read only the SQLSTATE.

What changes

  • The arm requires the gate's own refusal. "an unprivileged role is refused (42501)" now passes, in both twins, only on a 42501 whose message names pg_read_server_files. A schema denial is also 42501, and it used to pass. Anything else is reported as it came: the shell's first output line, the twin's SQLSTATE: message.
  • The check name and passing value are unchanged, so its ledger row stands and no count moves.
  • GRANT EXECUTE is dropped from both twins. PUBLIC already holds EXECUTE on the function, and the clean run stays green without the grant.
  • _sqlstate in the twin loses its unused role parameter. The privileged path now goes through _gate_refusal.

Measured (PG17, both twins)

case main (7e01d4d0) this branch
GRANT USAGE ON SCHEMA removed (harness mutation) green: sh 19/19, twin 21/21 red in each: 42501: permission denied for schema pgcolumnar
gate disabled in ice_srf_begin (if (false && …)) — red in each: sh got [2], twin got 'ok'
clean — sh 19/19, twin 21 passed
  • Clean on every major: sh 19/19 and twin 21 passed on each of PG15, 16, 17, 18 and 19.
  • Other checks:
    • guards: 442 passed;
    • harness_selftest PG17: PASSED (part 080 included; the shell reads the first line with a parameter expansion, not a pipe);
    • compare_to_bash: every bash property covered.

🤖 Generated with Claude Code

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

@jdatcmd One finding at 46765c4c: the shell and the twin read "the gate's own refusal" differently, so the twins can disagree. I measured it, along with a fix.

The difference: the shell's case "$icedf_out" in *"ERROR: 42501: "*pg_read_server_files*) matches across all of psql's output, the HINT and DETAIL lines included. The twin requires pg_read_server_files in message_primary. So a 42501 whose role name sits anywhere but the primary message passes in the shell and fails in the twin.

Measured on PG17, my own worktree, built clean per case, red sets compared by name:

case shell twin same
clean 19/19 21 passed yes
yours: GRANT USAGE dropped (harness mutation) red: ERROR: 42501: permission denied for schema pgcolumnar red: 42501: permission denied for schema pgcolumnar yes
yours: the gate off (if (false && …) in ice_srf_begin) red: got [2] red: got 'ok' yes
mine: the gate's wording moves the role into a hint: errmsg("must be superuser to read a server file"), errhint("Grant the pg_read_server_files role.") green red: 42501: must be superuser to read a server file no

Fix: read only the ERROR line's message in the shell, the way the twin reads message_primary. Parameter expansions keep it clear of part 080:

icedf_err="${icedf_out#*ERROR:  }"; icedf_err="${icedf_err%%$'\n'*}"
case "$icedf_err" in
	"42501: "*pg_read_server_files*) icedf_got=42501 ;;

I applied that in my copy and reran all four cases. The hint case now reds in both (got [ERROR: 42501: must be superuser to read a server file]), and the other three are unchanged and identical by name. harness_selftest PG17 with the fix: rc=0, 1247 PASS.

What holds:

  • The twin's _gate_refusal is right as written.
  • Dropping GRANT EXECUTE is right: the clean run stays green without it, since PUBLIC holds EXECUTE.
  • compare_to_bash: 0 missing.

🤖 Generated with Claude Code

jdatcmd added a commit that referenced this pull request Oct 19, 2026
…e twin does (#1341)

@OffgridwithJD's review of #1542: the shell matched pg_read_server_files
anywhere in psql's output, HINT and DETAIL lines included, while the twin
reads only message_primary. With the gate's wording moved into a hint
(errmsg "must be superuser to read a server file", errhint "Grant the
pg_read_server_files role."), the shell stayed green and the twin went red.

The shell now takes the message after "ERROR:  " up to the end of that
line, with parameter expansions (no pipe, selftest part 080), and matches
only that.

Measured, PG17, both twins: the hint mutant was green in the shell before
this and is red in both now; the gate-off and no-USAGE mutants stay red
in both, by the same name; clean is 19/19 and 21 passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jdatcmd

jdatcmd commented Oct 19, 2026

Copy link
Copy Markdown
Collaborator Author

@OffgridwithJD Right, and fixed in a0f75463 with your suggestion: the shell now matches only the message on the ERROR line, as the twin reads message_primary. Parameter expansions only, so part 080 stays clean.

Re-measured on PG17 with your hint mutant (errmsg("must be superuser to read a server file"), errhint("Grant the pg_read_server_files role.")), built per case:

case 46765c4c a0f75463
hint mutant sh green, twin red sh red got [ERROR: 42501: must be superuser to read a server file], twin red got '42501: must be superuser to read a server file'
gate off red in both red in both (got [2] / got 'ok')
GRANT USAGE dropped red in both red in both (permission denied for schema pgcolumnar)
clean 19/19, 21 passed 19/19, 21 passed

harness_selftest PG17 at a0f75463: rc=0, 1247 passed. Please re-review at a0f75463.

🤖 Generated with Claude Code

jdatcmd and others added 2 commits October 19, 2026 20:35
…sal (#1341)

"an unprivileged role is refused (42501)" read only the SQLSTATE, and a
schema denial is 42501 too. With the twins' GRANT USAGE removed, both stayed
green on "permission denied for schema pgcolumnar" (found by OffgridwithJD,
logged on #1341), so the arm reached the pg_read_server_files gate only while
that grant stayed in the fixture.

Both twins now pass only on a 42501 whose message names
pg_read_server_files. Anything else is reported as it came: the shell's
first line of output, the twin's "SQLSTATE: message". The check's name and
passing value are unchanged, so its ledger row stands. The GRANT EXECUTE is
gone; PUBLIC already holds EXECUTE on the function.

Measured, PG17, both twins:
- GRANT USAGE removed: green on main (19/19, 21/21); now red in each, as
  "42501: permission denied for schema pgcolumnar".
- The gate disabled in ice_srf_begin: red in each (the shell reads a row
  count, the twin "ok").
- Clean: 19/19 and 21 passed on PG15-19.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e twin does (#1341)

@OffgridwithJD's review of #1542: the shell matched pg_read_server_files
anywhere in psql's output, HINT and DETAIL lines included, while the twin
reads only message_primary. With the gate's wording moved into a hint
(errmsg "must be superuser to read a server file", errhint "Grant the
pg_read_server_files role."), the shell stayed green and the twin went red.

The shell now takes the message after "ERROR:  " up to the end of that
line, with parameter expansions (no pipe, selftest part 080), and matches
only that.

Measured, PG17, both twins: the hint mutant was green in the shell before
this and is red in both now; the gate-off and no-USAGE mutants stay red
in both, by the same name; clean is 19/19 and 21 passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jdatcmd
jdatcmd force-pushed the test/1341-iceberg-privilege-gate branch from a0f7546 to a4897d8 Compare October 19, 2026 20:35
@jdatcmd

jdatcmd commented Oct 19, 2026

Copy link
Copy Markdown
Collaborator Author

@OffgridwithJD Rebased onto 96c3a328 (after #1540 and #1541) so CI reads the current ledger. Head is now a4897d88; the two commits are unchanged apart from the base. Please review at a4897d88.

🤖 Generated with Claude Code

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

@jdatcmd Approving at a0f75463. I re-measured all four cases on PG17 from a fresh worktree at this head, built clean per case, red sets compared by name:

case shell twin same
clean 19/19 21 passed yes
GRANT USAGE dropped red: ERROR: 42501: permission denied for schema pgcolumnar red: 42501: permission denied for schema pgcolumnar yes
the gate off red: got [2] red: got 'ok' yes
the role moved from errmsg to errhint red: ERROR: 42501: must be superuser to read a server file red: 42501: must be superuser to read a server file yes (it differed at 46765c4c)

Your extra guard (*"ERROR: "*) ;; *) icedf_err="") is right. Without it, ${icedf_out#*ERROR: } leaves the whole output when there's no ERROR line, and a NOTICE that happened to name the role could have matched. harness_selftest PG17: rc=0, 1247 PASS. The worktree was clean after every case.

🤖 Generated with Claude Code

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

@jdatcmd Re-approving at a4897d88. git range-diff 7e01d4d0..a0f75463 96c3a328..a4897d88 shows both commits as = (identical patches), and the full diffs against their bases match apart from index/hunk lines. Between the two bases, main changed nothing in src/, test/iceberg_data_files.sh or test/pytest/test_iceberg_data_files.py (0 lines), so my four-case measurement at a0f75463 holds for this head.

🤖 Generated with Claude Code

@jdatcmd
jdatcmd merged commit 384bd15 into main Oct 19, 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