diff --git a/pkg/image/containerd/daemon_provider.go b/pkg/image/containerd/daemon_provider.go index 26b4476f..5f1e85b5 100644 --- a/pkg/image/containerd/daemon_provider.go +++ b/pkg/image/containerd/daemon_provider.go @@ -319,7 +319,7 @@ func (p *daemonImageProvider) fetchPlatformFromConfig(ctx context.Context, clien } func (p *daemonImageProvider) pullImageIfMissing(ctx context.Context, client *containerd.Client) (string, *platforms.Platform, error) { - p.imageStr = checkRegistryHostMissing(p.imageStr) + p.imageStr = ensureRegistryHostPrefix(p.imageStr) // try to get the image first before pulling resolvedImage, resolvedPlatform, err := p.resolveImage(ctx, client, p.imageStr) @@ -504,13 +504,21 @@ func withMetadata(platform *platforms.Platform, ref string) (metadata []image.Ad return metadata } -// if image doesn't have host set, add docker hub by default -func checkRegistryHostMissing(imageName string) string { +// if imageName doesn't have an identifiable hostname prefix set, +// add docker hub by default +func ensureRegistryHostPrefix(imageName string) string { parts := strings.Split(imageName, "/") if len(parts) == 1 { return fmt.Sprintf("docker.io/library/%s", imageName) - } else if len(parts) > 1 && !strings.Contains(parts[0], ".") { - return fmt.Sprintf("docker.io/%s", imageName) } - return imageName + if isRegistryHostname(parts[0]) { + return imageName + } + return fmt.Sprintf("docker.io/%s", imageName) +} + +// isRegistryHostname returns true if the string passed in can be interpreted +// as a container registry hostname +func isRegistryHostname(s string) bool { + return s == "localhost" || strings.Contains(s, ".") || strings.Contains(s, ":") } diff --git a/pkg/image/containerd/daemon_provider_test.go b/pkg/image/containerd/daemon_provider_test.go index 07e0b402..d3c89199 100644 --- a/pkg/image/containerd/daemon_provider_test.go +++ b/pkg/image/containerd/daemon_provider_test.go @@ -11,7 +11,7 @@ import ( "github.com/anchore/stereoscope/pkg/image" ) -func Test_checkRegistryHostMissing(t *testing.T) { +func Test_ensureRegistryHostPrefix(t *testing.T) { tests := []struct { image string want string @@ -32,6 +32,22 @@ func Test_checkRegistryHostMissing(t *testing.T) { image: "registry.place.io/thing:version", want: "registry.place.io/thing:version", }, + { + image: "127.0.0.1/thing:version", + want: "127.0.0.1/thing:version", + }, + { + image: "127.0.0.1:1234/thing:version", + want: "127.0.0.1:1234/thing:version", + }, + { + image: "localhost/thing:version", + want: "localhost/thing:version", + }, + { + image: "localhost:1234/thing:version", + want: "localhost:1234/thing:version", + }, { image: "alpine@sha256:95cf004f559831017cdf4628aaf1bb30133677be8702a8c5f2994629f637a209", want: "docker.io/library/alpine@sha256:95cf004f559831017cdf4628aaf1bb30133677be8702a8c5f2994629f637a209", @@ -43,7 +59,7 @@ func Test_checkRegistryHostMissing(t *testing.T) { } for _, tt := range tests { t.Run(tt.image, func(t *testing.T) { - got := checkRegistryHostMissing(tt.image) + got := ensureRegistryHostPrefix(tt.image) require.NotNil(t, got) assert.Equal(t, tt.want, got) })