From 196b5aa3ad5126b1c783c0b0107ab2331bec62b0 Mon Sep 17 00:00:00 2001 From: Valentin Rothberg Date: Mon, 22 Nov 2021 13:21:48 +0100 Subject: [PATCH] libimage: enforce "latest" tag when looking up images Make sure to enforce the "latest" tag when looking up images in the local storage. Also make sure that digested short-names are subject to the extended digest lookups. Context: containers/podman/issues/11964 Signed-off-by: Valentin Rothberg --- libimage/image.go | 7 ++++--- libimage/pull_test.go | 21 +++++++++++++-------- libimage/runtime.go | 36 ++++++++++++++++-------------------- 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/libimage/image.go b/libimage/image.go index bf3310da2..50dbc9725 100644 --- a/libimage/image.go +++ b/libimage/image.go @@ -624,8 +624,7 @@ func (i *Image) NamedRepoTags() ([]reference.Named, error) { } // inRepoTags looks for the specified name/tag pair in the image's repo tags. -// Note that tag may be empty. -func (i *Image) inRepoTags(name, tag string) (reference.Named, error) { +func (i *Image) inRepoTags(namedTagged reference.NamedTagged) (reference.Named, error) { repoTags, err := i.NamedRepoTags() if err != nil { return nil, err @@ -636,8 +635,10 @@ func (i *Image) inRepoTags(name, tag string) (reference.Named, error) { return nil, err } + name := namedTagged.Name() + tag := namedTagged.Tag() for _, pair := range pairs { - if tag != "" && tag != pair.Tag { + if tag != pair.Tag { continue } if !strings.HasSuffix(pair.Name, name) { diff --git a/libimage/pull_test.go b/libimage/pull_test.go index eebda644d..c3e2c1707 100644 --- a/libimage/pull_test.go +++ b/libimage/pull_test.go @@ -85,35 +85,40 @@ func TestPullPlatforms(t *testing.T) { localArch := goruntime.GOARCH localOS := goruntime.GOOS - pulledImages, err := runtime.Pull(ctx, "busybox", config.PullPolicyAlways, pullOptions) + withTag := "busybox:musl" + + pulledImages, err := runtime.Pull(ctx, withTag, config.PullPolicyAlways, pullOptions) require.NoError(t, err, "pull busybox") require.Len(t, pulledImages, 1) - image, _, err := runtime.LookupImage("busybox", nil) + image, _, err := runtime.LookupImage(withTag, nil) require.NoError(t, err, "lookup busybox") require.NotNil(t, image, "lookup busybox") - image, _, err = runtime.LookupImage("busybox", &LookupImageOptions{Architecture: localArch}) + _, _, err = runtime.LookupImage("busybox", nil) + require.Error(t, err, "untagged image resolves to non-existent :latest") + + image, _, err = runtime.LookupImage(withTag, &LookupImageOptions{Architecture: localArch}) require.NoError(t, err, "lookup busybox - by local arch") require.NotNil(t, image, "lookup busybox - by local arch") - image, _, err = runtime.LookupImage("busybox", &LookupImageOptions{OS: localOS}) + image, _, err = runtime.LookupImage(withTag, &LookupImageOptions{OS: localOS}) require.NoError(t, err, "lookup busybox - by local arch") require.NotNil(t, image, "lookup busybox - by local arch") - _, _, err = runtime.LookupImage("busybox", &LookupImageOptions{Architecture: "bogus"}) + _, _, err = runtime.LookupImage(withTag, &LookupImageOptions{Architecture: "bogus"}) require.Error(t, err, "lookup busybox - bogus arch") - _, _, err = runtime.LookupImage("busybox", &LookupImageOptions{OS: "bogus"}) + _, _, err = runtime.LookupImage(withTag, &LookupImageOptions{OS: "bogus"}) require.Error(t, err, "lookup busybox - bogus OS") pullOptions.Architecture = "arm" - pulledImages, err = runtime.Pull(ctx, "busybox", config.PullPolicyAlways, pullOptions) + pulledImages, err = runtime.Pull(ctx, withTag, config.PullPolicyAlways, pullOptions) require.NoError(t, err, "pull busybox - arm") require.Len(t, pulledImages, 1) pullOptions.Architecture = "" - image, _, err = runtime.LookupImage("busybox", &LookupImageOptions{Architecture: "arm"}) + image, _, err = runtime.LookupImage(withTag, &LookupImageOptions{Architecture: "arm"}) require.NoError(t, err, "lookup busybox - by arm") require.NotNil(t, image, "lookup busybox - by local arch") } diff --git a/libimage/runtime.go b/libimage/runtime.go index d1b6e6cfb..31e6df1c8 100644 --- a/libimage/runtime.go +++ b/libimage/runtime.go @@ -389,16 +389,17 @@ func (r *Runtime) lookupImageInDigestsAndRepoTags(name string, options *LookupIm return nil, "", err } - if !shortnames.IsShortName(name) { - named, err := reference.ParseNormalizedNamed(name) - if err != nil { - return nil, "", err - } - digested, hasDigest := named.(reference.Digested) - if !hasDigest { - return nil, "", errors.Wrap(storage.ErrImageUnknown, name) - } + ref, err := reference.Parse(name) + if err != nil { + return nil, "", err + } + named, isNamed := ref.(reference.Named) + if !isNamed { + return nil, "", errors.Wrap(storage.ErrImageUnknown, name) + } + digested, isDigested := named.(reference.Digested) + if isDigested { logrus.Debug("Looking for image with matching recorded digests") digest := digested.Digest() for _, image := range allImages { @@ -408,22 +409,17 @@ func (r *Runtime) lookupImageInDigestsAndRepoTags(name string, options *LookupIm } } } - return nil, "", errors.Wrap(storage.ErrImageUnknown, name) } - // Podman compat: if we're looking for a short name but couldn't - // resolve it via the registries.conf dance, we need to look at *all* - // images and check if the name we're looking for matches a repo tag. - // Split the name into a repo/tag pair - split := strings.SplitN(name, ":", 2) - repo := split[0] - tag := "" - if len(split) == 2 { - tag = split[1] + if !shortnames.IsShortName(name) { + return nil, "", errors.Wrap(storage.ErrImageUnknown, name) } + + named = reference.TagNameOnly(named) // Make sure to add ":latest" if needed + namedTagged, _ := named.(reference.NamedTagged) for _, image := range allImages { - named, err := image.inRepoTags(repo, tag) + named, err := image.inRepoTags(namedTagged) if err != nil { return nil, "", err }