Repository navigation
fix(catalog): grants, rules and catalog grants follow a table rename - #764
Merged
Merged
Conversation
…a table rename Spec and implementation plan for KI-308 and KI-309: restrictive grants and path rules are copied to a renamed table before the commit and stay on the old name, allows and catalog grants move after it, restrictive patterns and hand-written restrictions refuse the rename, and stale references are reported. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
G5 lets a rename through when the new name is already covered by a restriction of the same kind and equal effect (defined per kind; partial covers refuse and the 409 names what is missing; egret never creates the cover). G6 accepts the allow gap and records it as a docs Limitation. The plan gains a cover task; open questions are closed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Trino's tag row regresses to -1 on the first tag poll after every policy download. A rename that waits for a Trino tag pair and a Trino policy pair would otherwise wait one more tag poll after both were reported. Each pair is now latched the first time every recent plugin reports it (spec D7). Also records Step 0 of the grants-follow-rename package in the spec (§14). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
egret_perm_compile::follow sorts the catalog's explicit grants and path rules for one coordinate move: literal rows follow (deny grants and path rules are copied, allows moved), restrictive patterns that stop matching refuse, allow patterns that stop matching are left, and a destination of more than one namespace level refuses restrictions and leaves allows (spec D3, D4, D14). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…'s rows follow::handwritten_via finds the enabled operator policies on the bound profiles that name the source literally: a mask, a row filter, a deny or an exclusion list on the renamed level refuses, a plain allow is reported (spec D5, G3). copy_in_tx inserts a restrictive row's copy on the destination, skipping one whose equivalent is already there and naming a rule copy '<name> (<destination>)' with a suffix on a collision (D1, D13); delete_copies_in_tx undoes exactly those; move_allows_in_tx re-points an allow in place, keeping its id (D2). refusal_message words the 409 (§8). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A held rename's copy compiles both names with the source marked leaving, and the profile total skipped every body on a leaving coordinate. Grants and path rules stay on the old name after the rename (spec G2), so their bodies are served afterwards: only clearance and tag-rule bodies, which move with the classifications, are skipped now (D12). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A grant or rule create, patch or delete that names a literal table a held rename is moving now answers 409 table_change_held, as a catalog-tag write does: it tries the hold's name lock for the old and the new scope on its own transaction (spec D10). A steward's form saved during the hold can no longer re-point a moved allow back or remove a copy the compensation then cannot find. Pattern scopes and catalogs without an embedded warehouse take no lock. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…name commits A table rename whose source a deny grant, a path mask or a path row filter names now takes the hold, whether or not it is classified. The copy transaction re-reads what the move carries under the locks, refuses there what a pattern or a hand-written policy would let escape, and inserts a copy of each restriction on the new name; the originals stay on the old name (spec G2, D1, D11). A copied restriction adds the Trino profiles' policy versions to the wait (D6); a refused or undone rename deletes exactly the copies. The fake Trino plugin of the tests polls its policies too, as Trino 483 does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After a held rename commits, its allow grants are re-pointed to the new name in place, ids kept, in the after-commit transaction (spec G2, D2, G6); a rename that carries only allows waits for no plugin (D11). The same transaction records perm_grant:move per allow and perm_grant:copy / perm_rule:copy per restriction copied, by the catalog client that renamed (D9), so a refused or undone rename records nothing. The governance feed words them for policy:read readers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A deny grant, mask or row filter whose name pattern or schema scope covered the renamed table and would not cover its new name refuses the rename with 409, naming the rows, at plan time and again under the hold's locks; a following restriction into a namespace of several levels refuses too (spec G4, D4, D14). An allow pattern that stops covering the table is left as it is and recorded as perm_grant:left, which the feed words. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…estricted A restrictive pattern row that would stop covering a renamed table no longer refuses when the new name already carries the same restriction: denies whose actions and subjects together cover it, or a mask or row filter of the same type and expression exempting no more; the rename's own copies count (spec G5, §5.9, D21). A partial cover still refuses and the 409 says what the new name lacks. A covered rename takes the hold without a wait, so the cover cannot be deleted while it is checked again under the locks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An enabled operator policy on a profile bound to the catalog that names the renamed table literally with a mask, a row filter, a deny or an exclusion list refuses the rename with 409 naming profile/policy (id); the policy is never rewritten (spec G3, D5). A plain hand-written allow naming it is reported as ranger_policy:left, which the feed words. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The swap pattern leaves the new table under the original deny while the allows follow their tables; renaming back and forth does not stack copies (D13); a case-only rename, a view sent to the table endpoint and a source that carries nothing move nothing; a 500 after a committed rename still moves the allows. A migrated restriction stays undoable after a rename, and a moved migrated allow makes its undo refuse (spec §10). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A renamed column keeps its path mask and column deny on both names, copied before the commit and waited for on Trino; its column allow moves after the commit; a column pattern that would stop covering it refuses; swapped columns carry both sets of denies, and swapped columns with different masks are refused by the overlap check (spec §5.4). The column plan landed with the table rename's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After a rename of a live table commits, held or not, every table catalog grant on the old name is re-pointed to the new one, names compared with lakekeeper's collation as the guard compares them; a grant the role already holds there merges; namespace grants stay (spec D8, KI-309). The guard reads grants on every request, so nothing waits, and since F4 the vended credentials follow too. Each move records catalog_grant:move by the verified caller in a new Catalog family of the feed, read with catalog_registry:read (D9). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ped namespace After a recursive namespace drop commits, the literal allow grants on its tables go in the purge transaction, recorded as perm_grant:delete with the trigger iceberg_drop_namespace, and then the table catalog grants in the namespace and below it, recorded as catalog_grant:delete, both by the caller (spec D15). Deny grants, path rules, schema and pattern scopes and namespace catalog grants stay. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hat do not exist Three Overview findings (spec D16): permissions_on_missing_tables (literal grants, path rules and hand-written policy tables on names with no table, one sample per name, saying when a rename kept a restriction there on purpose), permissions_on_missing_columns (column-level grants and rules a live table lacks, with the rename candidate), both for policy:read, and catalog_grants_on_missing_tables for catalog_registry:read, at any namespace depth through the new table_states_ns_via, which the single-level table_states_via now wraps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two Overview findings beside renamed_names_reused (spec D17): renamed_names_lost_grants for policy:read readers, from perm_grant:move events, and renamed_names_lost_catalog_grants for catalog_registry:read readers, from catalog_grant:move events. A name is reported when it is a live table again and carries none of the moved grants; the sample links the renamed table. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Overview's Not checked for you lines name the five checks the grants-follow package adds instead of their raw kinds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The governance changes route's description now names the catalog-grant events a catalog_registry:read reader sees. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cts 1-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
… names The "name lost its allows / catalog grants" findings read only each grant's latest move, so a grant moved on again (table renamed twice) erased the report for the name it left, and a new table carrying one moved allow hid the finding for all of them. Every move now counts, and a name is reported unless it carries every moved allow. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A table or column rename now carries the permissions that name it. Before this, a rename left the new name without its deny grants, path masks and row filters (so the table could escape its restrictions), and left allow and catalog grants on the old name (so the renamed table lost its readers).
tablesecurable) are re-pointed after the commit. Uncancellable; a failure is logged.tablecatalog grants under the namespace.permissions_on_missing_tables,permissions_on_missing_columns,catalog_grants_on_missing_tables,renamed_names_lost_grants,renamed_names_lost_catalog_grants. Governance > Changes gains sentences forperm_grant:move|copy|left,perm_rule:copy,ranger_policy:left,catalog_grant:move|delete.Spec:
docs/en/specs/2026-10-27-grants-follow-table-rename-design.md(G1–G6 user decisions, D1–D21 defaults, §9 release note and Limitation, §14 deviations and live-check notes). Plan:docs/en/plans/2026-10-27-grants-follow-table-rename.md.Refs KI-308, KI-309. Prerequisite F-A (#758) and the vended-credentials package (#760) are merged.
Defaults the user may revisit (spec §4)
D1–D21 are recorded with their reasons in spec §4. The ones most worth a look: D1 (the hold is a copy-then-forward, not a block on reads), D4 (patterns are refused or reported, never split), D8 (catalog grants are re-pointed with no hold), D10 (grant and rule writes on a held name wait their turn), D17 (the two lost-grant findings).
Gate
cargo fmt --all -- --check: clean.cargo clippy --workspace --all-targets -- -D warnings: clean (after mergingorigin/mainataed09501).cargo test -p egret-controlplane -p egret-catalog-engine -p egret-perm-compile: 77 binaries pass. One failure,table_hook_db::a_rename_no_trino_plugin_confirms_is_refused_and_undone, failed with "other permission changes were being written" under parallel load and passed alone (5.8 s). It is a name-lock timing flake in the rename path, which this PR does not change.fd0d57ae: workspace tests 8573 pass, 0 DB skips; known environment-only failures:egret-workflow --test sql_starrocks_live(needs a live StarRocks) andegret-dataapi --test serving_shared_store(needsEGRET_TEST_SHARED_STORE_URL).tsc -b, build and the bundle tests pass.Live check (plan Task 19, Trino 483 + StarRocks 4.1.6, real Ranger plugins, rename read loop every 2 s)
Two runs. Run 2 is on
139db73dand is the one to read.eurows; email hashed for uncleared users-1regression seen once (E27)<no plugin has polled>; after restart 204 in 56 s. Allow-only rename 204 in ~1 s while Trino was stoppedranger_policy:left,catalog_grant:deleteand the Who column not checkedG6 gap (commit to first allowed read), run 1: about 28.8 s on Trino, 14 s on StarRocks. Run 2: no refusal observed at 2 s granularity.
D1/D2 (lost-grant findings), fixed in this PR: both now show for
orders_v2after the swap and persist to the end.Known limitations and observations (not fixed)
emailto 128 hex characters; Trino to 64.Non-goals
Views and their renames (spec §11, item 1); case-only renames of catalog grants (F-B, §11 item 2); credential lifetime (KI-315, separate package); cross-warehouse registration (KI-316).
Docs
egret-data/docs(KI-308, KI-309, spec §11 rows, the G6 Limitation of spec §9, D20) is not opened yet. Per the repo's CLAUDE.md, a PR that changes user-visible behaviour must include it. This PR changes the Overview findings and the Changes sentences.Related defects
🤖 Generated with Claude Code