Skip to content

Commit ae8d7c0

Browse files
renovate[bot]github-actions[bot]unknown
authored
Update stacklok/toolhive-registry-server to v1.4.1 (#847)
* Update stacklok/toolhive-registry-server to v1.4.1 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * Refresh reference assets for toolhive-registry-server v1.4.1 * Polish v1.4.1 default-deny authz prose Tighten editorial pass on the registry authorization update for toolhive-registry-server v1.4.1: avoid the overloaded word "entry" when describing source/registry config, and align "authentication is enabled" wording with the existing publish-rules section. Co-authored-by: Unknown <Unknown@users.noreply.github.com> * Apply prettier and eslint fixups to skill output --------- Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Unknown <Unknown@users.noreply.github.com>
1 parent b5c5cdf commit ae8d7c0

3 files changed

Lines changed: 59 additions & 28 deletions

File tree

.github/upstream-projects.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
projects:
2121
- id: toolhive-registry-server
2222
repo: stacklok/toolhive-registry-server
23-
version: v1.4.0
23+
version: v1.4.1
2424
docs_paths:
2525
- docs/toolhive/guides-registry
2626
- docs/toolhive/concepts/registry-criteria.mdx

docs/toolhive/guides-registry/authorization.mdx

Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -202,26 +202,49 @@ that include `org: "acme"` and `team: "platform"`. Otherwise, the server returns
202202
The server uses **containment** (superset check) for claim validation: the
203203
caller's claims must be a superset of the resource's claims. For example:
204204

205-
| Resource claims | Caller JWT claims | Result |
206-
| --------------------------------- | --------------------------------- | ------- |
207-
| `{org: "acme"}` | `{org: "acme", team: "platform"}` | Allowed |
208-
| `{org: "acme", team: "platform"}` | `{org: "acme"}` | Denied |
209-
| `{}` (no claims) | `{org: "acme"}` | Allowed |
210-
| `{org: "acme"}` | `{org: "contoso"}` | Denied |
211-
212-
Registries and sources with no claims are accessible to all authenticated
213-
callers.
214-
215-
:::warning[Entries without claims are invisible when authorization is enabled]
216-
217-
Entries with no claims are visible in anonymous mode and
218-
[auth-only mode](#auth-only-mode), but **invisible** when full authorization is
219-
enabled. The per-entry filter requires both sides to have claims for a match.
220-
Entries without claims are filtered out. To make entries visible, attach claims
221-
to the source (for synced sources) or to individual entries (via the publish
222-
payload or the
223-
[`authz-claims` annotation](./configuration.mdx#per-entry-claims-via-annotation)
224-
for Kubernetes sources).
205+
| Resource claims | Caller JWT claims | Result |
206+
| --------------------------------- | --------------------------------- | ---------------------------------- |
207+
| `{org: "acme"}` | `{org: "acme", team: "platform"}` | Allowed |
208+
| `{org: "acme", team: "platform"}` | `{org: "acme"}` | Denied |
209+
| `{}` (no claims) | `{org: "acme"}` | Denied (default-deny on unlabeled) |
210+
| `{org: "acme"}` | `{org: "contoso"}` | Denied |
211+
212+
:::warning[Unlabeled resources are invisible when authorization is enabled]
213+
214+
When `auth.authz` is configured, sources, registries, and entries with no claims
215+
are treated as **default-deny**: invisible to every authenticated caller except
216+
a super-admin. The list endpoints and the single-resource gate agree, so a
217+
resource is either visible everywhere or nowhere.
218+
219+
Anonymous mode and [auth-only mode](#auth-only-mode) bypass the gate entirely,
220+
so unlabeled resources remain accessible there.
221+
222+
To make a resource reachable under full authorization, attach claims to it:
223+
224+
- **Sources and registries**: set the `claims` field on the source or registry
225+
in your configuration file.
226+
- **Entries from synced sources**: tag the source so its claims are inherited
227+
during sync.
228+
- **Entries on Kubernetes sources**: use the
229+
[`authz-claims` annotation](./configuration.mdx#per-entry-claims-via-annotation)
230+
on the CRD.
231+
- **Entries on managed sources**: include `claims` in the publish payload or
232+
call `PUT /v1/entries/{type}/{name}/claims` from a super-admin.
233+
234+
:::
235+
236+
:::info[Upgrading from earlier releases]
237+
238+
Releases before v1.4.1 treated an unlabeled resource as visible to every
239+
authenticated caller, but only on single-resource paths like
240+
`GET /v1/sources/{name}`. List endpoints already filtered them out, so the same
241+
row could appear via one path and not another.
242+
243+
After upgrading to v1.4.1 or later with `auth.authz` configured, those unlabeled
244+
rows become invisible to every non-super-admin caller. To restore access, a
245+
super-admin can tag them in place via the per-entry claims endpoint, or
246+
operators can add a tenant-wide claim to the source so synced entries inherit it
247+
on the next sync.
225248

226249
:::
227250

@@ -398,6 +421,8 @@ sources:
398421
399422
- name: shared
400423
managed: {}
424+
claims:
425+
org: 'acme'
401426
402427
registries:
403428
- name: platform
@@ -441,17 +466,20 @@ With this configuration:
441466
`shared`.
442467
- **Data team members** (JWT with `org: "acme"`, `team: "data"`) can access the
443468
`data` registry and see entries from `data-tools` and `shared`.
444-
- **Writers** (JWT with `role: "writer"`) can publish to the `shared` managed
445-
source.
469+
- **Writers** in the `acme` org (JWT with `org: "acme"`, `role: "writer"`) can
470+
publish to the `shared` managed source. The `org: "acme"` claim on the source
471+
is what makes it reachable to non-super-admin callers under default-deny.
446472
- **Admins** (JWT with `org: "acme"`, `role: "admin"`) can manage sources and
447473
registries within the `acme` org.
448474
- **Super-admins** (JWT with `role: "super-admin"`) can access and manage
449475
everything.
450476

451-
Entries published to the `shared` source without claims are visible through any
452-
registry that includes it, subject only to the registry-level claims gate. To
453-
restrict visibility further, attach claims when
454-
[publishing entries](#claims-on-published-entries).
477+
Every entry published to the `shared` source must carry claims (publishing
478+
without claims is rejected when authentication is enabled), and those claims
479+
must be a subset of the publisher's JWT. To narrow visibility within a registry,
480+
publish with team-scoped claims like `{org: "acme", team: "platform"}` so only
481+
that team's registry surfaces the entry. See
482+
[Claims on published entries](#claims-on-published-entries) for the full rules.
455483

456484
## Next steps
457485

static/api-specs/toolhive-registry-api.yaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ components:
275275
description: Last sync attempt
276276
type: string
277277
lastSyncTime:
278-
description: Last successful sync
278+
description: Last completed sync attempt
279279
type: string
280280
message:
281281
description: Status or error message
@@ -525,6 +525,7 @@ components:
525525
description: Version is the package version (required for npm, pypi, nuget;
526526
optional for mcpb; not used by oci where version is in the identifier)
527527
example: 1.0.2
528+
maxLength: 255
528529
minLength: 1
529530
type: string
530531
type: object
@@ -773,6 +774,8 @@ components:
773774
type: string
774775
version:
775776
example: 1.0.2
777+
maxLength: 255
778+
minLength: 1
776779
type: string
777780
websiteUrl:
778781
example: https://modelcontextprotocol.io/examples

0 commit comments

Comments
 (0)