Repository: tetratelabs/getenvoy
Pull request #179 (2021-04-15 04:33:32)

Removes dependency on docker distribution
Signed-off-by: Adrian Cole <adrian@tetrate.io>

codefromthecrypt: this takes another almost 2MB off the binary size after #178
codefromthecrypt: looks like we didn't indicate `--use-http true` before as the default went to accept plain text. From now on, if someone is using a registry that isn't https, they need to pass `--use-http true` to `getenvoy extension push`

Patch:
diff --git a/go.mod b/go.mod
index 8355cdf..27512aa 100644
--- a/go.mod
+++ b/go.mod
@@ -14,8 +14,6 @@ require (
 	github.com/containerd/containerd v1.4.4
 	github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e // indirect
 	github.com/deislabs/oras v0.11.1
-	github.com/docker/distribution v2.7.1+incompatible
-	github.com/docker/docker v20.10.5+incompatible // indirect
 	github.com/docker/go-metrics v0.0.1 // indirect
 	github.com/envoyproxy/go-control-plane v0.9.8-0.20201019204000-12785f608982
 	github.com/envoyproxy/protoc-gen-validate v0.5.1 // indirect
diff --git a/go.sum b/go.sum
index 8e01749..c46865e 100644
--- a/go.sum
+++ b/go.sum
@@ -254,7 +254,6 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
 github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
 github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
 github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
-github.com/docker/cli v20.10.5+incompatible h1:bjflayQbWg+xOkF2WPEAOi4Y7zWhR7ptoPhV/VqLVDE=
 github.com/docker/cli v20.10.5+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
 github.com/docker/distribution v0.0.0-20191216044856-a8371794149d/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
 github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
@@ -262,17 +261,12 @@ github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4Kfc
 github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
 github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
 github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/docker v20.10.5+incompatible h1:o5WL5onN4awYGwrW7+oTn5x9AF2prw7V0Ox8ZEkoCdg=
-github.com/docker/docker v20.10.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ=
 github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
-github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
 github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
 github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
 github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
 github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
 github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
-github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
 github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
 github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arXfYcAtECDFgAgHklGI8CxgjHnXKJ4=
 github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
@@ -766,7 +760,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
 github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
 github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
 github.com/mozilla/tls-observatory v0.0.0-20200317151703-4fa42e1c2dee/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk=
 github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
diff --git a/pkg/cmd/extension/common/toolchain.go b/pkg/cmd/extension/common/toolchain.go
index 9ce08f7..0077d60 100644
--- a/pkg/cmd/extension/common/toolchain.go
+++ b/pkg/cmd/extension/common/toolchain.go
@@ -15,8 +15,10 @@
 package common
 
 import (
-	"github.com/docker/distribution/reference"
-	"github.com/pkg/errors"
+	"errors"
+	"fmt"
+
+	"github.com/containerd/containerd/reference/docker"
 	"github.com/spf13/cobra"
 
 	builtinconfig "github.com/tetratelabs/getenvoy/pkg/extension/workspace/config/toolchain/builtin"
@@ -50,7 +52,7 @@ type BuiltinToolchainOpts struct {
 // Validate returns an error if ToolchainOpts is not valid.
 func (o *ToolchainOpts) Validate() error {
 	if o.Name == "" {
-		return errors.Errorf("toolchain name cannot be empty")
+		return errors.New("toolchain name cannot be empty")
 	}
 	return o.Builtin.Validate()
 }
@@ -58,8 +60,8 @@ func (o *ToolchainOpts) Validate() error {
 // Validate returns an error if BuiltinToolchainOpts is not valid.
 func (o *BuiltinToolchainOpts) Validate() error {
 	if o.ContainerImage != "" {
-		if _, err := reference.Parse(o.ContainerImage); err != nil {
-			return errors.Wrapf(err, "%q is not a valid image name", o.ContainerImage)
+		if _, err := docker.Parse(o.ContainerImage); err != nil {
+			return fmt.Errorf("%q is not a valid image name: %w", o.ContainerImage, err)
 		}
 	}
 	if len(o.ContainerOptions) > 0 {
diff --git a/pkg/cmd/extension/push/cmd.go b/pkg/cmd/extension/push/cmd.go
index 3d6b7c8..c89b0d0 100644
--- a/pkg/cmd/extension/push/cmd.go
+++ b/pkg/cmd/extension/push/cmd.go
@@ -18,7 +18,7 @@ import (
 	"errors"
 	"fmt"
 
-	"github.com/docker/distribution/reference"
+	"github.com/containerd/containerd/reference/docker"
 	"github.com/spf13/cobra"
 
 	"github.com/tetratelabs/getenvoy/pkg/cmd/extension/common"
@@ -36,7 +36,7 @@ type cmdOpts struct {
 	extension runtime.ExtensionOpts
 
 	allowInsecure bool
-	useHTTP       bool
+	plainHTTP     bool
 }
 
 func newCmdOpts() *cmdOpts {
@@ -46,7 +46,7 @@ func newCmdOpts() *cmdOpts {
 		},
 		extension:     runtime.ExtensionOpts{},
 		allowInsecure: false,
-		useHTTP:       false,
+		plainHTTP:     false,
 	}
 }
 
@@ -96,15 +96,15 @@ Push the built WASM extension to the OCI-compliant registry. This command requir
 				imagePath = tc.GetBuildOutputWasmFile()
 			}
 			imageRef := args[0]
-			ref, err := reference.ParseNormalizedNamed(imageRef)
+			ref, err := docker.ParseNormalizedNamed(imageRef)
 			if err != nil {
 				return fmt.Errorf("invalid image-reference: %w", err)
 			}
-			ref = reference.TagNameOnly(ref)
-			if tagged, ok := ref.(reference.Tagged); ok {
+			ref = docker.TagNameOnly(ref)
+			if tagged, ok := ref.(docker.Tagged); ok {
 				cmd.Printf("Using default tag: %s\n", tagged.Tag())
 			}
-			pusher, err := wasmimage.NewPusher(opts.allowInsecure, opts.useHTTP)
+			pusher, err := wasmimage.NewPusher(opts.allowInsecure, opts.plainHTTP)
 			if err != nil {
 				return fmt.Errorf("failed to push the wasm image: %w", err)
 			}
@@ -122,7 +122,7 @@ Push the built WASM extension to the OCI-compliant registry. This command requir
 	cmd.PersistentFlags().StringVar(&opts.toolchain.Name, "toolchain", opts.toolchain.Name,
 		`Name of the toolchain to use, e.g. "default" toolchain that is backed by a Docker build container`)
 	cmd.PersistentFlags().BoolVar(&opts.allowInsecure, "allow-insecure", opts.allowInsecure, `allow insecure TLS communication with registry`)
-	cmd.PersistentFlags().BoolVar(&opts.useHTTP, "use-http", opts.useHTTP, `Use HTTP for communication with registry`)
+	cmd.PersistentFlags().BoolVar(&opts.plainHTTP, "use-http", opts.plainHTTP, `Use HTTP for communication with registry`)
 	cmd.PersistentFlags().StringVar(&opts.extension.WasmFile, "extension-file", opts.extension.WasmFile,
 		`Use a pre-built *.wasm file`)
 	return cmd
diff --git a/pkg/extension/wasmimage/puller.go b/pkg/extension/wasmimage/puller.go
index 0b2e2e1..6c90ec5 100644
--- a/pkg/extension/wasmimage/puller.go
+++ b/pkg/extension/wasmimage/puller.go
@@ -15,14 +15,11 @@
 package wasmimage
 
 import (
-	"context"
-	"crypto/tls"
 	"fmt"
-	"net/http"
 	"os"
 
 	"github.com/containerd/containerd/remotes"
-	"github.com/deislabs/oras/pkg/auth/docker"
+	"github.com/containerd/containerd/remotes/docker"
 	orascnt "github.com/deislabs/oras/pkg/content"
 	orasctx "github.com/deislabs/oras/pkg/context"
 	"github.com/deislabs/oras/pkg/oras"
@@ -35,25 +32,10 @@ type Puller struct {
 }
 
 // NewPuller returns a new Puller instance.
-func NewPuller(insecure, useHTTP bool) (*Puller, error) {
-	client := http.DefaultClient
-
-	client.Transport = &http.Transport{
-		TLSClientConfig: &tls.Config{
-			// this option is only enabled when the user specify the insecure flag.
-			InsecureSkipVerify: insecure, // nolint:gosec
-		},
-	}
-
-	// TODO(musaprg): separate these instructions into another functions
-	auth, err := docker.NewClient()
-	if err != nil {
-		return nil, err
-	}
-	resolver, err := auth.Resolver(context.Background(), client, useHTTP)
-	if err != nil {
-		return nil, err
-	}
+func NewPuller(insecure, plainHTTP bool) (*Puller, error) {
+	resolver := docker.NewResolver(docker.ResolverOptions{
+		Hosts: registryHosts(insecure, plainHTTP),
+	})
 	return &Puller{resolver: resolver}, nil
 }
 
diff --git a/pkg/extension/wasmimage/pusher.go b/pkg/extension/wasmimage/pusher.go
index db9e34c..134ebf6 100644
--- a/pkg/extension/wasmimage/pusher.go
+++ b/pkg/extension/wasmimage/pusher.go
@@ -15,13 +15,10 @@
 package wasmimage
 
 import (
-	"context"
-	"crypto/tls"
 	"fmt"
-	"net/http"
 
 	"github.com/containerd/containerd/remotes"
-	"github.com/deislabs/oras/pkg/auth/docker"
+	"github.com/containerd/containerd/remotes/docker"
 	orasctx "github.com/deislabs/oras/pkg/context"
 	"github.com/deislabs/oras/pkg/oras"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
@@ -33,27 +30,10 @@ type Pusher struct {
 }
 
 // NewPusher returns a new Pusher instance.
-func NewPusher(insecure, useHTTP bool) (*Pusher, error) {
-	client := http.DefaultClient
-
-	if insecure {
-		client.Transport = &http.Transport{
-			TLSClientConfig: &tls.Config{
-				// this option is only enabled when the user specify the insecure flag.
-				InsecureSkipVerify: true, // nolint:gosec
-			},
-		}
-	}
-
-	// TODO(musaprg): separate these instructions into another functions
-	auth, err := docker.NewClient()
-	if err != nil {
-		return nil, fmt.Errorf("failed to create Pusher: %w", err)
-	}
-	resolver, err := auth.Resolver(context.Background(), client, useHTTP)
-	if err != nil {
-		return nil, fmt.Errorf("failed to create Pusher: %w", err)
-	}
+func NewPusher(insecure, plainHTTP bool) (*Pusher, error) {
+	resolver := docker.NewResolver(docker.ResolverOptions{
+		Hosts: registryHosts(insecure, plainHTTP),
+	})
 	return &Pusher{resolver: resolver}, nil
 }
 
diff --git a/pkg/extension/wasmimage/wasmimage.go b/pkg/extension/wasmimage/wasmimage.go
index 89b8217..d2e0472 100644
--- a/pkg/extension/wasmimage/wasmimage.go
+++ b/pkg/extension/wasmimage/wasmimage.go
@@ -16,10 +16,13 @@ package wasmimage
 
 import (
 	"bytes"
+	"crypto/tls"
 	"fmt"
+	"net/http"
 	"os"
 	"path/filepath"
 
+	"github.com/containerd/containerd/remotes/docker"
 	orascnt "github.com/deislabs/oras/pkg/content"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 )
@@ -85,3 +88,25 @@ func isWasmBinary(path string) bool {
 	}
 	return bytes.Equal(buffer, magic)
 }
+
+func registryHosts(insecure, plainHTTP bool) docker.RegistryHosts {
+	client := http.DefaultClient
+
+	if insecure && !plainHTTP {
+		client.Transport = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}} // nolint:gosec
+	}
+
+	return func(host string) ([]docker.RegistryHost, error) {
+		config := docker.RegistryHost{
+			Client:       client,
+			Host:         host,
+			Scheme:       "https",
+			Path:         "/v2", // For Docker registry:2 https://docs.docker.com/registry/spec/api/#overview
+			Capabilities: docker.HostCapabilityPull | docker.HostCapabilityResolve | docker.HostCapabilityPush,
+		}
+		if plainHTTP {
+			config.Scheme = "http"
+		}
+		return []docker.RegistryHost{config}, nil
+	}
+}
diff --git a/pkg/extension/workspace/config/toolchain/builtin/helpers.go b/pkg/extension/workspace/config/toolchain/builtin/helpers.go
index 4282eb1..0ab931a 100644
--- a/pkg/extension/workspace/config/toolchain/builtin/helpers.go
+++ b/pkg/extension/workspace/config/toolchain/builtin/helpers.go
@@ -15,10 +15,11 @@
 package builtin
 
 import (
+	"errors"
+	"fmt"
 	"path"
 
-	"github.com/docker/distribution/reference"
-	"github.com/pkg/errors"
+	"github.com/containerd/containerd/reference/docker"
 	"github.com/tetratelabs/multierror"
 
 	"github.com/tetratelabs/getenvoy/pkg/extension/workspace/config"
@@ -121,16 +122,16 @@ func (c *ToolchainConfig) Validate() (errs error) {
 		errs = multierror.Append(errs, errors.New("configuration of the default build container cannot be empty"))
 	}
 	if err := c.Container.Validate(); err != nil {
-		errs = multierror.Append(errs, errors.Wrap(err, "configuration of the default build container is not valid"))
+		errs = multierror.Append(errs, fmt.Errorf("configuration of the default build container is not valid: %w", err))
 	}
 	if err := c.Build.Validate(); err != nil {
-		errs = multierror.Append(errs, errors.Wrap(err, "'build' tool config is not valid"))
+		errs = multierror.Append(errs, fmt.Errorf("'build' tool config is not valid: %w", err))
 	}
 	if err := c.Test.Validate(); err != nil {
-		errs = multierror.Append(errs, errors.Wrap(err, "'test' tool config is not valid"))
+		errs = multierror.Append(errs, fmt.Errorf("'test' tool config is not valid: %w", err))
 	}
 	if err := c.Clean.Validate(); err != nil {
-		errs = multierror.Append(errs, errors.Wrap(err, "'clean' tool config is not valid"))
+		errs = multierror.Append(errs, fmt.Errorf("'clean' tool config is not valid: %w", err))
 	}
 	return
 }
@@ -141,10 +142,10 @@ func (c *BuildConfig) Validate() (errs error) {
 		return
 	}
 	if err := c.Container.Validate(); err != nil {
-		errs = multierror.Append(errs, errors.Wrap(err, "container configuration is not valid"))
+		errs = multierror.Append(errs, fmt.Errorf("container configuration is not valid: %w", err))
 	}
 	if err := c.Output.Validate(); err != nil {
-		errs = multierror.Append(errs, errors.Wrap(err, "output configuration is not valid"))
+		errs = multierror.Append(errs, fmt.Errorf("output configuration is not valid: %w", err))
 	}
 	return
 }
@@ -169,7 +170,7 @@ func (c *TestConfig) Validate() (errs error) {
 		return
 	}
 	if err := c.Container.Validate(); err != nil {
-		errs = multierror.Append(errs, errors.Wrap(err, "container configuration is not valid"))
+		errs = multierror.Append(errs, fmt.Errorf("container configuration is not valid: %w", err))
 	}
 	return
 }
@@ -180,7 +181,7 @@ func (c *CleanConfig) Validate() (errs error) {
 		return
 	}
 	if err := c.Container.Validate(); err != nil {
-		errs = multierror.Append(errs, errors.Wrap(err, "container configuration is not valid"))
+		errs = multierror.Append(errs, fmt.Errorf("container configuration is not valid: %w", err))
 	}
 	return
 }
@@ -194,8 +195,8 @@ func (c *ContainerConfig) Validate() (errs error) {
 		errs = multierror.Append(errs, errors.New("image name cannot be empty"))
 	}
 	if c.Image != "" {
-		if _, err := reference.Parse(c.Image); err != nil {
-			errs = multierror.Append(errs, errors.Wrapf(err, "%q is not a valid image name", c.Image))
+		if _, err := docker.Parse(c.Image); err != nil {
+			errs = multierror.Append(errs, fmt.Errorf("%q is not a valid image name: %w", c.Image, err))
 		}
 	}
 	return


Test patch:
diff --git a/pkg/cmd/extension/push/cmd_test.go b/pkg/cmd/extension/push/cmd_test.go
index 09ef996..8015ed6 100644
--- a/pkg/cmd/extension/push/cmd_test.go
+++ b/pkg/cmd/extension/push/cmd_test.go
@@ -51,7 +51,7 @@ func TestGetEnvoyExtensionPush(t *testing.T) {
 
 	// Run "getenvoy extension push localhost:5000/getenvoy/sample"
 	c, stdout, stderr := cmd.NewRootCommand()
-	c.SetArgs([]string{"extension", "push", localRegistryWasmImageRef})
+	c.SetArgs([]string{"extension", "push", localRegistryWasmImageRef, "--use-http", "true"})
 	err := cmdutil.Execute(c)
 
 	// A fully qualified image ref includes the tag
@@ -106,7 +106,7 @@ func TestGetEnvoyExtensionPushWithExplicitFileOption(t *testing.T) {
 
 	// Run "getenvoy extension push localhost:5000/getenvoy/sample --extension-file testdata/workspace/extension.wasm"
 	c, stdout, stderr := cmd.NewRootCommand()
-	c.SetArgs([]string{"extension", "push", localRegistryWasmImageRef, "--extension-file", wasm})
+	c.SetArgs([]string{"extension", "push", localRegistryWasmImageRef, "--extension-file", wasm, "--use-http", "true"})
 	err := cmdutil.Execute(c)
 
 	// Verify the pushed a latest tag to the correct registry
diff --git a/pkg/extension/wasmimage/wasmimage_test.go b/pkg/extension/wasmimage/wasmimage_test.go
new file mode 100644
index 0000000..8f5315e
--- /dev/null
+++ b/pkg/extension/wasmimage/wasmimage_test.go
@@ -0,0 +1,75 @@
+// Copyright 2020 Tetrate
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package wasmimage
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/require"
+)
+
+func TestRegistryHosts(t *testing.T) {
+	tests := []struct {
+		name           string
+		insecure       bool
+		plainHTTP      bool
+		inputHost      string
+		expectedScheme string
+		expectedHost   string
+		expectedPath   string
+	}{
+		{
+			name:           "docker.io",
+			insecure:       false,
+			plainHTTP:      false,
+			inputHost:      "docker.io",
+			expectedScheme: "https",
+			expectedHost:   "docker.io",
+			expectedPath:   "/v2",
+		},
+		{
+			name:           "localhost:5000",
+			insecure:       false,
+			plainHTTP:      false,
+			inputHost:      "localhost:5000",
+			expectedScheme: "https",
+			expectedHost:   "localhost:5000",
+			expectedPath:   "/v2",
+		},
+		{
+			name:           "localhost:5000,plainHTTP=true",
+			insecure:       false,
+			plainHTTP:      true,
+			inputHost:      "localhost:5000",
+			expectedScheme: "http",
+			expectedHost:   "localhost:5000",
+			expectedPath:   "/v2",
+		},
+	}
+
+	for _, tt := range tests {
+		tc := tt
+		t.Run(tc.name, func(t *testing.T) {
+			hosts, err := registryHosts(tc.insecure, tc.plainHTTP)(tc.inputHost)
+			require.NoError(t, err)
+			require.Equal(t, 1, len(hosts))
+			host := hosts[0]
+
+			require.Equal(t, tc.expectedScheme, host.Scheme)
+			require.Equal(t, tc.expectedHost, host.Host)
+			require.Equal(t, tc.expectedPath, host.Path)
+		})
+	}
+}
diff --git a/test/e2e/getenvoy_extension_push_test.go b/test/e2e/getenvoy_extension_push_test.go
index f70328c..2000116 100644
--- a/test/e2e/getenvoy_extension_push_test.go
+++ b/test/e2e/getenvoy_extension_push_test.go
@@ -18,6 +18,7 @@ import (
 	"fmt"
 	"os"
 	"path/filepath"
+	"strconv"
 	"testing"
 
 	"github.com/stretchr/testify/require"
@@ -39,6 +40,8 @@ func TestGetEnvoyExtensionPush(t *testing.T) {
 	const extensionName = "getenvoy_extension_push"
 	// localRegistryWasmImageRef corresponds to a Docker container running the image "registry:2"
 	const localRegistryWasmImageRef = "localhost:5000/getenvoy/" + extensionName
+	// The above registry is HTTP not HTTPS
+	const useHTTP = true
 	// When unspecified, we default the tag to Docker's default "latest". Note: recent tools enforce qualifying this!
 	const defaultTag = "latest"
 
@@ -70,7 +73,7 @@ func TestGetEnvoyExtensionPush(t *testing.T) {
 			wasmBytes := requireExtensionBuild(t, test.Language, workDir)
 
 			// After pushing, stderr should include the registry URL and the image tag.
-			c := getEnvoy("extension push").Arg(localRegistryWasmImageRef)
+			c := getEnvoy("extension push").Arg(localRegistryWasmImageRef).Arg("--use-http").Arg(strconv.FormatBool(useHTTP))
 			stderr := requireExecNoStdout(t, c)
 
 			// Assemble a fully-qualified image ref as we'll pull this later
@@ -82,7 +85,7 @@ Pushed %s
 digest: sha256`, defaultTag, imageRef), `unexpected stderr after running [%v]`, c)
 
 			// Get a puller we can use to pull what we just pushed.
-			puller, err := wasmimage.NewPuller(false, false)
+			puller, err := wasmimage.NewPuller(false, useHTTP)
 			require.NoError(t, err, `error getting puller instance after running [%v]`, c)
 			require.NotNil(t, puller, `nil puller instance after running [%v]`, c)