Skip to content

Docker: an image a selector of the caller's grant hides is not found (404) - #704

Merged
schmitch merged 1 commit into
mainfrom
schmitch/docker-hidden-404-703
Oct 30, 2026
Merged

schmitch merged 1 commit into
mainfrom
schmitch/docker-hidden-404-703

Conversation

@schmitch

Copy link
Copy Markdown
Member

Fixes #703

Follow-up of #648 / #700: with a content selector on the grant of the requested repository (a group, or a hosted or proxy repository pulled directly), Docker refused a hidden image with 403 DENIED, where #648 asks for 404 like a package that does not exist (and where a hidden member already gave 404).

Change (crates/server/src/images/dispatch.rs)

  • rbac_decision replaces the boolean check inside decide: no read on the repository → Deny (401/403 as before); read allowed but a selector hides the image → Hidden for a read, Deny for a push or delete.
  • refusal answers Hidden with 404 NAME_UNKNOWN (the same answer an unknown repository gives an admin), on every endpoint under /v2/<name>/: manifests, blobs, tags, referrers, HEAD too. A proxy asks its upstream nothing for it, as before.
  • write_target turns a Hidden group read into Deny, so a push through a group outside the selector stays 403.
  • rbac_allows (used by the token service and imports) keeps its meaning: true only for Allow. A registry token still grants pull only on names the caller may read; a hidden name's request answers 404 whatever the token's scope.

Tests

Checks run

  • cargo test -p forge-server --lib --test registry (248 + 47)
  • cargo clippy --workspace --all-targets -- -D warnings, cargo fmt --all --check, cargo xtask changelog --check

docs/docker.md describes what a hidden image answers. Changelog: docs/changes/2.2.0/703.fixed.md.


Generated by Claude Code

`Registry::decide` folded the caller's content selectors into the
permission check, so a pull of an image a selector of the requested
repository's grant hid (a group's included) was refused with 403
`DENIED` (401 for an anonymous caller), while the same image hidden
through a group's member answered 404, and NuGet and npm answer a
package a selector hides as not found.

`rbac_decision` now tells the two apart: a caller who may not read the
repository is `Deny` as before; one who may, asking for an image a
selector hides, is `Hidden` to a read, which `refusal` answers as a
name that does not exist (404 `NAME_UNKNOWN`) on every endpoint. A push
or delete outside the selector stays `Deny` (403), also the read check
a push through a group makes first. `rbac_allows`, which the token
service uses, still allows only what the caller may see, so a registry
token grants `pull` on no hidden name.

The #648 group test now expects 404 for a selector on the group's
grant, and a new test pulls hidden images of a hosted repository on
every endpoint (HEAD too), and checks that a push and a delete outside
the selector, and a pull by a caller who may not read the repository,
are still refused.

Fixes #703

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012e6DJZaXD2mBH9tURsdutM
@schmitch
schmitch added this pull request to the merge queue Oct 30, 2026
Merged via the queue into main with commit 3a27785 Oct 30, 2026
18 checks passed
@schmitch
schmitch deleted the schmitch/docker-hidden-404-703 branch October 30, 2026 06:22
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.

Docker: an image a selector of the caller's own grant hides answers 404 (NAME_UNKNOWN), not 403

2 participants