Skip to content

Schema- and catalog-level read grants, reserved to metastore administrators - #25

Merged
hujincalrin41 merged 12 commits into
mainfrom
schema-catalog-read
Oct 10, 2026
Merged

hujincalrin41 merged 12 commits into
mainfrom
schema-catalog-read

Conversation

@hujincalrin41

Copy link
Copy Markdown
Contributor

What

Read access at the schema and catalog level, for service accounts that should see every table under a schema (or catalog) without a grant per table — the Unity Catalog counterpart of granting on a tag or a database in other catalogs.

The server already resolved SELECT/MODIFY through the hierarchy (a schema-level SELECT covers every table beneath it, tables created later included). This PR exposes it, reserves it, and documents it.

Server

  • SELECT and MODIFY on a catalog or schema can be granted or revoked only by a metastore owner (the built-in admin, or anyone appointed through PUT /api/1.0/unity-control/metastore/admins/<email>). A catalog or schema owner who tries gets PERMISSION_DENIED; a request mixing USE_* with SELECT is refused as a whole, nothing half-applied.
  • USE CATALOG / USE SCHEMA and CREATE_* keep their existing rules: owners still grant them, so single-table grants by a table owner keep working.

UI

  • Grant access on a schema or catalog page offers a read level (writes USE CATALOG + USE SCHEMA + SELECT; for a catalog all three on the catalog, since USE SCHEMA granted there inherits to every schema, present and future). Offered to metastore admins only; the Access panel lists read and create rows separately and lets only an admin revoke read there.
  • The Users page's Grant access dialog follows the same gate, and its Grant button stays off on a catalog the user neither owns nor administers.
  • The Users page itself is shown to metastore administrators only (they alone may create, deactivate, delete or promote accounts); others get no menu entry and /users sends them to the catalogs. The SCIM listing is unchanged.

Docs

  • deploy/README.md / README.zh-CN.md: a new Authorization model section — the two kinds of privilege, how inheritance works and what it does not reach (a sibling schema, another catalog), the schema-wide and catalog-wide recipes, who may grant what and why USE_* is deliberately not reserved, and who sees the user directory.

Tests

  • Server: SdkHierarchyGrantAccessControlTest, 12 scenarios — inheritance to existing and later tables/schemas, revoke closing everything at once, no reach into sibling schemas or other catalogs, the metastore-owner gate (owner denied, appointed admin allowed and stood down again, holder cannot pass on or give up, mixed request refused whole), USE_* alone reads nothing, temporary table credentials following the inherited SELECT/MODIFY.
  • UI: +15 cases across access.test.ts, AccessPanel, GrantAccessModal, GrantToUserModal and App routing; suite 122/122.

🤖 Generated with Claude Code

hujincalrin41 and others added 12 commits October 10, 2026 08:47
…re owner

SELECT and MODIFY resolve through the hierarchy: granted on a schema they cover
every table in it, tables created later included, and on a catalog every
schema's tables. That is what a service account needs instead of a grant per
table -- and it is why the grant must not be an owner's to give: a schema's
owner is whoever created it, and could open everything beneath it.

Require the metastore owner for SELECT/MODIFY changes on a catalog or schema.
USE_* and CREATE_* stay with the owners, since a table's owner granting read on
that one table must be able to add the USE_* its ancestors require.

Tests pin the reach (existing and future tables, list/get, revoke taking all
of them at once, catalog level through two levels) and the rule (owner refused
on SELECT/MODIFY at both levels, including revoke; owner still grants USE_*,
CREATE_* and table-level read).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The simplified Grant access dialog offered only 'create' on a schema or a
catalog, and its comments said privileges do not inherit. They do: SELECT on a
schema reaches every table beneath it. Offer 'read' there, writing the USE_*
the ancestors need plus SELECT on the securable; revoke removes only that
SELECT. The access panel lists one row per (principal, level) so read and
create holders are told apart.

Read on a schema or catalog is reserved to the metastore owner server-side, so
the dialog disables it for anyone else and says why, and the panel's revoke
control for such a row follows the same signal rather than ownership.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Which privileges inherit and which do not, what USE_* is for, how to give a
service account every table in a schema with one grant, and who may grant
what. Both guides.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ogs; catalog read needs USE_SCHEMA on the catalog

Three new scenarios beside the two inheritance ones: a schema-level read sees
nothing in a sibling schema created later (even once let in with USE_SCHEMA)
nor in a new catalog; a catalog-level read reaches schemas created after the
grant; a catalog-level read sees nothing in another catalog.

The catalog read recipe is USE_CATALOG + USE_SCHEMA + SELECT, all on the
catalog: USE_SCHEMA is checked per schema and only inherits to new schemas
when granted on the catalog. Catalogs, schemas and tables in these tests are
created by principal-1, since the create expressions have no metastore-OWNER
clause and the admin token cannot create inside someone else's catalog.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Without it the principal cannot enter any schema, so the catalog-wide SELECT
reached nothing; granted on the catalog, USE_SCHEMA inherits to every schema,
present and future. One PATCH on the catalog carries all three.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Adds the catalog recipe (USE CATALOG + USE SCHEMA + SELECT on the catalog),
states that a read covers its subtree only (no sibling schema, no other
catalog), and corrects the claim that USE_* never inherits: USE SCHEMA
granted on a catalog does reach every schema in it. Only OWNER never inherits.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Six more scenarios around the schema/catalog-level SELECT:
- MODIFY on a catalog, and revoking a catalog SELECT, are reserved to the
  metastore owner like the rest.
- An owner's request that mixes USE_* with SELECT/MODIFY is refused as a
  whole; the USE_* part does not land either.
- A user appointed metastore administrator through the control API can grant
  and revoke at those levels; standing them down takes it away again.
- A user who holds an inherited SELECT can neither pass it on (at the schema,
  the catalog or a table beneath) nor revoke it from themselves.
- USE_* alone lists container names and reads no table; a schema SELECT
  without USE_CATALOG, or a catalog SELECT without USE_SCHEMA, reaches nothing.
- Temporary table credentials follow the inherited grants: READ with schema
  SELECT, READ_WRITE only once schema MODIFY is added, both closed when SELECT
  is revoked.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… above a table does not

States the decision and its reasoning: there is no grant option, holding a
privilege never includes passing it on; USE CATALOG / USE SCHEMA are entry
rights that read nothing and are needed for an owner's single-table grants,
so reserving them would cost self-service and buy no safety; the data right
is SELECT/MODIFY, and that is what is reserved to the metastore owner. Also
names the control-API call that appoints a metastore administrator, and
that a mixed USE+SELECT request is refused whole.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The Users page's "Grant access" dialog (GrantToUserModal) offered read on a
catalog or schema to any signed-in user, and its Grant button lit up on any
catalog. The server refused both (403), but the dialog should not promise what
the server will not do. Now, as in GrantAccessModal: read on a catalog or
schema is disabled for a non-admin with the reason shown, the level falls back
to create, and the button stays off on a catalog the user neither owns nor
administers, since every level writes USE_CATALOG there.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Only a metastore owner may create, deactivate, delete or promote accounts, so
the directory has nothing on it for anyone else. The Users entry leaves the
navigation for a non-admin and /users sends them back to the catalogs; with
authorization switched off nobody is restricted and the gate stays open. The
SCIM listing itself is untouched: the per-securable Grant access dialog picks
its grantee from it, which an owner granting on their own table relies on.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@hujincalrin41
hujincalrin41 merged commit 5a38db9 into main Oct 10, 2026
13 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.

1 participant