fix: image ls with a bare repository name should match all tags - #5115
Merged
AkihiroSuda merged 1 commit intoAug 1, 2026
Merged
Conversation
`nerdctl image ls myapp`, where myapp is a bare repository name (no tag or digest), returned nothing unless myapp happened to have a `:latest` tag - unlike `docker image ls myapp`, which lists every tag of the repository. referenceutil.Parse normalizes a bare repository name by unconditionally applying distribution/reference's TagNameOnly, which appends an implicit ":latest" tag. listOptions then built an exact-match filter from that normalized reference (`name==docker.io/library/myapp:latest`), so any image tagged anything other than "latest" was silently excluded. Extract the filter-construction logic into a small nameFilterFor helper. When the argument named an explicit tag or digest, keep matching it exactly. When it was a bare repository name, build a `name~=^<repo>:` regex filter instead (escaping the repository name with regexp.QuoteMeta), so it matches any tag under that repository. This mirrors the `~=` regex-filter pattern already used elsewhere in the codebase for similar purposes, e.g. pkg/idutil/imagewalker/imagewalker.go and pkg/idutil/containerwalker/containerwalker.go. Added TestNameFilterFor covering a bare repository name (now matches any tag), an explicit tag, an explicit ":latest" tag, a digest, and a bare name with a domain that needs regex-escaping. Verified this test fails without the fix, reproducing the exact reported behaviour (name==docker.io/library/myapp:latest instead of a repo-wide match). Fixes containerd#5113 Signed-off-by: ankit090701 <ankitanku090701@gmail.com>
Contributor
Author
|
The 5 red CI jobs are all pre-existing environmental flakiness, unrelated to this change - I traced each one down to the actual assertion/error, not just the test name:
None of these touch I don't have permission to re-run the failed jobs on this repo ( |
|
@ankit090701 Thanks! |
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.
What's the bug
nerdctl image ls myapp, wheremyappis a bare repository name (no tag or digest), returns nothing unlessmyapphappens to have a:latesttag. This is different fromdocker image ls myapp, which lists every tag of the repository.even though
myapp:9.8-ltsc2022-...clearly exists.Root cause
referenceutil.Parsenormalizes a bare repository name by unconditionally applyingdistribution/reference'sTagNameOnly, which appends an implicit:latesttag (referenceutil.go#L133-L134).listOptionsincmd/nerdctl/image/image_list.gothen built an exact-match filter straight from that normalized reference:which becomes
name==docker.io/library/myapp:latest- so any image tagged with anything other thanlatestis silently excluded.The fix
Extracted the filter-construction logic into a small
nameFilterForhelper:parsedReference.ExplicitTag != "" || parsedReference.Digest != ""), keep matching it exactly withname==....name~=^<repo>:regex filter instead (escaping the repository name withregexp.QuoteMeta), so it matches any tag under that repository.This mirrors the
~=regex-filter pattern already used elsewhere in the codebase for similar name/id matching, e.g.pkg/idutil/imagewalker/imagewalker.goandpkg/idutil/containerwalker/containerwalker.go, both of which already buildfield~=regexfilters withregexp.QuoteMetaescaping - so this isn't introducing a new pattern, just applying an existing one to close this gap.Testing
TestNameFilterFor, a focused unit test on the extracted helper (no daemon required), covering:name~=^docker\.io/library/myapp:regex filter (matches any tag)myapp:v1) → still an exactname==...:v1filter:latesttag → still an exactname==...:latestfiltername==...@sha256:...filterregistry.example.com/foo/my.app)name==docker.io/library/myapp:latestinstead of a repo-wide match.go build ./...andgo vet ./...pass. The rest of the package's tests aretigron/E2E tests that shell out to a builtnerdctlbinary against a live containerd daemon, which I don't have available in my sandboxed environment - those fail withunable to find binary "nerdctl"regardless of this change (verified against an unmodified checkout).Fixes #5113