Conversation
POST /images/{name}/push names its subject in two pieces: the repository
in the path and the tag in ?tag=. imageIdentifier strips the "/push"
suffix and handed the bare repository to the ownership inspect, which
resolves the daemon's default tag (typically :latest). Two failures
followed:
- A proxy-scoped build pushed as {name}:{tag} was denied with "owner
policy could not resolve image" whenever {name}:latest happened to be
absent. That is the standard `docker push registry/repo:tag` CLI
spelling (the CLI sends the tag in the query, never in the path), so
every tagged push against an image without a local :latest tag failed.
- When {name}:latest WAS present, the push was authorized on tag-ref
equality: a caller owning only :latest could push {name}:{anything}.
The mutation pass now captures the query tag
(ownershipRequestReferences.imagePushTag) and the authorization pass
qualifies the identifier with it, so the inspect resolves exactly the
local image the daemon will push.
Push forms whose effective reference one image inspect cannot enumerate
are refused instead of guessed at, via the denyReason path commit
already uses for query-named resources:
- No tag at all: distribution.Push pushes every local reference of the
repository (daemon/internal/distribution/push.go: "If no tag is
provided, all tags are pushed"), an effect one image inspect cannot
enumerate — the same shape imageEffectDenial refuses per-image exports
and deletes for. The docker CLI never sends this form (it resolves a
name-only reference to ?tag=latest), so it is reachable only by direct
API clients.
- A repeated or case-variant tag spelling: dockerd reads the first value
and Podman's compat handler the last (filter.FoldedScalarQueryValue is
the existing helper for this disagreement).
The retag route POST /images/{name}/tag keeps its bare-path
authorization: the resource it mutates is the source image the path
names, and `docker tag src dst` spells the full source reference into
the path. Podman's native POST /libpod/images/{name}/push carries the
full reference in the path and is unaffected.
Verified end to end against dockerd 26.1.3: a tagged push of an owned
image without any local :latest succeeds; the bare and repeated-tag
forms get their new denials; a foreign-owned tag is refused with the
ordinary cross-owner denial.
MgSrdEer
requested review from
ALARGECOMPANY,
biggest-littlest and
scttbnsn
as code owners
September 11, 2026 03:25
|
@MgSrdEer is attempting to deploy a commit to the CodesWhat Team on Vercel. A member of the Team first needs to authorize it. |
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
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.
Problem
POST /images/{name}/pushnames its subject in two pieces: the repository in the path and the tag in?tag=.imageIdentifierstrips the/pushsuffix and handed the bare repository to the ownership inspect, which resolves the daemon's default tag (typically:latest). Two failures followed:{name}:{tag}was denied withowner policy could not resolve imagewhenever{name}:latesthappened to be absent. That is the standarddocker push registry/repo:tagCLI spelling (the CLI sends the tag in the query, never in the path), so every tagged push against an image without a local:latesttag failed.{name}:latestWAS present, the push was authorized on tag-ref equality: a caller owning only:latestcould push{name}:{anything}.Fix
The mutation pass captures the query tag (
ownershipRequestReferences.imagePushTag) and the authorization pass qualifies the identifier with it (appendImagePushTag), so the inspect resolves exactly the local image the daemon will push.Push forms whose effective reference one image inspect cannot enumerate are refused instead of guessed at, via the
denyReasonpath commit already uses for query-named resources:distribution.Pushpushes every local reference of the repository (daemon/internal/distribution/push.go: "If no tag is provided, all tags are pushed"), an effect one image inspect cannot enumerate — the same shapeimageEffectDenialrefuses per-image exports and deletes for. The docker CLI never sends this form (it resolves a name-only reference to?tag=latest), so it is reachable only by direct API clients.filter.FoldedScalarQueryValueis the existing helper for this disagreement).The retag route
POST /images/{name}/tagkeeps its bare-path authorization: the resource it mutates is the source image the path names, anddocker tag src dstspells the full source reference into the path. Podman's nativePOST /libpod/images/{name}/pushcarries the full reference in the path and is unaffected.Verification
Unit tests in
image_push_test.go(fake-inspector middleware tests, route classification, query parsing), plus an end-to-end run against dockerd 26.1.3 with a real registry:{repo}:{tag}, no local:latesttagquerydocker push repo(CLI resolves to?tag=latest):latestabsent, allowed when owned?tag=a&tag=bPOST /images/{name}/tag)go test ./...passes (41 packages).