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 d98b21f49..e53342ddf 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 926074e93..652ac8deb 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 5f1349a90..fc7c5a498 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 2024dfb4f..eb7bbccda 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 6d05c1962..a2733ccf6 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 d3a08c79d..6776f9c15 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 467207bdb..a8630f825 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 1c09c9c39..925fc0d73 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 00d3eb486..9875b5411 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 6d111993e..dad36f21a 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 62d565f24..1e3602b87 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 cec9f712a..cb4f6fe5f 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 06fb2c071..b961de8ef 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 80044e80f..8a3a69dea 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 965c410ae..2cdfef35e 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 }