From 261d8bcf8dcb04ffa9bb5a0a28ce1cfe52677e12 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Thu, 25 Sep 2025 10:30:35 +0200 Subject: [PATCH] trust: add internal utility for checking DOCKER_CONTENT_TRUST Signed-off-by: Sebastiaan van Stijn (cherry picked from commit 1bae6aafa86629d2f840a9432999708e13c4f468) Signed-off-by: Sebastiaan van Stijn --- cli/command/container/create.go | 2 +- cli/command/container/create_test.go | 3 ++- cli/command/container/run.go | 3 ++- cli/command/container/run_test.go | 3 ++- cli/command/image/pull.go | 2 +- cli/command/image/pull_test.go | 3 ++- cli/command/image/push.go | 3 ++- cli/command/service/trust.go | 2 +- cli/trust/trust.go | 15 +++++++++++++++ internal/test/cli.go | 11 ----------- 10 files changed, 28 insertions(+), 19 deletions(-) diff --git a/cli/command/container/create.go b/cli/command/container/create.go index f38746fd3c..05368ef987 100644 --- a/cli/command/container/create.go +++ b/cli/command/container/create.go @@ -96,7 +96,7 @@ func newCreateCommand(dockerCLI command.Cli) *cobra.Command { addPlatformFlag(flags, &options.platform) _ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms) - flags.BoolVar(&options.untrusted, "disable-content-trust", !dockerCLI.ContentTrustEnabled(), "Skip image verification") + flags.BoolVar(&options.untrusted, "disable-content-trust", !trust.Enabled(), "Skip image verification") copts = addFlags(flags) addCompletions(cmd, dockerCLI) diff --git a/cli/command/container/create_test.go b/cli/command/container/create_test.go index 1b7add5637..3e1379b161 100644 --- a/cli/command/container/create_test.go +++ b/cli/command/container/create_test.go @@ -249,6 +249,7 @@ func TestNewCreateCommandWithContentTrustErrors(t *testing.T) { } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { + t.Setenv("DOCKER_CONTENT_TRUST", "true") fakeCLI := test.NewFakeCli(&fakeClient{ createContainerFunc: func(config *container.Config, hostConfig *container.HostConfig, @@ -258,7 +259,7 @@ func TestNewCreateCommandWithContentTrustErrors(t *testing.T) { ) (container.CreateResponse, error) { return container.CreateResponse{}, errors.New("shouldn't try to pull image") }, - }, test.EnableContentTrust) + }) fakeCLI.SetNotaryClient(tc.notaryFunc) cmd := newCreateCommand(fakeCLI) cmd.SetOut(io.Discard) diff --git a/cli/command/container/run.go b/cli/command/container/run.go index 3cdb71c927..1b55400daf 100644 --- a/cli/command/container/run.go +++ b/cli/command/container/run.go @@ -10,6 +10,7 @@ import ( "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command/completion" + "github.com/docker/cli/cli/trust" "github.com/docker/cli/opts" "github.com/docker/docker/api/types/container" "github.com/moby/sys/signal" @@ -74,7 +75,7 @@ func newRunCommand(dockerCLI command.Cli) *cobra.Command { // TODO(thaJeztah): consider adding platform as "image create option" on containerOptions addPlatformFlag(flags, &options.platform) - flags.BoolVar(&options.untrusted, "disable-content-trust", !dockerCLI.ContentTrustEnabled(), "Skip image verification") + flags.BoolVar(&options.untrusted, "disable-content-trust", !trust.Enabled(), "Skip image verification") copts = addFlags(flags) _ = cmd.RegisterFlagCompletionFunc("detach-keys", completeDetachKeys) diff --git a/cli/command/container/run_test.go b/cli/command/container/run_test.go index f75fe7ebef..332c6a493f 100644 --- a/cli/command/container/run_test.go +++ b/cli/command/container/run_test.go @@ -323,6 +323,7 @@ func TestRunCommandWithContentTrustErrors(t *testing.T) { } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { + t.Setenv("DOCKER_CONTENT_TRUST", "true") fakeCLI := test.NewFakeCli(&fakeClient{ createContainerFunc: func(config *container.Config, hostConfig *container.HostConfig, @@ -332,7 +333,7 @@ func TestRunCommandWithContentTrustErrors(t *testing.T) { ) (container.CreateResponse, error) { return container.CreateResponse{}, errors.New("shouldn't try to pull image") }, - }, test.EnableContentTrust) + }) fakeCLI.SetNotaryClient(tc.notaryFunc) cmd := newRunCommand(fakeCLI) cmd.SetArgs(tc.args) diff --git a/cli/command/image/pull.go b/cli/command/image/pull.go index 2f010fb6f1..a45e0b7435 100644 --- a/cli/command/image/pull.go +++ b/cli/command/image/pull.go @@ -56,7 +56,7 @@ func newPullCommand(dockerCLI command.Cli) *cobra.Command { flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Suppress verbose output") addPlatformFlag(flags, &opts.platform) - flags.BoolVar(&opts.untrusted, "disable-content-trust", !dockerCLI.ContentTrustEnabled(), "Skip image verification") + flags.BoolVar(&opts.untrusted, "disable-content-trust", !trust.Enabled(), "Skip image verification") _ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms) diff --git a/cli/command/image/pull_test.go b/cli/command/image/pull_test.go index ba7ff06213..baf375fdfe 100644 --- a/cli/command/image/pull_test.go +++ b/cli/command/image/pull_test.go @@ -118,11 +118,12 @@ func TestNewPullCommandWithContentTrustErrors(t *testing.T) { } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { + t.Setenv("DOCKER_CONTENT_TRUST", "true") cli := test.NewFakeCli(&fakeClient{ imagePullFunc: func(ref string, options image.PullOptions) (io.ReadCloser, error) { return io.NopCloser(strings.NewReader("")), errors.New("shouldn't try to pull image") }, - }, test.EnableContentTrust) + }) cli.SetNotaryClient(tc.notaryFunc) cmd := newPullCommand(cli) cmd.SetOut(io.Discard) diff --git a/cli/command/image/push.go b/cli/command/image/push.go index 480ee0d31b..5da2f3e469 100644 --- a/cli/command/image/push.go +++ b/cli/command/image/push.go @@ -15,6 +15,7 @@ import ( "github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command/completion" "github.com/docker/cli/cli/streams" + "github.com/docker/cli/cli/trust" "github.com/docker/cli/internal/jsonstream" "github.com/docker/cli/internal/registry" "github.com/docker/cli/internal/tui" @@ -64,7 +65,7 @@ func newPushCommand(dockerCLI command.Cli) *cobra.Command { flags := cmd.Flags() flags.BoolVarP(&opts.all, "all-tags", "a", false, "Push all tags of an image to the repository") flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Suppress verbose output") - flags.BoolVar(&opts.untrusted, "disable-content-trust", !dockerCLI.ContentTrustEnabled(), "Skip image signing") + flags.BoolVar(&opts.untrusted, "disable-content-trust", !trust.Enabled(), "Skip image signing") // Don't default to DOCKER_DEFAULT_PLATFORM env variable, always default to // pushing the image as-is. This also avoids forcing the platform selection diff --git a/cli/command/service/trust.go b/cli/command/service/trust.go index ea79161ad5..fe4b08c67b 100644 --- a/cli/command/service/trust.go +++ b/cli/command/service/trust.go @@ -15,7 +15,7 @@ import ( ) func resolveServiceImageDigestContentTrust(dockerCli command.Cli, service *swarm.ServiceSpec) error { - if !dockerCli.ContentTrustEnabled() { + if !trust.Enabled() { // When not using content trust, digest resolution happens later when // contacting the registry to retrieve image information. return nil diff --git a/cli/trust/trust.go b/cli/trust/trust.go index eeddc912b3..0e9be5d364 100644 --- a/cli/trust/trust.go +++ b/cli/trust/trust.go @@ -10,6 +10,7 @@ import ( "os" "path" "path/filepath" + "strconv" "time" "github.com/distribution/reference" @@ -42,6 +43,20 @@ var ( ActionsPushAndPull = []string{"pull", "push"} ) +// Enabled returns whether content-trust is enabled through the DOCKER_CONTENT_TRUST env-var. +// +// IMPORTANT: this function is for internal use, and may be removed at any moment. +func Enabled() bool { + var enabled bool + if e := os.Getenv("DOCKER_CONTENT_TRUST"); e != "" { + if t, err := strconv.ParseBool(e); t || err != nil { + // treat any other value as true + enabled = true + } + } + return enabled +} + // NotaryServer is the endpoint serving the Notary trust server const NotaryServer = "https://notary.docker.io" diff --git a/internal/test/cli.go b/internal/test/cli.go index 5a2d74b678..72591bac1b 100644 --- a/internal/test/cli.go +++ b/internal/test/cli.go @@ -36,7 +36,6 @@ type FakeCli struct { notaryClientFunc NotaryClientFuncType manifestStore manifeststore.Store registryClient registryclient.RegistryClient - contentTrust bool contextStore store.Store currentContext string dockerEndpoint docker.Endpoint @@ -198,16 +197,6 @@ func (c *FakeCli) SetRegistryClient(registryClient registryclient.RegistryClient c.registryClient = registryClient } -// ContentTrustEnabled on the fake cli -func (c *FakeCli) ContentTrustEnabled() bool { - return c.contentTrust -} - -// EnableContentTrust on the fake cli -func EnableContentTrust(c *FakeCli) { - c.contentTrust = true -} - // BuildKitEnabled on the fake cli func (*FakeCli) BuildKitEnabled() (bool, error) { return true, nil