From 1ace9aec347807c708ea9554a7bb867c00191c2e Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Thu, 25 Sep 2025 10:24:03 +0200 Subject: [PATCH 1/3] cli/command: don't use DCT status for trust stub-flags This is a follow-up to 7609dde8d0ab23b25be29adc9eb6069f4edb5e80 and 3f5b1bdd3240d390f48290c75dd724788eddfb6f, which removed support for DCT for build and plugin commands. As these flags are just stubs, hidden by default and no longer functional, they don't have to reflect the current state of DCT. Signed-off-by: Sebastiaan van Stijn --- cli/command/image/build.go | 2 +- cli/command/plugin/install.go | 2 +- cli/command/plugin/push.go | 2 +- cli/command/plugin/upgrade.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cli/command/image/build.go b/cli/command/image/build.go index d98b21f493..e53342ddf8 100644 --- a/cli/command/image/build.go +++ b/cli/command/image/build.go @@ -147,7 +147,7 @@ func newBuildCommand(dockerCLI command.Cli) *cobra.Command { flags.SetAnnotation("target", annotation.ExternalURL, []string{"https://docs.docker.com/reference/cli/docker/buildx/build/#target"}) flags.StringVar(&options.imageIDFile, "iidfile", "", "Write the image ID to the file") - flags.Bool("disable-content-trust", dockerCLI.ContentTrustEnabled(), "Skip image verification (deprecated)") + flags.Bool("disable-content-trust", true, "Skip image verification (deprecated)") _ = flags.MarkHidden("disable-content-trust") flags.StringVar(&options.platform, "platform", os.Getenv("DOCKER_DEFAULT_PLATFORM"), "Set platform if server is multi-platform capable") diff --git a/cli/command/plugin/install.go b/cli/command/plugin/install.go index 926074e933..652ac8deb7 100644 --- a/cli/command/plugin/install.go +++ b/cli/command/plugin/install.go @@ -44,7 +44,7 @@ func newInstallCommand(dockerCLI command.Cli) *cobra.Command { flags.BoolVar(&options.grantPerms, "grant-all-permissions", false, "Grant all permissions necessary to run the plugin") flags.BoolVar(&options.disable, "disable", false, "Do not enable the plugin on install") flags.StringVar(&options.localName, "alias", "", "Local name for plugin") - flags.Bool("disable-content-trust", dockerCLI.ContentTrustEnabled(), "Skip image verification (deprecated)") + flags.Bool("disable-content-trust", true, "Skip image verification (deprecated)") _ = flags.MarkHidden("disable-content-trust") return cmd } diff --git a/cli/command/plugin/push.go b/cli/command/plugin/push.go index 5f1349a900..fc7c5a4980 100644 --- a/cli/command/plugin/push.go +++ b/cli/command/plugin/push.go @@ -25,7 +25,7 @@ func newPushCommand(dockerCLI command.Cli) *cobra.Command { } flags := cmd.Flags() - flags.Bool("disable-content-trust", dockerCLI.ContentTrustEnabled(), "Skip image verification (deprecated)") + flags.Bool("disable-content-trust", true, "Skip image verification (deprecated)") _ = flags.MarkHidden("disable-content-trust") return cmd } diff --git a/cli/command/plugin/upgrade.go b/cli/command/plugin/upgrade.go index 2024dfb4f9..eb7bbccda7 100644 --- a/cli/command/plugin/upgrade.go +++ b/cli/command/plugin/upgrade.go @@ -33,7 +33,7 @@ func newUpgradeCommand(dockerCLI command.Cli) *cobra.Command { flags := cmd.Flags() flags.BoolVar(&options.grantPerms, "grant-all-permissions", false, "Grant all permissions necessary to run the plugin") - flags.Bool("disable-content-trust", dockerCLI.ContentTrustEnabled(), "Skip image verification (deprecated)") + flags.Bool("disable-content-trust", true, "Skip image verification (deprecated)") _ = flags.MarkHidden("disable-content-trust") flags.BoolVar(&options.skipRemoteCheck, "skip-remote-check", false, "Do not check if specified remote plugin matches existing plugin image") return cmd From 1bae6aafa86629d2f840a9432999708e13c4f468 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Thu, 25 Sep 2025 10:30:35 +0200 Subject: [PATCH 2/3] trust: add internal utility for checking DOCKER_CONTENT_TRUST 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 6d05c19622..a2733ccf60 100644 --- a/cli/command/container/create.go +++ b/cli/command/container/create.go @@ -90,7 +90,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 d3a08c79d8..6776f9c159 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 467207bdbc..a8630f8256 100644 --- a/cli/command/container/run.go +++ b/cli/command/container/run.go @@ -11,6 +11,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/moby/moby/api/types/container" "github.com/moby/moby/client" @@ -70,7 +71,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 1c09c9c395..925fc0d73f 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 00d3eb486c..9875b54116 100644 --- a/cli/command/image/pull.go +++ b/cli/command/image/pull.go @@ -50,7 +50,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 6d111993ec..dad36f21a6 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 client.ImagePullOptions) (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 62d565f24f..1e3602b871 100644 --- a/cli/command/image/push.go +++ b/cli/command/image/push.go @@ -16,6 +16,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" @@ -58,7 +59,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 cec9f712a0..cb4f6fe5f7 100644 --- a/cli/command/service/trust.go +++ b/cli/command/service/trust.go @@ -16,7 +16,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 06fb2c0710..b961de8ef4 100644 --- a/cli/trust/trust.go +++ b/cli/trust/trust.go @@ -12,6 +12,7 @@ import ( "os" "path" "path/filepath" + "strconv" "time" "github.com/distribution/reference" @@ -43,6 +44,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 80044e80f3..8a3a69dea8 100644 --- a/internal/test/cli.go +++ b/internal/test/cli.go @@ -35,7 +35,6 @@ type FakeCli struct { notaryClientFunc NotaryClientFuncType manifestStore manifeststore.Store registryClient registryclient.RegistryClient - contentTrust bool contextStore store.Store currentContext string dockerEndpoint docker.Endpoint @@ -197,16 +196,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 From 11d40488dd818aadbb4757ff57da040479b4e9a6 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Thu, 25 Sep 2025 09:54:40 +0200 Subject: [PATCH 3/3] cli/command: deprecate DockerCli.ContentTrustEnabled This function was used internally, but is no longer used. Users should check the value of the `DOCKER_CONTENT_TRUST` environment variable instead. There are no known external users of this method, so already removing it from the Cli interface; this method will be removed in the next release. Signed-off-by: Sebastiaan van Stijn --- cli/command/cli.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cli/command/cli.go b/cli/command/cli.go index 965c410ae9..2cdfef35e5 100644 --- a/cli/command/cli.go +++ b/cli/command/cli.go @@ -48,7 +48,6 @@ type Cli interface { config.Provider ServerInfo() ServerInfo CurrentVersion() string - ContentTrustEnabled() bool BuildKitEnabled() (bool, error) ContextStore() store.Store CurrentContext() string @@ -160,6 +159,8 @@ func (cli *DockerCli) ServerInfo() ServerInfo { // ContentTrustEnabled returns whether content trust has been enabled by an // environment variable. +// +// Deprecated: check the value of the DOCKER_CONTENT_TRUST environment variable to detect whether content-trust is enabled. func (cli *DockerCli) ContentTrustEnabled() bool { return cli.contentTrust }