diff --git a/daemon/containerd/image.go b/daemon/containerd/image.go index 72fe786ccd954..c43ceb3d26458 100644 --- a/daemon/containerd/image.go +++ b/daemon/containerd/image.go @@ -19,6 +19,7 @@ import ( "github.com/docker/docker/daemon/images" "github.com/docker/docker/errdefs" "github.com/docker/docker/image" + "github.com/docker/docker/internal/sliceutil" imagespec "github.com/moby/docker-image-spec/specs-go/v1" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" @@ -109,7 +110,7 @@ func (i *ImageService) GetImage(ctx context.Context, refOrID string, options bac } img.Details = &image.Details{ - References: refs, + References: sliceutil.Dedup(refs), Size: size, Metadata: nil, Driver: i.snapshotter, diff --git a/daemon/containerd/image_list.go b/daemon/containerd/image_list.go index a66e8476b19ff..f9818e7d9a403 100644 --- a/daemon/containerd/image_list.go +++ b/daemon/containerd/image_list.go @@ -22,6 +22,7 @@ import ( imagetypes "github.com/docker/docker/api/types/image" timetypes "github.com/docker/docker/api/types/time" "github.com/docker/docker/errdefs" + "github.com/docker/docker/internal/sliceutil" "github.com/moby/buildkit/util/attestation" dockerspec "github.com/moby/docker-image-spec/specs-go/v1" "github.com/opencontainers/go-digest" @@ -501,7 +502,7 @@ func (i *ImageService) singlePlatformImage(ctx context.Context, contentStore con summary := &imagetypes.Summary{ ParentID: rawImg.Labels[imageLabelClassicBuilderParent], ID: target.String(), - RepoDigests: repoDigests, + RepoDigests: sliceutil.Dedup(repoDigests), RepoTags: repoTags, Size: totalSize, Labels: cfg.Config.Labels, diff --git a/integration/image/inspect_test.go b/integration/image/inspect_test.go index e512ed6ce8eb1..1668fb937e1bf 100644 --- a/integration/image/inspect_test.go +++ b/integration/image/inspect_test.go @@ -4,6 +4,7 @@ import ( "encoding/json" "testing" + "github.com/docker/docker/api/types/image" "github.com/docker/docker/internal/testutils/specialimage" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" @@ -34,3 +35,27 @@ func TestImageInspectEmptyTagsAndDigests(t *testing.T) { assert.Check(t, is.Len(rawJson["RepoTags"], 0)) assert.Check(t, is.Len(rawJson["RepoDigests"], 0)) } + +// Regression test for: https://github.com/moby/moby/issues/48747 +func TestImageInspectUniqueRepoDigests(t *testing.T) { + ctx := setupTest(t) + + client := testEnv.APIClient() + + before, _, err := client.ImageInspectWithRaw(ctx, "busybox") + assert.NilError(t, err) + + for _, tag := range []string{"master", "newest"} { + imgName := "busybox:" + tag + err := client.ImageTag(ctx, "busybox", imgName) + assert.NilError(t, err) + defer func() { + _, _ = client.ImageRemove(ctx, imgName, image.RemoveOptions{Force: true}) + }() + } + + after, _, err := client.ImageInspectWithRaw(ctx, "busybox") + assert.NilError(t, err) + + assert.Check(t, is.Len(after.RepoDigests, len(before.RepoDigests))) +}