diff --git a/Makefile b/Makefile
index 971f696d3..1556bf08f 100644
--- a/Makefile
+++ b/Makefile
@@ -11,6 +11,10 @@ lint-all:
@echo "Running lint in all modules..."
$(call for-all-modules,make lint)
+tidy-all:
+ @echo "Running lint in all modules..."
+ $(call for-all-modules,go mod tidy)
+
tidy-all:
@echo "Running tidy in all modules..."
$(call for-all-modules,go mod tidy)
diff --git a/README.md b/README.md
index 9f6aa9afc..4a95af990 100644
--- a/README.md
+++ b/README.md
@@ -237,35 +237,6 @@ func main() {
-#### Reading the current Docker context
-
-With the `moby/moby/client` package, you basically can't do it, as this functionality is part of the client code of the Docker CLI.
-
-With the `go-sdk`, you can do:
-
-
- See the code
-
-```go
-package main
-
-import (
- "fmt"
-
- "github.com/docker/go-sdk/context"
-)
-
-func main() {
- ctx, err := context.Current()
- if err != nil {
- panic(err)
- }
- fmt.Println("Current Docker context name:", ctx)
-}
-```
-
-
-
## Features
- Initialize a Docker client, using the current Docker context to resolve the Docker host and socket
@@ -278,9 +249,7 @@ func main() {
```bash
go get github.com/docker/go-sdk/client
-go get github.com/docker/go-sdk/config
go get github.com/docker/go-sdk/container
-go get github.com/docker/go-sdk/context
go get github.com/docker/go-sdk/image
go get github.com/docker/go-sdk/network
go get github.com/docker/go-sdk/volume
diff --git a/client/client.go b/client/client.go
index 761d85eae..66c13999a 100644
--- a/client/client.go
+++ b/client/client.go
@@ -5,22 +5,10 @@ import (
"fmt"
"io"
"log/slog"
- "maps"
- "path/filepath"
"time"
- "github.com/docker/docker/client"
- dockercontext "github.com/docker/go-sdk/context"
-)
-
-const (
- // Headers used for docker client requests.
- headerUserAgent = "User-Agent"
-
- // TLS certificate files.
- tlsCACertFile = "ca.pem"
- tlsCertFile = "cert.pem"
- tlsKeyFile = "key.pem"
+ "github.com/docker/cli/cli/command"
+ "github.com/docker/cli/cli/flags"
)
var (
@@ -28,8 +16,6 @@ var (
defaultUserAgent = "docker-go-sdk/" + Version()
- defaultOpts = []client.Opt{client.FromEnv, client.WithAPIVersionNegotiation()}
-
defaultHealthCheck = func(ctx context.Context) func(c SDKClient) error {
return func(c SDKClient) error {
var pingErr error
@@ -71,112 +57,28 @@ func New(ctx context.Context, options ...ClientOption) (SDKClient, error) {
log: defaultLogger,
healthCheck: defaultHealthCheck,
}
- for _, opt := range options {
- if err := opt.Apply(c); err != nil {
- return nil, fmt.Errorf("apply option: %w", err)
- }
- }
- if err := c.init(); err != nil {
- return nil, fmt.Errorf("load config: %w", err)
- }
-
- if err := c.healthCheck(ctx)(c); err != nil {
- return nil, fmt.Errorf("health check: %w", err)
- }
-
- return c, nil
-}
-
-// init initializes the client.
-// This method is safe for concurrent use by multiple goroutines.
-func (c *sdkClient) init() error {
- if c.APIClient != nil || c.err != nil {
- return c.err
- }
-
- // Set the default values for the client:
- // - log
- // - dockerHost
- // - currentContext
- if c.err = c.defaultValues(); c.err != nil {
- return fmt.Errorf("default values: %w", c.err)
- }
-
- if c.cfg, c.err = newConfig(c.dockerHost); c.err != nil {
- return c.err
- }
-
- opts := make([]client.Opt, len(defaultOpts), len(defaultOpts)+len(c.dockerOpts))
- copy(opts, defaultOpts)
-
- // Add all collected Docker options
- opts = append(opts, c.dockerOpts...)
-
- if c.cfg.TLSVerify {
- // For further information see:
- // https://docs.docker.com/engine/security/protect-access/#use-tls-https-to-protect-the-docker-daemon-socket
- opts = append(opts, client.WithTLSClientConfig(
- filepath.Join(c.cfg.CertPath, tlsCACertFile),
- filepath.Join(c.cfg.CertPath, tlsCertFile),
- filepath.Join(c.cfg.CertPath, tlsKeyFile),
- ))
- }
- if c.cfg.Host != "" {
- // apply the host from the config if it is set
- opts = append(opts, client.WithHost(c.cfg.Host))
- }
-
- httpHeaders := make(map[string]string)
- maps.Copy(httpHeaders, c.extraHeaders)
-
- // Append the SDK headers last.
- httpHeaders[headerUserAgent] = defaultUserAgent
-
- opts = append(opts, client.WithHTTPHeaders(httpHeaders))
-
- api, err := client.NewClientWithOpts(opts...)
+ cli, err := command.NewDockerCli(command.WithUserAgent(defaultUserAgent))
if err != nil {
- return fmt.Errorf("new client: %w", err)
+ return nil, err
}
- c.APIClient = api
- return nil
-}
-// defaultValues sets the default values for the client.
-// If no logger is provided, the default one is used.
-// If no docker host is provided and no docker context is provided, the current docker host and context are used.
-// If no docker host is provided but a docker context is provided, the docker host from the context is used.
-// If a docker host is provided, it is used as is.
-func (c *sdkClient) defaultValues() error {
- if c.log == nil {
- c.log = defaultLogger
+ err = cli.Initialize(flags.NewClientOptions())
+ if err != nil {
+ return nil, err
}
+ c.APIClient = cli.Client()
+ c.config = cli.ConfigFile()
- if c.dockerHost == "" && c.dockerContext == "" {
- currentDockerHost, err := dockercontext.CurrentDockerHost()
- if err != nil {
- return fmt.Errorf("current docker host: %w", err)
- }
- currentContext, err := dockercontext.Current()
- if err != nil {
- return fmt.Errorf("current context: %w", err)
+ for _, opt := range options {
+ if err := opt.Apply(c); err != nil {
+ return nil, fmt.Errorf("apply option: %w", err)
}
-
- c.dockerHost = currentDockerHost
- c.dockerContext = currentContext
-
- return nil
}
- if c.dockerContext != "" {
- dockerHost, err := dockercontext.DockerHostFromContext(c.dockerContext)
- if err != nil {
- return fmt.Errorf("docker host from context: %w", err)
- }
-
- c.dockerHost = dockerHost
+ if err := c.healthCheck(ctx)(c); err != nil {
+ return nil, fmt.Errorf("health check: %w", err)
}
- return nil
+ return c, nil
}
diff --git a/client/client_test.go b/client/client_test.go
index 9563cb597..1b7bce15e 100644
--- a/client/client_test.go
+++ b/client/client_test.go
@@ -2,22 +2,13 @@ package client_test
import (
"context"
- "path/filepath"
"testing"
"github.com/stretchr/testify/require"
- dockerclient "github.com/docker/docker/client"
"github.com/docker/go-sdk/client"
- dockercontext "github.com/docker/go-sdk/context"
)
-var noopHealthCheck = func(_ context.Context) func(c client.SDKClient) error {
- return func(_ client.SDKClient) error {
- return nil
- }
-}
-
func TestNew(t *testing.T) {
t.Run("success", func(t *testing.T) {
cli, err := client.New(context.Background())
@@ -60,75 +51,4 @@ func TestNew(t *testing.T) {
require.NoError(t, cli.Close())
require.NoError(t, cli.Close())
})
-
- t.Run("success/tls-verify", func(t *testing.T) {
- t.Setenv("DOCKER_TLS_VERIFY", "1")
- t.Setenv("DOCKER_CERT_PATH", filepath.Join("testdata", "certificates"))
-
- cli, err := client.New(context.Background())
- require.Error(t, err)
- require.Nil(t, cli)
- })
-
- t.Run("success/apply-option", func(t *testing.T) {
- cli, err := client.New(context.Background(), client.FromDockerOpt(dockerclient.WithHost("tcp://foobar:2375")))
- require.NoError(t, err)
- require.NotNil(t, cli)
- })
-
- t.Run("error", func(t *testing.T) {
- cli, err := client.New(context.Background(), client.FromDockerOpt(dockerclient.WithHost("foobar")))
- require.Error(t, err)
- require.Nil(t, cli)
- })
-
- t.Run("healthcheck/nil", func(t *testing.T) {
- cli, err := client.New(context.Background(), client.WithHealthCheck(nil))
- require.ErrorContains(t, err, "health check is nil")
- require.Nil(t, cli)
- })
-
- t.Run("healthcheck/noop", func(t *testing.T) {
- cli, err := client.New(context.Background(), client.WithHealthCheck(noopHealthCheck))
- require.NoError(t, err)
- require.NotNil(t, cli)
- })
-
- t.Run("healthcheck/info", func(t *testing.T) {
- t.Setenv(dockercontext.EnvOverrideHost, "tcp://foobar:2375") // this URL is parseable, although not reachable
-
- infoHealthCheck := func(ctx context.Context) func(c client.SDKClient) error {
- return func(c client.SDKClient) error {
- _, err := c.Info(ctx)
- return err
- }
- }
-
- cli, err := client.New(context.Background(), client.WithHealthCheck(infoHealthCheck))
- require.Error(t, err)
- require.Nil(t, cli)
- })
-
- t.Run("docker-host/precedence", func(t *testing.T) {
- t.Run("env-var-wins", func(t *testing.T) {
- t.Setenv(dockercontext.EnvOverrideHost, "tcp://foobar:2375") // this URL is parseable, although not reachable
- cli, err := client.New(context.Background())
- require.Error(t, err)
- require.Nil(t, cli)
- })
-
- t.Run("context-wins/found", func(t *testing.T) {
- t.Setenv(dockercontext.EnvOverrideContext, dockercontext.DefaultContextName)
- cli, err := client.New(context.Background(), client.WithHealthCheck(noopHealthCheck))
- require.NoError(t, err)
- require.NotNil(t, cli)
- })
-
- t.Run("context-wins/not-found", func(t *testing.T) {
- t.Setenv(dockercontext.EnvOverrideContext, "foocontext") // this context does not exist
- cli, err := client.New(context.Background())
- require.Error(t, err)
- require.Nil(t, cli)
- })
- })
}
diff --git a/client/client_unit_test.go b/client/client_unit_test.go
deleted file mode 100644
index 423285f0c..000000000
--- a/client/client_unit_test.go
+++ /dev/null
@@ -1,162 +0,0 @@
-package client
-
-import (
- "bytes"
- "context"
- "errors"
- "io"
- "log/slog"
- "testing"
-
- "github.com/stretchr/testify/require"
-
- dockercontext "github.com/docker/go-sdk/context"
-)
-
-func TestNew_internal_state(t *testing.T) {
- t.Run("success", func(t *testing.T) {
- sdk, err := New(context.Background())
- require.NoError(t, err)
- require.NotNil(t, sdk)
- client := sdk.(*sdkClient)
-
- require.Empty(t, client.extraHeaders)
- require.NotNil(t, client.cfg)
- require.NotNil(t, client.log)
- require.Equal(t, slog.New(slog.NewTextHandler(io.Discard, nil)), client.log)
- require.False(t, client.dockerInfoSet)
- require.Empty(t, client.dockerInfo)
- require.NoError(t, client.err)
- })
-
- t.Run("with-headers", func(t *testing.T) {
- sdk, err := New(context.Background(), WithExtraHeaders(map[string]string{"X-Test": "test"}))
- require.NoError(t, err)
- require.NotNil(t, sdk)
- client := sdk.(*sdkClient)
-
- require.Equal(t, map[string]string{"X-Test": "test"}, client.extraHeaders)
- })
-
- t.Run("with-logger", func(t *testing.T) {
- logger := slog.New(slog.NewTextHandler(io.Discard, nil))
-
- sdk, err := New(context.Background(), WithLogger(logger))
- require.NoError(t, err)
- require.NotNil(t, sdk)
- client := sdk.(*sdkClient)
-
- require.Equal(t, logger, client.log)
- })
-
- t.Run("with-healthcheck", func(t *testing.T) {
- buf := bytes.NewBuffer(nil)
- logger := slog.New(slog.NewTextHandler(buf, nil))
-
- healthcheck := func(_ context.Context) func(SDKClient) error {
- return func(_ SDKClient) error {
- logger.Info("healthcheck")
- return nil
- }
- }
-
- sdk, err := New(context.Background(), WithHealthCheck(healthcheck), WithLogger(logger))
- require.NoError(t, err)
- require.NotNil(t, sdk)
- client := sdk.(*sdkClient)
-
- require.Equal(t, logger, client.log)
- require.Contains(t, buf.String(), "healthcheck")
- })
-
- t.Run("with-healthcheck-error", func(t *testing.T) {
- healthcheck := func(_ context.Context) func(SDKClient) error {
- return func(_ SDKClient) error {
- return errors.New("healthcheck error")
- }
- }
-
- client, err := New(context.Background(), WithHealthCheck(healthcheck))
- require.ErrorContains(t, err, "healthcheck error")
- require.Nil(t, client)
- })
-
- t.Run("with-dockerhost", func(t *testing.T) {
- noopHealthCheck := func(_ context.Context) func(SDKClient) error {
- return func(_ SDKClient) error {
- // NOOP for testing
- return nil
- }
- }
-
- sdk, err := New(context.Background(), WithHealthCheck(noopHealthCheck), WithDockerHost("unix:///var/run/docker.sock"))
- require.NoError(t, err)
- require.NotNil(t, sdk)
- client := sdk.(*sdkClient)
-
- require.Equal(t, "unix:///var/run/docker.sock", client.cfg.Host)
- })
-
- t.Run("with-dockerhost-and-dockercontext", func(t *testing.T) {
- noopHealthCheck := func(_ context.Context) func(SDKClient) error {
- return func(_ SDKClient) error {
- // NOOP for testing
- return nil
- }
- }
-
- // current context is context1
- dockercontext.SetupTestDockerContexts(t, 1, 1)
-
- sdk, err := New(
- context.Background(),
- WithHealthCheck(noopHealthCheck),
- WithDockerHost("wont-be-used"),
- WithDockerContext("context1"),
- )
- require.NoError(t, err)
- require.NotNil(t, sdk)
- client := sdk.(*sdkClient)
-
- // the docker host from the context takes precedence over the one set with WithDockerHost
- require.Equal(t, "tcp://127.0.0.1:1", client.cfg.Host)
- })
-
- t.Run("with-dockercontext", func(t *testing.T) {
- noopHealthCheck := func(_ context.Context) func(SDKClient) error {
- return func(_ SDKClient) error {
- // NOOP for testing
- return nil
- }
- }
-
- // current context is context1
- dockercontext.SetupTestDockerContexts(t, 1, 1)
-
- sdk, err := New(
- context.Background(),
- WithHealthCheck(noopHealthCheck),
- WithDockerContext("context1"),
- )
- require.NoError(t, err)
- require.NotNil(t, sdk)
- client := sdk.(*sdkClient)
-
- // the docker host from the context is used
- require.Equal(t, "tcp://127.0.0.1:1", client.cfg.Host)
- })
-
- t.Run("with-docker-context/not-existing", func(t *testing.T) {
- noopHealthCheck := func(_ context.Context) func(SDKClient) error {
- return func(_ SDKClient) error {
- // NOOP for testing
- return nil
- }
- }
-
- // the test context does not exist, so the client creation fails
- client, err := New(context.Background(), WithHealthCheck(noopHealthCheck), WithDockerContext("test"))
- require.ErrorContains(t, err, "docker host from context")
- require.Nil(t, client)
- })
-}
diff --git a/client/config.go b/client/config.go
deleted file mode 100644
index d95e0cbfa..000000000
--- a/client/config.go
+++ /dev/null
@@ -1,63 +0,0 @@
-package client
-
-import (
- "errors"
- "fmt"
- "os"
-
- "github.com/caarlos0/env/v11"
-)
-
-// config represents the configuration for the Docker client.
-// User values are read from the specified environment variables.
-type config struct {
- // Host is the address of the Docker daemon.
- // Default: ""
- Host string `env:"DOCKER_HOST"`
-
- // TLSVerify is a flag to enable or disable TLS verification when connecting to a Docker daemon.
- // Default: 0
- TLSVerify bool `env:"DOCKER_TLS_VERIFY"`
-
- // CertPath is the path to the directory containing the Docker certificates.
- // This is used when connecting to a Docker daemon over TLS.
- // Default: ""
- CertPath string `env:"DOCKER_CERT_PATH"`
-}
-
-// newConfig returns a new configuration loaded from the properties file
-// located in the user's home directory and overridden by environment variables.
-func newConfig(host string) (*config, error) {
- cfg := &config{
- Host: host,
- }
-
- if err := env.Parse(cfg); err != nil {
- return nil, fmt.Errorf("parse env: %w", err)
- }
-
- if err := cfg.validate(); err != nil {
- return nil, fmt.Errorf("validate: %w", err)
- }
-
- return cfg, nil
-}
-
-// validate verifies the configuration is valid.
-func (c *config) validate() error {
- if c.TLSVerify && c.CertPath == "" {
- return errors.New("cert path required when TLS is enabled")
- }
-
- if c.TLSVerify {
- if _, err := os.Stat(c.CertPath); os.IsNotExist(err) {
- return fmt.Errorf("cert path does not exist: %s", c.CertPath)
- }
- }
-
- if c.Host == "" {
- return errors.New("host is required")
- }
-
- return nil
-}
diff --git a/client/config_test.go b/client/config_test.go
deleted file mode 100644
index 3babed2b5..000000000
--- a/client/config_test.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package client
-
-import (
- "path/filepath"
- "testing"
-
- "github.com/stretchr/testify/require"
-)
-
-func Test_newConfig(t *testing.T) {
- t.Run("success", func(t *testing.T) {
- cfg, err := newConfig("docker-host")
- require.NoError(t, err)
- require.Equal(t, "docker-host", cfg.Host)
- require.False(t, cfg.TLSVerify)
- require.Empty(t, cfg.CertPath)
- })
-
- t.Run("success/tls-verify", func(t *testing.T) {
- certDir := filepath.Join("testdata", "certificates")
-
- t.Setenv("DOCKER_TLS_VERIFY", "1")
- t.Setenv("DOCKER_CERT_PATH", certDir)
-
- cfg, err := newConfig("docker-host")
- require.NoError(t, err)
- require.Equal(t, "docker-host", cfg.Host)
- require.True(t, cfg.TLSVerify)
- require.Equal(t, certDir, cfg.CertPath)
- })
-
- t.Run("error/host-required", func(t *testing.T) {
- cfg, err := newConfig("")
- require.Error(t, err)
- require.Nil(t, cfg)
- })
-
- t.Run("error/cert-path-required-for-tls", func(t *testing.T) {
- t.Setenv("DOCKER_TLS_VERIFY", "1")
-
- cfg, err := newConfig("docker-host")
- require.Error(t, err)
- require.Nil(t, cfg)
- })
-}
diff --git a/client/go.mod b/client/go.mod
index 0a79941a6..cd1f18fa8 100644
--- a/client/go.mod
+++ b/client/go.mod
@@ -2,52 +2,71 @@ module github.com/docker/go-sdk/client
go 1.24
-replace (
- github.com/docker/go-sdk/config => ../config
- github.com/docker/go-sdk/context => ../context
-)
-
require (
- github.com/caarlos0/env/v11 v11.3.1
github.com/containerd/errdefs v1.0.0
+ github.com/distribution/reference v0.6.0
+ github.com/docker/cli v28.5.1+incompatible
github.com/docker/docker v28.3.2+incompatible
github.com/docker/go-connections v0.5.0
- github.com/docker/go-sdk/context v0.1.0-alpha011
github.com/opencontainers/image-spec v1.1.1
- github.com/stretchr/testify v1.10.0
+ github.com/stretchr/testify v1.11.1
)
require (
+ github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
+ github.com/cenkalti/backoff/v5 v5.0.3 // indirect
+ github.com/clipperhouse/uax29/v2 v2.2.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
- github.com/distribution/reference v0.6.0 // indirect
- github.com/docker/go-sdk/config v0.1.0-alpha011 // indirect
+ github.com/docker/distribution v2.8.3+incompatible // indirect
+ github.com/docker/docker-credential-helpers v0.9.4 // indirect
+ github.com/docker/go-metrics v0.0.1 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
+ github.com/fvbommel/sortorder v1.1.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
- github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 // indirect
+ github.com/google/uuid v1.6.0 // indirect
+ github.com/gorilla/mux v1.8.1 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
+ github.com/inconshreveable/mousetrap v1.1.0 // indirect
+ github.com/mattn/go-runewidth v0.0.19 // indirect
+ github.com/miekg/pkcs11 v1.1.1 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/sys/atomicwriter v0.1.0 // indirect
+ github.com/moby/sys/sequential v0.6.0 // indirect
github.com/moby/term v0.5.2 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
+ github.com/sirupsen/logrus v1.9.3 // indirect
+ github.com/spf13/cobra v1.10.1 // indirect
+ github.com/spf13/pflag v1.0.10 // indirect
+ github.com/theupdateframework/notary v0.7.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
- go.opentelemetry.io/otel v1.37.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 // indirect
+ go.opentelemetry.io/otel v1.38.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0 // indirect
- go.opentelemetry.io/otel/metric v1.37.0 // indirect
- go.opentelemetry.io/otel/sdk v1.37.0 // indirect
- go.opentelemetry.io/otel/trace v1.37.0 // indirect
- go.opentelemetry.io/proto/otlp v1.7.0 // indirect
- golang.org/x/sys v0.33.0 // indirect
+ go.opentelemetry.io/otel/metric v1.38.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.38.0 // indirect
+ go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect
+ go.opentelemetry.io/otel/trace v1.38.0 // indirect
+ go.opentelemetry.io/proto/otlp v1.7.1 // indirect
+ golang.org/x/net v0.43.0 // indirect
+ golang.org/x/sys v0.35.0 // indirect
+ golang.org/x/text v0.28.0 // indirect
golang.org/x/time v0.11.0 // indirect
- google.golang.org/grpc v1.73.0 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
+ google.golang.org/grpc v1.75.0 // indirect
+ google.golang.org/protobuf v1.36.8 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
+ gotest.tools/v3 v3.5.2 // indirect
)
diff --git a/client/go.sum b/client/go.sum
index 218ed7eb4..4aebaf4f3 100644
--- a/client/go.sum
+++ b/client/go.sum
@@ -1,48 +1,138 @@
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
-github.com/caarlos0/env/v11 v11.3.1 h1:cArPWC15hWmEt+gWk7YBi7lEXTXCvpaSdCiZE2X5mCA=
-github.com/caarlos0/env/v11 v11.3.1/go.mod h1:qupehSf/Y0TUTsxKywqRt/vJjN5nz6vauiYEUUr8P4U=
-github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8=
-github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
+github.com/Shopify/logrus-bugsnag v0.0.0-20170309145241-6dbc35f2c30d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/beorn7/perks v0.0.0-20150223135152-b965b613227f/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bitly/go-hostpool v0.1.0/go.mod h1:4gOCgp6+NZnVqlKyZ/iBZFTAJKembaVENUpMkpg42fw=
+github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
+github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
+github.com/bugsnag/bugsnag-go v1.0.5-0.20150529004307-13fd6b8acda0/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
+github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
+github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
+github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
+github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
+github.com/clipperhouse/uax29/v2 v2.2.0 h1:ChwIKnQN3kcZteTXMgb1wztSgaU+ZemkgWdohwgs8tY=
+github.com/clipperhouse/uax29/v2 v2.2.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
+github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA=
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
+github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
+github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
+github.com/docker/cli v28.5.1+incompatible h1:ESutzBALAD6qyCLqbQSEf1a/U8Ybms5agw59yGVc+yY=
+github.com/docker/cli v28.5.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
+github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v28.3.2+incompatible h1:wn66NJ6pWB1vBZIilP8G3qQPqHy5XymfYn5vsqeA5oA=
github.com/docker/docker v28.3.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker-credential-helpers v0.9.4 h1:76ItO69/AP/V4yT9V4uuuItG0B1N8hvt0T0c0NN/DzI=
+github.com/docker/docker-credential-helpers v0.9.4/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c=
+github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
+github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q=
+github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
+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.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
+github.com/dvsekhvalnov/jose2go v0.0.0-20170216131308-f21a8cedbbae/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM=
+github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fvbommel/sortorder v1.1.0 h1:fUmoe+HLsBTctBDoaBwpQo5N+nrCp8g/BjKb/6ZQmYw=
+github.com/fvbommel/sortorder v1.1.0/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/google/certificate-transparency-go v1.0.10-0.20180222191210-5ab67e519c93/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90=
+github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
+github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs=
+github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
+github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
+github.com/jinzhu/gorm v0.0.0-20170222002820-5409931a1bb8/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo=
+github.com/jinzhu/inflection v0.0.0-20170102125226-1c35d901db3d/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
+github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/lib/pq v0.0.0-20150723085316-0dad96c0b94f/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/magiconair/properties v1.5.3/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw=
+github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
+github.com/mattn/go-sqlite3 v1.6.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
+github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
+github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU=
+github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
+github.com/mitchellh/mapstructure v0.0.0-20150613213606-2caf8efc9366/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
@@ -51,67 +141,153 @@ github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7z
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+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/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
+github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
+github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
+github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_golang v0.9.0-pre1.0.20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8=
+github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
+github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.6.0 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkpEo=
+github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
+github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.3 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURmKE=
+github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
-github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
-github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/spf13/cast v0.0.0-20150508191742-4d07383ffe94/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
+github.com/spf13/cobra v0.0.1/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
+github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
+github.com/spf13/jwalterweatherman v0.0.0-20141219030609-3d60171a6431/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/pflag v1.0.0/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
+github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v0.0.0-20150530192845-be5ff3e4840c/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
+github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
+github.com/theupdateframework/notary v0.7.0 h1:QyagRZ7wlSpjT5N2qQAh/pN+DVqgekv4DzbAiAiEL3c=
+github.com/theupdateframework/notary v0.7.0/go.mod h1:c9DRxcmhHmVLDay4/2fUYdISnHqbFDGRSlXPO0AhYWw=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
-go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
-go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M=
+go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
+go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9obrcoWVKp/lwl8tRE33853I8Xru9HFbw/skNeLs8=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0/go.mod h1:GAXRxmLJcVM3u22IjTg74zWBrRCKq8BnOqUVLodpcpw=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0 h1:nRVXXvf78e00EwY6Wp0YII8ww2JVWshZ20HfTlE11AM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0/go.mod h1:r49hO7CgrxY9Voaj3Xe8pANWtr0Oq916d0XAmOoCZAQ=
-go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
-go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
-go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
-go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
-go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
-go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
-go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
-go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
-go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os=
-go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo=
+go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
+go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
+go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
+go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
+go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
+go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
+go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
+go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
+go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=
+go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=
+go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
+go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
+golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
-golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
+golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
+golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
-golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
+golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
+golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
+golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
-golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
+golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
+golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -122,17 +298,33 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY=
-google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
-google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
-google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
-google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
-google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
+gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
+gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
+google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY=
+google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc=
+google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
+google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4=
+google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
+google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
+google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
+gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/cenkalti/backoff.v2 v2.2.1/go.mod h1:S0QdOvT2AlerfSBkp0O+dk+bbIMaNbEmVk876gPCthU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
+gopkg.in/rethinkdb/rethinkdb-go.v6 v6.2.1/go.mod h1:WbjuEoo1oadwzQ4apSDU+JTvmllEHtsNHS6y7vFc7iw=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
diff --git a/client/registry.go b/client/registry.go
new file mode 100644
index 000000000..2110e7c23
--- /dev/null
+++ b/client/registry.go
@@ -0,0 +1,39 @@
+package client
+
+import (
+ "fmt"
+
+ "github.com/docker/docker/api/types/registry"
+ cr "github.com/docker/go-sdk/client/registry"
+)
+
+// AuthConfigForImage returns the auth config for a single image
+func (c *sdkClient) AuthConfigForImage(img string) (string, registry.AuthConfig, error) {
+ ref, err := cr.ParseImageRef(img)
+ if err != nil {
+ return "", registry.AuthConfig{}, fmt.Errorf("parse image ref: %w", err)
+ }
+
+ authConfig, err := c.AuthConfigForHostname(ref.Registry)
+ if err != nil {
+ return ref.Registry, registry.AuthConfig{}, err
+ }
+
+ authConfig.ServerAddress = ref.Registry
+ return ref.Registry, authConfig, nil
+}
+
+func (c *sdkClient) AuthConfigForHostname(host string) (registry.AuthConfig, error) {
+ config, err := c.config.GetAuthConfig(host)
+ if err != nil {
+ return registry.AuthConfig{}, err
+ }
+ return registry.AuthConfig{
+ Username: config.Username,
+ Password: config.Password,
+ IdentityToken: config.IdentityToken,
+ RegistryToken: config.RegistryToken,
+ Auth: config.Auth,
+ ServerAddress: config.ServerAddress,
+ }, nil
+}
diff --git a/config/auth/registry.go b/client/registry/registry.go
similarity index 99%
rename from config/auth/registry.go
rename to client/registry/registry.go
index aa7c11fbe..88a6308a3 100644
--- a/config/auth/registry.go
+++ b/client/registry/registry.go
@@ -1,4 +1,4 @@
-package auth
+package registry
import (
"fmt"
diff --git a/config/auth/registry_test.go b/client/registry/registry_test.go
similarity index 75%
rename from config/auth/registry_test.go
rename to client/registry/registry_test.go
index 1022126c5..6901daa73 100644
--- a/config/auth/registry_test.go
+++ b/client/registry/registry_test.go
@@ -1,11 +1,11 @@
-package auth_test
+package registry_test
import (
"testing"
"github.com/stretchr/testify/require"
- "github.com/docker/go-sdk/config/auth"
+ "github.com/docker/go-sdk/client/registry"
)
const (
@@ -17,28 +17,28 @@ const (
func TestParseImageRef(t *testing.T) {
t.Run("empty-image", func(t *testing.T) {
- ref, err := auth.ParseImageRef("")
+ ref, err := registry.ParseImageRef("")
require.Error(t, err)
require.Empty(t, ref)
})
t.Run("numbers", func(t *testing.T) {
- ref, err := auth.ParseImageRef("1234567890")
+ ref, err := registry.ParseImageRef("1234567890")
require.NoError(t, err)
- require.Equal(t, auth.DockerRegistry, ref.Registry)
+ require.Equal(t, registry.DockerRegistry, ref.Registry)
require.Equal(t, "library/1234567890", ref.Repository)
require.Empty(t, ref.Tag)
require.Empty(t, ref.Digest)
})
t.Run("malformed-image", func(t *testing.T) {
- ref, err := auth.ParseImageRef("--malformed--")
+ ref, err := registry.ParseImageRef("--malformed--")
require.Error(t, err)
require.Empty(t, ref)
})
t.Run("protocol-registry", func(t *testing.T) {
- ref, err := auth.ParseImageRef("http://docker.io/library/nginx")
+ ref, err := registry.ParseImageRef("http://docker.io/library/nginx")
require.Error(t, err)
require.Empty(t, ref)
})
@@ -52,11 +52,11 @@ func TestParseImageRef(t *testing.T) {
testRegistry += "/"
} else {
expectedRepositoryPrefix = "library/"
- expectedRegistry = auth.DockerRegistry
+ expectedRegistry = registry.DockerRegistry
}
t.Run("image", func(t *testing.T) {
- ref, err := auth.ParseImageRef(testRegistry + "nginx")
+ ref, err := registry.ParseImageRef(testRegistry + "nginx")
require.NoError(t, err)
require.Equal(t, expectedRegistry, ref.Registry)
require.Equal(t, expectedRepositoryPrefix+"nginx", ref.Repository)
@@ -65,7 +65,7 @@ func TestParseImageRef(t *testing.T) {
})
t.Run("image@256digest", func(t *testing.T) {
- ref, err := auth.ParseImageRef(testRegistry + "nginx@" + string(testDigest256))
+ ref, err := registry.ParseImageRef(testRegistry + "nginx@" + string(testDigest256))
require.NoError(t, err)
require.Equal(t, expectedRegistry, ref.Registry)
require.Equal(t, expectedRepositoryPrefix+"nginx", ref.Repository)
@@ -74,7 +74,7 @@ func TestParseImageRef(t *testing.T) {
})
t.Run("image@512digest", func(t *testing.T) {
- ref, err := auth.ParseImageRef(testRegistry + "nginx@" + string(testDigest512))
+ ref, err := registry.ParseImageRef(testRegistry + "nginx@" + string(testDigest512))
require.NoError(t, err)
require.Equal(t, expectedRegistry, ref.Registry)
require.Equal(t, expectedRepositoryPrefix+"nginx", ref.Repository)
@@ -83,7 +83,7 @@ func TestParseImageRef(t *testing.T) {
})
t.Run("image:tag", func(t *testing.T) {
- ref, err := auth.ParseImageRef(testRegistry + "nginx:latest")
+ ref, err := registry.ParseImageRef(testRegistry + "nginx:latest")
require.NoError(t, err)
require.Equal(t, expectedRegistry, ref.Registry)
require.Equal(t, expectedRepositoryPrefix+"nginx", ref.Repository)
@@ -92,7 +92,7 @@ func TestParseImageRef(t *testing.T) {
})
t.Run("image:tag@256digest", func(t *testing.T) {
- ref, err := auth.ParseImageRef(testRegistry + "nginx:latest@" + string(testDigest256))
+ ref, err := registry.ParseImageRef(testRegistry + "nginx:latest@" + string(testDigest256))
require.NoError(t, err)
require.Equal(t, expectedRegistry, ref.Registry)
require.Equal(t, expectedRepositoryPrefix+"nginx", ref.Repository)
@@ -101,7 +101,7 @@ func TestParseImageRef(t *testing.T) {
})
t.Run("image:tag@512digest", func(t *testing.T) {
- ref, err := auth.ParseImageRef(testRegistry + "nginx:latest@" + string(testDigest512))
+ ref, err := registry.ParseImageRef(testRegistry + "nginx:latest@" + string(testDigest512))
require.NoError(t, err)
require.Equal(t, expectedRegistry, ref.Registry)
require.Equal(t, expectedRepositoryPrefix+"nginx", ref.Repository)
@@ -110,7 +110,7 @@ func TestParseImageRef(t *testing.T) {
})
t.Run("repository/image", func(t *testing.T) {
- ref, err := auth.ParseImageRef(testRegistry + "testcontainers/ryuk")
+ ref, err := registry.ParseImageRef(testRegistry + "testcontainers/ryuk")
require.NoError(t, err)
require.Equal(t, expectedRegistry, ref.Registry)
require.Equal(t, "testcontainers/ryuk", ref.Repository)
@@ -119,7 +119,7 @@ func TestParseImageRef(t *testing.T) {
})
t.Run("repository/image@256digest", func(t *testing.T) {
- ref, err := auth.ParseImageRef(testRegistry + "testcontainers/ryuk@" + string(testDigest256))
+ ref, err := registry.ParseImageRef(testRegistry + "testcontainers/ryuk@" + string(testDigest256))
require.NoError(t, err)
require.Equal(t, expectedRegistry, ref.Registry)
require.Equal(t, "testcontainers/ryuk", ref.Repository)
@@ -128,7 +128,7 @@ func TestParseImageRef(t *testing.T) {
})
t.Run("repository/image@512digest", func(t *testing.T) {
- ref, err := auth.ParseImageRef(testRegistry + "testcontainers/ryuk@" + string(testDigest512))
+ ref, err := registry.ParseImageRef(testRegistry + "testcontainers/ryuk@" + string(testDigest512))
require.NoError(t, err)
require.Equal(t, expectedRegistry, ref.Registry)
require.Equal(t, "testcontainers/ryuk", ref.Repository)
@@ -137,7 +137,7 @@ func TestParseImageRef(t *testing.T) {
})
t.Run("repository/image:tag", func(t *testing.T) {
- ref, err := auth.ParseImageRef(testRegistry + "testcontainers/ryuk:latest")
+ ref, err := registry.ParseImageRef(testRegistry + "testcontainers/ryuk:latest")
require.NoError(t, err)
require.Equal(t, expectedRegistry, ref.Registry)
require.Equal(t, "testcontainers/ryuk", ref.Repository)
@@ -146,7 +146,7 @@ func TestParseImageRef(t *testing.T) {
})
t.Run("repository/image:tag@256digest", func(t *testing.T) {
- ref, err := auth.ParseImageRef(testRegistry + "testcontainers/ryuk:latest@" + string(testDigest256))
+ ref, err := registry.ParseImageRef(testRegistry + "testcontainers/ryuk:latest@" + string(testDigest256))
require.NoError(t, err)
require.Equal(t, expectedRegistry, ref.Registry)
require.Equal(t, "testcontainers/ryuk", ref.Repository)
@@ -155,13 +155,13 @@ func TestParseImageRef(t *testing.T) {
})
t.Run("repository/image:tag@wrong-256digest", func(t *testing.T) {
- ref, err := auth.ParseImageRef(testRegistry + "testcontainers/ryuk:latest@" + string(wrongDigest256))
+ ref, err := registry.ParseImageRef(testRegistry + "testcontainers/ryuk:latest@" + string(wrongDigest256))
require.Error(t, err)
require.Empty(t, ref)
})
t.Run("repository/image:tag@512digest", func(t *testing.T) {
- ref, err := auth.ParseImageRef(testRegistry + "testcontainers/ryuk:latest@" + string(testDigest512))
+ ref, err := registry.ParseImageRef(testRegistry + "testcontainers/ryuk:latest@" + string(testDigest512))
require.NoError(t, err)
require.Equal(t, expectedRegistry, ref.Registry)
require.Equal(t, "testcontainers/ryuk", ref.Repository)
@@ -170,7 +170,7 @@ func TestParseImageRef(t *testing.T) {
})
t.Run("repository/image:tag@wrong-512digest", func(t *testing.T) {
- ref, err := auth.ParseImageRef(testRegistry + "testcontainers/ryuk:latest@" + string(wrongDigest512))
+ ref, err := registry.ParseImageRef(testRegistry + "testcontainers/ryuk:latest@" + string(wrongDigest512))
require.Error(t, err)
require.Empty(t, ref)
})
diff --git a/config/auth/registry_unit_test.go b/client/registry/registry_unit_test.go
similarity index 98%
rename from config/auth/registry_unit_test.go
rename to client/registry/registry_unit_test.go
index c2d0196d4..bdec838a2 100644
--- a/config/auth/registry_unit_test.go
+++ b/client/registry/registry_unit_test.go
@@ -1,4 +1,4 @@
-package auth
+package registry
import (
"testing"
diff --git a/client/types.go b/client/types.go
index 2f9e58887..69b8198e6 100644
--- a/client/types.go
+++ b/client/types.go
@@ -6,7 +6,9 @@ import (
"log/slog"
"sync"
+ "github.com/docker/cli/cli/config/configfile"
"github.com/docker/docker/api/types/container"
+ "github.com/docker/docker/api/types/registry"
"github.com/docker/docker/api/types/system"
"github.com/docker/docker/client"
)
@@ -26,6 +28,10 @@ type SDKClient interface {
// FindContainerByName finds a container by name.
FindContainerByName(ctx context.Context, name string) (*container.Summary, error)
+
+ AuthConfigForImage(image string) (string, registry.AuthConfig, error)
+
+ AuthConfigForHostname(host string) (registry.AuthConfig, error)
}
var _ client.APIClient = &sdkClient{}
@@ -33,6 +39,7 @@ var _ client.APIClient = &sdkClient{}
// sdkClient is a type that represents a client for interacting with containers.
type sdkClient struct {
client.APIClient
+ config *configfile.ConfigFile
// log is the logger for the client.
log *slog.Logger
@@ -40,12 +47,6 @@ type sdkClient struct {
// mtx is a mutex for synchronizing access to the fields below.
mtx sync.RWMutex
- // cfg is the configuration for the client, obtained from the environment variables.
- cfg *config
-
- // err is used to store errors that occur during the client's initialization.
- err error
-
// dockerOpts are options to be passed to the docker client.
dockerOpts []client.Opt
diff --git a/config/Makefile b/config/Makefile
deleted file mode 100644
index 748cb213e..000000000
--- a/config/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-include ../commons-test.mk
diff --git a/config/README.md b/config/README.md
deleted file mode 100644
index 3ce098028..000000000
--- a/config/README.md
+++ /dev/null
@@ -1,92 +0,0 @@
-# Docker Config
-
-This package provides a simple API to load docker CLI configs, auths, etc. with minimal deps.
-
-This library is a fork of [github.com/cpuguy83/dockercfg](https://github.com/cpuguy83/dockercfg). Read the [NOTICE](../NOTICE) file for more details.
-
-## Installation
-
-```bash
-go get github.com/docker/go-sdk/config
-```
-
-## Usage
-
-### Docker Config
-
-#### Directory
-
-It returns the current Docker config directory.
-
-```go
-dir, err := config.Dir()
-if err != nil {
- log.Fatalf("failed to get current docker config directory: %v", err)
-}
-
-fmt.Printf("current docker config directory: %s", dir)
-```
-
-#### Filepath
-
-It returns the path to the Docker config file.
-
-```go
-filepath, err := config.Filepath()
-if err != nil {
- log.Fatalf("failed to get current docker config file path: %v", err)
-}
-
-fmt.Printf("current docker config file path: %s", filepath)
-```
-
-#### Load
-
-It returns the Docker config.
-
-```go
-cfg, err := config.Load()
-if err != nil {
- log.Fatalf("failed to load docker config: %v", err)
-}
-
-fmt.Printf("docker config: %+v", cfg)
-```
-
-#### Save
-
-Once you have loaded a config, you can save it back to the file system.
-
-```go
-if err := cfg.Save(); err != nil {
- log.Fatalf("failed to save docker config: %v", err)
-}
-```
-
-### Auth
-
-#### AuthConfigs
-
-It returns a maps of the registry credentials for the given Docker images, indexed by the registry hostname.
-
-```go
-authConfigs, err := config.AuthConfigs("nginx:latest")
-if err != nil {
- log.Fatalf("failed to get registry credentials: %v", err)
-}
-
-fmt.Printf("registry credentials: %+v", authConfigs)
-```
-
-#### Auth Configs For Hostname
-
-It returns the registry credentials for the given Docker registry.
-
-```go
-authConfig, err := config.AuthConfigForHostname("https://index.docker.io/v1/")
-if err != nil {
- log.Fatalf("failed to get registry credentials: %v", err)
-}
-
-fmt.Printf("registry credentials: %+v", authConfig)
-```
diff --git a/config/auth.go b/config/auth.go
deleted file mode 100644
index 2908a469e..000000000
--- a/config/auth.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package config
-
-import (
- "fmt"
-
- "github.com/docker/docker/api/types/registry"
-)
-
-// This is used by the docker CLI in cases where an oauth identity token is used.
-// In that case the username is stored literally as ``
-// When fetching the credentials we check for this value to determine if.
-const tokenUsername = ""
-
-// AuthConfigs returns the auth configs for the given images.
-// The images slice must contain images that are used in a Dockerfile.
-// The returned map is keyed by the registry registry hostname for each image.
-func AuthConfigs(images ...string) (map[string]registry.AuthConfig, error) {
- cfg, err := Load()
- if err != nil {
- return nil, fmt.Errorf("load config: %w", err)
- }
-
- return cfg.AuthConfigsForImages(images)
-}
-
-// AuthConfigForHostname gets registry credentials for the passed in registry host.
-//
-// This will use [Load] to read registry auth details from the config.
-// If the config doesn't exist, it will attempt to load registry credentials using the default credential helper for the platform.
-func AuthConfigForHostname(hostname string) (registry.AuthConfig, error) {
- cfg, err := Load()
- if err != nil {
- return registry.AuthConfig{}, fmt.Errorf("load config: %w", err)
- }
-
- return cfg.AuthConfigForHostname(hostname)
-}
-
-// EncodeBase64 encodes an AuthConfig into base64.
-func EncodeBase64(authConfig registry.AuthConfig) (string, error) {
- return registry.EncodeAuthConfig(authConfig)
-}
diff --git a/config/auth_examples_test.go b/config/auth_examples_test.go
deleted file mode 100644
index 159fbf6f7..000000000
--- a/config/auth_examples_test.go
+++ /dev/null
@@ -1,30 +0,0 @@
-package config_test
-
-import (
- "fmt"
-
- "github.com/docker/go-sdk/config"
- "github.com/docker/go-sdk/config/auth"
-)
-
-func ExampleAuthConfigs() {
- authConfigs, err := config.AuthConfigs("nginx:latest")
- fmt.Println(err)
- fmt.Println(len(authConfigs))
- fmt.Println(authConfigs[auth.DockerRegistry].ServerAddress)
-
- // Output:
- //
- // 1
- // docker.io
-}
-
-func ExampleAuthConfigForHostname() {
- authConfig, err := config.AuthConfigForHostname(auth.IndexDockerIO)
- fmt.Println(err)
- fmt.Println(authConfig.Username != "")
-
- // Output:
- //
- // true
-}
diff --git a/config/auth_test.go b/config/auth_test.go
deleted file mode 100644
index 90acc634e..000000000
--- a/config/auth_test.go
+++ /dev/null
@@ -1,332 +0,0 @@
-package config
-
-import (
- "encoding/base64"
- "errors"
- "io"
- "os"
- "path/filepath"
- "strconv"
- "testing"
-
- "github.com/stretchr/testify/require"
-
- "github.com/docker/docker/api/types/registry"
-)
-
-func TestDecodeBase64Auth(t *testing.T) {
- for _, tc := range base64TestCases() {
- t.Run(tc.name, testBase64Case(tc, func() (registry.AuthConfig, error) {
- user, pass, err := decodeBase64Auth(tc.config)
- return registry.AuthConfig{
- Username: user,
- Password: pass,
- }, err
- }))
- }
-}
-
-func TestConfig_RegistryCredentialsForHostname(t *testing.T) {
- t.Run("from base64 auth", func(t *testing.T) {
- for _, tc := range base64TestCases() {
- t.Run(tc.name, func(t *testing.T) {
- config := Config{
- AuthConfigs: map[string]registry.AuthConfig{
- "some.domain": tc.config,
- },
- }
- testBase64Case(tc, func() (registry.AuthConfig, error) {
- return config.AuthConfigForHostname("some.domain")
- })(t)
- })
- }
- })
-}
-
-type base64TestCase struct {
- name string
- config registry.AuthConfig
- expUser string
- expPass string
- expErr bool
-}
-
-func base64TestCases() []base64TestCase {
- cases := []base64TestCase{
- {name: "empty"},
- {name: "not base64", expErr: true, config: registry.AuthConfig{Auth: "not base64"}},
- {name: "invalid format", expErr: true, config: registry.AuthConfig{
- Auth: base64.StdEncoding.EncodeToString([]byte("invalid format")),
- }},
- {name: "happy case", expUser: "user", expPass: "pass", config: registry.AuthConfig{
- Auth: base64.StdEncoding.EncodeToString([]byte("user:pass")),
- }},
- }
-
- return cases
-}
-
-type testAuthFn func() (registry.AuthConfig, error)
-
-func testBase64Case(tc base64TestCase, authFn testAuthFn) func(t *testing.T) {
- return func(t *testing.T) {
- t.Helper()
-
- creds, err := authFn()
- if tc.expErr {
- require.Error(t, err)
- } else {
- require.NoError(t, err)
- }
-
- require.Equal(t, tc.expUser, creds.Username)
- require.Equal(t, tc.expPass, creds.Password)
- }
-}
-
-// validateAuthForHostname is a helper function to validate the username and password for a given hostname.
-func validateAuthForHostname(t *testing.T, hostname, expectedUser, expectedPass string, expectedErr error) {
- t.Helper()
-
- creds, err := AuthConfigForHostname(hostname)
- if expectedErr != nil {
- require.ErrorContains(t, err, expectedErr.Error())
- } else {
- require.NoError(t, err)
- }
- require.Equal(t, expectedUser, creds.Username)
- require.Equal(t, expectedPass, creds.Password)
- if creds.ServerAddress != "" {
- require.Equal(t, hostname, creds.ServerAddress)
- }
-}
-
-// validateAuthForImage is a helper function to validate the username and password for a given image reference.
-func validateAuthForImage(t *testing.T, imageRef, expectedUser, expectedPass, expectedRegistry string, expectedErr error) {
- t.Helper()
-
- authConfigs, err := AuthConfigs(imageRef)
- if expectedErr != nil {
- require.ErrorContains(t, err, expectedErr.Error())
- } else {
- require.NoError(t, err)
- }
-
- creds, ok := authConfigs[expectedRegistry]
- require.Equal(t, (expectedErr == nil), ok)
-
- require.Equal(t, expectedUser, creds.Username)
- require.Equal(t, expectedPass, creds.Password)
- require.Equal(t, expectedRegistry, creds.ServerAddress)
-}
-
-// validateAuthErrorForHostname is a helper function to validate we get an error for the given hostname.
-func validateAuthErrorForHostname(t *testing.T, hostname string, expectedErr error) {
- t.Helper()
-
- creds, err := AuthConfigForHostname(hostname)
- require.Error(t, err)
- require.Equal(t, expectedErr.Error(), err.Error())
- require.Empty(t, creds.Username)
- require.Empty(t, creds.Password)
- if creds.ServerAddress != "" {
- require.Equal(t, hostname, creds.ServerAddress)
- }
-}
-
-// validateAuthErrorForImage is a helper function to validate we get an error for the given image reference.
-func validateAuthErrorForImage(t *testing.T, imageRef string, expectedErr error) {
- t.Helper()
-
- authConfigs, err := AuthConfigs(imageRef)
- require.Error(t, err)
- require.ErrorContains(t, err, expectedErr.Error())
- require.Empty(t, authConfigs)
-}
-
-func TestRegistryCredentialsForImage(t *testing.T) {
- t.Setenv(EnvOverrideDir, filepath.Join("testdata", "credhelpers-config"))
-
- t.Run("auths/user-pass", func(t *testing.T) {
- validateAuthForImage(t, "userpass.io/repo/image:tag", "user", "pass", "userpass.io", nil)
- })
-
- t.Run("auths/auth", func(t *testing.T) {
- validateAuthForImage(t, "auth.io/repo/image:tag", "auth", "authsecret", "auth.io", nil)
- })
-
- t.Run("credsStore", func(t *testing.T) {
- validateAuthForImage(t, "credstore.io/repo/image:tag", "", "", "credstore.io", nil)
- })
-
- t.Run("credHelpers/user-pass", func(t *testing.T) {
- mockExecCommand(t, `HELPER_STDOUT={"Username":"credhelper","Secret":"credhelpersecret", "ServerURL":"helper.io"}`)
- validateAuthForImage(t, "helper.io/repo/image:tag", "credhelper", "credhelpersecret", "helper.io", nil)
- })
-
- t.Run("credHelpers/token", func(t *testing.T) {
- mockExecCommand(t, `HELPER_STDOUT={"Username":"", "Secret":"credhelpersecret", "ServerURL":"helper.io"}`)
- validateAuthForImage(t, "helper.io/repo/image:tag", "", "credhelpersecret", "helper.io", nil)
- })
-
- t.Run("credHelpers/not-found", func(t *testing.T) {
- mockExecCommand(t, "HELPER_STDOUT="+ErrCredentialsNotFound.Error(), "HELPER_EXIT_CODE=1")
- validateAuthForImage(t, "helper.io/repo/image:tag", "", "", "helper.io", nil)
- })
-
- t.Run("credHelpers/missing-url", func(t *testing.T) {
- mockExecCommand(t, "HELPER_STDOUT="+ErrCredentialsMissingServerURL.Error(), "HELPER_EXIT_CODE=1")
- validateAuthErrorForImage(t, "helper.io/repo/image:tag", ErrCredentialsMissingServerURL)
- })
-
- t.Run("credHelpers/other-error", func(t *testing.T) {
- mockExecCommand(t, "HELPER_STDOUT=output", "HELPER_STDERR=my error", "HELPER_EXIT_CODE=10")
- expectedErr := errors.New(`execute "docker-credential-helper" stdout: "output" stderr: "my error": exit status 10`)
- validateAuthErrorForImage(t, "helper.io/repo/image:tag", expectedErr)
- })
-
- t.Run("credHelpers/lookup-not-found", func(t *testing.T) {
- mockExecCommand(t, "HELPER_STDOUT=output", "HELPER_STDERR=my error", "HELPER_EXIT_CODE=10")
- validateAuthForImage(t, "other.io/repo/image:tag", "", "", "other.io", nil)
- })
-
- t.Run("credHelpers/lookup-error", func(t *testing.T) {
- mockExecCommand(t, "HELPER_STDOUT=output", "HELPER_STDERR=my error", "HELPER_EXIT_CODE=10")
- expectedErr := errors.New(`look up "docker-credential-error": lookup error`)
- validateAuthErrorForImage(t, "error.io/repo/image:tag", expectedErr)
- })
-
- t.Run("credHelpers/decode-json", func(t *testing.T) {
- mockExecCommand(t, "HELPER_STDOUT=bad-json")
- expectedErr := errors.New(`unmarshal credentials from: "docker-credential-helper": invalid character 'b' looking for beginning of value`)
- validateAuthErrorForImage(t, "helper.io/repo/image:tag", expectedErr)
- })
-
- t.Run("config/not-found", func(t *testing.T) {
- t.Setenv(EnvOverrideDir, filepath.Join("testdata", "missing"))
- validateAuthForImage(t, "userpass.io/repo/image:tag", "", "", "", errors.New("file does not exist"))
- })
-}
-
-func TestRegistryCredentialsForHostname(t *testing.T) {
- t.Setenv(EnvOverrideDir, filepath.Join("testdata", "credhelpers-config"))
-
- t.Run("auths/user-pass", func(t *testing.T) {
- validateAuthForHostname(t, "userpass.io", "user", "pass", nil)
- })
-
- t.Run("auths/auth", func(t *testing.T) {
- validateAuthForHostname(t, "auth.io", "auth", "authsecret", nil)
- })
-
- t.Run("credsStore", func(t *testing.T) {
- validateAuthForHostname(t, "credstore.io", "", "", nil)
- })
-
- t.Run("credHelpers/user-pass", func(t *testing.T) {
- mockExecCommand(t, `HELPER_STDOUT={"Username":"credhelper","Secret":"credhelpersecret"}`)
- validateAuthForHostname(t, "helper.io", "credhelper", "credhelpersecret", nil)
- })
-
- t.Run("credHelpers/token", func(t *testing.T) {
- mockExecCommand(t, `HELPER_STDOUT={"Username":"", "Secret":"credhelpersecret"}`)
- validateAuthForHostname(t, "helper.io", "", "credhelpersecret", nil)
- })
-
- t.Run("credHelpers/not-found", func(t *testing.T) {
- mockExecCommand(t, "HELPER_STDOUT="+ErrCredentialsNotFound.Error(), "HELPER_EXIT_CODE=1")
- validateAuthForHostname(t, "helper.io", "", "", nil)
- })
-
- t.Run("credHelpers/missing-url", func(t *testing.T) {
- mockExecCommand(t, "HELPER_STDOUT="+ErrCredentialsMissingServerURL.Error(), "HELPER_EXIT_CODE=1")
- validateAuthErrorForHostname(t, "helper.io", ErrCredentialsMissingServerURL)
- })
-
- t.Run("credHelpers/other-error", func(t *testing.T) {
- mockExecCommand(t, "HELPER_STDOUT=output", "HELPER_STDERR=my error", "HELPER_EXIT_CODE=10")
- expectedErr := errors.New(`execute "docker-credential-helper" stdout: "output" stderr: "my error": exit status 10`)
- validateAuthErrorForHostname(t, "helper.io", expectedErr)
- })
-
- t.Run("credHelpers/lookup-not-found", func(t *testing.T) {
- mockExecCommand(t, "HELPER_STDOUT=output", "HELPER_STDERR=my error", "HELPER_EXIT_CODE=10")
- validateAuthForHostname(t, "other.io", "", "", nil)
- })
-
- t.Run("credHelpers/lookup-error", func(t *testing.T) {
- mockExecCommand(t, "HELPER_STDOUT=output", "HELPER_STDERR=my error", "HELPER_EXIT_CODE=10")
- expectedErr := errors.New(`look up "docker-credential-error": lookup error`)
- validateAuthErrorForHostname(t, "error.io", expectedErr)
- })
-
- t.Run("credHelpers/decode-json", func(t *testing.T) {
- mockExecCommand(t, "HELPER_STDOUT=bad-json")
- expectedErr := errors.New(`unmarshal credentials from: "docker-credential-helper": invalid character 'b' looking for beginning of value`)
- validateAuthErrorForHostname(t, "helper.io", expectedErr)
- })
-
- t.Run("config/not-found", func(t *testing.T) {
- t.Setenv(EnvOverrideDir, filepath.Join("testdata", "missing"))
- validateAuthForHostname(t, "userpass.io", "", "", errors.New("file does not exist"))
- })
-}
-
-// TestMain is hijacked so we can run a test helper which can write
-// cleanly to stdout and stderr.
-func TestMain(m *testing.M) {
- pid := os.Getpid()
- if os.Getenv("GO_EXEC_TEST_PID") == "" {
- os.Setenv("GO_EXEC_TEST_PID", strconv.Itoa(pid))
- // Run the tests.
- os.Exit(m.Run())
- }
-
- // Run the helper which slurps stdin and writes to stdout and stderr.
- if _, err := io.Copy(io.Discard, os.Stdin); err != nil {
- if _, err = os.Stderr.WriteString(err.Error()); err != nil {
- panic(err)
- }
- }
-
- if out := os.Getenv("HELPER_STDOUT"); out != "" {
- if _, err := os.Stdout.WriteString(out); err != nil {
- panic(err)
- }
- }
-
- if out := os.Getenv("HELPER_STDERR"); out != "" {
- if _, err := os.Stderr.WriteString(out); err != nil {
- panic(err)
- }
- }
-
- if code := os.Getenv("HELPER_EXIT_CODE"); code != "" {
- code, err := strconv.Atoi(code)
- if err != nil {
- panic(err)
- }
-
- os.Exit(code)
- }
-}
-
-func TestAuthConfigs(t *testing.T) {
- t.Setenv(EnvOverrideDir, filepath.Join("testdata", "credhelpers-config"))
-
- t.Run("success", func(t *testing.T) {
- authConfigs, err := AuthConfigs("userpass.io/repo/image:tag")
- require.NoError(t, err)
- require.Equal(t, "user", authConfigs["userpass.io"].Username)
- require.Equal(t, "pass", authConfigs["userpass.io"].Password)
- require.Equal(t, "userpass.io", authConfigs["userpass.io"].ServerAddress)
- })
-
- t.Run("not-cached", func(t *testing.T) {
- authConfigs, err := AuthConfigs("notcached.io/repo/image:tag")
- require.NoError(t, err)
- require.Empty(t, authConfigs["notcached.io"].Username)
- require.Empty(t, authConfigs["notcached.io"].Password)
- require.Equal(t, "notcached.io", authConfigs["notcached.io"].ServerAddress)
- })
-}
diff --git a/config/config.go b/config/config.go
deleted file mode 100644
index e5ef4cff7..000000000
--- a/config/config.go
+++ /dev/null
@@ -1,311 +0,0 @@
-package config
-
-import (
- "crypto/md5"
- "encoding/base64"
- "encoding/hex"
- "encoding/json"
- "errors"
- "fmt"
- "os"
- "strings"
- "sync"
- "time"
-
- "github.com/docker/docker/api/types/registry"
- "github.com/docker/go-sdk/config/auth"
-)
-
-var cacheInitMutex sync.Mutex
-
-// authConfigCache holds the caching state for a Config instance
-type authConfigCache struct {
- entries map[string]registry.AuthConfig
- mutex sync.RWMutex
- key string
-}
-
-// clearAuthCache clears the cached auth configs
-func (c *Config) clearAuthCache() {
- cache := c.getCache()
- cache.mutex.Lock()
- defer cache.mutex.Unlock()
-
- cache.entries = make(map[string]registry.AuthConfig)
-}
-
-// cacheStats returns statistics about the auth config cache
-func (c *Config) cacheStats() cacheStats {
- cache := c.getCache()
- cache.mutex.RLock()
- defer cache.mutex.RUnlock()
-
- return cacheStats{
- Size: len(cache.entries),
- CacheKey: cache.key,
- }
-}
-
-type cacheStats struct {
- Size int
- CacheKey string
-}
-
-// getCache safely returns the cache, initializing it if necessary
-func (c *Config) getCache() *authConfigCache {
- c.initCache()
- return c.cache.Load().(*authConfigCache)
-}
-
-// initCache initializes the cache if it hasn't been initialized yet
-func (c *Config) initCache() {
- // Try to load existing cache
- if c.cache.Load() != nil {
- return // Fast path - cache already initialized
- }
-
- cacheInitMutex.Lock()
- defer cacheInitMutex.Unlock()
-
- // Double-check pattern
- if c.cache.Load() != nil {
- return // Another goroutine initialized it
- }
-
- newCache := &authConfigCache{
- entries: make(map[string]registry.AuthConfig),
- key: c.generateCacheKey(),
- }
-
- c.cache.Store(newCache)
-}
-
-// generateCacheKey creates a unique key for this config instance
-func (c *Config) generateCacheKey() string {
- h := md5.New()
- if err := json.NewEncoder(h).Encode(c); err != nil {
- return fmt.Sprintf("fallback-%d", time.Now().UnixNano())
- }
- return hex.EncodeToString(h.Sum(nil))
-}
-
-// AuthConfigForHostname returns the auth config for the given hostname with caching
-func (c *Config) AuthConfigForHostname(hostname string) (registry.AuthConfig, error) {
- cache := c.getCache()
-
- // Try cache first
- cache.mutex.RLock()
- if authConfig, exists := cache.entries[hostname]; exists {
- cache.mutex.RUnlock()
- return authConfig, nil
- }
- cache.mutex.RUnlock()
-
- // Cache miss - resolve auth config
- authConfig, err := c.resolveAuthConfigForHostname(hostname)
- if err != nil {
- return registry.AuthConfig{}, err
- }
-
- // Cache the result
- cache.mutex.Lock()
- cache.entries[hostname] = authConfig
- cache.mutex.Unlock()
-
- return authConfig, nil
-}
-
-// AuthConfigsForImages returns auth configs for multiple images with caching
-func (c *Config) AuthConfigsForImages(images []string) (map[string]registry.AuthConfig, error) {
- result := make(map[string]registry.AuthConfig)
- var errs []error
-
- // Process each image
- for _, image := range images {
- registry, authConfig, err := c.AuthConfigForImage(image)
- if err != nil {
- if !errors.Is(err, ErrCredentialsNotFound) {
- errs = append(errs, fmt.Errorf("auth config for %q: %w", registry, err))
- continue
- }
- // Skip if credentials not found
- continue
- }
-
- authConfig.ServerAddress = registry
- result[registry] = authConfig
- }
-
- if len(errs) > 0 {
- return nil, errors.Join(errs...)
- }
-
- return result, nil
-}
-
-// AuthConfigForImage returns the auth config for a single image
-func (c *Config) AuthConfigForImage(image string) (string, registry.AuthConfig, error) {
- ref, err := auth.ParseImageRef(image)
- if err != nil {
- return "", registry.AuthConfig{}, fmt.Errorf("parse image ref: %w", err)
- }
-
- authConfig, err := c.AuthConfigForHostname(ref.Registry)
- if err != nil {
- return ref.Registry, registry.AuthConfig{}, err
- }
-
- authConfig.ServerAddress = ref.Registry
- return ref.Registry, authConfig, nil
-}
-
-// ParseProxyConfig computes proxy configuration by retrieving the config for the provided host and
-// then checking this against any environment variables provided to the container
-func (c *Config) ParseProxyConfig(host string, runOpts map[string]*string) map[string]*string {
- var cfgKey string
-
- if _, ok := c.Proxies[host]; !ok {
- cfgKey = "default"
- } else {
- cfgKey = host
- }
-
- conf := c.Proxies[cfgKey]
- permitted := map[string]*string{
- "HTTP_PROXY": &conf.HTTPProxy,
- "HTTPS_PROXY": &conf.HTTPSProxy,
- "NO_PROXY": &conf.NoProxy,
- "FTP_PROXY": &conf.FTPProxy,
- "ALL_PROXY": &conf.AllProxy,
- }
- m := runOpts
- if m == nil {
- m = make(map[string]*string)
- }
- for k := range permitted {
- if *permitted[k] == "" {
- continue
- }
- if _, ok := m[k]; !ok {
- m[k] = permitted[k]
- }
- if _, ok := m[strings.ToLower(k)]; !ok {
- m[strings.ToLower(k)] = permitted[k]
- }
- }
- return m
-}
-
-// Save saves the config to the file system
-func (c *Config) Save() error {
- data, err := json.Marshal(c)
- if err != nil {
- return fmt.Errorf("json marshal: %w", err)
- }
-
- return os.WriteFile(c.filepath, data, 0o644)
-}
-
-// resolveAuthConfigForHostname performs the actual auth config resolution
-func (c *Config) resolveAuthConfigForHostname(hostname string) (registry.AuthConfig, error) {
- // Normalize Docker registry hostnames
- hostname = auth.ResolveRegistryHost(hostname)
-
- // Check credential helpers first
- if helper, exists := c.CredentialHelpers[hostname]; exists {
- return c.resolveFromCredentialHelper(helper, hostname)
- }
-
- // Check global credential store
- if c.CredentialsStore != "" {
- if authConfig, err := c.resolveFromCredentialHelper(c.CredentialsStore, hostname); err == nil {
- if authConfig.Username != "" || authConfig.Password != "" {
- return authConfig, nil
- }
- }
- }
-
- // Check stored auth configs
- if authConfig, exists := c.AuthConfigs[hostname]; exists {
- return c.processStoredAuthConfig(authConfig, hostname)
- }
-
- // Fallback to default credential helper
- return c.resolveFromCredentialHelper("", hostname)
-}
-
-// resolveFromCredentialHelper resolves credentials from a credential helper
-func (c *Config) resolveFromCredentialHelper(helper, hostname string) (registry.AuthConfig, error) {
- // Use existing credentialsFromHelper function but adapt to return AuthConfig
- credentials, err := credentialsFromHelper(helper, hostname)
- if err != nil {
- return registry.AuthConfig{}, err
- }
-
- return credentials, nil
-}
-
-// processStoredAuthConfig processes auth config from stored configuration
-func (c *Config) processStoredAuthConfig(stored registry.AuthConfig, hostname string) (registry.AuthConfig, error) {
- authConfig := registry.AuthConfig{
- Auth: stored.Auth,
- IdentityToken: stored.IdentityToken,
- Password: stored.Password,
- RegistryToken: stored.RegistryToken,
- ServerAddress: hostname,
- Username: stored.Username,
- }
-
- // Handle different auth scenarios
- switch {
- case authConfig.IdentityToken != "":
- // Identity token case
- authConfig.Username = ""
- authConfig.Password = authConfig.IdentityToken
-
- case authConfig.Username != "" && authConfig.Password != "":
- // Username/password case - already set
-
- case authConfig.Auth != "":
- // Base64 auth case
- user, pass, err := decodeBase64Auth(authConfig)
- if err != nil {
- return registry.AuthConfig{}, fmt.Errorf("decode base64 auth: %w", err)
- }
- authConfig.Username = user
- authConfig.Password = pass
-
- default:
- // No stored credentials, try credential helper
- return c.resolveFromCredentialHelper("", hostname)
- }
-
- return authConfig, nil
-}
-
-// decodeBase64Auth decodes the legacy file-based auth storage from the docker CLI.
-// It takes the "Auth" filed from AuthConfig and decodes that into a username and password.
-//
-// If "Auth" is empty, an empty user/pass will be returned, but not an error.
-func decodeBase64Auth(auth registry.AuthConfig) (string, string, error) {
- if auth.Auth == "" {
- return "", "", nil
- }
-
- decLen := base64.StdEncoding.DecodedLen(len(auth.Auth))
- decoded := make([]byte, decLen)
- n, err := base64.StdEncoding.Decode(decoded, []byte(auth.Auth))
- if err != nil {
- return "", "", fmt.Errorf("decode auth: %w", err)
- }
-
- decoded = decoded[:n]
-
- const sep = ":"
- user, pass, found := strings.Cut(string(decoded), sep)
- if !found {
- return "", "", fmt.Errorf("invalid auth: missing %q separator", sep)
- }
-
- return user, pass, nil
-}
diff --git a/config/config_benchmarks_test.go b/config/config_benchmarks_test.go
deleted file mode 100644
index 9fc84e6a6..000000000
--- a/config/config_benchmarks_test.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package config
-
-import (
- "testing"
-
- "github.com/stretchr/testify/require"
-
- "github.com/docker/docker/api/types/registry"
-)
-
-func BenchmarkAuthConfigCaching(b *testing.B) {
- cfg := Config{
- AuthConfigs: map[string]registry.AuthConfig{
- "test.io": {Username: "user", Password: "pass"},
- },
- }
-
- b.Run("first-access", func(b *testing.B) {
- for i := 0; i < b.N; i++ {
- cfg.clearAuthCache()
- _, err := cfg.AuthConfigForHostname("test.io")
- require.NoError(b, err)
- }
- })
-
- b.Run("cached-access", func(b *testing.B) {
- // Prime the cache
- _, _ = cfg.AuthConfigForHostname("test.io")
-
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- _, err := cfg.AuthConfigForHostname("test.io")
- require.NoError(b, err)
- }
- })
-}
diff --git a/config/config_test.go b/config/config_test.go
deleted file mode 100644
index 6c3971319..000000000
--- a/config/config_test.go
+++ /dev/null
@@ -1,133 +0,0 @@
-package config
-
-import (
- "os"
- "path/filepath"
- "sync"
- "testing"
-
- "github.com/stretchr/testify/require"
-
- "github.com/docker/docker/api/types/registry"
-)
-
-func TestConfig_AuthConfigsForImages(t *testing.T) {
- config := Config{
- AuthConfigs: map[string]registry.AuthConfig{
- "registry1.io": {Username: "user1", Password: "pass1"},
- "registry2.io": {Username: "user2", Password: "pass2"},
- },
- }
-
- images := []string{
- "registry1.io/repo/image:tag",
- "registry2.io/repo/image:tag",
- }
-
- authConfigs, err := config.AuthConfigsForImages(images)
- require.NoError(t, err)
- require.Len(t, authConfigs, 2)
- require.Equal(t, "user1", authConfigs["registry1.io"].Username)
- require.Equal(t, "user2", authConfigs["registry2.io"].Username)
-
- // Verify caching worked
- stats := config.cacheStats()
- require.Equal(t, 2, stats.Size)
-}
-
-func TestConfig_CacheManagement(t *testing.T) {
- config := Config{
- AuthConfigs: map[string]registry.AuthConfig{
- "test.io": {Username: "user", Password: "pass"},
- },
- }
-
- t.Run("cache-initialization", func(t *testing.T) {
- stats := config.cacheStats()
- require.Equal(t, 0, stats.Size)
- require.NotEmpty(t, stats.CacheKey)
- })
-
- t.Run("cache-population", func(t *testing.T) {
- _, err := config.AuthConfigForHostname("test.io")
- require.NoError(t, err)
-
- stats := config.cacheStats()
- require.Equal(t, 1, stats.Size)
- })
-
- t.Run("cache-clearing", func(t *testing.T) {
- config.clearAuthCache()
- stats := config.cacheStats()
- require.Equal(t, 0, stats.Size)
- })
-}
-
-func TestConfig_ConcurrentAccess(t *testing.T) {
- config := Config{
- AuthConfigs: map[string]registry.AuthConfig{
- "test.io": {Username: "user", Password: "pass"},
- },
- }
-
- const numGoroutines = 10
- var wg sync.WaitGroup
- wg.Add(numGoroutines)
-
- for i := 0; i < numGoroutines; i++ {
- go func() {
- defer wg.Done()
- _, err := config.AuthConfigForHostname("test.io")
- require.NoError(t, err)
- }()
- }
-
- wg.Wait()
- stats := config.cacheStats()
- require.Equal(t, 1, stats.Size)
-}
-
-func TestConfig_CacheKeyGeneration(t *testing.T) {
- config1 := Config{
- AuthConfigs: map[string]registry.AuthConfig{
- "test.io": {Username: "user1", Password: "pass1"},
- },
- }
-
- config2 := Config{
- AuthConfigs: map[string]registry.AuthConfig{
- "test.io": {Username: "user2", Password: "pass2"},
- },
- }
-
- stats1 := config1.cacheStats()
- stats2 := config2.cacheStats()
-
- require.NotEqual(t, stats1.CacheKey, stats2.CacheKey)
-}
-
-func TestConfigSave(t *testing.T) {
- tmpDir := t.TempDir()
- setupHome(t, tmpDir)
-
- dockerDir := filepath.Join(tmpDir, ".docker")
-
- err := os.MkdirAll(dockerDir, 0o755)
- require.NoError(t, err)
-
- _, err = os.Create(filepath.Join(dockerDir, FileName))
- require.NoError(t, err)
-
- c := Config{
- filepath: filepath.Join(dockerDir, FileName),
- CurrentContext: "test",
- AuthConfigs: map[string]registry.AuthConfig{},
- }
-
- require.NoError(t, c.Save())
-
- cfg, err := Load()
- require.NoError(t, err)
- require.Equal(t, c.CurrentContext, cfg.CurrentContext)
- require.Equal(t, c.AuthConfigs, cfg.AuthConfigs)
-}
diff --git a/config/credentials_helpers.go b/config/credentials_helpers.go
deleted file mode 100644
index c2883932f..000000000
--- a/config/credentials_helpers.go
+++ /dev/null
@@ -1,127 +0,0 @@
-package config
-
-import (
- "bytes"
- "encoding/json"
- "errors"
- "fmt"
- "os/exec"
- "runtime"
- "strings"
-
- "github.com/docker/docker/api/types/registry"
-)
-
-// Errors from credential helpers.
-var (
- ErrCredentialsNotFound = errors.New("credentials not found in native keychain")
- ErrCredentialsMissingServerURL = errors.New("no credentials server URL")
-)
-
-//nolint:gochecknoglobals // These are used to mock exec in tests.
-var (
- // execLookPath is a variable that can be used to mock exec.LookPath in tests.
- execLookPath = exec.LookPath
- // execCommand is a variable that can be used to mock exec.Command in tests.
- execCommand = exec.Command
-)
-
-// credentialsFromHelper attempts to lookup credentials from the passed in docker credential helper.
-//
-// The credential helper should just be the suffix name (no "docker-credential-").
-// If the passed in helper program is empty this will look up the default helper for the platform.
-//
-// If the credentials are not found, no error is returned, only empty credentials.
-//
-// Hostnames should already be resolved using [ResolveRegistryHost]
-//
-// If the username string is empty, the password string is an identity token.
-func credentialsFromHelper(helper, hostname string) (registry.AuthConfig, error) {
- var creds registry.AuthConfig
- credHelperName := helper
- if helper == "" {
- helper, helperErr := getCredentialHelper()
- if helperErr != nil {
- return creds, fmt.Errorf("get credential helper: %w", helperErr)
- }
-
- if helper == "" {
- return creds, nil
- }
-
- credHelperName = helper
- }
-
- helper = "docker-credential-" + credHelperName
- p, err := execLookPath(helper)
- if err != nil {
- if !errors.Is(err, exec.ErrNotFound) {
- return creds, fmt.Errorf("look up %q: %w", helper, err)
- }
-
- return creds, nil
- }
-
- var outBuf, errBuf bytes.Buffer
- cmd := execCommand(p, "get")
- cmd.Stdin = strings.NewReader(hostname)
- cmd.Stdout = &outBuf
- cmd.Stderr = &errBuf
-
- if err = cmd.Run(); err != nil {
- out := strings.TrimSpace(outBuf.String())
- switch out {
- case ErrCredentialsNotFound.Error():
- return creds, nil
- case ErrCredentialsMissingServerURL.Error():
- return creds, ErrCredentialsMissingServerURL
- default:
- return creds, fmt.Errorf("execute %q stdout: %q stderr: %q: %w",
- helper, out, strings.TrimSpace(errBuf.String()), err,
- )
- }
- }
-
- // ServerURL is not always present in the output,
- // only some credential helpers include it (e.g. Google Cloud).
- var bytesCreds struct {
- Username string `json:"Username"`
- Secret string `json:"Secret"`
- ServerURL string `json:"ServerURL,omitempty"`
- }
-
- if err = json.Unmarshal(outBuf.Bytes(), &bytesCreds); err != nil {
- return creds, fmt.Errorf("unmarshal credentials from: %q: %w", helper, err)
- }
-
- // When tokenUsername is used, the output is an identity token and the username is garbage.
- if bytesCreds.Username == tokenUsername {
- bytesCreds.Username = ""
- }
-
- creds.Username = bytesCreds.Username
- creds.Password = bytesCreds.Secret
- creds.ServerAddress = bytesCreds.ServerURL
-
- return creds, nil
-}
-
-// getCredentialHelper gets the default credential helper name for the current platform.
-func getCredentialHelper() (string, error) {
- switch runtime.GOOS {
- case "linux":
- if _, err := execLookPath("pass"); err != nil {
- if errors.Is(err, exec.ErrNotFound) {
- return "secretservice", nil
- }
- return "", fmt.Errorf(`look up "pass": %w`, err)
- }
- return "pass", nil
- case "darwin":
- return "osxkeychain", nil
- case "windows":
- return "wincred", nil
- default:
- return "", nil
- }
-}
diff --git a/config/credentials_helpers_test.go b/config/credentials_helpers_test.go
deleted file mode 100644
index 5f9f2a6de..000000000
--- a/config/credentials_helpers_test.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package config
-
-import (
- "errors"
- "os"
- "os/exec"
- "testing"
-)
-
-// mockExecCommand is a helper function to mock exec.LookPath and exec.Command for testing.
-func mockExecCommand(t *testing.T, env ...string) {
- t.Helper()
-
- execLookPath = func(file string) (string, error) {
- switch file {
- case "docker-credential-helper":
- return os.Args[0], nil
- case "docker-credential-error":
- return "", errors.New("lookup error")
- }
-
- return "", exec.ErrNotFound
- }
-
- execCommand = func(name string, arg ...string) *exec.Cmd {
- cmd := exec.Command(name, arg...)
- cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1")
- cmd.Env = append(cmd.Env, env...)
- return cmd
- }
-
- t.Cleanup(func() {
- execLookPath = exec.LookPath
- execCommand = exec.Command
- })
-}
diff --git a/config/go.mod b/config/go.mod
deleted file mode 100644
index 675b67d76..000000000
--- a/config/go.mod
+++ /dev/null
@@ -1,22 +0,0 @@
-module github.com/docker/go-sdk/config
-
-go 1.24
-
-require (
- github.com/distribution/reference v0.6.0
- github.com/docker/docker v28.3.2+incompatible
- github.com/stretchr/testify v1.10.0
-)
-
-require (
- github.com/davecgh/go-spew v1.1.1 // indirect
- github.com/google/go-cmp v0.7.0 // indirect
- github.com/kr/pretty v0.3.1 // indirect
- github.com/opencontainers/go-digest v1.0.0 // indirect
- github.com/opencontainers/image-spec v1.1.1 // indirect
- github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/rogpeppe/go-internal v1.13.1 // indirect
- gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
- gopkg.in/yaml.v3 v3.0.1 // indirect
- gotest.tools/v3 v3.5.2 // indirect
-)
diff --git a/config/go.sum b/config/go.sum
deleted file mode 100644
index c916d0807..000000000
--- a/config/go.sum
+++ /dev/null
@@ -1,35 +0,0 @@
-github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
-github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
-github.com/docker/docker v28.3.2+incompatible h1:wn66NJ6pWB1vBZIilP8G3qQPqHy5XymfYn5vsqeA5oA=
-github.com/docker/docker v28.3.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
-github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
-github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
-github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
-github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
-github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
-github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
-github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
-github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
-github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
-github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
-github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
-github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
-github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
-gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
-gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
-gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
diff --git a/config/load.go b/config/load.go
deleted file mode 100644
index 116155f11..000000000
--- a/config/load.go
+++ /dev/null
@@ -1,136 +0,0 @@
-package config
-
-import (
- "encoding/json"
- "errors"
- "fmt"
- "os"
- "os/user"
- "path/filepath"
- "runtime"
-)
-
-// getHomeDir returns the home directory of the current user with the help of
-// environment variables depending on the target operating system.
-// Returned path should be used with "path/filepath" to form new paths.
-//
-// On non-Windows platforms, it falls back to nss lookups, if the home
-// directory cannot be obtained from environment-variables.
-//
-// If linking statically with cgo enabled against glibc, ensure the
-// osusergo build tag is used.
-//
-// If needing to do nss lookups, do not disable cgo or set osusergo.
-//
-// getHomeDir is a copy of [pkg/homedir.Get] to prevent adding docker/docker
-// as dependency for consumers that only need to read the config-file.
-//
-// [pkg/homedir.Get]: https://pkg.go.dev/github.com/docker/docker@v26.1.4+incompatible/pkg/homedir#Get
-func getHomeDir() (string, error) {
- home, _ := os.UserHomeDir()
- if home == "" && runtime.GOOS != "windows" {
- if u, err := user.Current(); err == nil {
- return u.HomeDir, nil
- }
- }
-
- if home == "" {
- return "", errors.New("user home directory not determined")
- }
-
- return home, nil
-}
-
-// Dir returns the directory the configuration file is stored in,
-// checking if the directory exists.
-func Dir() (string, error) {
- dir := os.Getenv(EnvOverrideDir)
- if dir != "" {
- if !fileExists(dir) {
- return "", fmt.Errorf("file does not exist (%s)", dir)
- }
- return dir, nil
- }
-
- home, err := getHomeDir()
- if err != nil {
- return "", fmt.Errorf("user home dir: %w", err)
- }
-
- configDir := filepath.Join(home, configFileDir)
- if !fileExists(configDir) {
- return "", fmt.Errorf("file does not exist (%s)", configDir)
- }
-
- return configDir, nil
-}
-
-func fileExists(path string) bool {
- if _, err := os.Stat(path); os.IsNotExist(err) {
- return false
- }
-
- return true
-}
-
-// Filepath returns the path to the docker cli config file,
-// checking if the file exists.
-func Filepath() (string, error) {
- dir, err := Dir()
- if err != nil {
- return "", fmt.Errorf("config dir: %w", err)
- }
-
- configFilePath := filepath.Join(dir, FileName)
- if !fileExists(configFilePath) {
- return "", fmt.Errorf("config file does not exist (%s)", configFilePath)
- }
-
- return configFilePath, nil
-}
-
-// Load returns the docker config file. It will internally check, in this particular order:
-// 1. the DOCKER_AUTH_CONFIG environment variable, unmarshalling it into a Config
-// 2. the DOCKER_CONFIG environment variable, as the path to the config file
-// 3. else it will load the default config file, which is ~/.docker/config.json
-func Load() (Config, error) {
- if env := os.Getenv("DOCKER_AUTH_CONFIG"); env != "" {
- var cfg Config
- if err := json.Unmarshal([]byte(env), &cfg); err != nil {
- return Config{}, fmt.Errorf("unmarshal DOCKER_AUTH_CONFIG: %w", err)
- }
- return cfg, nil
- }
-
- var cfg Config
- p, err := Filepath()
- if err != nil {
- return cfg, fmt.Errorf("config path: %w", err)
- }
-
- cfg, err = loadFromFilepath(p)
- if err != nil {
- return cfg, fmt.Errorf("load config: %w", err)
- }
-
- // store the location of the config file into the config, for future use
- cfg.filepath = p
-
- return cfg, nil
-}
-
-// loadFromFilepath loads config from the specified path into cfg.
-func loadFromFilepath(configPath string) (Config, error) {
- var cfg Config
- f, err := os.Open(configPath)
- if err != nil {
- return cfg, fmt.Errorf("open config: %w", err)
- }
- defer f.Close()
-
- if err = json.NewDecoder(f).Decode(&cfg); err != nil {
- return cfg, fmt.Errorf("decode config: %w", err)
- }
-
- return cfg, nil
-}
diff --git a/config/load_benchmark_test.go b/config/load_benchmark_test.go
deleted file mode 100644
index 2114bdb69..000000000
--- a/config/load_benchmark_test.go
+++ /dev/null
@@ -1,123 +0,0 @@
-package config
-
-import (
- "os"
- "path/filepath"
- "testing"
-
- "github.com/stretchr/testify/require"
-)
-
-func BenchmarkLoadConfig(b *testing.B) {
- tmpDir := b.TempDir()
-
- configPath := filepath.Join(tmpDir, "config.json")
- err := os.WriteFile(configPath, []byte(`{
- "auths": {
- "https://index.docker.io/v1/": {
- "auth": "dGVzdHVzZXI6dGVzdHBhc3N3b3Jk"
- },
- "https://registry.example.com": {
- "auth": "YW5vdGhlcnVzZXI6YW5vdGhlcnBhc3N3b3Jk"
- }
- },
- "credHelpers": {
- "registry.example.com": "ecr-login"
- }
- }`), 0o644)
- require.NoError(b, err)
-
- b.Setenv("DOCKER_CONFIG", tmpDir)
-
- b.Run("load-default", func(b *testing.B) {
- b.ResetTimer()
- b.ReportAllocs()
- for range b.N {
- cfg, err := Load()
- require.NoError(b, err)
- require.NotNil(b, cfg)
- }
- })
-
- b.Run("load-with-auth-config", func(b *testing.B) {
- authConfig := `{
- "auths": {
- "https://index.docker.io/v1/": {
- "auth": "dGVzdHVzZXI6dGVzdHBhc3N3b3Jk"
- }
- }
- }`
- b.Setenv("DOCKER_AUTH_CONFIG", authConfig)
-
- b.ResetTimer()
- b.ReportAllocs()
- for range b.N {
- cfg, err := Load()
- require.NoError(b, err)
- require.NotNil(b, cfg)
- }
- })
-}
-
-func BenchmarkAuthConfigForHostname(b *testing.B) {
- tmpDir := b.TempDir()
-
- configPath := filepath.Join(tmpDir, "config.json")
- err := os.WriteFile(configPath, []byte(`{
- "auths": {
- "https://index.docker.io/v1/": {
- "auth": "dGVzdHVzZXI6dGVzdHBhc3N3b3Jk"
- },
- "https://registry.example.com": {
- "auth": "YW5vdGhlcnVzZXI6YW5vdGhlcnBhc3N3b3Jk"
- }
- },
- "credHelpers": {
- "registry.example.com": "ecr-login"
- }
- }`), 0o644)
- require.NoError(b, err)
-
- b.Setenv("DOCKER_CONFIG", tmpDir)
-
- // Load config once for reuse
- cfg, err := Load()
- require.NoError(b, err)
- require.NotNil(b, cfg)
-
- b.Run("docker-io", func(b *testing.B) {
- b.ResetTimer()
- b.ReportAllocs()
- for range b.N {
- _, err := AuthConfigForHostname("https://index.docker.io/v1/")
- require.NoError(b, err)
- }
- })
-
- b.Run("example-com", func(b *testing.B) {
- b.ResetTimer()
- b.ReportAllocs()
- for range b.N {
- _, err := AuthConfigForHostname("https://registry.example.com")
- require.NoError(b, err)
- }
- })
-
- b.Run("not-found", func(b *testing.B) {
- b.ResetTimer()
- b.ReportAllocs()
- for range b.N {
- _, err := AuthConfigForHostname("https://nonexistent.registry.com")
- require.NoError(b, err)
- }
- })
-
- b.Run("registry-credentials-for-image", func(b *testing.B) {
- b.ResetTimer()
- b.ReportAllocs()
- for range b.N {
- _, err := AuthConfigs("docker.io/library/nginx:latest")
- require.NoError(b, err)
- }
- })
-}
diff --git a/config/load_examples_test.go b/config/load_examples_test.go
deleted file mode 100644
index 65fef1dbf..000000000
--- a/config/load_examples_test.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package config_test
-
-import (
- "fmt"
- "log"
- "strings"
-
- "github.com/docker/go-sdk/config"
-)
-
-func ExampleDir() {
- dir, err := config.Dir()
- fmt.Println(err)
- fmt.Println(strings.HasSuffix(dir, ".docker"))
-
- // Output:
- //
- // true
-}
-
-func ExampleFilepath() {
- filepath, err := config.Filepath()
- if err != nil {
- log.Printf("error getting config filepath: %s", err)
- return
- }
-
- fmt.Println(strings.HasSuffix(filepath, "config.json"))
-
- // Output:
- // true
-}
-
-func ExampleLoad() {
- cfg, err := config.Load()
- fmt.Println(err)
- fmt.Println(len(cfg.AuthConfigs) > 0)
-
- // Output:
- //
- // true
-}
diff --git a/config/load_test.go b/config/load_test.go
deleted file mode 100644
index e38c3a6f2..000000000
--- a/config/load_test.go
+++ /dev/null
@@ -1,163 +0,0 @@
-package config
-
-import (
- _ "embed"
- "encoding/json"
- "os"
- "path/filepath"
- "testing"
-
- "github.com/stretchr/testify/require"
-)
-
-//go:embed testdata/.docker/config.json
-var dockerConfig string
-
-func TestLoad(t *testing.T) {
- t.Run("HOME", func(t *testing.T) {
- t.Run("valid", func(t *testing.T) {
- setupHome(t, "testdata")
-
- var expectedConfig Config
- err := json.Unmarshal([]byte(dockerConfig), &expectedConfig)
- require.NoError(t, err)
-
- expectedConfig.filepath = filepath.Join("testdata", ".docker", FileName)
-
- cfg, err := Load()
- require.NoError(t, err)
- require.Equal(t, expectedConfig, cfg)
- })
-
- t.Run("not-found", func(t *testing.T) {
- setupHome(t, "testdata", "not-found")
-
- cfg, err := Load()
- require.ErrorContains(t, err, "file does not exist")
- require.Empty(t, cfg)
- })
-
- t.Run("invalid-config", func(t *testing.T) {
- setupHome(t, "testdata", "invalid-config")
-
- cfg, err := Load()
- require.ErrorContains(t, err, "json: cannot unmarshal array")
- require.Empty(t, cfg)
- })
- })
-
- t.Run("DOCKER_AUTH_CONFIG", func(t *testing.T) {
- t.Run("valid", func(t *testing.T) {
- setupHome(t, "testdata", "not-found")
- t.Setenv("DOCKER_AUTH_CONFIG", dockerConfig)
-
- var expectedConfig Config
- err := json.Unmarshal([]byte(dockerConfig), &expectedConfig)
- require.NoError(t, err)
-
- cfg, err := Load()
- require.NoError(t, err)
- require.Equal(t, expectedConfig, cfg)
- })
-
- t.Run("invalid-config", func(t *testing.T) {
- setupHome(t, "testdata", "not-found")
- t.Setenv("DOCKER_AUTH_CONFIG", `{"auths": []}`)
-
- cfg, err := Load()
- require.ErrorContains(t, err, "json: cannot unmarshal array")
- require.Empty(t, cfg)
- })
- })
-
- t.Run(EnvOverrideDir, func(t *testing.T) {
- t.Run("valid", func(t *testing.T) {
- setupHome(t, "testdata", "not-found")
- t.Setenv(EnvOverrideDir, filepath.Join("testdata", ".docker"))
-
- var expectedConfig Config
- err := json.Unmarshal([]byte(dockerConfig), &expectedConfig)
- require.NoError(t, err)
-
- expectedConfig.filepath = filepath.Join("testdata", ".docker", FileName)
-
- cfg, err := Load()
- require.NoError(t, err)
- require.Equal(t, expectedConfig, cfg)
- })
-
- t.Run("invalid-config", func(t *testing.T) {
- setupHome(t, "testdata", "not-found")
- t.Setenv(EnvOverrideDir, filepath.Join("testdata", "invalid-config", ".docker"))
-
- cfg, err := Load()
- require.ErrorContains(t, err, "json: cannot unmarshal array")
- require.Empty(t, cfg)
- })
- })
-}
-
-func TestDir(t *testing.T) {
- t.Run("HOME", func(t *testing.T) {
- t.Run("valid", func(t *testing.T) {
- tmpDir := t.TempDir()
- setupHome(t, tmpDir)
-
- // create the Docker config directory
- cfgDir := filepath.Join(tmpDir, configFileDir)
- err := os.Mkdir(cfgDir, 0o755)
- require.NoError(t, err)
-
- dir, err := Dir()
- require.NoError(t, err)
- require.Equal(t, cfgDir, dir)
- })
-
- t.Run("not-found", func(t *testing.T) {
- setupHome(t, "testdata", "not-found")
-
- dir, err := Dir()
- require.ErrorContains(t, err, "file does not exist")
- require.Empty(t, dir)
- })
- })
-
- t.Run(EnvOverrideDir, func(t *testing.T) {
- t.Run("valid", func(t *testing.T) {
- tmpDir := t.TempDir()
- setupDockerConfigs(t, tmpDir)
-
- dir, err := Dir()
- require.NoError(t, err)
- require.Equal(t, tmpDir, dir)
- })
-
- t.Run("not-found", func(t *testing.T) {
- setupDockerConfigs(t, "testdata", "not-found")
-
- dir, err := Dir()
- require.ErrorContains(t, err, "file does not exist")
- require.Empty(t, dir)
- })
- })
-}
-
-// setupHome sets the user's home directory to the given path
-// It also creates the Docker config directory.
-func setupHome(t *testing.T, dirs ...string) {
- t.Helper()
-
- dir := filepath.Join(dirs...)
- t.Setenv("HOME", dir)
- t.Setenv("USERPROFILE", dir) // Windows
-}
-
-// setupDockerConfigs sets the DOCKER_CONFIG environment variable to the given path,
-// and the DOCKER_AUTH_CONFIG environment variable to the testdata/config/config.json file.
-func setupDockerConfigs(t *testing.T, dirs ...string) {
- t.Helper()
-
- dir := filepath.Join(dirs...)
- t.Setenv("DOCKER_AUTH_CONFIG", dockerConfig)
- t.Setenv(EnvOverrideDir, dir)
-}
diff --git a/config/testdata/.docker/config.json b/config/testdata/.docker/config.json
deleted file mode 100644
index 5ce110622..000000000
--- a/config/testdata/.docker/config.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "auths": {
- "https://index.docker.io/v1/": {},
- "https://example.com": {},
- "https://my.private.registry": {}
- },
- "credsStore": "desktop"
-}
diff --git a/config/testdata/credhelpers-config/config.json b/config/testdata/credhelpers-config/config.json
deleted file mode 100644
index 653a25319..000000000
--- a/config/testdata/credhelpers-config/config.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "auths": {
- "userpass.io": {
- "username": "user",
- "password": "pass"
- },
- "auth.io": {
- "auth": "YXV0aDphdXRoc2VjcmV0"
- }
- },
- "credHelpers": {
- "helper.io": "helper",
- "other.io": "other",
- "error.io": "error"
- },
- "credsStore": "desktop"
- }
diff --git a/config/testdata/invalid-config/.docker/config.json b/config/testdata/invalid-config/.docker/config.json
deleted file mode 100644
index f0f444f35..000000000
--- a/config/testdata/invalid-config/.docker/config.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "auths": []
-}
diff --git a/config/types.go b/config/types.go
deleted file mode 100644
index bf2e20356..000000000
--- a/config/types.go
+++ /dev/null
@@ -1,74 +0,0 @@
-package config
-
-import (
- "sync/atomic"
-
- "github.com/docker/docker/api/types/registry"
-)
-
-const (
- // EnvOverrideDir is the name of the environment variable that can be
- // used to override the location of the client configuration files (~/.docker).
- //
- // It takes priority over the default.
- EnvOverrideDir = "DOCKER_CONFIG"
-
- // configFileDir is the name of the directory containing the client configuration files
- configFileDir = ".docker"
-
- // configFileName is the name of the client configuration file inside the
- // config-directory.
- FileName = "config.json"
-)
-
-// Config represents the on disk format of the docker CLI's config file.
-type Config struct {
- filepath string `json:"-"`
- AuthConfigs map[string]registry.AuthConfig `json:"auths"`
- HTTPHeaders map[string]string `json:"HttpHeaders,omitempty"`
- PsFormat string `json:"psFormat,omitempty"`
- ImagesFormat string `json:"imagesFormat,omitempty"`
- NetworksFormat string `json:"networksFormat,omitempty"`
- PluginsFormat string `json:"pluginsFormat,omitempty"`
- VolumesFormat string `json:"volumesFormat,omitempty"`
- StatsFormat string `json:"statsFormat,omitempty"`
- DetachKeys string `json:"detachKeys,omitempty"`
- CredentialsStore string `json:"credsStore,omitempty"`
- CredentialHelpers map[string]string `json:"credHelpers,omitempty"`
- Filename string `json:"-"` // Note: for internal use only.
- ServiceInspectFormat string `json:"serviceInspectFormat,omitempty"`
- ServicesFormat string `json:"servicesFormat,omitempty"`
- TasksFormat string `json:"tasksFormat,omitempty"`
- SecretFormat string `json:"secretFormat,omitempty"`
- ConfigFormat string `json:"configFormat,omitempty"`
- NodesFormat string `json:"nodesFormat,omitempty"`
- PruneFilters []string `json:"pruneFilters,omitempty"`
- Proxies map[string]ProxyConfig `json:"proxies,omitempty"`
- Experimental string `json:"experimental,omitempty"`
- StackOrchestrator string `json:"stackOrchestrator,omitempty"`
- Kubernetes *KubernetesConfig `json:"kubernetes,omitempty"`
- CurrentContext string `json:"currentContext,omitempty"`
- CLIPluginsExtraDirs []string `json:"cliPluginsExtraDirs,omitempty"`
- Aliases map[string]string `json:"aliases,omitempty"`
-
- // Cache pointer (unexported, not included in JSON, safe to copy)
- cache atomic.Value // stores *authConfigCache
-}
-
-// ProxyConfig contains proxy configuration settings.
-type ProxyConfig struct {
- HTTPProxy string `json:"httpProxy,omitempty"`
- HTTPSProxy string `json:"httpsProxy,omitempty"`
- NoProxy string `json:"noProxy,omitempty"`
- FTPProxy string `json:"ftpProxy,omitempty"`
- AllProxy string `json:"allProxy,omitempty"`
-}
-
-// AuthConfig contains authorization information for connecting to a Registry.
-// Deprecated: prefer use of registry.AuthConfig
-type AuthConfig registry.AuthConfig
-
-// KubernetesConfig contains Kubernetes orchestrator settings.
-type KubernetesConfig struct {
- AllNamespaces string `json:"allNamespaces,omitempty"`
-}
diff --git a/config/version.go b/config/version.go
deleted file mode 100644
index 36fc85f1d..000000000
--- a/config/version.go
+++ /dev/null
@@ -1,10 +0,0 @@
-package config
-
-const (
- version = "0.1.0-alpha011"
-)
-
-// Version returns the version of the config package.
-func Version() string {
- return version
-}
diff --git a/container/go.mod b/container/go.mod
index 7a9a4bd8e..ca227e536 100644
--- a/container/go.mod
+++ b/container/go.mod
@@ -4,8 +4,6 @@ go 1.24
replace (
github.com/docker/go-sdk/client => ../client
- github.com/docker/go-sdk/config => ../config
- github.com/docker/go-sdk/context => ../context
github.com/docker/go-sdk/image => ../image
github.com/docker/go-sdk/network => ../network
)
@@ -17,33 +15,40 @@ require (
github.com/docker/docker v28.3.2+incompatible
github.com/docker/go-connections v0.5.0
github.com/docker/go-sdk/client v0.1.0-alpha011
- github.com/docker/go-sdk/config v0.1.0-alpha011
github.com/docker/go-sdk/image v0.1.0-alpha012
github.com/docker/go-sdk/network v0.1.0-alpha011
- github.com/stretchr/testify v1.10.0
- golang.org/x/sys v0.33.0
+ github.com/stretchr/testify v1.11.1
+ golang.org/x/sys v0.35.0
)
require (
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
- github.com/caarlos0/env/v11 v11.3.1 // indirect
+ github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
+ github.com/cenkalti/backoff/v5 v5.0.3 // indirect
+ github.com/clipperhouse/uax29/v2 v2.2.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/distribution/reference v0.6.0 // indirect
- github.com/docker/go-sdk/context v0.1.0-alpha011 // indirect
+ github.com/docker/cli v28.5.1+incompatible // indirect
+ github.com/docker/docker-credential-helpers v0.9.4 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
+ github.com/fvbommel/sortorder v1.1.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/uuid v1.6.0 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
+ github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/klauspost/compress v1.18.0 // indirect
+ github.com/mattn/go-runewidth v0.0.19 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/go-archive v0.1.0 // indirect
github.com/moby/patternmatcher v0.6.0 // indirect
+ github.com/moby/sys/atomicwriter v0.1.0 // indirect
github.com/moby/sys/sequential v0.6.0 // indirect
github.com/moby/sys/user v0.4.0 // indirect
github.com/moby/sys/userns v0.1.0 // indirect
@@ -53,12 +58,29 @@ require (
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
+ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 // indirect
+ github.com/prometheus/common v0.6.0 // indirect
+ github.com/prometheus/procfs v0.0.3 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
+ github.com/spf13/cobra v1.10.1 // indirect
+ github.com/spf13/pflag v1.0.10 // indirect
github.com/stretchr/objx v0.5.2 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
- go.opentelemetry.io/otel v1.37.0 // indirect
- go.opentelemetry.io/otel/metric v1.37.0 // indirect
- go.opentelemetry.io/otel/trace v1.37.0 // indirect
+ go.opentelemetry.io/otel v1.38.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect
+ go.opentelemetry.io/otel/metric v1.38.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.38.0 // indirect
+ go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect
+ go.opentelemetry.io/otel/trace v1.38.0 // indirect
+ go.opentelemetry.io/proto/otlp v1.7.1 // indirect
+ golang.org/x/net v0.43.0 // indirect
+ golang.org/x/text v0.28.0 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
+ google.golang.org/grpc v1.75.0 // indirect
+ google.golang.org/protobuf v1.36.8 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/container/go.sum b/container/go.sum
index 69a6485ae..02681b482 100644
--- a/container/go.sum
+++ b/container/go.sum
@@ -6,12 +6,18 @@ github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEK
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
-github.com/caarlos0/env/v11 v11.3.1 h1:cArPWC15hWmEt+gWk7YBi7lEXTXCvpaSdCiZE2X5mCA=
-github.com/caarlos0/env/v11 v11.3.1/go.mod h1:qupehSf/Y0TUTsxKywqRt/vJjN5nz6vauiYEUUr8P4U=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
-github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8=
-github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
+github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
+github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
+github.com/clipperhouse/uax29/v2 v2.2.0 h1:ChwIKnQN3kcZteTXMgb1wztSgaU+ZemkgWdohwgs8tY=
+github.com/clipperhouse/uax29/v2 v2.2.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
@@ -20,6 +26,7 @@ github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
+github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -27,35 +34,71 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
+github.com/docker/cli v28.5.1+incompatible h1:ESutzBALAD6qyCLqbQSEf1a/U8Ybms5agw59yGVc+yY=
+github.com/docker/cli v28.5.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
+github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v28.3.2+incompatible h1:wn66NJ6pWB1vBZIilP8G3qQPqHy5XymfYn5vsqeA5oA=
github.com/docker/docker v28.3.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker-credential-helpers v0.9.4 h1:76ItO69/AP/V4yT9V4uuuItG0B1N8hvt0T0c0NN/DzI=
+github.com/docker/docker-credential-helpers v0.9.4/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c=
+github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
+github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
+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.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
+github.com/fvbommel/sortorder v1.1.0 h1:fUmoe+HLsBTctBDoaBwpQo5N+nrCp8g/BjKb/6ZQmYw=
+github.com/fvbommel/sortorder v1.1.0/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90=
+github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
+github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs=
+github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
+github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw=
+github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
+github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU=
+github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ=
@@ -72,73 +115,120 @@ github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+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/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8=
+github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.6.0 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkpEo=
+github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.3 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURmKE=
+github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
+github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
+github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
+github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
-github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
+github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
+github.com/theupdateframework/notary v0.7.0 h1:QyagRZ7wlSpjT5N2qQAh/pN+DVqgekv4DzbAiAiEL3c=
+github.com/theupdateframework/notary v0.7.0/go.mod h1:c9DRxcmhHmVLDay4/2fUYdISnHqbFDGRSlXPO0AhYWw=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
-go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
-go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M=
+go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
+go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9obrcoWVKp/lwl8tRE33853I8Xru9HFbw/skNeLs8=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0/go.mod h1:GAXRxmLJcVM3u22IjTg74zWBrRCKq8BnOqUVLodpcpw=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0 h1:nRVXXvf78e00EwY6Wp0YII8ww2JVWshZ20HfTlE11AM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0/go.mod h1:r49hO7CgrxY9Voaj3Xe8pANWtr0Oq916d0XAmOoCZAQ=
-go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
-go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
-go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
-go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
-go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
-go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
-go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
-go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
-go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os=
-go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo=
+go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
+go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
+go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
+go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
+go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
+go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
+go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
+go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
+go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=
+go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=
+go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
+go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
+golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
-golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
+golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
+golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
-golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
+golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
+golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
-golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
+golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
+golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -149,17 +239,21 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY=
-google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
-google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
-google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
-google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
-google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
+gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
+gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
+google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY=
+google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc=
+google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4=
+google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
+google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
+google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/container/image_substitutors.go b/container/image_substitutors.go
index e5f4daaf7..da6678516 100644
--- a/container/image_substitutors.go
+++ b/container/image_substitutors.go
@@ -4,7 +4,7 @@ import (
"fmt"
"net/url"
- "github.com/docker/go-sdk/config/auth"
+ "github.com/docker/go-sdk/client/registry"
)
// ImageSubstitutor represents a way to substitute container image names
@@ -36,26 +36,26 @@ func (c CustomHubSubstitutor) Description() string {
// Substitute replaces the hub of the image with the provided one, with certain conditions:
// - if the hub is empty, the image is returned as is.
// - if the image already contains a registry, the image is returned as is.
-func (c CustomHubSubstitutor) Substitute(image string) (string, error) {
- ref, err := auth.ParseImageRef(image)
+func (c CustomHubSubstitutor) Substitute(img string) (string, error) {
+ ref, err := registry.ParseImageRef(img)
if err != nil {
return "", err
}
- registry := ref.Registry
+ domain := ref.Registry
exclusions := []func() bool{
func() bool { return c.hub == "" },
- func() bool { return registry != auth.DockerRegistry },
+ func() bool { return domain != registry.DockerRegistry },
}
for _, exclusion := range exclusions {
if exclusion() {
- return image, nil
+ return img, nil
}
}
- result, err := url.JoinPath(c.hub, image)
+ result, err := url.JoinPath(c.hub, img)
if err != nil {
return "", err
}
@@ -86,27 +86,27 @@ func (p prependHubRegistry) Description() string {
// - if the image is a non-hub image (e.g. where another registry is set), the image is returned as is.
// - if the image is a Docker Hub image where the hub registry is explicitly part of the name
// (i.e. anything with a registry.hub.docker.com host part), the image is returned as is.
-func (p prependHubRegistry) Substitute(image string) (string, error) {
- ref, err := auth.ParseImageRef(image)
+func (p prependHubRegistry) Substitute(img string) (string, error) {
+ ref, err := registry.ParseImageRef(img)
if err != nil {
return "", err
}
- registry := ref.Registry
+ domain := ref.Registry
// add the exclusions in the right order
exclusions := []func() bool{
- func() bool { return p.prefix == "" }, // no prefix set at the configuration level
- func() bool { return registry != auth.DockerRegistry }, // explicitly including Docker's URLs
+ func() bool { return p.prefix == "" }, // no prefix set at the configuration level
+ func() bool { return domain != registry.DockerRegistry }, // explicitly including Docker's URLs
}
for _, exclusion := range exclusions {
if exclusion() {
- return image, nil
+ return img, nil
}
}
- result, err := url.JoinPath(p.prefix, image)
+ result, err := url.JoinPath(p.prefix, img)
if err != nil {
return "", err
}
diff --git a/context/Makefile b/context/Makefile
deleted file mode 100644
index 748cb213e..000000000
--- a/context/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-include ../commons-test.mk
diff --git a/context/README.md b/context/README.md
deleted file mode 100644
index 848ea2a09..000000000
--- a/context/README.md
+++ /dev/null
@@ -1,123 +0,0 @@
-# Docker Contexts
-
-This package provides a simple API to interact with Docker contexts.
-
-## Installation
-
-```bash
-go get github.com/docker/go-sdk/context
-```
-
-## Usage
-
-### Current Context
-
-It returns the current Docker context name.
-
-```go
-current, err := context.Current()
-if err != nil {
- log.Fatalf("failed to get current docker context: %v", err)
-}
-
-fmt.Printf("current docker context: %s", current)
-```
-
-### Current Docker Host
-
-It returns the Docker host that the current context is configured to use.
-
-```go
-dockerHost, err := context.CurrentDockerHost()
-if err != nil {
- log.Fatalf("failed to get current docker host: %v", err)
-}
-fmt.Printf("current docker host: %s", dockerHost)
-```
-
-### Docker Host From Context
-
-It returns the Docker host that the given context is configured to use.
-
-```go
-dockerHost, err := context.DockerHostFromContext("desktop-linux")
-if err != nil {
- log.Printf("error getting docker host from context: %s", err)
- return
-}
-
-fmt.Printf("docker host from context: %s", dockerHost)
-```
-
-### Inspect Context
-
-It returns the description of the given context.
-
-```go
-description, err := context.Inspect("context1")
-if err != nil {
- log.Printf("failed to inspect context: %v", err)
- return
-}
-
-fmt.Printf("description: %s", description)
-```
-
-If the context is not found, it returns an `ErrDockerContextNotFound` error.
-
-### List Contexts
-
-It returns the list of contexts available in the Docker configuration.
-
-```go
-contexts, err := context.List()
-if err != nil {
- log.Printf("failed to list contexts: %v", err)
- return
-}
-
-fmt.Printf("contexts: %v", contexts)
-```
-
-### Add Context
-
-It adds a new context to the Docker configuration, identified by a name. It's possible to pass options to customize the context definition.
-
-```go
-ctx, err := context.New("my-context")
-if err != nil {
- log.Printf("failed to add context: %v", err)
- return
-}
-
-fmt.Printf("context added: %s", ctx.Name)
-```
-
-### Available Options
-
-The following options are available to customize the context definition:
-
-- `WithHost(host string) CreateContextOption` sets the host for the context.
-- `WithDescription(description string) CreateContextOption` sets the description for the context.
-- `WithAdditionalFields(fields map[string]any) CreateContextOption` sets the additional fields for the context.
-- `WithSkipTLSVerify() CreateContextOption` sets the skipTLSVerify flag to true.
-- `AsCurrent() CreateContextOption` sets the context as the current context, saving the current context to the Docker configuration.
-
-### Delete Context
-
-It deletes a context from the Docker configuration.
-
-```go
-ctx, err := context.New("my-context")
-if err != nil {
- log.Printf("error adding context: %s", err)
- return
-}
-
-if err := ctx.Delete(); err != nil {
- log.Printf("failed to delete context: %v", err)
- return
-}
-
-fmt.Printf("context deleted: %s", ctx.Name)
-```
\ No newline at end of file
diff --git a/context/context.add.go b/context/context.add.go
deleted file mode 100644
index ecdb232b6..000000000
--- a/context/context.add.go
+++ /dev/null
@@ -1,81 +0,0 @@
-package context
-
-import (
- "errors"
- "fmt"
-
- "github.com/opencontainers/go-digest"
-
- "github.com/docker/go-sdk/config"
-)
-
-// New creates a new context.
-//
-// If the context already exists, it returns an error.
-//
-// If the [AsCurrent] option is passed, it updates the Docker config
-// file, setting the current context to the new context.
-func New(name string, opts ...CreateContextOption) (*Context, error) {
- switch name {
- case "":
- return nil, errors.New("name is required")
- case "default":
- return nil, errors.New("name cannot be 'default'")
- }
-
- _, err := Inspect(name)
- if err == nil {
- return nil, fmt.Errorf("context %s already exists", name)
- }
-
- defaultOptions := &contextOptions{}
- for _, opt := range opts {
- if err := opt(defaultOptions); err != nil {
- return nil, fmt.Errorf("apply option: %w", err)
- }
- }
-
- ctx := &Context{
- Name: name,
- encodedName: digest.FromString(name).Encoded(),
- Metadata: &Metadata{
- Description: defaultOptions.description,
- additionalFields: defaultOptions.additionalFields,
- },
- Endpoints: map[string]*endpoint{
- "docker": {
- Host: defaultOptions.host,
- SkipTLSVerify: defaultOptions.skipTLSVerify,
- },
- },
- }
-
- metaRoot, err := metaRoot()
- if err != nil {
- return nil, fmt.Errorf("meta root: %w", err)
- }
-
- s := &store{root: metaRoot}
-
- if err := s.add(ctx); err != nil {
- return nil, fmt.Errorf("add context: %w", err)
- }
-
- // set the context as the current context if the option is set
- if defaultOptions.current {
- cfg, err := config.Load()
- if err != nil {
- return nil, fmt.Errorf("load config: %w", err)
- }
-
- cfg.CurrentContext = ctx.Name
-
- if err := cfg.Save(); err != nil {
- return nil, fmt.Errorf("save config: %w", err)
- }
-
- ctx.isCurrent = true
- }
-
- return ctx, nil
-}
diff --git a/context/context.add_test.go b/context/context.add_test.go
deleted file mode 100644
index 5126b70bf..000000000
--- a/context/context.add_test.go
+++ /dev/null
@@ -1,88 +0,0 @@
-package context_test
-
-import (
- "testing"
-
- "github.com/stretchr/testify/require"
-
- "github.com/docker/go-sdk/context"
-)
-
-func TestNew(t *testing.T) {
- t.Run("empty-name", func(tt *testing.T) {
- _, err := context.New("")
- require.Error(tt, err)
- })
-
- t.Run("default-name", func(tt *testing.T) {
- _, err := context.New("default")
- require.Error(tt, err)
- })
-
- t.Run("error/meta-root", func(tt *testing.T) {
- tt.Setenv("HOME", tt.TempDir())
- tt.Setenv("USERPROFILE", tt.TempDir()) // Windows support
-
- _, err := context.New("test")
- require.Error(tt, err)
- })
-
- t.Run("success", func(t *testing.T) {
- context.SetupTestDockerContexts(t, 1, 3)
-
- t.Run("no-current", func(tt *testing.T) {
- ctx, err := context.New(
- "test1234",
- context.WithHost("tcp://127.0.0.1:1234"),
- context.WithDescription("test description"),
- context.WithAdditionalFields(map[string]any{"testKey": "testValue"}),
- )
- require.NoError(tt, err)
- defer func() {
- require.NoError(tt, ctx.Delete())
- }()
-
- list, err := context.List()
- require.NoError(tt, err)
- require.Contains(tt, list, ctx.Name)
-
- require.Equal(tt, "test1234", ctx.Name)
- require.Equal(tt, "test description", ctx.Metadata.Description)
- require.Equal(tt, "tcp://127.0.0.1:1234", ctx.Endpoints["docker"].Host)
- require.False(tt, ctx.Endpoints["docker"].SkipTLSVerify)
-
- fields := ctx.Metadata.Fields()
- require.Equal(tt, map[string]any{"testKey": "testValue"}, fields)
-
- value, exists := fields["testKey"]
- require.True(tt, exists)
- require.Equal(tt, "testValue", value)
-
- // the current context is not the new one
- current, err := context.Current()
- require.NoError(tt, err)
- require.NotEqual(tt, "test1234", current)
- })
-
- t.Run("as-current", func(tt *testing.T) {
- ctx, err := context.New("test1234", context.WithHost("tcp://127.0.0.1:1234"), context.AsCurrent())
- require.NoError(tt, err)
- defer func() {
- require.NoError(tt, ctx.Delete())
- }()
-
- list, err := context.List()
- require.NoError(tt, err)
- require.Contains(tt, list, ctx.Name)
-
- require.Equal(tt, "test1234", ctx.Name)
- require.Equal(tt, "tcp://127.0.0.1:1234", ctx.Endpoints["docker"].Host)
- require.False(tt, ctx.Endpoints["docker"].SkipTLSVerify)
-
- // the current context is the new one
- current, err := context.Current()
- require.NoError(tt, err)
- require.Equal(tt, "test1234", current)
- })
- })
-}
diff --git a/context/context.delete.go b/context/context.delete.go
deleted file mode 100644
index 062e7c95a..000000000
--- a/context/context.delete.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package context
-
-import (
- "errors"
- "fmt"
-
- "github.com/docker/go-sdk/config"
-)
-
-// Delete deletes a context. The context must exist: it must have been created with [New]
-// or inspected with [Inspect].
-// If the context is the default context, the current context will be reset to the default context.
-func (ctx *Context) Delete() error {
- if ctx.encodedName == "" {
- return errors.New("context has no encoded name")
- }
-
- metaRoot, err := metaRoot()
- if err != nil {
- return fmt.Errorf("meta root: %w", err)
- }
-
- s := &store{root: metaRoot}
-
- err = s.delete(ctx.encodedName)
- if err != nil {
- return fmt.Errorf("delete: %w", err)
- }
-
- if ctx.isCurrent {
- // reset the current context to the default context
- cfg, err := config.Load()
- if err != nil {
- return fmt.Errorf("load config: %w", err)
- }
-
- cfg.CurrentContext = DefaultContextName
-
- if err := cfg.Save(); err != nil {
- return fmt.Errorf("save config: %w", err)
- }
- }
-
- return nil
-}
diff --git a/context/context.delete_test.go b/context/context.delete_test.go
deleted file mode 100644
index e703cc63a..000000000
--- a/context/context.delete_test.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package context_test
-
-import (
- "testing"
-
- "github.com/stretchr/testify/require"
-
- "github.com/docker/go-sdk/context"
-)
-
-func TestDelete(t *testing.T) {
- context.SetupTestDockerContexts(t, 1, 3)
-
- t.Run("success", func(tt *testing.T) {
- ctx, err := context.New("test", context.WithHost("tcp://127.0.0.1:1234"))
- require.NoError(tt, err)
- require.NoError(tt, ctx.Delete())
-
- list, err := context.List()
- require.NoError(tt, err)
- require.NotContains(tt, list, ctx.Name)
-
- got, err := context.Inspect(ctx.Name)
- require.ErrorIs(tt, err, context.ErrDockerContextNotFound)
- require.Empty(tt, got)
- })
-
- t.Run("error/encoded-name", func(tt *testing.T) {
- context.SetupTestDockerContexts(tt, 1, 3)
-
- ctx := context.Context{
- Name: "test",
- }
-
- err := ctx.Delete()
- require.ErrorContains(tt, err, "context has no encoded name")
- })
-}
diff --git a/context/context.go b/context/context.go
deleted file mode 100644
index 7820cf10b..000000000
--- a/context/context.go
+++ /dev/null
@@ -1,108 +0,0 @@
-package context
-
-// The code in this file has been extracted from https://github.com/docker/cli,
-// more especifically from https://github.com/docker/cli/blob/master/cli/context/store/metadatastore.go
-// with the goal of not consuming the CLI package and all its dependencies.
-
-import (
- "fmt"
- "path/filepath"
-
- "github.com/docker/go-sdk/config"
-)
-
-const (
- // DefaultContextName is the name reserved for the default context (config & env based)
- DefaultContextName = "default"
-
- // EnvOverrideContext is the name of the environment variable that can be
- // used to override the context to use. If set, it overrides the context
- // that's set in the CLI's configuration file, but takes no effect if the
- // "DOCKER_HOST" env-var is set (which takes precedence.
- EnvOverrideContext = "DOCKER_CONTEXT"
-
- // EnvOverrideHost is the name of the environment variable that can be used
- // to override the default host to connect to (DefaultDockerHost).
- //
- // This env-var is read by FromEnv and WithHostFromEnv and when set to a
- // non-empty value, takes precedence over the default host (which is platform
- // specific), or any host already set.
- EnvOverrideHost = "DOCKER_HOST"
-
- // contextsDir is the name of the directory containing the contexts
- contextsDir = "contexts"
-
- // metadataDir is the name of the directory containing the metadata
- metadataDir = "meta"
-
- // metaFile is the name of the file containing the context metadata
- metaFile = "meta.json"
-)
-
-var (
- // DefaultDockerHost is the default host to connect to the Docker socket.
- // The actual value is platform-specific and defined in host_unix.go and host_windows.go.
- DefaultDockerHost = ""
-
- // DefaultSchema is the default schema to use for the Docker host.
- // The actual value is platform-specific and defined in host_unix.go and host_windows.go.
- DefaultSchema = ""
-
- // TCPSchema is the schema to use for TCP connections.
- TCPSchema = "tcp://"
-)
-
-// DockerHostFromContext returns the Docker host from the given context.
-func DockerHostFromContext(ctxName string) (string, error) {
- ctx, err := Inspect(ctxName)
- if err != nil {
- return "", fmt.Errorf("inspect context: %w", err)
- }
-
- // Inspect already validates that the docker endpoint is set
- return ctx.Endpoints["docker"].Host, nil
-}
-
-// Inspect returns the given context.
-// It returns an error if the context is not found or if the docker endpoint is not set.
-func Inspect(ctxName string) (Context, error) {
- metaRoot, err := metaRoot()
- if err != nil {
- return Context{}, fmt.Errorf("meta root: %w", err)
- }
-
- s := &store{root: metaRoot}
-
- return s.inspect(ctxName)
-}
-
-// List returns the list of contexts available in the Docker configuration.
-func List() ([]string, error) {
- metaRoot, err := metaRoot()
- if err != nil {
- return nil, fmt.Errorf("meta root: %w", err)
- }
-
- s := &store{root: metaRoot}
-
- contexts, err := s.list()
- if err != nil {
- return nil, fmt.Errorf("list contexts: %w", err)
- }
-
- names := make([]string, len(contexts))
- for i, ctx := range contexts {
- names[i] = ctx.Name
- }
- return names, nil
-}
-
-// metaRoot returns the root directory of the Docker context metadata.
-func metaRoot() (string, error) {
- dir, err := config.Dir()
- if err != nil {
- return "", fmt.Errorf("docker config dir: %w", err)
- }
-
- return filepath.Join(dir, contextsDir, metadataDir), nil
-}
diff --git a/context/context_benchmark_test.go b/context/context_benchmark_test.go
deleted file mode 100644
index 11893244f..000000000
--- a/context/context_benchmark_test.go
+++ /dev/null
@@ -1,212 +0,0 @@
-package context
-
-import (
- "fmt"
- "testing"
-
- "github.com/stretchr/testify/require"
-)
-
-func BenchmarkCurrentContext(b *testing.B) {
- SetupTestDockerContexts(b, 1, 3) // current context is context1
-
- b.Run("current-context", func(b *testing.B) {
- b.ResetTimer()
- b.ReportAllocs()
- for range b.N {
- current, err := Current()
- require.NoError(b, err)
- require.Equal(b, "context1", current)
- }
- })
-
- b.Run("current-context/context-env-override", func(b *testing.B) {
- b.Setenv(EnvOverrideContext, "context2")
- b.ResetTimer()
- b.ReportAllocs()
- for range b.N {
- current, err := Current()
- require.NoError(b, err)
- require.Equal(b, "context2", current)
- }
- })
-
- b.Run("current-context/host-env-override", func(b *testing.B) {
- b.Setenv(EnvOverrideHost, "tcp://127.0.0.1:123")
- b.ResetTimer()
- b.ReportAllocs()
- for range b.N {
- current, err := Current()
- require.NoError(b, err)
- require.Equal(b, DefaultContextName, current)
- }
- })
-
- b.Run("current-docker-host", func(b *testing.B) {
- b.ResetTimer()
- b.ReportAllocs()
- for range b.N {
- host, err := CurrentDockerHost()
- require.NoError(b, err)
- require.Equal(b, "tcp://127.0.0.1:1", host)
- }
- })
-
- b.Run("current-docker-host/context-env-override", func(b *testing.B) {
- b.Setenv(EnvOverrideContext, "context2")
- b.ResetTimer()
- b.ReportAllocs()
- for range b.N {
- host, err := CurrentDockerHost()
- require.NoError(b, err)
- require.Equal(b, "tcp://127.0.0.1:2", host)
- }
- })
-
- b.Run("current-docker-host/host-env-override", func(b *testing.B) {
- b.Setenv(EnvOverrideHost, "tcp://127.0.0.1:123")
- b.ResetTimer()
- b.ReportAllocs()
- for range b.N {
- host, err := CurrentDockerHost()
- require.NoError(b, err)
- require.Equal(b, "tcp://127.0.0.1:123", host)
- }
- })
-
- b.Run("current-docker-host/default", func(b *testing.B) {
- b.Setenv(EnvOverrideContext, DefaultContextName)
- b.ResetTimer()
- b.ReportAllocs()
- for range b.N {
- host, err := CurrentDockerHost()
- require.NoError(b, err)
- require.Equal(b, DefaultDockerHost, host)
- }
- })
-
- b.Run("current-docker-host/not-found", func(b *testing.B) {
- b.Setenv(EnvOverrideContext, "non-existent")
- b.ResetTimer()
- b.ReportAllocs()
- for range b.N {
- host, err := CurrentDockerHost()
- require.Error(b, err)
- require.Empty(b, host)
- }
- })
-}
-
-func BenchmarkCurrentNestedContext(b *testing.B) {
- SetupTestDockerContexts(b, 1, 3) // Creates 3 contexts at root level
-
- metaDir, err := metaRoot()
- require.NoError(b, err)
-
- createDockerContext(b, metaDir, "nested/context", 1, "tcp://127.0.0.1:4")
- createDockerContext(b, metaDir, "nested/deep/context", 2, "tcp://127.0.0.1:5")
-
- b.Run("current-docker-host/nested", func(b *testing.B) {
- b.Setenv(EnvOverrideContext, "nested/context1")
- b.ResetTimer()
- b.ReportAllocs()
- for range b.N {
- host, err := CurrentDockerHost()
- require.NoError(b, err)
- require.Equal(b, "tcp://127.0.0.1:4", host)
- }
- })
-
- b.Run("current-docker-host/deep-nested", func(b *testing.B) {
- b.Setenv(EnvOverrideContext, "nested/deep/context2")
- b.ResetTimer()
- b.ReportAllocs()
- for range b.N {
- host, err := CurrentDockerHost()
- require.NoError(b, err)
- require.Equal(b, "tcp://127.0.0.1:5", host)
- }
- })
-}
-
-func BenchmarkContextAdd(b *testing.B) {
- SetupTestDockerContexts(b, 1, 3) // Creates 3 contexts at root level
-
- b.Run("success", func(b *testing.B) {
- b.ResetTimer()
- b.ReportAllocs()
- for i := range b.N {
- b.StartTimer()
- ctx, err := New(fmt.Sprintf("benchmark-%d", i))
- require.NoError(b, err)
- b.StopTimer()
-
- require.NoError(b, ctx.Delete())
- }
- })
-
- b.Run("as-current", func(b *testing.B) {
- b.ResetTimer()
- b.ReportAllocs()
- for i := range b.N {
- b.StartTimer()
- ctx, err := New(fmt.Sprintf("benchmark-current-%d", i), AsCurrent())
- require.NoError(b, err)
- b.StopTimer()
-
- require.NoError(b, ctx.Delete())
- }
- })
-}
-
-func BenchmarkContextDelete(b *testing.B) {
- SetupTestDockerContexts(b, 1, 3) // Creates 3 contexts at root level
-
- b.Run("success", func(b *testing.B) {
- b.ResetTimer()
- b.ReportAllocs()
- for i := range b.N {
- ctx, err := New(fmt.Sprintf("benchmark-delete-%d", i))
- require.NoError(b, err)
-
- b.StartTimer()
- require.NoError(b, ctx.Delete())
- b.StopTimer()
- }
- })
-}
-
-func BenchmarkContextList(b *testing.B) {
- SetupTestDockerContexts(b, 1, 3) // Creates 3 contexts at root level
-
- b.Run("context-list", func(b *testing.B) {
- b.ResetTimer()
- b.ReportAllocs()
- for range b.N {
- _, err := List()
- require.NoError(b, err)
- }
- })
-}
-
-func BenchmarkContextInspect(b *testing.B) {
- SetupTestDockerContexts(b, 1, 3) // Creates 3 contexts at root level
-
- b.Run("context-inspect", func(b *testing.B) {
- b.ResetTimer()
- b.ReportAllocs()
- for range b.N {
- _, err := Inspect("context1")
- require.NoError(b, err)
- }
- })
-
- b.Run("context-inspect/not-found", func(b *testing.B) {
- b.ResetTimer()
- b.ReportAllocs()
- for range b.N {
- _, err := Inspect("non-existent")
- require.ErrorIs(b, err, ErrDockerContextNotFound)
- }
- })
-}
diff --git a/context/context_examples_test.go b/context/context_examples_test.go
deleted file mode 100644
index 104744bbd..000000000
--- a/context/context_examples_test.go
+++ /dev/null
@@ -1,119 +0,0 @@
-package context_test
-
-import (
- "fmt"
- "log"
-
- "github.com/docker/go-sdk/context"
-)
-
-func ExampleCurrent() {
- ctx, err := context.Current()
- fmt.Println(err)
- fmt.Println(ctx != "")
-
- // Output:
- //
- // true
-}
-
-func ExampleCurrentDockerHost() {
- host, err := context.CurrentDockerHost()
- fmt.Println(err)
- fmt.Println(host != "")
-
- // Output:
- //
- // true
-}
-
-func ExampleDockerHostFromContext() {
- host, err := context.DockerHostFromContext("desktop-linux")
- if err != nil {
- log.Printf("error getting docker host from context: %s", err)
- return
- }
-
- fmt.Println(host)
-
- // Intentionally not printing the output, as the context could not exist in the CI environment
-}
-
-func ExampleNew() {
- ctx, err := context.New("my-context")
- if err != nil {
- log.Printf("error adding context: %s", err)
- return
- }
- defer func() {
- if err := ctx.Delete(); err != nil {
- log.Printf("error deleting context: %s", err)
- }
- }()
-
- fmt.Println(ctx.Name)
-
- // Output:
- // my-context
-}
-
-func ExampleNew_asCurrent() {
- ctx, err := context.New("my-context", context.AsCurrent(), context.WithHost("tcp://127.0.0.1:2375"))
- if err != nil {
- log.Printf("error adding context: %s", err)
- return
- }
- defer func() {
- if err := ctx.Delete(); err != nil {
- log.Printf("error deleting context: %s", err)
- }
- }()
-
- fmt.Println(ctx.Name)
-
- current, err := context.Current()
- if err != nil {
- log.Printf("error getting current context: %s", err)
- return
- }
- fmt.Println(current)
-
- host, err := context.CurrentDockerHost()
- if err != nil {
- log.Printf("error getting current docker host: %s", err)
- return
- }
-
- fmt.Println(host)
-
- // Output:
- // my-context
- // my-context
- // tcp://127.0.0.1:2375
-}
-
-func ExampleList() {
- contexts, err := context.List()
- if err != nil {
- log.Printf("error listing contexts: %s", err)
- return
- }
-
- fmt.Println(contexts)
-
- // Intentionally not printing the output, as the contexts could not exist in the CI environment
-}
-
-func ExampleInspect() {
- ctx, err := context.Inspect("docker-cloud")
- if err != nil {
- log.Printf("error inspecting context: %s", err)
- return
- }
-
- fmt.Println(ctx.Metadata.Description)
- fmt.Println(ctx.Metadata.Field("otel"))
- fmt.Println(ctx.Metadata.Fields())
-
- // Intentionally not printing the output, as the context could not exist in the CI environment
-}
diff --git a/context/context_test.go b/context/context_test.go
deleted file mode 100644
index b0c2f0f16..000000000
--- a/context/context_test.go
+++ /dev/null
@@ -1,210 +0,0 @@
-package context
-
-import (
- "os"
- "path/filepath"
- "testing"
-
- "github.com/stretchr/testify/require"
-)
-
-func TestCurrent(t *testing.T) {
- t.Run("current/1", func(tt *testing.T) {
- SetupTestDockerContexts(tt, 1, 3) // current context is context1
-
- current, err := Current()
- require.NoError(t, err)
- require.Equal(t, "context1", current)
- })
-
- t.Run("current/auth-error", func(tt *testing.T) {
- tt.Setenv("DOCKER_AUTH_CONFIG", "invalid-auth-config")
-
- current, err := Current()
- require.Error(t, err)
- require.Empty(t, current)
- })
-
- t.Run("current/override-host", func(tt *testing.T) {
- tt.Setenv(EnvOverrideHost, "tcp://127.0.0.1:2")
-
- current, err := Current()
- require.NoError(t, err)
- require.Equal(t, DefaultContextName, current)
- })
-
- t.Run("current/override-context", func(tt *testing.T) {
- SetupTestDockerContexts(tt, 1, 3) // current context is context1
- tt.Setenv(EnvOverrideContext, "context2") // override the current context
-
- current, err := Current()
- require.NoError(t, err)
- require.Equal(t, "context2", current)
- })
-
- t.Run("current/empty-context", func(tt *testing.T) {
- contextCount := 3
- SetupTestDockerContexts(tt, contextCount+1, contextCount) // current context is the empty one
-
- current, err := Current()
- require.NoError(t, err)
- require.Equal(t, DefaultContextName, current)
- })
-}
-
-func TestCurrentDockerHost(t *testing.T) {
- t.Run("override-host", func(tt *testing.T) {
- SetupTestDockerContexts(tt, 1, 3) // current context is context1
- tt.Setenv(EnvOverrideHost, "tcp://127.0.0.1:123")
-
- host, err := CurrentDockerHost()
- require.NoError(t, err)
- require.Equal(t, "tcp://127.0.0.1:123", host) // from context1
- })
-
- t.Run("default", func(tt *testing.T) {
- tt.Setenv(EnvOverrideContext, DefaultContextName)
-
- host, err := CurrentDockerHost()
- require.NoError(t, err)
- require.Equal(t, DefaultDockerHost, host)
- })
-
- t.Run("docker-context/1", func(tt *testing.T) {
- SetupTestDockerContexts(tt, 1, 3) // current context is context1
-
- host, err := CurrentDockerHost()
- require.NoError(t, err)
- require.Equal(t, "tcp://127.0.0.1:1", host) // from context1
- })
-
- t.Run("docker-context/2", func(tt *testing.T) {
- SetupTestDockerContexts(tt, 2, 3) // current context is context2
-
- host, err := CurrentDockerHost()
- require.NoError(t, err)
- require.Equal(t, "tcp://127.0.0.1:2", host) // from context2
- })
-
- t.Run("rootless", func(tt *testing.T) {
- tmpDir := tt.TempDir()
- t.Setenv("XDG_RUNTIME_DIR", tmpDir)
-
- err := os.WriteFile(filepath.Join(tmpDir, "docker.sock"), []byte("synthetic docker socket"), 0o755)
- require.NoError(tt, err)
-
- host, err := CurrentDockerHost()
- require.NoError(tt, err)
- require.Equal(tt, DefaultSchema+filepath.Join(tmpDir, "docker.sock"), host)
- })
-}
-
-func TestDockerHostFromContext(t *testing.T) {
- t.Run("docker-context/override-host", func(tt *testing.T) {
- SetupTestDockerContexts(tt, 1, 3) // current context is context1
- tt.Setenv(EnvOverrideHost, "tcp://127.0.0.1:123")
-
- host, err := DockerHostFromContext("context1")
- require.NoError(t, err)
- require.Equal(t, "tcp://127.0.0.1:1", host) // from context1
- })
-
- t.Run("docker-context/default", func(tt *testing.T) {
- SetupTestDockerContexts(tt, 1, 3) // current context is context1
- tt.Setenv(EnvOverrideContext, DefaultContextName)
-
- host, err := DockerHostFromContext("context1")
- require.NoError(t, err)
- require.Equal(t, "tcp://127.0.0.1:1", host)
- })
-
- t.Run("docker-context/1", func(tt *testing.T) {
- SetupTestDockerContexts(tt, 1, 3) // current context is context1
-
- host, err := DockerHostFromContext("context1")
- require.NoError(t, err)
- require.Equal(t, "tcp://127.0.0.1:1", host) // from context1
- })
-
- t.Run("docker-context/2", func(tt *testing.T) {
- SetupTestDockerContexts(tt, 2, 3) // current context is context2
-
- host, err := DockerHostFromContext("context2")
- require.NoError(t, err)
- require.Equal(t, "tcp://127.0.0.1:2", host) // from context2
- })
-
- t.Run("docker-context/4-no-host", func(tt *testing.T) {
- SetupTestDockerContexts(tt, 4, 3) // current context is context4
-
- host, err := DockerHostFromContext("context4")
- require.ErrorIs(t, err, ErrDockerHostNotSet)
- require.Empty(t, host)
- })
-
- t.Run("docker-context/not-found", func(tt *testing.T) {
- SetupTestDockerContexts(tt, 1, 1) // current context is context1
-
- host, err := DockerHostFromContext("context-not-found")
- require.Error(t, err)
- require.Empty(t, host)
- })
-
- t.Run("docker-context/5-no-host", func(tt *testing.T) {
- SetupTestDockerContexts(tt, 5, 3) // current context is context5
-
- host, err := DockerHostFromContext("context5")
- require.ErrorIs(t, err, ErrDockerHostNotSet)
- require.Empty(t, host)
- })
-}
-
-func TestInspect(t *testing.T) {
- SetupTestDockerContexts(t, 1, 3) // current context is context1
-
- t.Run("inspect/1", func(t *testing.T) {
- c, err := Inspect("context1")
- require.NoError(t, err)
- require.Equal(t, "Docker Go SDK 1", c.Metadata.Description)
- })
-
- t.Run("inspect/2", func(t *testing.T) {
- c, err := Inspect("context2")
- require.NoError(t, err)
- require.Equal(t, "Docker Go SDK 2", c.Metadata.Description)
- })
-
- t.Run("inspect/not-found", func(t *testing.T) {
- c, err := Inspect("context-not-found")
- require.ErrorIs(t, err, ErrDockerContextNotFound)
- require.Empty(t, c)
- })
-
- t.Run("inspect/5-no-docker-endpoint", func(t *testing.T) {
- c, err := Inspect("context5")
- require.ErrorIs(t, err, ErrDockerHostNotSet)
- require.Empty(t, c)
- })
-}
-
-func TestList(t *testing.T) {
- t.Run("list/1", func(t *testing.T) {
- SetupTestDockerContexts(t, 1, 3) // current context is context1
-
- contexts, err := List()
- require.NoError(t, err)
- require.Equal(t, []string{"context1", "context2", "context3", "context4", "context5"}, contexts)
- })
-
- t.Run("list/empty", func(t *testing.T) {
- tmpDir := t.TempDir()
- t.Setenv("HOME", tmpDir)
- t.Setenv("USERPROFILE", tmpDir) // Windows support
-
- tempMkdirAll(t, filepath.Join(tmpDir, ".docker"))
-
- contexts, err := List()
- require.ErrorIs(t, err, os.ErrNotExist)
- require.Empty(t, contexts)
- })
-}
diff --git a/context/current.go b/context/current.go
deleted file mode 100644
index 7e86deed9..000000000
--- a/context/current.go
+++ /dev/null
@@ -1,108 +0,0 @@
-package context
-
-import (
- "fmt"
- "net/url"
- "os"
-
- "github.com/docker/go-sdk/config"
-)
-
-// Current returns the current context name, based on
-// environment variables and the cli configuration file. It does not
-// validate if the given context exists or if it's valid.
-//
-// If the current context is not found, it returns the default context name.
-func Current() (string, error) {
- // Check env vars first (clearer precedence)
- if ctx := getContextFromEnv(); ctx != "" {
- return ctx, nil
- }
-
- // Then check config
- cfg, err := config.Load()
- if err != nil {
- if os.IsNotExist(err) {
- return DefaultContextName, nil
- }
- return "", fmt.Errorf("load docker config: %w", err)
- }
-
- if cfg.CurrentContext != "" {
- return cfg.CurrentContext, nil
- }
-
- return DefaultContextName, nil
-}
-
-// CurrentDockerHost returns the Docker host from the current Docker context.
-// For that, it traverses the directory structure of the Docker configuration directory,
-// looking for the current context and its Docker endpoint.
-//
-// If the Rootless Docker socket is found, using the XDG_RUNTIME_DIR environment variable,
-// it returns the path to the socket.
-//
-// If the current context is the default context, it returns the value of the
-// DOCKER_HOST environment variable.
-//
-// It validates that the Docker host is a valid URL and that the schema is
-// either unix, npipe (on Windows) or tcp.
-func CurrentDockerHost() (string, error) {
- rootlessSocketPath, err := rootlessSocketPathFromEnv()
- if err == nil {
- return parseURL(rootlessSocketPath)
- }
-
- current, err := Current()
- if err != nil {
- return "", fmt.Errorf("current context: %w", err)
- }
-
- if current == DefaultContextName {
- dockerHost := os.Getenv(EnvOverrideHost)
- if dockerHost != "" {
- return parseURL(dockerHost)
- }
-
- return parseURL(DefaultDockerHost)
- }
-
- ctx, err := Inspect(current)
- if err != nil {
- return "", fmt.Errorf("inspect context: %w", err)
- }
-
- // Inspect already validates that the docker endpoint is set
- return parseURL(ctx.Endpoints["docker"].Host)
-}
-
-// getContextFromEnv returns the context name from the environment variables.
-func getContextFromEnv() string {
- if os.Getenv(EnvOverrideHost) != "" {
- return DefaultContextName
- }
-
- if ctxName := os.Getenv(EnvOverrideContext); ctxName != "" {
- return ctxName
- }
-
- return ""
-}
-
-func parseURL(s string) (string, error) {
- hostURL, err := url.Parse(s)
- if err != nil {
- return "", err
- }
-
- switch hostURL.Scheme + "://" {
- case DefaultSchema:
- // return the original URL, as it is a valid socket URL
- return s, nil
- case TCPSchema:
- // return the original URL, as it is a valid TCP URL
- return s, nil
- default:
- return "", ErrInvalidSchema
- }
-}
diff --git a/context/current_test.go b/context/current_test.go
deleted file mode 100644
index 58357f860..000000000
--- a/context/current_test.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package context
-
-import (
- "testing"
-
- "github.com/stretchr/testify/require"
-)
-
-func TestParseURL(t *testing.T) {
- t.Run("success", func(t *testing.T) {
- path, err := parseURL(DefaultDockerHost)
- require.NoError(t, err)
- require.Equal(t, DefaultDockerHost, path)
- })
-
- t.Run("success/tcp", func(t *testing.T) {
- path, err := parseURL("tcp://localhost:2375")
- require.NoError(t, err)
- require.Equal(t, "tcp://localhost:2375", path)
- })
-
- t.Run("error/invalid-schema", func(t *testing.T) {
- _, err := parseURL("http://localhost:2375")
- require.Error(t, err)
- })
-
- t.Run("error/invalid-url", func(t *testing.T) {
- _, err := parseURL("~wrong~://**~invalid url~**")
- require.Error(t, err)
- })
-}
diff --git a/context/errors.go b/context/errors.go
deleted file mode 100644
index 1d10f0984..000000000
--- a/context/errors.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package context
-
-import "errors"
-
-var (
- // ErrDockerHostNotSet is returned when the Docker host is not set in the Docker context.
- ErrDockerHostNotSet = errors.New("docker host not set in Docker context")
-
- // ErrDockerContextNotFound is returned when the Docker context is not found.
- ErrDockerContextNotFound = errors.New("docker context not found")
-)
diff --git a/context/go.mod b/context/go.mod
deleted file mode 100644
index 142c6260c..000000000
--- a/context/go.mod
+++ /dev/null
@@ -1,21 +0,0 @@
-module github.com/docker/go-sdk/context
-
-go 1.24
-
-replace github.com/docker/go-sdk/config => ../config
-
-require (
- github.com/docker/go-sdk/config v0.1.0-alpha011
- github.com/opencontainers/go-digest v1.0.0
- github.com/stretchr/testify v1.10.0
-)
-
-require (
- github.com/davecgh/go-spew v1.1.1 // indirect
- github.com/distribution/reference v0.6.0 // indirect
- github.com/docker/docker v28.3.2+incompatible // indirect
- github.com/kr/text v0.2.0 // indirect
- github.com/opencontainers/image-spec v1.1.1 // indirect
- github.com/pmezard/go-difflib v1.0.0 // indirect
- gopkg.in/yaml.v3 v3.0.1 // indirect
-)
diff --git a/context/go.sum b/context/go.sum
deleted file mode 100644
index 15726ca6f..000000000
--- a/context/go.sum
+++ /dev/null
@@ -1,30 +0,0 @@
-github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
-github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
-github.com/docker/docker v28.3.2+incompatible h1:wn66NJ6pWB1vBZIilP8G3qQPqHy5XymfYn5vsqeA5oA=
-github.com/docker/docker v28.3.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
-github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
-github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
-github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
-github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
-github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
-github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
-github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
-github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
-github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
-github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
-github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
-gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
-gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
-gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
diff --git a/context/host_unix.go b/context/host_unix.go
deleted file mode 100644
index cdda194fc..000000000
--- a/context/host_unix.go
+++ /dev/null
@@ -1,12 +0,0 @@
-//go:build !windows
-// +build !windows
-
-package context
-
-func init() {
- // DefaultSchema is the default schema to use for the Docker host on Linux
- DefaultSchema = "unix://"
-
- // DefaultDockerHost is the default host to connect to the Docker socket on Linux
- DefaultDockerHost = DefaultSchema + "/var/run/docker.sock"
-}
diff --git a/context/host_windows.go b/context/host_windows.go
deleted file mode 100644
index 9e5318b48..000000000
--- a/context/host_windows.go
+++ /dev/null
@@ -1,12 +0,0 @@
-//go:build windows
-// +build windows
-
-package context
-
-func init() {
- // DefaultSchema is the default schema to use for the Docker host on Windows
- DefaultSchema = "npipe://"
-
- // DefaultDockerHost is the default host to connect to the Docker socket on Windows
- DefaultDockerHost = DefaultSchema + "//./pipe/docker_engine"
-}
diff --git a/context/options.go b/context/options.go
deleted file mode 100644
index 87424223c..000000000
--- a/context/options.go
+++ /dev/null
@@ -1,53 +0,0 @@
-package context
-
-// contextOptions is the options for creating a context.
-type contextOptions struct {
- host string
- description string
- additionalFields map[string]any
- skipTLSVerify bool
- current bool
-}
-
-// CreateContextOption is a function that can be used to create a context.
-type CreateContextOption func(*contextOptions) error
-
-// WithHost sets the host for the context.
-func WithHost(host string) CreateContextOption {
- return func(c *contextOptions) error {
- c.host = host
- return nil
- }
-}
-
-// WithDescription sets the description for the context.
-func WithDescription(description string) CreateContextOption {
- return func(c *contextOptions) error {
- c.description = description
- return nil
- }
-}
-
-// WithAdditionalFields sets the additional fields for the context.
-func WithAdditionalFields(fields map[string]any) CreateContextOption {
- return func(c *contextOptions) error {
- c.additionalFields = fields
- return nil
- }
-}
-
-// WithSkipTLSVerify sets the skipTLSVerify flag to true.
-func WithSkipTLSVerify() CreateContextOption {
- return func(c *contextOptions) error {
- c.skipTLSVerify = true
- return nil
- }
-}
-
-// AsCurrent sets the context as the current context.
-func AsCurrent() CreateContextOption {
- return func(c *contextOptions) error {
- c.current = true
- return nil
- }
-}
diff --git a/context/rootless.go b/context/rootless.go
deleted file mode 100644
index 01cc1381c..000000000
--- a/context/rootless.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package context
-
-import (
- "errors"
- "os"
- "path/filepath"
-)
-
-var (
- ErrRootlessDockerNotFoundXDGRuntimeDir = errors.New("docker.sock not found in $XDG_RUNTIME_DIR")
- ErrXDGRuntimeDirNotSet = errors.New("$XDG_RUNTIME_DIR is not set")
- ErrInvalidSchema = errors.New("URL schema is not " + DefaultSchema + " or tcp")
-)
-
-// rootlessSocketPathFromEnv returns the path to the rootless Docker socket from the XDG_RUNTIME_DIR environment variable.
-// It should include the Docker socket schema (unix://, npipe:// or tcp://) in the returned path.
-func rootlessSocketPathFromEnv() (string, error) {
- xdgRuntimeDir, exists := os.LookupEnv("XDG_RUNTIME_DIR")
- if exists && xdgRuntimeDir != "" {
- f := filepath.Join(xdgRuntimeDir, "docker.sock")
- if fileExists(f) {
- return DefaultSchema + f, nil
- }
-
- return "", ErrRootlessDockerNotFoundXDGRuntimeDir
- }
-
- return "", ErrXDGRuntimeDirNotSet
-}
-
-// fileExists checks if a file exists.
-func fileExists(path string) bool {
- if _, err := os.Stat(path); os.IsNotExist(err) {
- return false
- }
-
- return true
-}
diff --git a/context/rootless_test.go b/context/rootless_test.go
deleted file mode 100644
index 7a713924a..000000000
--- a/context/rootless_test.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package context
-
-import (
- "os"
- "path/filepath"
- "testing"
-
- "github.com/stretchr/testify/require"
-)
-
-func TestRootlessSocketPathFromEnv(t *testing.T) {
- t.Run("success", func(t *testing.T) {
- tmpDir := t.TempDir()
- t.Setenv("XDG_RUNTIME_DIR", tmpDir)
-
- err := os.WriteFile(filepath.Join(tmpDir, "docker.sock"), []byte("synthetic docker socket"), 0o755)
- require.NoError(t, err)
-
- path, err := rootlessSocketPathFromEnv()
- require.NoError(t, err)
- require.Equal(t, DefaultSchema+filepath.Join(tmpDir, "docker.sock"), path)
- })
-
- t.Run("env-var-not-set", func(t *testing.T) {
- t.Setenv("XDG_RUNTIME_DIR", "")
- path, err := rootlessSocketPathFromEnv()
- require.ErrorIs(t, err, ErrXDGRuntimeDirNotSet)
- require.Empty(t, path)
- })
-
- t.Run("docker-socket-not-found", func(t *testing.T) {
- tmpDir := t.TempDir()
- t.Setenv("XDG_RUNTIME_DIR", tmpDir)
-
- path, err := rootlessSocketPathFromEnv()
- require.ErrorIs(t, err, ErrRootlessDockerNotFoundXDGRuntimeDir)
- require.Empty(t, path)
- })
-}
diff --git a/context/store.go b/context/store.go
deleted file mode 100644
index 8acaf1e17..000000000
--- a/context/store.go
+++ /dev/null
@@ -1,249 +0,0 @@
-package context
-
-import (
- "encoding/json"
- "errors"
- "fmt"
- "maps"
- "os"
- "path/filepath"
-
- "github.com/opencontainers/go-digest"
-
- "github.com/docker/go-sdk/config"
-)
-
-// Context represents a Docker context
-type Context struct {
- // Name is the name of the context
- Name string `json:"Name,omitempty"`
-
- // encodedName is the digest of the context name
- encodedName string `json:"-"`
-
- // isCurrent is true if the context is the current context
- isCurrent bool `json:"-"`
-
- // Metadata is the metadata stored for a context
- Metadata *Metadata `json:"Metadata,omitempty"`
-
- // Endpoints is the list of endpoints for the context
- Endpoints map[string]*endpoint `json:"Endpoints,omitempty"`
-}
-
-// store manages Docker context metadata files
-type store struct {
- root string
-}
-
-// Metadata represents the metadata stored for a context
-type Metadata struct {
- // Description is the description of the context
- Description string `json:"Description,omitempty"`
-
- // additionalFields holds any additional fields that are not part of the standard metadata.
- // These are marshaled/unmarshaled at the same level as Description, not nested under a "Fields" key.
- additionalFields map[string]any
-}
-
-// MarshalJSON implements custom JSON marshaling for dockerContext
-func (dc *Metadata) MarshalJSON() ([]byte, error) {
- // Pre-allocate with capacity for additional fields + Description field
- result := make(map[string]any, len(dc.additionalFields)+1)
-
- // Add Description if not empty
- if dc.Description != "" {
- result["Description"] = dc.Description
- }
-
- // Add all additional fields at the same level
- for key, value := range dc.additionalFields {
- result[key] = value
- }
-
- return json.Marshal(result)
-}
-
-// UnmarshalJSON implements custom JSON unmarshaling for dockerContext
-func (dc *Metadata) UnmarshalJSON(data []byte) error {
- // First unmarshal into a generic map
- var raw map[string]any
- if err := json.Unmarshal(data, &raw); err != nil {
- return err
- }
-
- // Extract known fields
- if desc, ok := raw["Description"]; ok {
- if descStr, ok := desc.(string); ok {
- dc.Description = descStr
- }
- delete(raw, "Description")
- }
-
- // Store remaining fields as additional fields
- dc.additionalFields = raw
-
- return nil
-}
-
-// Field returns the value of an additional field
-func (dc *Metadata) Field(key string) (any, bool) {
- if dc.additionalFields == nil {
- return nil, false
- }
- value, exists := dc.additionalFields[key]
- return value, exists
-}
-
-// SetField sets the value of an additional field
-func (dc *Metadata) SetField(key string, value any) {
- if dc.additionalFields == nil {
- dc.additionalFields = make(map[string]any)
- }
- dc.additionalFields[key] = value
-}
-
-// Fields returns a copy of all additional fields
-func (dc *Metadata) Fields() map[string]any {
- if dc.additionalFields == nil {
- return make(map[string]any)
- }
- // Return a copy to prevent external modification
- result := make(map[string]any, len(dc.additionalFields))
-
- maps.Copy(result, dc.additionalFields)
-
- return result
-}
-
-// endpoint represents a Docker endpoint configuration
-type endpoint struct {
- // Host is the host of the endpoint
- Host string `json:",omitempty"`
-
- // SkipTLSVerify is the flag to skip TLS verification
- SkipTLSVerify bool
-}
-
-// inspect inspects a context by name
-func (s *store) inspect(ctxName string) (Context, error) {
- contexts, err := s.list()
- if err != nil {
- return Context{}, fmt.Errorf("list contexts: %w", err)
- }
-
- for _, ctx := range contexts {
- if ctx.Name == ctxName {
- ep, ok := ctx.Endpoints["docker"]
- if !ok || ep == nil || ep.Host == "" {
- return Context{}, ErrDockerHostNotSet
- }
-
- cfg, err := config.Load()
- if err != nil {
- return Context{}, fmt.Errorf("load config: %w", err)
- }
- ctx.isCurrent = cfg.CurrentContext == ctx.Name
-
- ctx.encodedName = digest.FromString(ctx.Name).Encoded()
-
- return *ctx, nil
- }
- }
-
- return Context{}, ErrDockerContextNotFound
-}
-
-// add adds a context to the store, creating the directory if it doesn't exist.
-func (s *store) add(ctx *Context) error {
- if ctx.encodedName == "" {
- // it's fine to calculate the encoded name here because the context is not yet added to the store
- ctx.encodedName = digest.FromString(ctx.Name).Encoded()
- }
-
- if fileExists(filepath.Join(s.root, ctx.encodedName)) {
- return fmt.Errorf("context already exists: %s", ctx.Name)
- }
-
- err := os.MkdirAll(filepath.Join(s.root, ctx.encodedName), 0o755)
- if err != nil {
- return fmt.Errorf("mkdir: %w", err)
- }
-
- data, err := json.Marshal(ctx)
- if err != nil {
- return fmt.Errorf("json marshal: %w", err)
- }
-
- if err := os.WriteFile(filepath.Join(s.root, ctx.encodedName, metaFile), data, 0o644); err != nil {
- return fmt.Errorf("write: %w", err)
- }
-
- return nil
-}
-
-// delete deletes a context from the store.
-// The encoded name is the digest of the context name.
-func (s *store) delete(encodedName string) error {
- return os.RemoveAll(filepath.Join(s.root, encodedName))
-}
-
-// list lists all contexts in the store
-func (s *store) list() ([]*Context, error) {
- dirs, err := s.findMetadataDirs(s.root)
- if err != nil {
- return nil, fmt.Errorf("find contexts: %w", err)
- }
-
- var contexts []*Context
- for _, dir := range dirs {
- ctx, err := s.load(dir)
- if err != nil {
- if errors.Is(err, os.ErrNotExist) {
- continue
- }
- return nil, fmt.Errorf("load context %s: %w", dir, err)
- }
- contexts = append(contexts, ctx)
- }
- return contexts, nil
-}
-
-// load loads a context from a directory
-func (s *store) load(dir string) (*Context, error) {
- data, err := os.ReadFile(filepath.Join(dir, metaFile))
- if err != nil {
- return nil, err
- }
-
- var meta Context
- if err := json.Unmarshal(data, &meta); err != nil {
- return nil, fmt.Errorf("parse metadata: %w", err)
- }
- return &meta, nil
-}
-
-// findMetadataDirs finds all metadata directories in the store,
-// checking for the presence of a meta.json file in each directory.
-func (s *store) findMetadataDirs(root string) ([]string, error) {
- var dirs []string
- err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
- if err != nil {
- return err
- }
- if info.IsDir() {
- if hasMetaFile(path) {
- dirs = append(dirs, path)
- return filepath.SkipDir // don't recurse into context dirs
- }
- }
- return nil
- })
- return dirs, err
-}
-
-// hasMetaFile checks if a directory contains a meta.json file
-func hasMetaFile(dir string) bool {
- info, err := os.Stat(filepath.Join(dir, metaFile))
- return err == nil && !info.IsDir()
-}
diff --git a/context/store_test.go b/context/store_test.go
deleted file mode 100644
index 01d4adc2f..000000000
--- a/context/store_test.go
+++ /dev/null
@@ -1,763 +0,0 @@
-package context
-
-import (
- "encoding/json"
- "os"
- "path/filepath"
- "runtime"
- "testing"
-
- "github.com/stretchr/testify/require"
-)
-
-func TestExtractDockerHost(t *testing.T) {
- t.Run("context-found-with-host", func(t *testing.T) {
- host := requireDockerHost(t, "test-context", Context{
- Name: "test-context",
- Endpoints: map[string]*endpoint{
- "docker": {Host: "tcp://1.2.3.4:2375"},
- },
- })
- require.Equal(t, "tcp://1.2.3.4:2375", host)
- })
-
- t.Run("context-found-without-host", func(t *testing.T) {
- requireDockerHostError(t, "test-context", Context{
- Name: "test-context",
- Endpoints: map[string]*endpoint{
- "docker": {},
- },
- }, ErrDockerHostNotSet)
- })
-
- t.Run("context-not-found", func(t *testing.T) {
- requireDockerHostError(t, "missing", Context{
- Name: "other-context",
- Endpoints: map[string]*endpoint{
- "docker": {Host: "tcp://1.2.3.4:2375"},
- },
- }, ErrDockerContextNotFound)
- })
-
- t.Run("nested-context-found", func(t *testing.T) {
- host := requireDockerHostInPath(t, "nested-context", "parent/nested-context", Context{
- Name: "nested-context",
- Endpoints: map[string]*endpoint{
- "docker": {Host: "tcp://1.2.3.4:2375"},
- },
- })
- require.Equal(t, "tcp://1.2.3.4:2375", host)
- })
-}
-
-func TestStore_add(t *testing.T) {
- t.Run("success", func(t *testing.T) {
- tmpDir := t.TempDir()
- s := &store{root: tmpDir}
-
- ctx := Context{
- Name: "test",
- Metadata: &Metadata{
- Description: "test context",
- additionalFields: map[string]any{
- "test": map[string]any{
- "nested": "nested",
- },
- },
- },
- Endpoints: map[string]*endpoint{
- "docker": {Host: "tcp://localhost:2375"},
- },
- }
-
- require.NoError(t, s.add(&ctx))
-
- got, err := s.load(filepath.Join(tmpDir, ctx.encodedName))
- require.NoError(t, err)
- require.Equal(t, ctx.Name, got.Name)
- require.Equal(t, ctx.Metadata.Description, got.Metadata.Description)
- require.Equal(t, ctx.Endpoints["docker"].Host, got.Endpoints["docker"].Host)
- require.Equal(t, ctx.Endpoints["docker"].SkipTLSVerify, got.Endpoints["docker"].SkipTLSVerify)
-
- // verify additional fields
- fields := got.Metadata.Fields()
- require.Equal(t, map[string]any{
- "test": map[string]any{
- "nested": "nested",
- },
- }, fields)
- })
-
- t.Run("error/mkdir", func(t *testing.T) {
- tmpDir := t.TempDir()
- s := &store{root: tmpDir}
-
- ctx := Context{
- Name: "test",
- }
-
- require.NoError(t, s.add(&ctx))
-
- // second add should fail because the context already exists
- require.Error(t, s.add(&ctx))
- })
-}
-
-func TestStore_Inspect(t *testing.T) {
- tmpDir := t.TempDir()
- setupTestContext(t, tmpDir, "test", Context{
- Name: "test",
- Metadata: &Metadata{
- Description: "test context",
- },
- Endpoints: map[string]*endpoint{
- "docker": {
- Host: "tcp://localhost:2375",
- },
- },
- })
-
- s := &store{root: tmpDir}
-
- t.Run("inspect/1", func(tt *testing.T) {
- ctx, err := s.inspect("test")
- require.NoError(tt, err)
- require.Equal(tt, "test", ctx.Name)
- require.Equal(tt, "test context", ctx.Metadata.Description)
- require.Equal(tt, "tcp://localhost:2375", ctx.Endpoints["docker"].Host)
- require.False(tt, ctx.Endpoints["docker"].SkipTLSVerify)
- })
-
- t.Run("inspect/not-found", func(tt *testing.T) {
- ctx, err := s.inspect("not-found")
- require.ErrorIs(tt, err, ErrDockerContextNotFound)
- require.Empty(tt, ctx)
- })
-
- t.Run("inspect/with-fields", func(tt *testing.T) {
- // Create a dockerContext and set additional fields using the new methods
- dockerCtx := &Metadata{
- Description: "ctx with fields",
- }
- dockerCtx.SetField("otel", map[string]any{
- "OTEL_EXPORTER_OTLP_ENDPOINT": "unix:///Users/mdelapenya/.docker/cloud/daemon.grpc.sock",
- "OTEL_EXPORTER_OTLP_PROTOCOL": "grpc",
- })
-
- setupTestContext(t, tmpDir, "fields", Context{
- Name: "ctx-with-fields",
- Metadata: dockerCtx,
- Endpoints: map[string]*endpoint{
- "docker": {
- Host: "tcp://localhost:2375",
- },
- },
- })
-
- ctx, err := s.inspect("ctx-with-fields")
- require.NoError(tt, err)
- require.Equal(tt, "ctx-with-fields", ctx.Name)
- require.Equal(tt, "ctx with fields", ctx.Metadata.Description)
- require.Equal(tt, "tcp://localhost:2375", ctx.Endpoints["docker"].Host)
- require.False(tt, ctx.Endpoints["docker"].SkipTLSVerify)
-
- // Verify additional fields are accessible
- otelValue, exists := ctx.Metadata.Field("otel")
- require.True(tt, exists)
- require.NotNil(tt, otelValue)
-
- // Verify the structure of the otel field
- otelMap, ok := otelValue.(map[string]any)
- require.True(tt, ok)
- require.Len(tt, otelMap, 2)
- require.Equal(tt, "unix:///Users/mdelapenya/.docker/cloud/daemon.grpc.sock", otelMap["OTEL_EXPORTER_OTLP_ENDPOINT"])
- require.Equal(tt, "grpc", otelMap["OTEL_EXPORTER_OTLP_PROTOCOL"])
- })
-}
-
-func TestStore_List(t *testing.T) {
- t.Run("list/1", func(tt *testing.T) {
- tmpDir := t.TempDir()
-
- // Create a dockerContext and set additional fields using the new methods
- dockerCtx := &Metadata{
- Description: "test context",
- }
- dockerCtx.SetField("test", true)
-
- want := Context{
- Name: "test",
- Metadata: dockerCtx,
- Endpoints: map[string]*endpoint{
- "docker": {
- Host: "tcp://localhost:2375",
- SkipTLSVerify: true,
- },
- },
- }
-
- setupTestContext(tt, tmpDir, "test", want)
-
- s := &store{root: tmpDir}
-
- got, err := s.list()
- require.NoError(tt, err)
- require.Len(tt, got, 1)
- require.Equal(tt, "test", got[0].Name)
- require.Equal(tt, "test context", got[0].Metadata.Description)
- require.Equal(tt, "tcp://localhost:2375", got[0].Endpoints["docker"].Host)
- require.True(tt, got[0].Endpoints["docker"].SkipTLSVerify)
-
- // Verify additional fields
- wantTestField, _ := want.Metadata.Field("test")
- gotTestField, exists := got[0].Metadata.Field("test")
- require.True(tt, exists)
- require.Equal(tt, wantTestField, gotTestField)
- })
-
- t.Run("list/empty", func(t *testing.T) {
- tmpDir := t.TempDir()
- t.Setenv("HOME", tmpDir)
- t.Setenv("USERPROFILE", tmpDir) // Windows support
-
- tempMkdirAll(t, filepath.Join(tmpDir, ".docker"))
-
- s := &store{root: tmpDir}
-
- contexts, err := s.list()
- require.NoError(t, err)
- require.Empty(t, contexts)
- })
-}
-
-func TestStore_load(t *testing.T) {
- t.Run("success", func(t *testing.T) {
- tmpDir := t.TempDir()
- s := &store{root: tmpDir}
-
- // Create a dockerContext and set additional fields using the new methods
- dockerCtx := &Metadata{
- Description: "test context",
- }
- dockerCtx.SetField("test", true)
-
- want := Context{
- Name: "test",
- Metadata: dockerCtx,
- Endpoints: map[string]*endpoint{
- "docker": {
- Host: "tcp://localhost:2375",
- SkipTLSVerify: true,
- },
- },
- }
-
- contextDir := filepath.Join(tmpDir, "test")
- setupTestContext(t, tmpDir, "test", want)
-
- got, err := s.load(contextDir)
- require.NoError(t, err)
- require.Equal(t, want.Name, got.Name)
- require.Equal(t, want.Metadata.Description, got.Metadata.Description)
-
- // Verify additional fields
- wantTestField, _ := want.Metadata.Field("test")
- gotTestField, exists := got.Metadata.Field("test")
- require.True(t, exists)
- require.Equal(t, wantTestField, gotTestField)
-
- require.Equal(t, want.Endpoints["docker"].Host, got.Endpoints["docker"].Host)
- require.Equal(t, want.Endpoints["docker"].SkipTLSVerify, got.Endpoints["docker"].SkipTLSVerify)
- })
-
- t.Run("directory-does-not-exist", func(t *testing.T) {
- tmpDir := t.TempDir()
- s := &store{root: tmpDir}
-
- nonExistentDir := filepath.Join(tmpDir, "does-not-exist")
- _, err := s.load(nonExistentDir)
- require.Error(t, err)
- require.True(t, os.IsNotExist(err))
- })
-
- t.Run("meta-json-does-not-exist", func(t *testing.T) {
- tmpDir := t.TempDir()
- s := &store{root: tmpDir}
-
- contextDir := filepath.Join(tmpDir, "empty")
- require.NoError(t, os.MkdirAll(contextDir, 0o755))
-
- _, err := s.load(contextDir)
- require.Error(t, err)
- require.True(t, os.IsNotExist(err))
- })
-
- t.Run("invalid-json", func(t *testing.T) {
- tmpDir := t.TempDir()
- s := &store{root: tmpDir}
-
- contextDir := filepath.Join(tmpDir, "invalid")
- require.NoError(t, os.MkdirAll(contextDir, 0o755))
- require.NoError(t, os.WriteFile(
- filepath.Join(contextDir, metaFile),
- []byte("invalid json"),
- 0o644,
- ))
-
- _, err := s.load(contextDir)
- require.Error(t, err)
- require.Contains(t, err.Error(), "parse metadata")
- })
-
- t.Run("permission-denied", func(t *testing.T) {
- if runtime.GOOS == "windows" {
- t.Skip("permission tests not supported on Windows")
- }
-
- if os.Getuid() == 0 {
- t.Skip("cannot test permission denied as root")
- }
-
- tmpDir := t.TempDir()
- s := &store{root: tmpDir}
-
- contextDir := filepath.Join(tmpDir, "no-access")
- require.NoError(t, os.MkdirAll(contextDir, 0o755))
-
- meta := Context{
- Name: "test",
- Endpoints: map[string]*endpoint{
- "docker": {Host: "tcp://localhost:2375"},
- },
- }
- setupTestContext(t, tmpDir, "no-access", meta)
-
- // Remove read permissions
- require.NoError(t, os.Chmod(filepath.Join(contextDir, metaFile), 0o000))
-
- _, err := s.load(contextDir)
- require.Error(t, err)
- require.Contains(t, err.Error(), "permission denied")
- })
-
- t.Run("windows-file-access-error", func(t *testing.T) {
- if runtime.GOOS != "windows" {
- t.Skip("Windows-specific test")
- }
-
- tmpDir := t.TempDir()
- s := &store{root: tmpDir}
-
- contextDir := filepath.Join(tmpDir, "locked")
- require.NoError(t, os.MkdirAll(contextDir, 0o755))
-
- // Create and lock the file
- f, err := os.Create(filepath.Join(contextDir, metaFile))
- require.NoError(t, err)
- require.NoError(t, f.Close())
-
- // Try to load while file is locked
- f2, err := os.OpenFile(filepath.Join(contextDir, metaFile), os.O_RDWR, 0o644)
- require.NoError(t, err)
- defer f2.Close()
-
- _, err = s.load(contextDir)
- require.Error(t, err)
- })
-
- t.Run("empty-but-valid-json", func(t *testing.T) {
- tmpDir := t.TempDir()
- s := &store{root: tmpDir}
-
- contextDir := filepath.Join(tmpDir, "empty")
- require.NoError(t, os.MkdirAll(contextDir, 0o755))
- require.NoError(t, os.WriteFile(
- filepath.Join(contextDir, metaFile),
- []byte("{}"),
- 0o644,
- ))
-
- got, err := s.load(contextDir)
- require.NoError(t, err)
- require.Empty(t, got.Name)
- require.Nil(t, got.Metadata)
- require.Empty(t, got.Endpoints)
- })
-
- t.Run("partial-metadata", func(t *testing.T) {
- tmpDir := t.TempDir()
- s := &store{root: tmpDir}
-
- contextDir := filepath.Join(tmpDir, "partial")
- require.NoError(t, os.MkdirAll(contextDir, 0o755))
-
- // Only name and docker endpoint, no context metadata
- meta := Context{
- Name: "test",
- Endpoints: map[string]*endpoint{
- "docker": {Host: "tcp://localhost:2375"},
- },
- }
- setupTestContext(t, tmpDir, "partial", meta)
-
- got, err := s.load(contextDir)
- require.NoError(t, err)
- require.Equal(t, "test", got.Name)
- require.Nil(t, got.Metadata)
- require.Equal(t, "tcp://localhost:2375", got.Endpoints["docker"].Host)
- })
-}
-
-func TestStore_list(t *testing.T) {
- t.Run("success", func(t *testing.T) {
- tmpDir := t.TempDir()
- s := &store{root: tmpDir}
-
- // Setup test contexts
- contexts := map[string]Context{
- "context1": {
- Name: "context1",
- Endpoints: map[string]*endpoint{
- "docker": {Host: "tcp://1.2.3.4:2375"},
- },
- },
- "nested/context2": {
- Name: "context2",
- Endpoints: map[string]*endpoint{
- "docker": {Host: "unix:///var/run/docker.sock"},
- },
- },
- }
-
- for path, meta := range contexts {
- setupTestContext(t, tmpDir, path, meta)
- }
-
- list, err := s.list()
- require.NoError(t, err)
- require.Len(t, list, 2)
- })
-
- t.Run("root-does-not-exist", func(t *testing.T) {
- tmpDir := t.TempDir()
- nonExistentDir := filepath.Join(tmpDir, "does-not-exist")
- s := &store{root: nonExistentDir}
-
- list, err := s.list()
- require.ErrorIs(t, err, os.ErrNotExist)
- require.Empty(t, list)
- })
-
- t.Run("corrupted-metadata-file", func(t *testing.T) {
- tmpDir := t.TempDir()
- s := &store{root: tmpDir}
-
- // Create a context directory with invalid JSON
- contextDir := filepath.Join(tmpDir, "invalid")
- require.NoError(t, os.MkdirAll(contextDir, 0o755))
- require.NoError(t, os.WriteFile(
- filepath.Join(contextDir, metaFile),
- []byte("invalid json"),
- 0o644,
- ))
-
- _, err := s.list()
- require.Error(t, err)
- require.Contains(t, err.Error(), "parse metadata")
- })
-
- t.Run("mixed-valid-and-invalid-contexts", func(t *testing.T) {
- tmpDir := t.TempDir()
- s := &store{root: tmpDir}
-
- // Setup one valid context
- validMeta := Context{
- Name: "valid",
- Endpoints: map[string]*endpoint{
- "docker": {Host: "tcp://1.2.3.4:2375"},
- },
- }
- setupTestContext(t, tmpDir, "valid", validMeta)
-
- // Setup an invalid context
- invalidDir := filepath.Join(tmpDir, "invalid")
- require.NoError(t, os.MkdirAll(invalidDir, 0o755))
- require.NoError(t, os.WriteFile(
- filepath.Join(invalidDir, metaFile),
- []byte("invalid json"),
- 0o644,
- ))
-
- _, err := s.list()
- require.Error(t, err)
- require.Contains(t, err.Error(), "parse metadata")
- })
-
- t.Run("permission-denied", func(t *testing.T) {
- if runtime.GOOS == "windows" {
- t.Skip("permission tests not supported on Windows")
- return
- }
-
- if os.Getuid() == 0 {
- t.Skip("cannot test permission denied as root")
- }
-
- tmpDir := t.TempDir()
- s := &store{root: tmpDir}
-
- // Create a context with no read permissions
- contextDir := filepath.Join(tmpDir, "no-access")
- require.NoError(t, os.MkdirAll(contextDir, 0o755))
-
- meta := Context{
- Name: "test",
- Endpoints: map[string]*endpoint{
- "docker": {Host: "tcp://1.2.3.4:2375"},
- },
- }
- setupTestContext(t, tmpDir, "no-access", meta)
-
- // Remove read permissions
- require.NoError(t, os.Chmod(filepath.Join(contextDir, metaFile), 0o000))
-
- list, err := s.list()
- require.Error(t, err)
- require.Contains(t, err.Error(), "permission denied")
- require.Empty(t, list)
- })
-
- t.Run("windows-file-access-error", func(t *testing.T) {
- if runtime.GOOS != "windows" {
- t.Skip("Windows-specific test")
- return
- }
-
- tmpDir := t.TempDir()
- s := &store{root: tmpDir}
-
- contextDir := filepath.Join(tmpDir, "locked")
- require.NoError(t, os.MkdirAll(contextDir, 0o755))
-
- // Create and lock the file
- f, err := os.Create(filepath.Join(contextDir, metaFile))
- require.NoError(t, err)
- require.NoError(t, f.Close())
-
- // Try to list while file is locked
- f2, err := os.OpenFile(filepath.Join(contextDir, metaFile), os.O_RDWR, 0o644)
- require.NoError(t, err)
- defer f2.Close()
-
- list, err := s.list()
- require.Error(t, err)
- require.Empty(t, list)
- })
-
- t.Run("empty-but-valid-context-file", func(t *testing.T) {
- tmpDir := t.TempDir()
- s := &store{root: tmpDir}
-
- // Create a context with empty but valid JSON
- contextDir := filepath.Join(tmpDir, "empty")
- require.NoError(t, os.MkdirAll(contextDir, 0o755))
- require.NoError(t, os.WriteFile(
- filepath.Join(contextDir, metaFile),
- []byte("{}"),
- 0o644,
- ))
-
- list, err := s.list()
- require.NoError(t, err)
- require.Len(t, list, 1)
- require.Empty(t, list[0].Name)
- require.Empty(t, list[0].Endpoints)
- })
-}
-
-func TestDockerContext_JSON_Marshaling(t *testing.T) {
- t.Run("marshal-with-additional-fields", func(t *testing.T) {
- // Create a dockerContext with additional fields
- dockerCtx := &Metadata{
- Description: "test context with fields",
- }
- dockerCtx.SetField("otel", map[string]any{
- "OTEL_EXPORTER_OTLP_ENDPOINT": "unix:///socket.sock",
- "OTEL_EXPORTER_OTLP_PROTOCOL": "grpc",
- })
- dockerCtx.SetField("cloud.docker.com", map[string]any{
- "accountName": "test-account",
- })
-
- // Marshal to JSON
- data, err := json.Marshal(dockerCtx)
- require.NoError(t, err)
-
- // Verify the JSON structure - additional fields should be at the same level as Description
- var result map[string]any
- err = json.Unmarshal(data, &result)
- require.NoError(t, err)
-
- // Description should be at the top level
- require.Equal(t, "test context with fields", result["Description"])
-
- // Additional fields should be at the same level, not nested under "Fields"
- require.Contains(t, result, "otel")
- require.Contains(t, result, "cloud.docker.com")
- require.NotContains(t, result, "Fields") // Should NOT have a Fields key
-
- // Verify otel structure
- otelValue, ok := result["otel"].(map[string]any)
- require.True(t, ok)
- require.Len(t, otelValue, 2)
- require.Equal(t, "unix:///socket.sock", otelValue["OTEL_EXPORTER_OTLP_ENDPOINT"])
- require.Equal(t, "grpc", otelValue["OTEL_EXPORTER_OTLP_PROTOCOL"])
-
- // Verify cloud.docker.com structure
- cloudValue, ok := result["cloud.docker.com"].(map[string]any)
- require.True(t, ok)
- require.Len(t, cloudValue, 1)
- require.Equal(t, "test-account", cloudValue["accountName"])
- })
-
- t.Run("unmarshal-with-additional-fields", func(t *testing.T) {
- // JSON data with additional fields at the same level as Description
- jsonData := `{
- "Description": "test context",
- "otel": {
- "OTEL_EXPORTER_OTLP_ENDPOINT": "unix:///socket.sock",
- "OTEL_EXPORTER_OTLP_PROTOCOL": "grpc"
- },
- "cloud.docker.com": {
- "accountName": "test-account"
- }
- }`
-
- var dockerCtx Metadata
- err := json.Unmarshal([]byte(jsonData), &dockerCtx)
- require.NoError(t, err)
-
- // Verify Description
- require.Equal(t, "test context", dockerCtx.Description)
-
- fields := dockerCtx.Fields()
- require.Len(t, fields, 2)
- require.Contains(t, fields, "otel")
- require.Contains(t, fields, "cloud.docker.com")
-
- // description is not a field, it's a top-level field
- description, exists := dockerCtx.Field("Description")
- require.False(t, exists)
- require.Empty(t, description)
-
- // Verify additional fields
- otelValue, exists := dockerCtx.Field("otel")
- require.True(t, exists)
- require.Len(t, otelValue, 2)
- otelMap, ok := otelValue.(map[string]any)
- require.True(t, ok)
- require.Equal(t, "unix:///socket.sock", otelMap["OTEL_EXPORTER_OTLP_ENDPOINT"])
- require.Equal(t, "grpc", otelMap["OTEL_EXPORTER_OTLP_PROTOCOL"])
-
- cloudValue, exists := dockerCtx.Field("cloud.docker.com")
- require.True(t, exists)
- require.Len(t, cloudValue, 1)
- cloudMap, ok := cloudValue.(map[string]any)
- require.True(t, ok)
- require.Equal(t, "test-account", cloudMap["accountName"])
- })
-
- t.Run("marshal-unmarshal-roundtrip", func(t *testing.T) {
- // Create original dockerContext
- original := &Metadata{
- Description: "roundtrip test",
- }
- original.SetField("custom", "value")
- original.SetField("complex", map[string]any{
- "nested": true,
- "count": 42,
- })
-
- // Marshal to JSON
- data, err := json.Marshal(original)
- require.NoError(t, err)
-
- // Unmarshal back
- var restored Metadata
- err = json.Unmarshal(data, &restored)
- require.NoError(t, err)
-
- // Verify everything matches
- require.Equal(t, original.Description, restored.Description)
-
- customValue, exists := restored.Field("custom")
- require.True(t, exists)
- require.Equal(t, "value", customValue)
-
- complexValue, exists := restored.Field("complex")
- require.True(t, exists)
- require.Len(t, complexValue, 2)
- complexMap, ok := complexValue.(map[string]any)
- require.True(t, ok)
- require.Equal(t, true, complexMap["nested"])
- require.Equal(t, float64(42), complexMap["count"]) // JSON numbers are float64
- })
-}
-
-// requireDockerHost creates a context and verifies host extraction succeeds
-func requireDockerHost(t *testing.T, contextName string, ctx Context) string {
- t.Helper()
- tmpDir := t.TempDir()
-
- setupTestContext(t, tmpDir, contextName, ctx)
-
- s := &store{root: tmpDir}
-
- ctx, err := s.inspect(contextName)
- require.NoError(t, err)
- return ctx.Endpoints["docker"].Host
-}
-
-// requireDockerHostInPath creates a context at a specific path and verifies host extraction
-func requireDockerHostInPath(t *testing.T, contextName, path string, ctx Context) string {
- t.Helper()
- tmpDir := t.TempDir()
-
- setupTestContext(t, tmpDir, path, ctx)
-
- s := &store{root: tmpDir}
-
- ctx, err := s.inspect(contextName)
- require.NoError(t, err)
- return ctx.Endpoints["docker"].Host
-}
-
-// requireDockerHostError creates a context and verifies expected error
-func requireDockerHostError(t *testing.T, contextName string, ctx Context, wantErr error) {
- t.Helper()
- tmpDir := t.TempDir()
-
- setupTestContext(t, tmpDir, contextName, ctx)
-
- s := &store{root: tmpDir}
-
- _, err := s.inspect(contextName)
- require.ErrorIs(t, err, wantErr)
-}
-
-// setupTestContext creates a test context file in the specified location
-func setupTestContext(tb testing.TB, root, relPath string, ctx Context) {
- tb.Helper()
-
- contextDir := filepath.Join(root, relPath)
- require.NoError(tb, os.MkdirAll(contextDir, 0o755))
-
- data, err := json.Marshal(ctx)
- require.NoError(tb, err)
-
- require.NoError(tb, os.WriteFile(
- filepath.Join(contextDir, metaFile),
- data,
- 0o644,
- ))
-}
diff --git a/context/testing.go b/context/testing.go
deleted file mode 100644
index 6ec9beac5..000000000
--- a/context/testing.go
+++ /dev/null
@@ -1,99 +0,0 @@
-package context
-
-import (
- "fmt"
- "os"
- "path/filepath"
- "testing"
-
- "github.com/stretchr/testify/require"
-
- "github.com/docker/go-sdk/config"
-)
-
-// SetupTestDockerContexts creates a temporary directory structure for testing the Docker context functions.
-// It creates the following structure, where $i is the index of the context, starting from 1:
-// - $HOME/.docker
-// - config.json
-// - contexts
-// - meta
-// - context$i
-// - meta.json
-//
-// The config.json file contains the current context, and the meta.json files contain the metadata for each context.
-// It generates the specified number of contexts, setting the current context to the one specified by currentContextIndex.
-// The docker host for each context is "tcp://127.0.0.1:$i".
-// Finally it always adds a context with an empty host, to validate the behavior when the host is not set,
-// and a context with a custom endpoint, to validate the behavior when the endpoint is not the default "docker".
-// This empty context can be used setting the currentContextIndex to a number greater than contextsCount.
-func SetupTestDockerContexts(tb testing.TB, currentContextIndex int, contextsCount int) {
- tb.Helper()
-
- tmpDir := tb.TempDir()
- tb.Setenv("HOME", tmpDir)
- tb.Setenv("USERPROFILE", tmpDir) // Windows support
-
- tempMkdirAll(tb, filepath.Join(tmpDir, ".docker"))
-
- configDir, err := config.Dir()
- require.NoError(tb, err)
-
- configJSON := filepath.Join(configDir, config.FileName)
-
- const baseContextName = "context"
-
- // default config.json with no current context
- configBytes := `{"currentContext": ""}`
-
- if currentContextIndex <= contextsCount {
- configBytes = fmt.Sprintf(`{
- "currentContext": "%s%d"
-}`, baseContextName, currentContextIndex)
- }
-
- err = os.WriteFile(configJSON, []byte(configBytes), 0o644)
- require.NoError(tb, err)
-
- metaDir, err := metaRoot()
- require.NoError(tb, err)
-
- tempMkdirAll(tb, metaDir)
-
- // first index is 1
- for i := 1; i <= contextsCount; i++ {
- createDockerContext(tb, metaDir, baseContextName, i, fmt.Sprintf("tcp://127.0.0.1:%d", i))
- }
-
- // add a context with no host
- createDockerContext(tb, metaDir, baseContextName, contextsCount+1, "")
-
- // add a context that does not have a docker endpoint
- createDockerContextWithCustomEndpoint(tb, metaDir, baseContextName, contextsCount+2, "foo", "")
-}
-
-// createDockerContext creates a Docker context with the specified name and host
-func createDockerContext(tb testing.TB, metaDir, baseContextName string, index int, host string) {
- tb.Helper()
-
- createDockerContextWithCustomEndpoint(tb, metaDir, baseContextName, index, "docker", host)
-}
-
-// createDockerContextWithoutDockerEndpoint creates a Docker context with the specified name and no docker endpoint
-func createDockerContextWithCustomEndpoint(tb testing.TB, metaDir, baseContextName string, index int, endpointName string, host string) {
- tb.Helper()
-
- contextDir := filepath.Join(metaDir, fmt.Sprintf("context%d", index))
- tempMkdirAll(tb, contextDir)
-
- context := fmt.Sprintf(`{"Name":"%s%d","Metadata":{"Description":"Docker Go SDK %d"},"Endpoints":{"%s":{"Host":"%s","SkipTLSVerify":false}}}`,
- baseContextName, index, index, endpointName, host)
- err := os.WriteFile(filepath.Join(contextDir, "meta.json"), []byte(context), 0o644)
- require.NoError(tb, err)
-}
-
-func tempMkdirAll(tb testing.TB, dir string) {
- tb.Helper()
-
- err := os.MkdirAll(dir, 0o755)
- require.NoError(tb, err)
-}
diff --git a/context/version.go b/context/version.go
deleted file mode 100644
index f8d5586f2..000000000
--- a/context/version.go
+++ /dev/null
@@ -1,10 +0,0 @@
-package context
-
-const (
- version = "0.1.0-alpha011"
-)
-
-// Version returns the version of the context package.
-func Version() string {
- return version
-}
diff --git a/go.work b/go.work
index deabaee5e..5cdfc4d73 100644
--- a/go.work
+++ b/go.work
@@ -2,11 +2,8 @@ go 1.24
use (
./client
- ./config
./container
- ./context
./image
- ./legacyadapters
./network
./volume
)
diff --git a/go.work.sum b/go.work.sum
index a266c1d19..56e43dc20 100644
--- a/go.work.sum
+++ b/go.work.sum
@@ -1,37 +1,80 @@
cel.dev/expr v0.20.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
cel.dev/expr v0.23.0 h1:wUb94w6OYQS4uXraxo9U+wUAs9jT47Xvl4iPgAwM2ss=
cel.dev/expr v0.23.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
+cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY=
+cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
+cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU=
+cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo=
+codeberg.org/go-fonts/liberation v0.5.0 h1:SsKoMO1v1OZmzkG2DY+7ZkCL9U+rrWI09niOLfQ5Bo0=
+codeberg.org/go-fonts/liberation v0.5.0/go.mod h1:zS/2e1354/mJ4pGzIIaEtm/59VFCFnYC7YV6YdGl5GU=
+codeberg.org/go-latex/latex v0.1.0 h1:hoGO86rIbWVyjtlDLzCqZPjNykpWQ9YuTZqAzPcfL3c=
+codeberg.org/go-latex/latex v0.1.0/go.mod h1:LA0q/AyWIYrqVd+A9Upkgsb+IqPcmSTKc9Dny04MHMw=
+codeberg.org/go-pdf/fpdf v0.10.0 h1:u+w669foDDx5Ds43mpiiayp40Ov6sZalgcPMDBcZRd4=
+codeberg.org/go-pdf/fpdf v0.10.0/go.mod h1:Y0DGRAdZ0OmnZPvjbMp/1bYxmIPxm0ws4tfoPOc4LjU=
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
+git.sr.ht/~sbinet/gg v0.6.0 h1:RIzgkizAk+9r7uPzf/VfbJHBMKUr0F5hRFxTUGMnt38=
+git.sr.ht/~sbinet/gg v0.6.0/go.mod h1:uucygbfC9wVPQIfrmwM2et0imr8L7KQWywX0xpFMm94=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1/go.mod h1:zGqV2R4Cr/k8Uye5w+dgQ06WJtEcbQG/8J7BB6hnCr4=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2/go.mod h1:SqINnQ9lVVdRlyC8cd1lCI0SdX4n2paeABd2K8ggfnE=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.26.0/go.mod h1:2bIszWvQRlJVmJLiuLhukLImRjKPcYdzzsx6darK02A=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 h1:ErKg/3iS1AKcTkf3yixlZ54f9U1rljCkQyEXWUnIUxc=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0/go.mod h1:yAZHSGnqScoU556rBOVkwLze6WP5N+U11RHuWaGVxwY=
+github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 h1:UQUsRi8WTzhZntp5313l+CHIAT95ojUI2lpP/ExlZa4=
+github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0/go.mod h1:Cz6ft6Dkn3Et6l2v2a9/RpN7epQ1GtDlO6lj8bEcOvw=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
+github.com/Shopify/logrus-bugsnag v0.0.0-20170309145241-6dbc35f2c30d h1:hi6J4K6DKrR4/ljxn6SF6nURyu785wKMuQcjt7H3VCQ=
+github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b h1:slYM766cy2nI3BwyRiyQj/Ud48djTMtMebDqepE95rw=
+github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=
github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
+github.com/bitly/go-hostpool v0.1.0 h1:XKmsF6k5el6xHG3WPJ8U0Ku/ye7njX7W81Ng7O2ioR0=
+github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y=
+github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
+github.com/bugsnag/bugsnag-go v1.0.5-0.20150529004307-13fd6b8acda0 h1:s7+5BfS4WFJoVF9pnB8kBk03S7pZXRdKamnV0FOl5Sc=
+github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ=
+github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o=
+github.com/campoy/embedmd v1.0.0 h1:V4kI2qTJJLf4J29RzI/MAt2c3Bl4dQSYPuflzwFH2hY=
+github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8=
github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004 h1:lkAMpLVBDaj17e85keuznYcH5rqI438v41pKcBl4ZxQ=
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f h1:C5bqEmzEPLsHm9Mv73lSE9e9bKV23aB1vxOsmZrkl3k=
github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
+github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls=
+github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
github.com/containerd/typeurl/v2 v2.2.0 h1:6NBDbQzr7I5LHgp34xAXYF5DOTQDn05X58lsPEmzLso=
github.com/containerd/typeurl/v2 v2.2.0/go.mod h1:8XOOxnyatxSWuG8OfsZXVnAF4iZfedjS/8UHSPJnX4g=
github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
+github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0=
github.com/danieljoos/wincred v1.2.2 h1:774zMFJrqaeYCK2W57BgAem/MLi6mtSE47MB6BOJ0i0=
github.com/danieljoos/wincred v1.2.2/go.mod h1:w7w4Utbrz8lqeMbDAK0lkNJUv5sAOkFi7nd/ogr0Uh8=
+github.com/danieljoos/wincred v1.2.3 h1:v7dZC2x32Ut3nEfRH+vhoZGvN72+dQ/snVXo/vMFLdQ=
+github.com/danieljoos/wincred v1.2.3/go.mod h1:6qqX0WNrS4RzPZ1tnroDzq9kY3fu1KwE7MRLQK4X0bs=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73 h1:OGNva6WhsKst5OZf7eZOklDztV3hwtTHovdrLHV+MsA=
+github.com/docker/docker v28.5.1+incompatible h1:Bm8DchhSD2J6PsFzxC35TZo4TLGR2PdW/E69rU45NhM=
+github.com/docker/docker v28.5.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-sdk/client v0.1.0-alpha001/go.mod h1:riIX1X9he2Oxx0Wra35V/3BOfoIZf/tMZ7B6Z7zQU48=
github.com/docker/go-sdk/config v0.1.0-alpha001/go.mod h1:eygQMlGzqLYetN/Qkc+lkHZJ9KJOMMCLy73OXn1rvzc=
github.com/docker/go-sdk/context v0.1.0-alpha001/go.mod h1:VY14aL5Z7Vk31IumcHtxGwam3+f6UrXlhP96w1ysEnk=
+github.com/docker/go-sdk/context v0.1.0-alpha010 h1:u+Ke5rS0vzQEGvjBezPCQUVwkmrHbHaz4UmvoEYyyhY=
+github.com/docker/go-sdk/context v0.1.0-alpha010/go.mod h1:Kp5bEhHA55J4wUBzVc33yhRaJGDx5x53xdc37UHa6+A=
github.com/docker/go-sdk/image v0.1.0-alpha001/go.mod h1:u2d+VLmIPRqj+B4JQSkYe965zSgYmRBDlNGecoN++zM=
github.com/docker/go-sdk/network v0.1.0-alpha001/go.mod h1:16/jt6p3N5DIJfAD3/rm8UETFI3tHpQMUWnMdkUP+ng=
+github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=
+github.com/dvsekhvalnov/jose2go v0.0.0-20170216131308-f21a8cedbbae h1:UTOyRlLeWJrZx+ynml6q6qzZ1uDkJe/0Z5CMZRbEIJg=
github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M=
github.com/envoyproxy/go-control-plane v0.13.4/go.mod h1:kDfuBlDVsSj2MjrLEtRWtHlsWIFcGyB2RMO44Dc5GZA=
github.com/envoyproxy/go-control-plane/envoy v1.32.4 h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A=
@@ -40,26 +83,60 @@ github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an
github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4=
github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8=
github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU=
+github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
+github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc=
github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE=
github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA=
+github.com/go-jose/go-jose/v4 v4.1.1 h1:JYhSgy4mXXzAdF3nUx3ygx347LRXJRrpgyU3adRmkAI=
+github.com/go-jose/go-jose/v4 v4.1.1/go.mod h1:BdsZGqgdO3b6tTc6LSE56wcDbMMLuPsw5d4ZD5f94kA=
+github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0=
+github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA=
+github.com/go-sql-driver/mysql v1.3.0 h1:pgwjLi/dvffoP9aabwkT3AKpXQM93QARkjFhDDqC1UE=
+github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
+github.com/goccmack/gocc v0.0.0-20230228185258-2292f9e40198 h1:FSii2UQeSLngl3jFoR4tUKZLprO7qUlh/TKKticc0BM=
+github.com/goccmack/gocc v0.0.0-20230228185258-2292f9e40198/go.mod h1:DTh/Y2+NbnOVVoypCCQrovMPDKUGp4yZpSbWg5D0XIM=
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
+github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
+github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
+github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/glog v1.2.4 h1:CNNw5U8lSiiBk7druxtSHHTsRWcxKoac6kZKm2peBBc=
github.com/golang/glog v1.2.4/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
+github.com/golang/glog v1.2.5 h1:DrW6hGnjIhtvhOIiAKT6Psh/Kd/ldepEa81DKeiRJ5I=
+github.com/golang/glog v1.2.5/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
-github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/google/certificate-transparency-go v1.0.10-0.20180222191210-5ab67e519c93 h1:jc2UWq7CbdszqeH6qu1ougXMIUBfSy8Pbh/anURYbGI=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
+github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
+github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
+github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI=
github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
+github.com/jinzhu/gorm v0.0.0-20170222002820-5409931a1bb8 h1:CZkYfurY6KGhVtlalI4QwQ6T0Cu6iuY3e0x5RLu96WE=
+github.com/jinzhu/inflection v0.0.0-20170102125226-1c35d901db3d h1:jRQLvyVGL+iVtDElaEIDdKwpPqUIZJfzkNLV34htpEc=
+github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E=
+github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
+github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8 h1:UUHMLvzt/31azWTN/ifGWef4WUqvXk0iRqdhdy/2uzI=
+github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g=
+github.com/keybase/dbus v0.0.0-20220506165403-5aa21ea2c23a h1:K0EAzgzEQHW4Y5lxrmvPMltmlRDzlhLfGmots9EHUTI=
+github.com/keybase/dbus v0.0.0-20220506165403-5aa21ea2c23a/go.mod h1:YPNKjjE7Ubp9dTbnWvsP3HT+hYnY6TfXzubYTBeUxc8=
github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU=
github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k=
github.com/kisielk/errcheck v1.5.0 h1:e8esj/e4R+SAOwFwN+n3zr0nYeCyeweozKfO23MvHzY=
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
+github.com/lib/pq v0.0.0-20150723085316-0dad96c0b94f h1:I1iYfgQavGa2tgdgKn+2Qg1yQhHEETvh/mNSxG3x5c0=
+github.com/lyft/protoc-gen-star/v2 v2.0.4-0.20230330145011-496ad1ac90a4 h1:sIXJOMrYnQZJu7OB7ANSF4MYri2fTEGIsRLz6LwI4xE=
github.com/lyft/protoc-gen-star/v2 v2.0.4-0.20230330145011-496ad1ac90a4/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk=
+github.com/magiconair/properties v1.5.3 h1:C8fxWnhYyME3n0klPOhVM7PtYUB3eV1W3DeFmN3j53Y=
+github.com/mattn/go-sqlite3 v1.6.0 h1:TDwTWbeII+88Qy55nWlof0DclgAtI4LqGujkYMzmQII=
+github.com/mitchellh/mapstructure v0.0.0-20150613213606-2caf8efc9366 h1:1ypTpKUfEOyX1YsJru6lLq7hrmK+QGECpJQ1PHUHuGo=
github.com/moby/sys/mount v0.3.4 h1:yn5jq4STPztkkzSKpZkLcmjue+bZJ0u2AuQY1iNI1Ww=
github.com/moby/sys/mount v0.3.4/go.mod h1:KcQJMbQdJHPlq5lcYT+/CjatWM4PuxKe+XLSVS4J6Os=
github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg=
@@ -69,27 +146,45 @@ github.com/moby/sys/reexec v0.1.0/go.mod h1:EqjBg8F3X7iZe5pU6nRZnYCMUTXoxsjiIfHu
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU=
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223 h1:F9x/1yl3T2AeKLr2AMdilSD8+f9bvMnNN8VS5iDtovc=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
+github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU=
+github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg=
+github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A=
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
+github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4=
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY=
+github.com/spf13/afero v1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY=
github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
+github.com/spf13/cast v0.0.0-20150508191742-4d07383ffe94 h1:JmfC365KywYwHB946TTiQWEb8kqPY+pybPLoGE9GgVk=
+github.com/spf13/jwalterweatherman v0.0.0-20141219030609-3d60171a6431 h1:XTHrT015sxHyJ5FnQ0AeemSspZWaDq7DoTRW0EVsDCE=
+github.com/spf13/viper v0.0.0-20150530192845-be5ff3e4840c h1:2EejZtjFjKJGk71ANb+wtFK5EjUzUkEM3R0xnp559xg=
github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE=
github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g=
github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM=
+github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM=
github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=
go.opentelemetry.io/contrib/detectors/gcp v1.34.0/go.mod h1:cV4BMFcscUR/ckqLkbfQmF0PRsq8w/lMGzdbCSveBHo=
go.opentelemetry.io/contrib/detectors/gcp v1.35.0 h1:bGvFt68+KTiAKFlacHW6AhA56GF2rS0bdD3aJYEnmzA=
go.opentelemetry.io/contrib/detectors/gcp v1.35.0/go.mod h1:qGWP8/+ILwMRIUf9uIVLloR1uo5ZYAslM4O6OqUi1DA=
+go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8FktLnIcy6jJNyOCQw=
+go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
@@ -101,23 +196,31 @@ go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
+go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
-go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
-go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
+go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
+go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
+golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
+golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ=
+golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
+golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
+golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
+golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
+golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M=
golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
@@ -132,11 +235,15 @@ golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
+golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
+golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0=
+golang.org/x/telemetry v0.0.0-20250710130107-8d8967aff50b h1:DU+gwOBXU+6bO0sEyO7o/NeMlxZxCZEvI7v+J4a1zRQ=
+golang.org/x/telemetry v0.0.0-20250710130107-8d8967aff50b/go.mod h1:4ZwOYna0/zsOKwuR5X/m0QFOJpSZvAxFfkQT+Erd9D4=
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
@@ -147,18 +254,36 @@ golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxb
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
+golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0=
+golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+gonum.org/v1/plot v0.15.2 h1:Tlfh/jBk2tqjLZ4/P8ZIwGrLEWQSPDLRm/SNWKNXiGI=
+gonum.org/v1/plot v0.15.2/go.mod h1:DX+x+DWso3LTha+AdkJEv5Txvi+Tql3KAGkehP0/Ubg=
google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a/go.mod h1:3kWAYMk1I75K4vykHtKt2ycnOgpA6974V7bREqbsenU=
google.golang.org/genproto/googleapis/api v0.0.0-20250324211829-b45e905df463/go.mod h1:U90ffi8eUL9MwPcrJylN5+Mk2v3vuPDptd5yyNUiRR8=
+google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:kXqgZtrWaf6qS3jZOCnCH7WYfrvFjkC51bM8fz3RsCA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo=
google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0=
google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
+google.golang.org/grpc/examples v0.0.0-20230224211313-3775f633ce20 h1:MLBCGN1O7GzIx+cBiwfYPwtmZ41U3Mn/cotLJciaArI=
google.golang.org/grpc/examples v0.0.0-20230224211313-3775f633ce20/go.mod h1:Nr5H8+MlGWr5+xX/STzdoEqJrO+YteqFbMyCsrb6mH0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
+gopkg.in/airbrake/gobrake.v2 v2.0.9 h1:7z2uVWwn7oVeeugY1DtlPAy5H+KYgB1KeKTnqjNatLo=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
+gopkg.in/cenkalti/backoff.v2 v2.2.1 h1:eJ9UAg01/HIHG987TwxvnzK2MgxXq97YY6rYDpY9aII=
+gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
+gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 h1:OAj3g0cR6Dx/R07QgQe8wkA9RNjB2u4i700xBkIT4e0=
+gopkg.in/rethinkdb/rethinkdb-go.v6 v6.2.1 h1:d4KQkxAaAiRY2h5Zqis161Pv91A37uZyJOx73duwUwM=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
+rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4=
+rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
diff --git a/image/go.mod b/image/go.mod
index da2849afb..56cfcb23d 100644
--- a/image/go.mod
+++ b/image/go.mod
@@ -2,43 +2,46 @@ module github.com/docker/go-sdk/image
go 1.24
-replace (
- github.com/docker/go-sdk/client => ../client
- github.com/docker/go-sdk/config => ../config
- github.com/docker/go-sdk/context => ../context
-)
+replace github.com/docker/go-sdk/client => ../client
require (
github.com/cenkalti/backoff/v4 v4.2.1
github.com/containerd/errdefs v1.0.0
github.com/docker/docker v28.3.2+incompatible
github.com/docker/go-sdk/client v0.1.0-alpha011
- github.com/docker/go-sdk/config v0.1.0-alpha011
github.com/moby/go-archive v0.1.0
github.com/moby/patternmatcher v0.6.0
github.com/moby/term v0.5.2
github.com/opencontainers/image-spec v1.1.1
- github.com/stretchr/testify v1.10.0
+ github.com/stretchr/testify v1.11.1
)
require (
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
- github.com/caarlos0/env/v11 v11.3.1 // indirect
- github.com/cenkalti/backoff/v5 v5.0.2 // indirect
+ github.com/cenkalti/backoff/v5 v5.0.3 // indirect
+ github.com/clipperhouse/uax29/v2 v2.2.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/distribution/reference v0.6.0 // indirect
+ github.com/docker/cli v28.5.1+incompatible // indirect
+ github.com/docker/docker-credential-helpers v0.9.4 // indirect
+ github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
github.com/docker/go-connections v0.5.0 // indirect
- github.com/docker/go-sdk/context v0.1.0-alpha011 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
+ github.com/fvbommel/sortorder v1.1.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
+ github.com/google/uuid v1.6.0 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
+ github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/klauspost/compress v1.18.0 // indirect
+ github.com/mattn/go-runewidth v0.0.19 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
+ github.com/moby/sys/atomicwriter v0.1.0 // indirect
github.com/moby/sys/sequential v0.6.0 // indirect
github.com/moby/sys/user v0.4.0 // indirect
github.com/moby/sys/userns v0.1.0 // indirect
@@ -46,17 +49,27 @@ require (
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
+ github.com/prometheus/client_golang v1.1.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
+ github.com/spf13/cobra v1.10.1 // indirect
+ github.com/spf13/pflag v1.0.10 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
- go.opentelemetry.io/otel v1.37.0 // indirect
- go.opentelemetry.io/otel/metric v1.37.0 // indirect
- go.opentelemetry.io/otel/trace v1.37.0 // indirect
- golang.org/x/net v0.40.0 // indirect
- golang.org/x/sys v0.33.0 // indirect
- golang.org/x/text v0.26.0 // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
- google.golang.org/protobuf v1.36.6 // indirect
+ go.opentelemetry.io/otel v1.38.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect
+ go.opentelemetry.io/otel/metric v1.38.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.38.0 // indirect
+ go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect
+ go.opentelemetry.io/otel/trace v1.38.0 // indirect
+ go.opentelemetry.io/proto/otlp v1.7.1 // indirect
+ golang.org/x/net v0.43.0 // indirect
+ golang.org/x/sys v0.35.0 // indirect
+ golang.org/x/text v0.28.0 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
+ google.golang.org/grpc v1.75.0 // indirect
+ google.golang.org/protobuf v1.36.8 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/image/go.sum b/image/go.sum
index 2059f8dad..0b7b95e41 100644
--- a/image/go.sum
+++ b/image/go.sum
@@ -4,18 +4,25 @@ github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEK
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
-github.com/caarlos0/env/v11 v11.3.1 h1:cArPWC15hWmEt+gWk7YBi7lEXTXCvpaSdCiZE2X5mCA=
-github.com/caarlos0/env/v11 v11.3.1/go.mod h1:qupehSf/Y0TUTsxKywqRt/vJjN5nz6vauiYEUUr8P4U=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
-github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8=
-github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
+github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
+github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
+github.com/clipperhouse/uax29/v2 v2.2.0 h1:ChwIKnQN3kcZteTXMgb1wztSgaU+ZemkgWdohwgs8tY=
+github.com/clipperhouse/uax29/v2 v2.2.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
+github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -23,35 +30,74 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
+github.com/docker/cli v28.5.1+incompatible h1:ESutzBALAD6qyCLqbQSEf1a/U8Ybms5agw59yGVc+yY=
+github.com/docker/cli v28.5.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
+github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v28.3.2+incompatible h1:wn66NJ6pWB1vBZIilP8G3qQPqHy5XymfYn5vsqeA5oA=
github.com/docker/docker v28.3.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker-credential-helpers v0.9.4 h1:76ItO69/AP/V4yT9V4uuuItG0B1N8hvt0T0c0NN/DzI=
+github.com/docker/docker-credential-helpers v0.9.4/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c=
+github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
+github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
+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.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
+github.com/fvbommel/sortorder v1.1.0 h1:fUmoe+HLsBTctBDoaBwpQo5N+nrCp8g/BjKb/6ZQmYw=
+github.com/fvbommel/sortorder v1.1.0/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90=
+github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
+github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs=
+github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
+github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw=
+github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
+github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU=
+github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ=
@@ -68,71 +114,121 @@ github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+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/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8=
+github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.6.0 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkpEo=
+github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.3 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURmKE=
+github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
+github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
+github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
+github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
-github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
+github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
+github.com/theupdateframework/notary v0.7.0 h1:QyagRZ7wlSpjT5N2qQAh/pN+DVqgekv4DzbAiAiEL3c=
+github.com/theupdateframework/notary v0.7.0/go.mod h1:c9DRxcmhHmVLDay4/2fUYdISnHqbFDGRSlXPO0AhYWw=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
-go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
-go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M=
+go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
+go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9obrcoWVKp/lwl8tRE33853I8Xru9HFbw/skNeLs8=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0/go.mod h1:GAXRxmLJcVM3u22IjTg74zWBrRCKq8BnOqUVLodpcpw=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0 h1:nRVXXvf78e00EwY6Wp0YII8ww2JVWshZ20HfTlE11AM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0/go.mod h1:r49hO7CgrxY9Voaj3Xe8pANWtr0Oq916d0XAmOoCZAQ=
-go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
-go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
-go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
-go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
-go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
-go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
-go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
-go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
-go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os=
-go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo=
+go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
+go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
+go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
+go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
+go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
+go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
+go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
+go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
+go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=
+go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=
+go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
+go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
+golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
-golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
+golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
+golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
-golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
+golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
+golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
-golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
+golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
+golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -143,17 +239,21 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY=
-google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
-google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
-google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
-google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
-google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
+gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
+gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
+google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY=
+google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc=
+google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4=
+google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
+google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
+google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/image/options.go b/image/options.go
index f5e4b971a..11e477b7c 100644
--- a/image/options.go
+++ b/image/options.go
@@ -2,7 +2,6 @@ package image
import (
"errors"
- "fmt"
"io"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
@@ -10,7 +9,6 @@ import (
"github.com/docker/docker/api/types/build"
"github.com/docker/docker/api/types/image"
"github.com/docker/go-sdk/client"
- "github.com/docker/go-sdk/config"
)
// BuildOption is a function that configures the build options.
@@ -59,20 +57,12 @@ func WithCredentialsFn(credentialsFn func(string) (string, string, error)) PullO
// WithCredentialsFromConfig configures pull to retrieve credentials from the CLI config
func WithCredentialsFromConfig(opts *pullOptions) error {
opts.credentialsFn = func(imageName string) (string, string, error) {
- authConfigs, err := config.AuthConfigs(imageName)
+ _, authConfig, err := opts.client.AuthConfigForImage(imageName)
if err != nil {
return "", "", err
}
- // there must be only one auth config for the image
- if len(authConfigs) > 1 {
- return "", "", fmt.Errorf("multiple auth configs found for image %s, expected only one", imageName)
- }
-
- for _, ac := range authConfigs {
- return ac.Username, ac.Password, nil
- }
- return "", "", nil
+ return authConfig.Username, authConfig.Password, nil
}
return nil
}
diff --git a/legacyadapters/Makefile b/legacyadapters/Makefile
deleted file mode 100644
index c2fac6b8c..000000000
--- a/legacyadapters/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-include ../commons-test.mk
\ No newline at end of file
diff --git a/legacyadapters/README.md b/legacyadapters/README.md
deleted file mode 100644
index f7fb5a57c..000000000
--- a/legacyadapters/README.md
+++ /dev/null
@@ -1,104 +0,0 @@
-# Legacy Adapters
-
-> **⚠️ DEPRECATION NOTICE**
->
-> This module is **temporary** and already **deprecated**. It will be removed in a future release when all Docker products have migrated to use the go-sdk natively.
->
-> **We strongly recommend avoiding this module in new projects.** Instead, use the native go-sdk types directly.
-> This module exists solely to provide a migration path for existing Docker products during the transition period.
-
-This package provides conversion utilities to bridge between the modern Docker Go SDK types and legacy Docker CLI/Docker Engine API types.
-
-## Installation
-
-```bash
-go get github.com/docker/go-sdk/legacyadapters
-```
-
-## Usage
-
-### Converting Auth Configuration
-
-Convert SDK auth config to Docker Engine API format:
-
-```go
-import (
- "github.com/docker/docker/api/types/registry"
- "github.com/docker/go-sdk/config"
- legacyconfig "github.com/docker/go-sdk/legacyadapters/config"
-)
-
-sdkAuth := registry.AuthConfig{
- Username: "myuser",
- Password: "mypass",
- ServerAddress: "registry.example.com",
-}
-
-// Convert to Docker Engine API format
-registryAuth := legacyconfig.ToRegistryAuthConfig(sdkAuth)
-
-// Convert to Docker CLI format
-cliAuth := legacyconfig.ToCLIAuthConfig(sdkAuth)
-```
-
-### Converting Full Configuration
-
-Convert SDK config to Docker CLI config file format:
-
-```go
-sdkConfig := config.Config{
- AuthConfigs: map[string]registry.AuthConfig{
- "registry.example.com": {
- Username: "user",
- Password: "pass",
- },
- },
- HTTPHeaders: map[string]string{
- "User-Agent": "my-app/1.0",
- },
- CredentialsStore: "desktop",
-}
-
-// Convert to Docker CLI config file format
-cliConfigFile := legacyconfig.ToConfigFile(sdkConfig)
-```
-
-### Converting Proxy Configuration
-
-```go
-sdkProxy := config.ProxyConfig{
- HTTPProxy: "http://proxy.example.com:8080",
- HTTPSProxy: "https://proxy.example.com:8443",
- NoProxy: "localhost,127.0.0.1",
-}
-
-// Convert to CLI proxy format
-cliProxy := legacyconfig.ToCLIProxyConfig(sdkProxy)
-
-// Convert multiple proxy configs
-sdkProxies := map[string]config.ProxyConfig{
- "default": sdkProxy,
-}
-cliProxies := legacyconfig.ToCLIProxyConfigs(sdkProxies)
-```
-
-## Available Functions
-
-### Auth Configuration Adapters
-
-- `ToRegistryAuthConfig`: Converts SDK `AuthConfig` to Docker Engine API `registry.AuthConfig`
-- `ToCLIAuthConfig`: Converts SDK `AuthConfig` to Docker CLI `types.AuthConfig`
-- `ToCLIAuthConfigs`: Converts map of SDK auth configs to map of CLI auth configs
-
-### Configuration File Adapters
-
-- `ToConfigFile`: Converts SDK `Config` to Docker CLI `configfile.ConfigFile`
-
-### Proxy Configuration Adapters
-
-- `ToCLIProxyConfig`: Converts SDK `ProxyConfig` to CLI `configfile.ProxyConfig`
-- `ToCLIProxyConfigs`: Converts map of SDK proxy configs to map of CLI proxy configs
-
-## Key Differences
-
-- **Email Field**: Always set to empty string in converted formats
\ No newline at end of file
diff --git a/legacyadapters/config/auth.go b/legacyadapters/config/auth.go
deleted file mode 100644
index ee0ecec9c..000000000
--- a/legacyadapters/config/auth.go
+++ /dev/null
@@ -1,112 +0,0 @@
-// Package config provides legacy adapters for converting between go-sdk config types
-// and Docker CLI/Engine API types.
-//
-// Deprecated: This package is deprecated and will be removed in a future release
-// when all Docker products have migrated to use the go-sdk natively.
-// Use the native go-sdk types directly and these adapters only when needed.
-package config
-
-import (
- "github.com/docker/cli/cli/config/configfile"
- "github.com/docker/cli/cli/config/types"
- "github.com/docker/docker/api/types/registry"
- "github.com/docker/go-sdk/config"
-)
-
-// ToRegistryAuthConfig converts a go-sdk AuthConfig to Docker Engine API registry.AuthConfig.
-// Since AuthConfig is now an alias to registry.AuthConfig, this simply returns the input.
-//
-// Deprecated: This function is deprecated and will be removed in a future release.
-// Use the native go-sdk types directly and these adapters only when needed.
-func ToRegistryAuthConfig(authConfig registry.AuthConfig) registry.AuthConfig {
- return authConfig
-}
-
-// ToConfigFile converts a go-sdk Config to Docker CLI configfile.ConfigFile.
-//
-// Deprecated: This function is deprecated and will be removed in a future release.
-// Use the native go-sdk types directly and these adapters only when needed.
-func ToConfigFile(cfg config.Config) *configfile.ConfigFile {
- return &configfile.ConfigFile{
- AuthConfigs: ToCLIAuthConfigs(cfg.AuthConfigs),
- HTTPHeaders: cfg.HTTPHeaders,
- PsFormat: cfg.PsFormat,
- ImagesFormat: cfg.ImagesFormat,
- NetworksFormat: cfg.NetworksFormat,
- PluginsFormat: cfg.PluginsFormat,
- VolumesFormat: cfg.VolumesFormat,
- StatsFormat: cfg.StatsFormat,
- DetachKeys: cfg.DetachKeys,
- CredentialsStore: cfg.CredentialsStore,
- CredentialHelpers: cfg.CredentialHelpers,
- Filename: cfg.Filename,
- ServiceInspectFormat: cfg.ServiceInspectFormat,
- ServicesFormat: cfg.ServicesFormat,
- TasksFormat: cfg.TasksFormat,
- SecretFormat: cfg.SecretFormat,
- ConfigFormat: cfg.ConfigFormat,
- NodesFormat: cfg.NodesFormat,
- PruneFilters: cfg.PruneFilters,
- Proxies: ToCLIProxyConfigs(cfg.Proxies),
- CurrentContext: cfg.CurrentContext,
- CLIPluginsExtraDirs: cfg.CLIPluginsExtraDirs,
- Plugins: make(map[string]map[string]string),
- Aliases: cfg.Aliases,
- Features: make(map[string]string),
- Experimental: cfg.Experimental,
- }
-}
-
-// ToCLIAuthConfig converts a go-sdk AuthConfig to Docker CLI types.AuthConfig.
-// Note: RegistryToken field is included but may not be used by all CLI components.
-//
-// Deprecated: This function is deprecated and will be removed in a future release.
-// Use the native go-sdk types directly and these adapters only when needed.
-func ToCLIAuthConfig(authConfig registry.AuthConfig) types.AuthConfig {
- return types.AuthConfig{
- Username: authConfig.Username,
- Password: authConfig.Password,
- Auth: authConfig.Auth,
- Email: "",
- ServerAddress: authConfig.ServerAddress,
- IdentityToken: authConfig.IdentityToken,
- RegistryToken: authConfig.RegistryToken,
- }
-}
-
-// ToCLIAuthConfigs converts a map of go-sdk AuthConfigs to Docker CLI types.AuthConfigs.
-//
-// Deprecated: This function is deprecated and will be removed in a future release.
-// Use the native go-sdk types directly and these adapters only when needed.
-func ToCLIAuthConfigs(authConfigs map[string]registry.AuthConfig) map[string]types.AuthConfig {
- result := make(map[string]types.AuthConfig, len(authConfigs))
- for name, authConfig := range authConfigs {
- result[name] = ToCLIAuthConfig(authConfig)
- }
- return result
-}
-
-// ToCLIProxyConfig converts a go-sdk ProxyConfig to Docker CLI configfile.ProxyConfig.
-//
-// Deprecated: This function is deprecated and will be removed in a future release.
-// Use the native go-sdk types directly and these adapters only when needed.
-func ToCLIProxyConfig(proxy config.ProxyConfig) configfile.ProxyConfig {
- return configfile.ProxyConfig{
- HTTPProxy: proxy.HTTPProxy,
- HTTPSProxy: proxy.HTTPSProxy,
- FTPProxy: proxy.FTPProxy,
- NoProxy: proxy.NoProxy,
- }
-}
-
-// ToCLIProxyConfigs converts a map of go-sdk ProxyConfigs to Docker CLI configfile.ProxyConfigs.
-//
-// Deprecated: This function is deprecated and will be removed in a future release.
-// Use the native go-sdk types directly and these adapters only when needed.
-func ToCLIProxyConfigs(proxies map[string]config.ProxyConfig) map[string]configfile.ProxyConfig {
- result := make(map[string]configfile.ProxyConfig, len(proxies))
- for name, proxy := range proxies {
- result[name] = ToCLIProxyConfig(proxy)
- }
- return result
-}
diff --git a/legacyadapters/config/auth_test.go b/legacyadapters/config/auth_test.go
deleted file mode 100644
index fc1bf46ce..000000000
--- a/legacyadapters/config/auth_test.go
+++ /dev/null
@@ -1,469 +0,0 @@
-package config
-
-import (
- "testing"
-
- "github.com/stretchr/testify/require"
-
- "github.com/docker/cli/cli/config/configfile"
- "github.com/docker/cli/cli/config/types"
- "github.com/docker/docker/api/types/registry"
- "github.com/docker/go-sdk/config"
-)
-
-func TestToRegistryAuthConfig(t *testing.T) {
- tests := []struct {
- name string
- input registry.AuthConfig
- expected registry.AuthConfig
- }{
- {
- name: "empty config",
- input: registry.AuthConfig{},
- expected: registry.AuthConfig{
- Email: "",
- },
- },
- {
- name: "basic username and password",
- input: registry.AuthConfig{
- Username: "testuser",
- Password: "testpass",
- },
- expected: registry.AuthConfig{
- Username: "testuser",
- Password: "testpass",
- Email: "",
- },
- },
- {
- name: "with auth field",
- input: registry.AuthConfig{
- Username: "user",
- Password: "pass",
- Auth: "dXNlcjpwYXNz", // base64 encoded "user:pass"
- },
- expected: registry.AuthConfig{
- Username: "user",
- Password: "pass",
- Auth: "dXNlcjpwYXNz",
- Email: "",
- },
- },
- {
- name: "with server address",
- input: registry.AuthConfig{
- Username: "user",
- Password: "pass",
- ServerAddress: "registry.example.com",
- },
- expected: registry.AuthConfig{
- Username: "user",
- Password: "pass",
- Email: "",
- ServerAddress: "registry.example.com",
- },
- },
- {
- name: "with identity token",
- input: registry.AuthConfig{
- Username: "user",
- IdentityToken: "identity-token-123",
- },
- expected: registry.AuthConfig{
- Username: "user",
- Email: "",
- IdentityToken: "identity-token-123",
- },
- },
- {
- name: "with registry token",
- input: registry.AuthConfig{
- Username: "user",
- RegistryToken: "registry-token-456",
- },
- expected: registry.AuthConfig{
- Username: "user",
- Email: "",
- RegistryToken: "registry-token-456",
- },
- },
- {
- name: "complete config",
- input: registry.AuthConfig{
- Username: "testuser",
- Password: "testpass",
- Auth: "dGVzdHVzZXI6dGVzdHBhc3M=", // base64 encoded "testuser:testpass"
- ServerAddress: "registry.example.com",
- IdentityToken: "identity-token-123",
- RegistryToken: "registry-token-456",
- },
- expected: registry.AuthConfig{
- Username: "testuser",
- Password: "testpass",
- Auth: "dGVzdHVzZXI6dGVzdHBhc3M=",
- Email: "",
- ServerAddress: "registry.example.com",
- IdentityToken: "identity-token-123",
- RegistryToken: "registry-token-456",
- },
- },
- }
-
- for _, tc := range tests {
- t.Run(tc.name, func(t *testing.T) {
- result := ToRegistryAuthConfig(tc.input)
- require.Equal(t, tc.expected, result)
- })
- }
-}
-
-func TestToRegistryAuthConfig_EmailAlwaysEmpty(t *testing.T) {
- // Test that Email field is always set to empty string, regardless of input
- input := registry.AuthConfig{
- Username: "user",
- Password: "pass",
- }
-
- result := ToRegistryAuthConfig(input)
- require.Empty(t, result.Email, "Email field should always be empty")
-}
-
-func TestConfigToConfigFile(t *testing.T) {
- t.Helper()
- tests := []struct {
- name string
- input config.Config
- validate func(t *testing.T, result *configfile.ConfigFile)
- }{
- {
- name: "empty config",
- input: config.Config{},
- validate: func(t *testing.T, result *configfile.ConfigFile) {
- t.Helper()
- require.NotNil(t, result)
- require.NotNil(t, result.AuthConfigs)
- require.NotNil(t, result.Plugins)
- require.NotNil(t, result.Features)
- require.Equal(t, map[string]types.AuthConfig{}, result.AuthConfigs)
- require.Equal(t, map[string]map[string]string{}, result.Plugins)
- require.Equal(t, map[string]string{}, result.Features)
- },
- },
- {
- name: "basic config with auth",
- input: config.Config{
- AuthConfigs: map[string]registry.AuthConfig{
- "registry.example.com": {
- Username: "testuser",
- Password: "testpass",
- },
- },
- HTTPHeaders: map[string]string{
- "User-Agent": "test-client",
- },
- PsFormat: "table {{.ID}}",
- ImagesFormat: "table {{.Repository}}",
- CredentialsStore: "desktop",
- CurrentContext: "test-context",
- },
- validate: func(t *testing.T, result *configfile.ConfigFile) {
- t.Helper()
- require.NotNil(t, result)
- require.Equal(t, "testuser", result.AuthConfigs["registry.example.com"].Username)
- require.Equal(t, "testpass", result.AuthConfigs["registry.example.com"].Password)
- require.Empty(t, result.AuthConfigs["registry.example.com"].Email)
- require.Equal(t, "test-client", result.HTTPHeaders["User-Agent"])
- require.Equal(t, "table {{.ID}}", result.PsFormat)
- require.Equal(t, "table {{.Repository}}", result.ImagesFormat)
- require.Equal(t, "desktop", result.CredentialsStore)
- require.Equal(t, "test-context", result.CurrentContext)
- },
- },
- {
- name: "config with proxies",
- input: config.Config{
- Proxies: map[string]config.ProxyConfig{
- "default": {
- HTTPProxy: "http://proxy.example.com:8080",
- HTTPSProxy: "https://proxy.example.com:8443",
- NoProxy: "localhost,127.0.0.1",
- FTPProxy: "ftp://proxy.example.com:21",
- },
- },
- },
- validate: func(t *testing.T, result *configfile.ConfigFile) {
- t.Helper()
- require.NotNil(t, result)
- require.Contains(t, result.Proxies, "default")
- proxy := result.Proxies["default"]
- require.Equal(t, "http://proxy.example.com:8080", proxy.HTTPProxy)
- require.Equal(t, "https://proxy.example.com:8443", proxy.HTTPSProxy)
- require.Equal(t, "localhost,127.0.0.1", proxy.NoProxy)
- require.Equal(t, "ftp://proxy.example.com:21", proxy.FTPProxy)
- },
- },
- }
-
- for _, tc := range tests {
- t.Run(tc.name, func(t *testing.T) {
- result := ToConfigFile(tc.input)
- tc.validate(t, result)
- })
- }
-}
-
-func TestToCLIAuthConfig(t *testing.T) {
- t.Helper()
- tests := []struct {
- name string
- input registry.AuthConfig
- expected types.AuthConfig
- }{
- {
- name: "empty config",
- input: registry.AuthConfig{},
- expected: types.AuthConfig{
- Email: "",
- },
- },
- {
- name: "basic username and password",
- input: registry.AuthConfig{
- Username: "testuser",
- Password: "testpass",
- },
- expected: types.AuthConfig{
- Username: "testuser",
- Password: "testpass",
- Email: "",
- },
- },
- {
- name: "with auth field",
- input: registry.AuthConfig{
- Username: "user",
- Password: "pass",
- Auth: "dXNlcjpwYXNz",
- },
- expected: types.AuthConfig{
- Username: "user",
- Password: "pass",
- Auth: "dXNlcjpwYXNz",
- Email: "",
- },
- },
- {
- name: "with server address and identity token",
- input: registry.AuthConfig{
- Username: "user",
- ServerAddress: "registry.example.com",
- IdentityToken: "identity-token-123",
- },
- expected: types.AuthConfig{
- Username: "user",
- Email: "",
- ServerAddress: "registry.example.com",
- IdentityToken: "identity-token-123",
- },
- },
- {
- name: "with registry token included",
- input: registry.AuthConfig{
- Username: "user",
- Password: "pass",
- RegistryToken: "registry-token-456",
- },
- expected: types.AuthConfig{
- Username: "user",
- Password: "pass",
- Email: "",
- RegistryToken: "registry-token-456",
- },
- },
- }
-
- for _, tc := range tests {
- t.Run(tc.name, func(t *testing.T) {
- result := ToCLIAuthConfig(tc.input)
- require.Equal(t, tc.expected, result)
- })
- }
-}
-
-func TestToCLIAuthConfigs(t *testing.T) {
- t.Helper()
- tests := []struct {
- name string
- input map[string]registry.AuthConfig
- expected map[string]types.AuthConfig
- }{
- {
- name: "empty map",
- input: map[string]registry.AuthConfig{},
- expected: map[string]types.AuthConfig{},
- },
- {
- name: "single auth config",
- input: map[string]registry.AuthConfig{
- "registry.example.com": {
- Username: "testuser",
- Password: "testpass",
- },
- },
- expected: map[string]types.AuthConfig{
- "registry.example.com": {
- Username: "testuser",
- Password: "testpass",
- Email: "",
- },
- },
- },
- {
- name: "multiple auth configs",
- input: map[string]registry.AuthConfig{
- "registry1.example.com": {
- Username: "user1",
- Password: "pass1",
- Auth: "dXNlcjE6cGFzczE=",
- },
- "registry2.example.com": {
- Username: "user2",
- IdentityToken: "token123",
- },
- },
- expected: map[string]types.AuthConfig{
- "registry1.example.com": {
- Username: "user1",
- Password: "pass1",
- Auth: "dXNlcjE6cGFzczE=",
- Email: "",
- },
- "registry2.example.com": {
- Username: "user2",
- IdentityToken: "token123",
- Email: "",
- },
- },
- },
- }
-
- for _, tc := range tests {
- t.Run(tc.name, func(t *testing.T) {
- result := ToCLIAuthConfigs(tc.input)
- require.Equal(t, tc.expected, result)
- })
- }
-}
-
-func TestToCLIProxyConfig(t *testing.T) {
- t.Helper()
- tests := []struct {
- name string
- input config.ProxyConfig
- expected configfile.ProxyConfig
- }{
- {
- name: "empty config",
- input: config.ProxyConfig{},
- expected: configfile.ProxyConfig{},
- },
- {
- name: "basic proxy config",
- input: config.ProxyConfig{
- HTTPProxy: "http://proxy.example.com:8080",
- HTTPSProxy: "https://proxy.example.com:8443",
- NoProxy: "localhost,127.0.0.1",
- },
- expected: configfile.ProxyConfig{
- HTTPProxy: "http://proxy.example.com:8080",
- HTTPSProxy: "https://proxy.example.com:8443",
- NoProxy: "localhost,127.0.0.1",
- },
- },
- {
- name: "complete proxy config",
- input: config.ProxyConfig{
- HTTPProxy: "http://proxy.example.com:8080",
- HTTPSProxy: "https://proxy.example.com:8443",
- FTPProxy: "ftp://proxy.example.com:21",
- NoProxy: "localhost,127.0.0.1,.internal",
- },
- expected: configfile.ProxyConfig{
- HTTPProxy: "http://proxy.example.com:8080",
- HTTPSProxy: "https://proxy.example.com:8443",
- FTPProxy: "ftp://proxy.example.com:21",
- NoProxy: "localhost,127.0.0.1,.internal",
- },
- },
- }
-
- for _, tc := range tests {
- t.Run(tc.name, func(t *testing.T) {
- result := ToCLIProxyConfig(tc.input)
- require.Equal(t, tc.expected, result)
- })
- }
-}
-
-func TestToCLIProxyConfigs(t *testing.T) {
- t.Helper()
- tests := []struct {
- name string
- input map[string]config.ProxyConfig
- expected map[string]configfile.ProxyConfig
- }{
- {
- name: "empty map",
- input: map[string]config.ProxyConfig{},
- expected: map[string]configfile.ProxyConfig{},
- },
- {
- name: "single proxy config",
- input: map[string]config.ProxyConfig{
- "default": {
- HTTPProxy: "http://proxy.example.com:8080",
- HTTPSProxy: "https://proxy.example.com:8443",
- },
- },
- expected: map[string]configfile.ProxyConfig{
- "default": {
- HTTPProxy: "http://proxy.example.com:8080",
- HTTPSProxy: "https://proxy.example.com:8443",
- },
- },
- },
- {
- name: "multiple proxy configs",
- input: map[string]config.ProxyConfig{
- "development": {
- HTTPProxy: "http://dev-proxy.example.com:8080",
- NoProxy: "localhost",
- },
- "production": {
- HTTPSProxy: "https://prod-proxy.example.com:8443",
- FTPProxy: "ftp://prod-proxy.example.com:21",
- NoProxy: "localhost,127.0.0.1,.internal",
- },
- },
- expected: map[string]configfile.ProxyConfig{
- "development": {
- HTTPProxy: "http://dev-proxy.example.com:8080",
- NoProxy: "localhost",
- },
- "production": {
- HTTPSProxy: "https://prod-proxy.example.com:8443",
- FTPProxy: "ftp://prod-proxy.example.com:21",
- NoProxy: "localhost,127.0.0.1,.internal",
- },
- },
- },
- }
-
- for _, tc := range tests {
- t.Run(tc.name, func(t *testing.T) {
- result := ToCLIProxyConfigs(tc.input)
- require.Equal(t, tc.expected, result)
- })
- }
-}
diff --git a/legacyadapters/doc.go b/legacyadapters/doc.go
deleted file mode 100644
index 7d3df02a1..000000000
--- a/legacyadapters/doc.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// Package legacyadapters provides conversion utilities to bridge between
-// the modern Docker Go SDK types and legacy Docker CLI/Docker Engine API types.
-//
-// Deprecated: This entire module is deprecated and temporary. It will be removed
-// in a future release when all Docker products have migrated to use the go-sdk
-// natively. We strongly recommend avoiding this module in new projects and using
-// the native go-sdk types directly instead.
-//
-// This module exists solely to provide a migration path for existing Docker
-// products during the transition period.
-package legacyadapters
diff --git a/legacyadapters/go.mod b/legacyadapters/go.mod
deleted file mode 100644
index cd219032f..000000000
--- a/legacyadapters/go.mod
+++ /dev/null
@@ -1,26 +0,0 @@
-module github.com/docker/go-sdk/legacyadapters
-
-go 1.24
-
-replace github.com/docker/go-sdk/config => ../config
-
-require (
- github.com/docker/cli v28.3.2+incompatible
- github.com/docker/docker v28.3.2+incompatible
- github.com/docker/go-sdk/config v0.1.0-alpha011
- github.com/stretchr/testify v1.10.0
-)
-
-require (
- github.com/davecgh/go-spew v1.1.1 // indirect
- github.com/distribution/reference v0.6.0 // indirect
- github.com/docker/docker-credential-helpers v0.9.3 // indirect
- github.com/kr/text v0.2.0 // indirect
- github.com/opencontainers/go-digest v1.0.0 // indirect
- github.com/opencontainers/image-spec v1.1.1 // indirect
- github.com/pkg/errors v0.9.1 // indirect
- github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/sirupsen/logrus v1.9.3 // indirect
- golang.org/x/sys v0.33.0 // indirect
- gopkg.in/yaml.v3 v3.0.1 // indirect
-)
diff --git a/legacyadapters/go.sum b/legacyadapters/go.sum
deleted file mode 100644
index 78881b541..000000000
--- a/legacyadapters/go.sum
+++ /dev/null
@@ -1,45 +0,0 @@
-github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
-github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
-github.com/docker/cli v28.3.2+incompatible h1:mOt9fcLE7zaACbxW1GeS65RI67wIJrTnqS3hP2huFsY=
-github.com/docker/cli v28.3.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
-github.com/docker/docker v28.3.2+incompatible h1:wn66NJ6pWB1vBZIilP8G3qQPqHy5XymfYn5vsqeA5oA=
-github.com/docker/docker v28.3.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8=
-github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo=
-github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
-github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
-github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
-github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
-github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
-github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
-github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
-github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
-github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
-github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
-github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
-github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
-github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
-github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
-github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
-golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
-gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
-gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
diff --git a/legacyadapters/version.go b/legacyadapters/version.go
deleted file mode 100644
index 6efc1b96a..000000000
--- a/legacyadapters/version.go
+++ /dev/null
@@ -1,10 +0,0 @@
-package legacyadapters
-
-const (
- version = "0.1.0-alpha003"
-)
-
-// Version returns the version of the legacyadapters package.
-func Version() string {
- return version
-}
diff --git a/network/go.mod b/network/go.mod
index 6e54b7a10..2468cf33a 100644
--- a/network/go.mod
+++ b/network/go.mod
@@ -2,52 +2,67 @@ module github.com/docker/go-sdk/network
go 1.24
-replace (
- github.com/docker/go-sdk/client => ../client
- github.com/docker/go-sdk/config => ../config
- github.com/docker/go-sdk/context => ../context
-)
+replace github.com/docker/go-sdk/client => ../client
require (
github.com/containerd/errdefs v1.0.0
github.com/docker/docker v28.3.2+incompatible
github.com/docker/go-sdk/client v0.1.0-alpha011
github.com/google/uuid v1.6.0
- github.com/stretchr/testify v1.10.0
+ github.com/stretchr/testify v1.11.1
)
require (
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
- github.com/caarlos0/env/v11 v11.3.1 // indirect
- github.com/cenkalti/backoff/v5 v5.0.2 // indirect
+ github.com/cenkalti/backoff/v5 v5.0.3 // indirect
+ github.com/clipperhouse/uax29/v2 v2.2.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/distribution/reference v0.6.0 // indirect
+ github.com/docker/cli v28.5.1+incompatible // indirect
+ github.com/docker/docker-credential-helpers v0.9.4 // indirect
+ github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
github.com/docker/go-connections v0.5.0 // indirect
- github.com/docker/go-sdk/config v0.1.0-alpha011 // indirect
- github.com/docker/go-sdk/context v0.1.0-alpha011 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
+ github.com/fvbommel/sortorder v1.1.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
+ github.com/inconshreveable/mousetrap v1.1.0 // indirect
+ github.com/mattn/go-runewidth v0.0.19 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
+ github.com/moby/sys/atomicwriter v0.1.0 // indirect
github.com/moby/sys/sequential v0.6.0 // indirect
+ github.com/moby/term v0.5.2 // indirect
+ github.com/morikuni/aec v1.0.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
+ github.com/prometheus/client_golang v1.1.0 // indirect
+ github.com/sirupsen/logrus v1.9.3 // indirect
+ github.com/spf13/cobra v1.10.1 // indirect
+ github.com/spf13/pflag v1.0.10 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
- go.opentelemetry.io/otel v1.37.0 // indirect
- go.opentelemetry.io/otel/metric v1.37.0 // indirect
- go.opentelemetry.io/otel/trace v1.37.0 // indirect
- golang.org/x/net v0.40.0 // indirect
- golang.org/x/sys v0.33.0 // indirect
- golang.org/x/text v0.26.0 // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
- google.golang.org/protobuf v1.36.6 // indirect
+ go.opentelemetry.io/otel v1.38.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect
+ go.opentelemetry.io/otel/metric v1.38.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.38.0 // indirect
+ go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect
+ go.opentelemetry.io/otel/trace v1.38.0 // indirect
+ go.opentelemetry.io/proto/otlp v1.7.1 // indirect
+ golang.org/x/net v0.43.0 // indirect
+ golang.org/x/sys v0.35.0 // indirect
+ golang.org/x/text v0.28.0 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
+ google.golang.org/grpc v1.75.0 // indirect
+ google.golang.org/protobuf v1.36.8 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/network/go.sum b/network/go.sum
index 1c8658ec8..8db033c49 100644
--- a/network/go.sum
+++ b/network/go.sum
@@ -2,47 +2,96 @@ github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEK
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
-github.com/caarlos0/env/v11 v11.3.1 h1:cArPWC15hWmEt+gWk7YBi7lEXTXCvpaSdCiZE2X5mCA=
-github.com/caarlos0/env/v11 v11.3.1/go.mod h1:qupehSf/Y0TUTsxKywqRt/vJjN5nz6vauiYEUUr8P4U=
-github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8=
-github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
+github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
+github.com/clipperhouse/uax29/v2 v2.2.0 h1:ChwIKnQN3kcZteTXMgb1wztSgaU+ZemkgWdohwgs8tY=
+github.com/clipperhouse/uax29/v2 v2.2.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
+github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
+github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
+github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
+github.com/docker/cli v28.5.1+incompatible h1:ESutzBALAD6qyCLqbQSEf1a/U8Ybms5agw59yGVc+yY=
+github.com/docker/cli v28.5.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
+github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v28.3.2+incompatible h1:wn66NJ6pWB1vBZIilP8G3qQPqHy5XymfYn5vsqeA5oA=
github.com/docker/docker v28.3.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker-credential-helpers v0.9.4 h1:76ItO69/AP/V4yT9V4uuuItG0B1N8hvt0T0c0NN/DzI=
+github.com/docker/docker-credential-helpers v0.9.4/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c=
+github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
+github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
+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.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
+github.com/fvbommel/sortorder v1.1.0 h1:fUmoe+HLsBTctBDoaBwpQo5N+nrCp8g/BjKb/6ZQmYw=
+github.com/fvbommel/sortorder v1.1.0/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90=
+github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
+github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs=
+github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
+github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw=
+github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
+github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU=
+github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
@@ -51,68 +100,121 @@ github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7z
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+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/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8=
+github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.6.0 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkpEo=
+github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.3 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURmKE=
+github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
-github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
-github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
+github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
+github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
+github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
+github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
+github.com/theupdateframework/notary v0.7.0 h1:QyagRZ7wlSpjT5N2qQAh/pN+DVqgekv4DzbAiAiEL3c=
+github.com/theupdateframework/notary v0.7.0/go.mod h1:c9DRxcmhHmVLDay4/2fUYdISnHqbFDGRSlXPO0AhYWw=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
-go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
-go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M=
+go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
+go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9obrcoWVKp/lwl8tRE33853I8Xru9HFbw/skNeLs8=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0/go.mod h1:GAXRxmLJcVM3u22IjTg74zWBrRCKq8BnOqUVLodpcpw=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0 h1:nRVXXvf78e00EwY6Wp0YII8ww2JVWshZ20HfTlE11AM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0/go.mod h1:r49hO7CgrxY9Voaj3Xe8pANWtr0Oq916d0XAmOoCZAQ=
-go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
-go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
-go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
-go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
-go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
-go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
-go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
-go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
-go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os=
-go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo=
+go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
+go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
+go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
+go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
+go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
+go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
+go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
+go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
+go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=
+go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=
+go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
+go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
+golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
-golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
+golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
+golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
-golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
+golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
+golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
-golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
+golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
+golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -123,17 +225,22 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY=
-google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
-google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
-google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
-google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
-google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
+gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
+gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
+google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY=
+google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc=
+google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4=
+google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
+google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
+google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
diff --git a/volume/go.mod b/volume/go.mod
index eef019799..6f23f5141 100644
--- a/volume/go.mod
+++ b/volume/go.mod
@@ -2,51 +2,67 @@ module github.com/docker/go-sdk/volume
go 1.24
-replace (
- github.com/docker/go-sdk/client => ../client
- github.com/docker/go-sdk/config => ../config
- github.com/docker/go-sdk/context => ../context
-)
+replace github.com/docker/go-sdk/client => ../client
require (
github.com/containerd/errdefs v1.0.0
github.com/docker/docker v28.3.2+incompatible
github.com/docker/go-sdk/client v0.1.0-alpha011
- github.com/stretchr/testify v1.10.0
+ github.com/stretchr/testify v1.11.1
)
require (
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
- github.com/caarlos0/env/v11 v11.3.1 // indirect
- github.com/cenkalti/backoff/v5 v5.0.2 // indirect
+ github.com/cenkalti/backoff/v5 v5.0.3 // indirect
+ github.com/clipperhouse/uax29/v2 v2.2.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/distribution/reference v0.6.0 // indirect
+ github.com/docker/cli v28.5.1+incompatible // indirect
+ github.com/docker/docker-credential-helpers v0.9.4 // indirect
+ github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
github.com/docker/go-connections v0.5.0 // indirect
- github.com/docker/go-sdk/config v0.1.0-alpha011 // indirect
- github.com/docker/go-sdk/context v0.1.0-alpha011 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
+ github.com/fvbommel/sortorder v1.1.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
+ github.com/google/uuid v1.6.0 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
+ github.com/inconshreveable/mousetrap v1.1.0 // indirect
+ github.com/mattn/go-runewidth v0.0.19 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
+ github.com/moby/sys/atomicwriter v0.1.0 // indirect
github.com/moby/sys/sequential v0.6.0 // indirect
+ github.com/moby/term v0.5.2 // indirect
+ github.com/morikuni/aec v1.0.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
+ github.com/prometheus/client_golang v1.1.0 // indirect
+ github.com/sirupsen/logrus v1.9.3 // indirect
+ github.com/spf13/cobra v1.10.1 // indirect
+ github.com/spf13/pflag v1.0.10 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
- go.opentelemetry.io/otel v1.37.0 // indirect
- go.opentelemetry.io/otel/metric v1.37.0 // indirect
- go.opentelemetry.io/otel/trace v1.37.0 // indirect
- golang.org/x/net v0.40.0 // indirect
- golang.org/x/sys v0.33.0 // indirect
- golang.org/x/text v0.26.0 // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
- google.golang.org/protobuf v1.36.6 // indirect
+ go.opentelemetry.io/otel v1.38.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect
+ go.opentelemetry.io/otel/metric v1.38.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.38.0 // indirect
+ go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect
+ go.opentelemetry.io/otel/trace v1.38.0 // indirect
+ go.opentelemetry.io/proto/otlp v1.7.1 // indirect
+ golang.org/x/net v0.43.0 // indirect
+ golang.org/x/sys v0.35.0 // indirect
+ golang.org/x/text v0.28.0 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
+ google.golang.org/grpc v1.75.0 // indirect
+ google.golang.org/protobuf v1.36.8 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/volume/go.sum b/volume/go.sum
index 1c8658ec8..8db033c49 100644
--- a/volume/go.sum
+++ b/volume/go.sum
@@ -2,47 +2,96 @@ github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEK
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
-github.com/caarlos0/env/v11 v11.3.1 h1:cArPWC15hWmEt+gWk7YBi7lEXTXCvpaSdCiZE2X5mCA=
-github.com/caarlos0/env/v11 v11.3.1/go.mod h1:qupehSf/Y0TUTsxKywqRt/vJjN5nz6vauiYEUUr8P4U=
-github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8=
-github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
+github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
+github.com/clipperhouse/uax29/v2 v2.2.0 h1:ChwIKnQN3kcZteTXMgb1wztSgaU+ZemkgWdohwgs8tY=
+github.com/clipperhouse/uax29/v2 v2.2.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
+github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
+github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
+github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
+github.com/docker/cli v28.5.1+incompatible h1:ESutzBALAD6qyCLqbQSEf1a/U8Ybms5agw59yGVc+yY=
+github.com/docker/cli v28.5.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
+github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v28.3.2+incompatible h1:wn66NJ6pWB1vBZIilP8G3qQPqHy5XymfYn5vsqeA5oA=
github.com/docker/docker v28.3.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker-credential-helpers v0.9.4 h1:76ItO69/AP/V4yT9V4uuuItG0B1N8hvt0T0c0NN/DzI=
+github.com/docker/docker-credential-helpers v0.9.4/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c=
+github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
+github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
+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.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
+github.com/fvbommel/sortorder v1.1.0 h1:fUmoe+HLsBTctBDoaBwpQo5N+nrCp8g/BjKb/6ZQmYw=
+github.com/fvbommel/sortorder v1.1.0/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90=
+github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
+github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs=
+github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
+github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw=
+github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
+github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU=
+github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
@@ -51,68 +100,121 @@ github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7z
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+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/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8=
+github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.6.0 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkpEo=
+github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.3 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURmKE=
+github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
-github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
-github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
+github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
+github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
+github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
+github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
+github.com/theupdateframework/notary v0.7.0 h1:QyagRZ7wlSpjT5N2qQAh/pN+DVqgekv4DzbAiAiEL3c=
+github.com/theupdateframework/notary v0.7.0/go.mod h1:c9DRxcmhHmVLDay4/2fUYdISnHqbFDGRSlXPO0AhYWw=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
-go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
-go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M=
+go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
+go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9obrcoWVKp/lwl8tRE33853I8Xru9HFbw/skNeLs8=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0/go.mod h1:GAXRxmLJcVM3u22IjTg74zWBrRCKq8BnOqUVLodpcpw=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0 h1:nRVXXvf78e00EwY6Wp0YII8ww2JVWshZ20HfTlE11AM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0/go.mod h1:r49hO7CgrxY9Voaj3Xe8pANWtr0Oq916d0XAmOoCZAQ=
-go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
-go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
-go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
-go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
-go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
-go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
-go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
-go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
-go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os=
-go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo=
+go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
+go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
+go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
+go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
+go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
+go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
+go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
+go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
+go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=
+go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=
+go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
+go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
+golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
-golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
+golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
+golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
-golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
+golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
+golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
-golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
+golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
+golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -123,17 +225,22 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY=
-google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
-google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
-google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
-google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
-google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
+gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
+gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
+google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY=
+google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc=
+google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4=
+google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
+google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
+google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=