From 648f91e9c6e95303f942e0dd2ddcc018eee0725d Mon Sep 17 00:00:00 2001 From: Atishyy27 Date: Thu, 20 Aug 2026 21:27:24 +0530 Subject: [PATCH] fix(remote): keep '=' in a prune filter value ImageEngine.Prune split each --filter on every '=' and kept everything after the first as separate values, so a filter whose value itself contains '=' was torn apart. podman-image-prune.1.md documents label=key=value and gives '--filter label=version=1.0' as an example, which produced filters["label"] = ["version", "1.0"] instead of ["version=1.0"]. libimage turns every element into its own label filter and MatchLabelFilters cuts each one on '=' itself, so the request became 'has a label key version' AND 'has a label key 1.0'. Nothing carries a key named 1.0, so the prune matched no images and silently removed nothing. Local podman is unaffected: the abi path passes opts.Filter through untouched. This is remote-only, and it diverges from both siblings -- List uses SplitN(filter, "=", 2) and Events validates then rejoins with strings.Join. Prune now mirrors List. The existing e2e case only used 'label=abc', a bare key, which survives the old split by accident; added one that uses a key=value label and checks the non-matching image is still there afterwards. Signed-off-by: Atishyy27 --- pkg/domain/infra/tunnel/images.go | 8 ++++++-- test/e2e/images_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go index 49e9eca0ca..bd7355c01c 100644 --- a/pkg/domain/infra/tunnel/images.go +++ b/pkg/domain/infra/tunnel/images.go @@ -101,8 +101,12 @@ func (ir *ImageEngine) History(_ context.Context, nameOrID string, _ entities.Im func (ir *ImageEngine) Prune(_ context.Context, opts entities.ImagePruneOptions) ([]*reports.PruneReport, error) { filters := make(map[string][]string, len(opts.Filter)) for _, filter := range opts.Filter { - f := strings.Split(filter, "=") - filters[f[0]] = f[1:] + f := strings.SplitN(filter, "=", 2) + if len(f) > 1 { + filters[f[0]] = append(filters[f[0]], f[1]) + } else { + filters[f[0]] = append(filters[f[0]], "") + } } options := new(images.PruneOptions).WithAll(opts.All).WithFilters(filters).WithExternal(opts.External).WithBuildCache(opts.BuildCache) reports, err := images.Prune(ir.ClientCtx, options) diff --git a/test/e2e/images_test.go b/test/e2e/images_test.go index 1be2052a10..0eaade981d 100644 --- a/test/e2e/images_test.go +++ b/test/e2e/images_test.go @@ -494,6 +494,31 @@ RUN > file2 Expect(result.OutputToStringArray()).To(BeEmpty()) }) + It("podman image prune --filter label=key=value", func() { + dockerfile := `FROM quay.io/libpod/alpine:latest +RUN > file +` + dockerfile2 := `FROM quay.io/libpod/alpine:latest +RUN > file2 +` + podmanTest.BuildImageWithLabel(dockerfile, "foobar.com/workdir:latest", "false", "version=1.0") + podmanTest.BuildImageWithLabel(dockerfile2, "foobar.com/workdir:latest", "false", "version=2.0") + + result := podmanTest.Podman([]string{"image", "prune", "--filter", "label=version=1.0", "--force"}) + result.WaitWithDefaultTimeout() + Expect(result).Should(ExitCleanly()) + Expect(result.OutputToStringArray()).To(HaveLen(1)) + + // only version=1.0 should be gone; version=2.0 must survive + result = podmanTest.Podman([]string{"image", "list", "--filter", "label=version=1.0"}) + Expect(result.OutputToStringArray()).To(BeEmpty()) + + result = podmanTest.Podman([]string{"image", "list", "--filter", "label=version=2.0", "-q"}) + result.WaitWithDefaultTimeout() + Expect(result).Should(ExitCleanly()) + Expect(result.OutputToStringArray()).To(HaveLen(1)) + }) + It("podman builder prune", func() { dockerfile := `FROM quay.io/libpod/alpine:latest RUN > file