From ad776d1e107b0d1cb3559a9c6b6391e11c3c51de Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Fri, 31 Oct 2025 21:45:22 +0100 Subject: [PATCH] remove support for client-side docker content trust validation Signed-off-by: Sebastiaan van Stijn --- cli/command/container/create.go | 24 +-- cli/command/container/create_test.go | 53 +---- cli/command/container/run.go | 6 +- cli/command/container/run_test.go | 49 ----- cli/command/image/build.go | 3 +- cli/command/image/pull.go | 60 ++---- cli/command/image/pull_test.go | 47 ---- cli/command/image/push.go | 19 +- cli/command/image/trust.go | 204 ------------------ cli/command/manifest/annotate.go | 37 +++- cli/command/plugin/install.go | 4 +- cli/command/plugin/push.go | 3 +- cli/command/plugin/upgrade.go | 3 +- cli/command/registry.go | 5 +- cli/command/service/create.go | 4 - cli/command/service/trust.go | 86 -------- cli/command/service/update.go | 3 - cli/command/trust/common.go | 36 +++- cli/command/trust/sign.go | 2 +- .../reference/commandline/container_create.md | 1 - docs/reference/commandline/container_run.md | 1 - docs/reference/commandline/create.md | 1 - docs/reference/commandline/docker.md | 2 - docs/reference/commandline/image_pull.md | 1 - docs/reference/commandline/image_push.md | 1 - docs/reference/commandline/pull.md | 11 +- docs/reference/commandline/push.md | 11 +- docs/reference/commandline/run.md | 1 - internal/registryclient/client.go | 4 +- 29 files changed, 132 insertions(+), 550 deletions(-) delete mode 100644 cli/command/image/trust.go delete mode 100644 cli/command/service/trust.go diff --git a/cli/command/container/create.go b/cli/command/container/create.go index 1820040784e3..a58eeaa16d2e 100644 --- a/cli/command/container/create.go +++ b/cli/command/container/create.go @@ -17,11 +17,9 @@ import ( "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command/completion" - "github.com/docker/cli/cli/command/image" "github.com/docker/cli/cli/config/configfile" "github.com/docker/cli/cli/config/types" "github.com/docker/cli/cli/streams" - "github.com/docker/cli/cli/trust" "github.com/docker/cli/internal/jsonstream" "github.com/docker/cli/opts" "github.com/moby/moby/api/types/mount" @@ -41,7 +39,6 @@ const ( type createOptions struct { name string platform string - untrusted bool pull string // always, missing, never quiet bool useAPISocket bool @@ -88,7 +85,9 @@ func newCreateCommand(dockerCLI command.Cli) *cobra.Command { _ = flags.SetAnnotation("platform", "version", []string{"1.32"}) _ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms()) - flags.BoolVar(&options.untrusted, "disable-content-trust", !trust.Enabled(), "Skip image verification") + // TODO(thaJeztah): DEPRECATED: remove in v29.1 or v30 + flags.Bool("disable-content-trust", true, "Skip image verification (deprecated)") + _ = flags.MarkDeprecated("disable-content-trust", "support for docker content trust was removed") copts = addFlags(flags) addCompletions(cmd, dockerCLI) @@ -213,10 +212,7 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *c hostConfig := containerCfg.HostConfig networkingConfig := containerCfg.NetworkingConfig - var ( - trustedRef reference.Canonical - namedRef reference.Named - ) + var namedRef reference.Named // TODO(thaJeztah): add a platform option-type / flag-type. if options.platform != "" { @@ -240,15 +236,6 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *c } if named, ok := ref.(reference.Named); ok { namedRef = reference.TagNameOnly(named) - - if taggedRef, ok := namedRef.(reference.NamedTagged); ok && !options.untrusted { - var err error - trustedRef, err = image.TrustedReference(ctx, dockerCli, taggedRef) - if err != nil { - return "", err - } - config.Image = reference.FamiliarString(trustedRef) - } } const dockerConfigPathInContainer = "/run/secrets/docker/config.json" @@ -331,9 +318,6 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *c if err := pullImage(ctx, dockerCli, config.Image, options); err != nil { return err } - if taggedRef, ok := namedRef.(reference.NamedTagged); ok && trustedRef != nil { - return trust.TagTrusted(ctx, dockerCli.Client(), dockerCli.Err(), trustedRef, taggedRef) - } return nil } diff --git a/cli/command/container/create_test.go b/cli/command/container/create_test.go index 4491a725f28d..597218cf7f13 100644 --- a/cli/command/container/create_test.go +++ b/cli/command/container/create_test.go @@ -13,7 +13,6 @@ import ( "github.com/docker/cli/cli" "github.com/docker/cli/cli/config/configfile" "github.com/docker/cli/internal/test" - "github.com/docker/cli/internal/test/notary" "github.com/google/go-cmp/cmp" "github.com/moby/moby/api/types/container" "github.com/moby/moby/api/types/system" @@ -136,10 +135,9 @@ func TestCreateContainerImagePullPolicy(t *testing.T) { } fakeCLI := test.NewFakeCli(apiClient) id, err := createContainer(context.Background(), fakeCLI, config, &createOptions{ - name: "name", - platform: runtime.GOOS, - untrusted: true, - pull: tc.PullPolicy, + name: "name", + platform: runtime.GOOS, + pull: tc.PullPolicy, }) if tc.ExpectedErrMsg != "" { @@ -215,51 +213,6 @@ func TestCreateContainerValidateFlags(t *testing.T) { } } -func TestNewCreateCommandWithContentTrustErrors(t *testing.T) { - testCases := []struct { - name string - args []string - expectedError string - notaryFunc test.NotaryClientFuncType - }{ - { - name: "offline-notary-server", - notaryFunc: notary.GetOfflineNotaryRepository, - expectedError: "client is offline", - args: []string{"image:tag"}, - }, - { - name: "uninitialized-notary-server", - notaryFunc: notary.GetUninitializedNotaryRepository, - expectedError: "remote trust data does not exist", - args: []string{"image:tag"}, - }, - { - name: "empty-notary-server", - notaryFunc: notary.GetEmptyTargetsNotaryRepository, - expectedError: "No valid trust data for tag", - args: []string{"image:tag"}, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - t.Setenv("DOCKER_CONTENT_TRUST", "true") - fakeCLI := test.NewFakeCli(&fakeClient{ - createContainerFunc: func(options client.ContainerCreateOptions) (client.ContainerCreateResult, error) { - return client.ContainerCreateResult{}, errors.New("shouldn't try to pull image") - }, - }) - fakeCLI.SetNotaryClient(tc.notaryFunc) - cmd := newCreateCommand(fakeCLI) - cmd.SetOut(io.Discard) - cmd.SetErr(io.Discard) - cmd.SetArgs(tc.args) - err := cmd.Execute() - assert.ErrorContains(t, err, tc.expectedError) - }) - } -} - func TestNewCreateCommandWithWarnings(t *testing.T) { testCases := []struct { name string diff --git a/cli/command/container/run.go b/cli/command/container/run.go index 1d7d56c08c80..2d75ec765b06 100644 --- a/cli/command/container/run.go +++ b/cli/command/container/run.go @@ -12,7 +12,6 @@ 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" @@ -73,7 +72,10 @@ func newRunCommand(dockerCLI command.Cli) *cobra.Command { // TODO(thaJeztah): consider adding platform as "image create option" on containerOptions flags.StringVar(&options.platform, "platform", os.Getenv("DOCKER_DEFAULT_PLATFORM"), "Set platform if server is multi-platform capable") _ = flags.SetAnnotation("platform", "version", []string{"1.32"}) - flags.BoolVar(&options.untrusted, "disable-content-trust", !trust.Enabled(), "Skip image verification") + + // TODO(thaJeztah): DEPRECATED: remove in v29.1 or v30 + flags.Bool("disable-content-trust", true, "Skip image verification (deprecated)") + _ = flags.MarkDeprecated("disable-content-trust", "support for docker content trust was removed") 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 4772bee0b315..c60ff0629a79 100644 --- a/cli/command/container/run_test.go +++ b/cli/command/container/run_test.go @@ -13,7 +13,6 @@ import ( "github.com/docker/cli/cli" "github.com/docker/cli/cli/streams" "github.com/docker/cli/internal/test" - "github.com/docker/cli/internal/test/notary" "github.com/moby/moby/api/types" "github.com/moby/moby/api/types/container" "github.com/moby/moby/client" @@ -295,54 +294,6 @@ func TestRunPullTermination(t *testing.T) { } } -func TestRunCommandWithContentTrustErrors(t *testing.T) { - testCases := []struct { - name string - args []string - expectedError string - notaryFunc test.NotaryClientFuncType - }{ - { - name: "offline-notary-server", - notaryFunc: notary.GetOfflineNotaryRepository, - expectedError: "client is offline", - args: []string{"image:tag"}, - }, - { - name: "uninitialized-notary-server", - notaryFunc: notary.GetUninitializedNotaryRepository, - expectedError: "remote trust data does not exist", - args: []string{"image:tag"}, - }, - { - name: "empty-notary-server", - notaryFunc: notary.GetEmptyTargetsNotaryRepository, - expectedError: "No valid trust data for tag", - args: []string{"image:tag"}, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - t.Setenv("DOCKER_CONTENT_TRUST", "true") - fakeCLI := test.NewFakeCli(&fakeClient{ - createContainerFunc: func(options client.ContainerCreateOptions) (client.ContainerCreateResult, error) { - return client.ContainerCreateResult{}, errors.New("shouldn't try to pull image") - }, - }) - fakeCLI.SetNotaryClient(tc.notaryFunc) - cmd := newRunCommand(fakeCLI) - cmd.SetArgs(tc.args) - cmd.SetOut(io.Discard) - cmd.SetErr(io.Discard) - err := cmd.Execute() - statusErr := cli.StatusError{} - assert.Check(t, errors.As(err, &statusErr)) - assert.Check(t, is.Equal(statusErr.StatusCode, 125)) - assert.Check(t, is.ErrorContains(err, tc.expectedError)) - }) - } -} - func TestRunContainerImagePullPolicyInvalid(t *testing.T) { cases := []struct { PullPolicy string diff --git a/cli/command/image/build.go b/cli/command/image/build.go index 8915308b3210..db33e0e7c64d 100644 --- a/cli/command/image/build.go +++ b/cli/command/image/build.go @@ -149,8 +149,9 @@ 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") + // TODO(thaJeztah): DEPRECATED: remove in v29.1 or v30 flags.Bool("disable-content-trust", true, "Skip image verification (deprecated)") - _ = flags.MarkHidden("disable-content-trust") + _ = flags.MarkDeprecated("disable-content-trust", "support for docker content trust was removed") flags.StringVar(&options.platform, "platform", os.Getenv("DOCKER_DEFAULT_PLATFORM"), "Set platform if server is multi-platform capable") flags.SetAnnotation("platform", "version", []string{"1.38"}) diff --git a/cli/command/image/pull.go b/cli/command/image/pull.go index e076781bf258..7485d21a6880 100644 --- a/cli/command/image/pull.go +++ b/cli/command/image/pull.go @@ -13,10 +13,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/moby/moby/api/pkg/authconfig" - registrytypes "github.com/moby/moby/api/types/registry" "github.com/moby/moby/client" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/spf13/cobra" @@ -24,11 +21,10 @@ import ( // pullOptions defines what and how to pull. type pullOptions struct { - remote string - all bool - platform string - quiet bool - untrusted bool + remote string + all bool + platform string + quiet bool } // newPullCommand creates a new `docker pull` command @@ -57,7 +53,11 @@ func newPullCommand(dockerCLI command.Cli) *cobra.Command { flags.BoolVarP(&opts.all, "all-tags", "a", false, "Download all tagged images in the repository") flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Suppress verbose output") - flags.BoolVar(&opts.untrusted, "disable-content-trust", !trust.Enabled(), "Skip image verification") + + // TODO(thaJeztah): DEPRECATED: remove in v29.1 or v30 + flags.Bool("disable-content-trust", true, "Skip image verification (deprecated)") + _ = flags.MarkDeprecated("disable-content-trust", "support for docker content trust was removed") + flags.StringVar(&opts.platform, "platform", os.Getenv("DOCKER_DEFAULT_PLATFORM"), "Set platform if server is multi-platform capable") _ = flags.SetAnnotation("platform", "version", []string{"1.32"}) _ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms()) @@ -80,46 +80,22 @@ func runPull(ctx context.Context, dockerCLI command.Cli, opts pullOptions) error } } + var ociPlatforms []ocispec.Platform if opts.platform != "" { // TODO(thaJeztah): add a platform option-type / flag-type. - if _, err = platforms.Parse(opts.platform); err != nil { + p, err := platforms.Parse(opts.platform) + if err != nil { return err } + ociPlatforms = append(ociPlatforms, p) } - imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, authResolver(dockerCLI), distributionRef.String()) + encodedAuth, err := command.RetrieveAuthTokenFromImage(dockerCLI.ConfigFile(), distributionRef.String()) if err != nil { return err } - // Check if reference has a digest - _, isCanonical := distributionRef.(reference.Canonical) - if !opts.untrusted && !isCanonical { - if err := trustedPull(ctx, dockerCLI, imgRefAndAuth, opts); err != nil { - return err - } - } else { - if err := imagePullPrivileged(ctx, dockerCLI, imgRefAndAuth.Reference(), imgRefAndAuth.AuthConfig(), opts); err != nil { - return err - } - } - _, _ = fmt.Fprintln(dockerCLI.Out(), imgRefAndAuth.Reference().String()) - return nil -} - -// imagePullPrivileged pulls the image and displays it to the output -func imagePullPrivileged(ctx context.Context, dockerCLI command.Cli, ref reference.Named, authConfig *registrytypes.AuthConfig, opts pullOptions) error { - encodedAuth, err := authconfig.Encode(*authConfig) - if err != nil { - return err - } - var ociPlatforms []ocispec.Platform - if opts.platform != "" { - // Already validated. - ociPlatforms = append(ociPlatforms, platforms.MustParse(opts.platform)) - } - - responseBody, err := dockerCLI.Client().ImagePull(ctx, reference.FamiliarString(ref), client.ImagePullOptions{ + responseBody, err := dockerCLI.Client().ImagePull(ctx, reference.FamiliarString(distributionRef), client.ImagePullOptions{ RegistryAuth: encodedAuth, PrivilegeFunc: nil, All: opts.all, @@ -134,5 +110,9 @@ func imagePullPrivileged(ctx context.Context, dockerCLI command.Cli, ref referen if opts.quiet { out = streams.NewOut(io.Discard) } - return jsonstream.Display(ctx, responseBody, out) + if err := jsonstream.Display(ctx, responseBody, out); err != nil { + return err + } + _, _ = fmt.Fprintln(dockerCLI.Out(), distributionRef.String()) + return nil } diff --git a/cli/command/image/pull_test.go b/cli/command/image/pull_test.go index 73e2fc7d4f1b..eb8edfbca699 100644 --- a/cli/command/image/pull_test.go +++ b/cli/command/image/pull_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/docker/cli/internal/test" - "github.com/docker/cli/internal/test/notary" "github.com/moby/moby/client" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" @@ -89,49 +88,3 @@ func TestNewPullCommandSuccess(t *testing.T) { }) } } - -func TestNewPullCommandWithContentTrustErrors(t *testing.T) { - testCases := []struct { - name string - args []string - expectedError string - notaryFunc test.NotaryClientFuncType - }{ - { - name: "offline-notary-server", - notaryFunc: notary.GetOfflineNotaryRepository, - expectedError: "client is offline", - args: []string{"image:tag"}, - }, - { - name: "uninitialized-notary-server", - notaryFunc: notary.GetUninitializedNotaryRepository, - expectedError: "remote trust data does not exist", - args: []string{"image:tag"}, - }, - { - name: "empty-notary-server", - notaryFunc: notary.GetEmptyTargetsNotaryRepository, - expectedError: "No valid trust data for tag", - args: []string{"image:tag"}, - }, - } - 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) (client.ImagePullResponse, error) { - // FIXME(thaJeztah): how to mock this? - return fakeStreamResult{ReadCloser: http.NoBody}, nil - }, - }) - cli.SetNotaryClient(tc.notaryFunc) - cmd := newPullCommand(cli) - cmd.SetOut(io.Discard) - cmd.SetErr(io.Discard) - cmd.SetArgs(tc.args) - err := cmd.Execute() - assert.ErrorContains(t, err, tc.expectedError) - }) - } -} diff --git a/cli/command/image/push.go b/cli/command/image/push.go index 50ace2b20915..5a6c61f8b6d7 100644 --- a/cli/command/image/push.go +++ b/cli/command/image/push.go @@ -16,7 +16,6 @@ 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/tui" "github.com/moby/moby/api/types/auxprogress" @@ -27,11 +26,10 @@ import ( ) type pushOptions struct { - all bool - remote string - untrusted bool - quiet bool - platform string + all bool + remote string + quiet bool + platform string } // newPushCommand creates a new `docker push` command @@ -57,7 +55,10 @@ 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", !trust.Enabled(), "Skip image signing") + + // TODO(thaJeztah): DEPRECATED: remove in v29.1 or v30 + flags.Bool("disable-content-trust", true, "Skip image verification (deprecated)") + _ = flags.MarkDeprecated("disable-content-trust", "support for docker content trust was removed") // Don't default to DOCKER_DEFAULT_PLATFORM env variable, always default to // pushing the image as-is. This also avoids forcing the platform selection @@ -129,10 +130,6 @@ To push the complete multi-platform image, remove the --platform flag. } }() - if !opts.untrusted { - return pushTrustedReference(ctx, dockerCli, ref, responseBody) - } - if opts.quiet { err = jsonstream.Display(ctx, responseBody, streams.NewOut(io.Discard), jsonstream.WithAuxCallback(handleAux())) if err == nil { diff --git a/cli/command/image/trust.go b/cli/command/image/trust.go deleted file mode 100644 index 2c999a6cba3a..000000000000 --- a/cli/command/image/trust.go +++ /dev/null @@ -1,204 +0,0 @@ -package image - -import ( - "context" - "encoding/hex" - "errors" - "fmt" - "io" - - "github.com/distribution/reference" - "github.com/docker/cli/cli/command" - "github.com/docker/cli/cli/config" - "github.com/docker/cli/cli/trust" - "github.com/docker/cli/internal/registry" - registrytypes "github.com/moby/moby/api/types/registry" - "github.com/moby/moby/client" - "github.com/opencontainers/go-digest" - "github.com/sirupsen/logrus" - notaryclient "github.com/theupdateframework/notary/client" - "github.com/theupdateframework/notary/tuf/data" -) - -type target struct { - name string - digest digest.Digest - size int64 -} - -// notaryClientProvider is used in tests to provide a dummy notary client. -type notaryClientProvider interface { - NotaryClient() (notaryclient.Repository, error) -} - -// newNotaryClient provides a Notary Repository to interact with signed metadata for an image. -func newNotaryClient(cli command.Streams, repoInfo *trust.RepositoryInfo, authConfig *registrytypes.AuthConfig) (notaryclient.Repository, error) { - if ncp, ok := cli.(notaryClientProvider); ok { - // notaryClientProvider is used in tests to provide a dummy notary client. - return ncp.NotaryClient() - } - return trust.GetNotaryRepository(cli.In(), cli.Out(), command.UserAgent(), repoInfo, authConfig, "pull") -} - -// pushTrustedReference pushes a canonical reference to the trust server. -func pushTrustedReference(ctx context.Context, dockerCLI command.Cli, ref reference.Named, responseBody io.Reader) error { - // Resolve the Repository name from fqn to RepositoryInfo, and create an - // IndexInfo. Docker Content Trust uses the IndexInfo.Official field to - // select the right domain for Docker Hub's Notary server; - // https://github.com/docker/cli/blob/v28.4.0/cli/trust/trust.go#L65-L79 - indexInfo := registry.NewIndexInfo(ref) - repoInfo := &trust.RepositoryInfo{ - Name: reference.TrimNamed(ref), - Index: indexInfo, - } - authConfig := command.ResolveAuthConfig(dockerCLI.ConfigFile(), indexInfo) - return trust.PushTrustedReference(ctx, dockerCLI, repoInfo, ref, authConfig, responseBody, command.UserAgent()) -} - -// trustedPull handles content trust pulling of an image -func trustedPull(ctx context.Context, cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth, opts pullOptions) error { - refs, err := getTrustedPullTargets(cli, imgRefAndAuth) - if err != nil { - return err - } - - ref := imgRefAndAuth.Reference() - for i, r := range refs { - displayTag := r.name - if displayTag != "" { - displayTag = ":" + displayTag - } - _, _ = fmt.Fprintf(cli.Out(), "Pull (%d of %d): %s%s@%s\n", i+1, len(refs), reference.FamiliarName(ref), displayTag, r.digest) - - trustedRef, err := reference.WithDigest(reference.TrimNamed(ref), r.digest) - if err != nil { - return err - } - updatedImgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, authResolver(cli), trustedRef.String()) - if err != nil { - return err - } - if err := imagePullPrivileged(ctx, cli, updatedImgRefAndAuth.Reference(), updatedImgRefAndAuth.AuthConfig(), pullOptions{ - all: false, - platform: opts.platform, - quiet: opts.quiet, - remote: opts.remote, - }); err != nil { - return err - } - - tagged, err := reference.WithTag(reference.TrimNamed(ref), r.name) - if err != nil { - return err - } - - // Use familiar references when interacting with client and output - familiarRef := reference.FamiliarString(tagged) - trustedFamiliarRef := reference.FamiliarString(trustedRef) - _, _ = fmt.Fprintf(cli.Err(), "Tagging %s as %s\n", trustedFamiliarRef, familiarRef) - _, err = cli.Client().ImageTag(ctx, client.ImageTagOptions{ - Source: trustedFamiliarRef, - Target: familiarRef, - }) - if err != nil { - return err - } - } - return nil -} - -func getTrustedPullTargets(cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth) ([]target, error) { - notaryRepo, err := newNotaryClient(cli, imgRefAndAuth.RepoInfo(), imgRefAndAuth.AuthConfig()) - if err != nil { - return nil, fmt.Errorf("error establishing connection to trust repository: %w", err) - } - - ref := imgRefAndAuth.Reference() - tagged, isTagged := ref.(reference.NamedTagged) - if !isTagged { - // List all targets - targets, err := notaryRepo.ListTargets(trust.ReleasesRole, data.CanonicalTargetsRole) - if err != nil { - return nil, trust.NotaryError(ref.Name(), err) - } - var refs []target - for _, tgt := range targets { - t, err := convertTarget(tgt.Target) - if err != nil { - _, _ = fmt.Fprintf(cli.Err(), "Skipping target for %q\n", reference.FamiliarName(ref)) - continue - } - // Only list tags in the top level targets role or the releases delegation role - ignore - // all other delegation roles - if tgt.Role != trust.ReleasesRole && tgt.Role != data.CanonicalTargetsRole { - continue - } - refs = append(refs, t) - } - if len(refs) == 0 { - return nil, trust.NotaryError(ref.Name(), fmt.Errorf("no trusted tags for %s", ref.Name())) - } - return refs, nil - } - - t, err := notaryRepo.GetTargetByName(tagged.Tag(), trust.ReleasesRole, data.CanonicalTargetsRole) - if err != nil { - return nil, trust.NotaryError(ref.Name(), err) - } - // Only get the tag if it's in the top level targets role or the releases delegation role - // ignore it if it's in any other delegation roles - if t.Role != trust.ReleasesRole && t.Role != data.CanonicalTargetsRole { - return nil, trust.NotaryError(ref.Name(), fmt.Errorf("no trust data for %s", tagged.Tag())) - } - - logrus.Debugf("retrieving target for %s role", t.Role) - r, err := convertTarget(t.Target) - return []target{r}, err -} - -// TrustedReference returns the canonical trusted reference for an image reference -func TrustedReference(ctx context.Context, cli command.Cli, ref reference.NamedTagged) (reference.Canonical, error) { - imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, authResolver(cli), ref.String()) - if err != nil { - return nil, err - } - - notaryRepo, err := newNotaryClient(cli, imgRefAndAuth.RepoInfo(), imgRefAndAuth.AuthConfig()) - if err != nil { - return nil, fmt.Errorf("error establishing connection to trust repository: %w", err) - } - - t, err := notaryRepo.GetTargetByName(ref.Tag(), trust.ReleasesRole, data.CanonicalTargetsRole) - if err != nil { - return nil, trust.NotaryError(imgRefAndAuth.RepoInfo().Name.Name(), err) - } - // Only list tags in the top level targets role or the releases delegation role - ignore - // all other delegation roles - if t.Role != trust.ReleasesRole && t.Role != data.CanonicalTargetsRole { - return nil, trust.NotaryError(imgRefAndAuth.RepoInfo().Name.Name(), notaryclient.ErrNoSuchTarget(ref.Tag())) - } - r, err := convertTarget(t.Target) - if err != nil { - return nil, err - } - return reference.WithDigest(reference.TrimNamed(ref), r.digest) -} - -func convertTarget(t notaryclient.Target) (target, error) { - h, ok := t.Hashes["sha256"] - if !ok { - return target{}, errors.New("no valid hash, expecting sha256") - } - return target{ - name: t.Name, - digest: digest.NewDigestFromHex("sha256", hex.EncodeToString(h)), - size: t.Length, - }, nil -} - -// authResolver returns an auth resolver function from a [config.Provider]. -func authResolver(dockerCLI config.Provider) func(ctx context.Context, index *registrytypes.IndexInfo) registrytypes.AuthConfig { - return func(ctx context.Context, index *registrytypes.IndexInfo) registrytypes.AuthConfig { - return command.ResolveAuthConfig(dockerCLI.ConfigFile(), index) - } -} diff --git a/cli/command/manifest/annotate.go b/cli/command/manifest/annotate.go index 052fd375cf8a..76385f079c8c 100644 --- a/cli/command/manifest/annotate.go +++ b/cli/command/manifest/annotate.go @@ -44,6 +44,27 @@ func newManifestStore(dockerCLI command.Cli) store.Store { return store.NewStore(filepath.Join(config.Dir(), "manifests")) } +// authConfigKey is the key used to store credentials for Docker Hub. It is +// a copy of [registry.IndexServer]. +// +// [registry.IndexServer]: https://pkg.go.dev/github.com/docker/docker@v28.3.3+incompatible/registry#IndexServer +const authConfigKey = "https://index.docker.io/v1/" + +// getAuthConfigKey special-cases using the full index address of the official +// index as the AuthConfig key, and uses the (host)name[:port] for private indexes. +// +// It is similar to [registry.GetAuthConfigKey], but does not require on +// [registrytypes.IndexInfo] as intermediate. +// +// [registry.GetAuthConfigKey]: https://pkg.go.dev/github.com/docker/docker@v28.3.3+incompatible/registry#GetAuthConfigKey +// [registrytypes.IndexInfo]: https://pkg.go.dev/github.com/docker/docker@v28.3.3+incompatible/api/types/registry#IndexInfo +func getAuthConfigKey(domainName string) string { + if domainName == "docker.io" || domainName == "index.docker.io" { + return authConfigKey + } + return domainName +} + // newRegistryClient returns a client for communicating with a Docker distribution // registry func newRegistryClient(dockerCLI command.Cli, allowInsecure bool) registryclient.RegistryClient { @@ -51,8 +72,20 @@ func newRegistryClient(dockerCLI command.Cli, allowInsecure bool) registryclient // manifestStoreProvider is used in tests to provide a dummy store. return msp.RegistryClient(allowInsecure) } - resolver := func(ctx context.Context, index *registry.IndexInfo) registry.AuthConfig { - return command.ResolveAuthConfig(dockerCLI.ConfigFile(), index) + cfg := dockerCLI.ConfigFile() + resolver := func(ctx context.Context, domainName string) registry.AuthConfig { + configKey := getAuthConfigKey(domainName) + a, _ := cfg.GetAuthConfig(configKey) + return registry.AuthConfig{ + Username: a.Username, + Password: a.Password, + ServerAddress: a.ServerAddress, + + // TODO(thaJeztah): Are these expected to be included? + Auth: a.Auth, + IdentityToken: a.IdentityToken, + RegistryToken: a.RegistryToken, + } } // FIXME(thaJeztah): this should use the userAgent as configured on the dockerCLI. return registryclient.NewRegistryClient(resolver, command.UserAgent(), allowInsecure) diff --git a/cli/command/plugin/install.go b/cli/command/plugin/install.go index 652ac8deb73f..7d2d9aafaeb0 100644 --- a/cli/command/plugin/install.go +++ b/cli/command/plugin/install.go @@ -44,8 +44,10 @@ 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") + + // TODO(thaJeztah): DEPRECATED: remove in v29.1 or v30 flags.Bool("disable-content-trust", true, "Skip image verification (deprecated)") - _ = flags.MarkHidden("disable-content-trust") + _ = flags.MarkDeprecated("disable-content-trust", "support for docker content trust was removed") return cmd } diff --git a/cli/command/plugin/push.go b/cli/command/plugin/push.go index 4264af3b9b11..af76db49ebef 100644 --- a/cli/command/plugin/push.go +++ b/cli/command/plugin/push.go @@ -26,8 +26,9 @@ func newPushCommand(dockerCLI command.Cli) *cobra.Command { } flags := cmd.Flags() + // TODO(thaJeztah): DEPRECATED: remove in v29.1 or v30 flags.Bool("disable-content-trust", true, "Skip image verification (deprecated)") - _ = flags.MarkHidden("disable-content-trust") + _ = flags.MarkDeprecated("disable-content-trust", "support for docker content trust was removed") return cmd } diff --git a/cli/command/plugin/upgrade.go b/cli/command/plugin/upgrade.go index 395eb98d5bf1..9053ce6e8980 100644 --- a/cli/command/plugin/upgrade.go +++ b/cli/command/plugin/upgrade.go @@ -34,8 +34,9 @@ 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") + // TODO(thaJeztah): DEPRECATED: remove in v29.1 or v30 flags.Bool("disable-content-trust", true, "Skip image verification (deprecated)") - _ = flags.MarkHidden("disable-content-trust") + _ = flags.MarkDeprecated("disable-content-trust", "support for docker content trust was removed") flags.BoolVar(&options.skipRemoteCheck, "skip-remote-check", false, "Do not check if specified remote plugin matches existing plugin image") return cmd } diff --git a/cli/command/registry.go b/cli/command/registry.go index 71d0b680d3ac..87c81c6da5da 100644 --- a/cli/command/registry.go +++ b/cli/command/registry.go @@ -39,10 +39,7 @@ const authConfigKey = "https://index.docker.io/v1/" // credential-store. It returns an empty AuthConfig if no credentials were // found. // -// It is similar to [registry.ResolveAuthConfig], but uses the credentials- -// store, instead of looking up credentials from a map. -// -// [registry.ResolveAuthConfig]: https://pkg.go.dev/github.com/docker/docker@v28.3.3+incompatible/registry#ResolveAuthConfig +// Deprecated: this function is no longer used, and will be removed in the next release. func ResolveAuthConfig(cfg *configfile.ConfigFile, index *registrytypes.IndexInfo) registrytypes.AuthConfig { configKey := index.Name if index.Official { diff --git a/cli/command/service/create.go b/cli/command/service/create.go index cea9a91d1b5e..45406d7b2633 100644 --- a/cli/command/service/create.go +++ b/cli/command/service/create.go @@ -115,10 +115,6 @@ func runCreate(ctx context.Context, dockerCLI command.Cli, flags *pflag.FlagSet, return err } - if err := resolveServiceImageDigestContentTrust(dockerCLI, &service); err != nil { - return err - } - // only send auth if flag was set var encodedAuth string if opts.registryAuth { diff --git a/cli/command/service/trust.go b/cli/command/service/trust.go deleted file mode 100644 index cb4f6fe5f728..000000000000 --- a/cli/command/service/trust.go +++ /dev/null @@ -1,86 +0,0 @@ -package service - -import ( - "encoding/hex" - "errors" - "fmt" - - "github.com/distribution/reference" - "github.com/docker/cli/cli/command" - "github.com/docker/cli/cli/trust" - "github.com/docker/cli/internal/registry" - "github.com/moby/moby/api/types/swarm" - "github.com/opencontainers/go-digest" - "github.com/sirupsen/logrus" - "github.com/theupdateframework/notary/tuf/data" -) - -func resolveServiceImageDigestContentTrust(dockerCli command.Cli, service *swarm.ServiceSpec) error { - if !trust.Enabled() { - // When not using content trust, digest resolution happens later when - // contacting the registry to retrieve image information. - return nil - } - - ref, err := reference.ParseAnyReference(service.TaskTemplate.ContainerSpec.Image) - if err != nil { - return fmt.Errorf("invalid reference %s: %w", service.TaskTemplate.ContainerSpec.Image, err) - } - - // If reference does not have digest (is not canonical nor image id) - if _, ok := ref.(reference.Digested); !ok { - namedRef, ok := ref.(reference.Named) - if !ok { - return errors.New("failed to resolve image digest using content trust: reference is not named") - } - namedRef = reference.TagNameOnly(namedRef) - taggedRef, ok := namedRef.(reference.NamedTagged) - if !ok { - return errors.New("failed to resolve image digest using content trust: reference is not tagged") - } - - resolvedImage, err := trustedResolveDigest(dockerCli, taggedRef) - if err != nil { - return fmt.Errorf("failed to resolve image digest using content trust: %w", err) - } - resolvedFamiliar := reference.FamiliarString(resolvedImage) - logrus.Debugf("resolved image tag to %s using content trust", resolvedFamiliar) - service.TaskTemplate.ContainerSpec.Image = resolvedFamiliar - } - - return nil -} - -func trustedResolveDigest(cli command.Cli, ref reference.NamedTagged) (reference.Canonical, error) { - indexInfo := registry.NewIndexInfo(ref) - authConfig := command.ResolveAuthConfig(cli.ConfigFile(), indexInfo) - repoInfo := &trust.RepositoryInfo{ - Name: reference.TrimNamed(ref), - Index: indexInfo, - } - notaryRepo, err := trust.GetNotaryRepository(cli.In(), cli.Out(), command.UserAgent(), repoInfo, &authConfig, "pull") - if err != nil { - return nil, fmt.Errorf("error establishing connection to trust repository: %w", err) - } - - t, err := notaryRepo.GetTargetByName(ref.Tag(), trust.ReleasesRole, data.CanonicalTargetsRole) - if err != nil { - return nil, trust.NotaryError(repoInfo.Name.Name(), err) - } - // Only get the tag if it's in the top level targets role or the releases delegation role - // ignore it if it's in any other delegation roles - if t.Role != trust.ReleasesRole && t.Role != data.CanonicalTargetsRole { - return nil, trust.NotaryError(repoInfo.Name.Name(), fmt.Errorf("no trust data for %s", reference.FamiliarString(ref))) - } - - logrus.Debugf("retrieving target for %s role", t.Role) - h, ok := t.Hashes["sha256"] - if !ok { - return nil, errors.New("no valid hash, expecting sha256") - } - - dgst := digest.NewDigestFromHex("sha256", hex.EncodeToString(h)) - - // Allow returning canonical reference with tag - return reference.WithDigest(ref, dgst) -} diff --git a/cli/command/service/update.go b/cli/command/service/update.go index 38913e3d2b63..0d07742f4bc6 100644 --- a/cli/command/service/update.go +++ b/cli/command/service/update.go @@ -193,9 +193,6 @@ func runUpdate(ctx context.Context, dockerCLI command.Cli, flags *pflag.FlagSet, } if flags.Changed("image") { - if err := resolveServiceImageDigestContentTrust(dockerCLI, spec); err != nil { - return err - } updateOpts.QueryRegistry = !options.noResolveImage } diff --git a/cli/command/trust/common.go b/cli/command/trust/common.go index 437b439729b7..2b8ad9daea2e 100644 --- a/cli/command/trust/common.go +++ b/cli/command/trust/common.go @@ -9,6 +9,7 @@ import ( "github.com/docker/cli/cli/command" "github.com/docker/cli/cli/config" + "github.com/docker/cli/cli/config/configfile" "github.com/docker/cli/cli/trust" "github.com/fvbommel/sortorder" registrytypes "github.com/moby/moby/api/types/registry" @@ -172,6 +173,39 @@ func matchReleasedSignatures(allTargets []client.TargetSignedStruct) []trustTagR // authResolver returns an auth resolver function from a [config.Provider]. func authResolver(dockerCLI config.Provider) func(ctx context.Context, index *registrytypes.IndexInfo) registrytypes.AuthConfig { return func(ctx context.Context, index *registrytypes.IndexInfo) registrytypes.AuthConfig { - return command.ResolveAuthConfig(dockerCLI.ConfigFile(), index) + return resolveAuthConfig(dockerCLI.ConfigFile(), index) + } +} + +// authConfigKey is the key used to store credentials for Docker Hub. It is +// a copy of [registry.IndexServer]. +// +// [registry.IndexServer]: https://pkg.go.dev/github.com/docker/docker@v28.3.3+incompatible/registry#IndexServer +const authConfigKey = "https://index.docker.io/v1/" + +// resolveAuthConfig returns auth-config for the given registry from the +// credential-store. It returns an empty AuthConfig if no credentials were +// found. +// +// It is similar to [registry.ResolveAuthConfig], but uses the credentials- +// store, instead of looking up credentials from a map. +// +// [registry.ResolveAuthConfig]: https://pkg.go.dev/github.com/docker/docker@v28.3.3+incompatible/registry#ResolveAuthConfig +func resolveAuthConfig(cfg *configfile.ConfigFile, index *registrytypes.IndexInfo) registrytypes.AuthConfig { + configKey := index.Name + if index.Official { + configKey = authConfigKey + } + + a, _ := cfg.GetAuthConfig(configKey) + return registrytypes.AuthConfig{ + Username: a.Username, + Password: a.Password, + ServerAddress: a.ServerAddress, + + // TODO(thaJeztah): Are these expected to be included? + Auth: a.Auth, + IdentityToken: a.IdentityToken, + RegistryToken: a.RegistryToken, } } diff --git a/cli/command/trust/sign.go b/cli/command/trust/sign.go index 0af3f7f0f25b..8d3489ec994b 100644 --- a/cli/command/trust/sign.go +++ b/cli/command/trust/sign.go @@ -92,7 +92,7 @@ func runSignImage(ctx context.Context, dockerCLI command.Cli, options signOption } _, _ = fmt.Fprintf(dockerCLI.Err(), "Signing and pushing trust data for local image %s, may overwrite remote trust data\n", imageName) - authConfig := command.ResolveAuthConfig(dockerCLI.ConfigFile(), imgRefAndAuth.RepoInfo().Index) + authConfig := resolveAuthConfig(dockerCLI.ConfigFile(), imgRefAndAuth.RepoInfo().Index) encodedAuth, err := authconfig.Encode(authConfig) if err != nil { return err diff --git a/docs/reference/commandline/container_create.md b/docs/reference/commandline/container_create.md index e22bea253fc9..5bb5e18442db 100644 --- a/docs/reference/commandline/container_create.md +++ b/docs/reference/commandline/container_create.md @@ -37,7 +37,6 @@ Create a new container | `--device-read-iops` | `list` | | Limit read rate (IO per second) from a device | | `--device-write-bps` | `list` | | Limit write rate (bytes per second) to a device | | `--device-write-iops` | `list` | | Limit write rate (IO per second) to a device | -| `--disable-content-trust` | `bool` | `true` | Skip image verification | | `--dns` | `list` | | Set custom DNS servers | | `--dns-option` | `list` | | Set DNS options | | `--dns-search` | `list` | | Set custom DNS search domains | diff --git a/docs/reference/commandline/container_run.md b/docs/reference/commandline/container_run.md index 41aaba0ff9a9..fa2b44354c4d 100644 --- a/docs/reference/commandline/container_run.md +++ b/docs/reference/commandline/container_run.md @@ -39,7 +39,6 @@ Create and run a new container from an image | `--device-read-iops` | `list` | | Limit read rate (IO per second) from a device | | `--device-write-bps` | `list` | | Limit write rate (bytes per second) to a device | | `--device-write-iops` | `list` | | Limit write rate (IO per second) to a device | -| `--disable-content-trust` | `bool` | `true` | Skip image verification | | `--dns` | `list` | | Set custom DNS servers | | `--dns-option` | `list` | | Set DNS options | | `--dns-search` | `list` | | Set custom DNS search domains | diff --git a/docs/reference/commandline/create.md b/docs/reference/commandline/create.md index 24867406acac..5a7390b7f26c 100644 --- a/docs/reference/commandline/create.md +++ b/docs/reference/commandline/create.md @@ -37,7 +37,6 @@ Create a new container | `--device-read-iops` | `list` | | Limit read rate (IO per second) from a device | | `--device-write-bps` | `list` | | Limit write rate (bytes per second) to a device | | `--device-write-iops` | `list` | | Limit write rate (IO per second) to a device | -| `--disable-content-trust` | `bool` | `true` | Skip image verification | | `--dns` | `list` | | Set custom DNS servers | | `--dns-option` | `list` | | Set DNS options | | `--dns-search` | `list` | | Set custom DNS search domains | diff --git a/docs/reference/commandline/docker.md b/docs/reference/commandline/docker.md index 03dbddc8cced..92be792819aa 100644 --- a/docs/reference/commandline/docker.md +++ b/docs/reference/commandline/docker.md @@ -123,8 +123,6 @@ line: | `DOCKER_API_VERSION` | Override the negotiated API version to use for debugging (e.g. `1.19`) | | `DOCKER_CERT_PATH` | Location of your authentication keys. This variable is used both by the `docker` CLI and the [`dockerd` daemon](https://docs.docker.com/reference/cli/dockerd/) | | `DOCKER_CONFIG` | The location of your client configuration files. | -| `DOCKER_CONTENT_TRUST_SERVER` | The URL of the Notary server to use. Defaults to the same URL as the registry. | -| `DOCKER_CONTENT_TRUST` | When set Docker uses notary to sign and verify images. Equates to `--disable-content-trust=false` for build, create, pull, push, run. | | `DOCKER_CONTEXT` | Name of the `docker context` to use (overrides `DOCKER_HOST` env var and default context set with `docker context use`) | | `DOCKER_CUSTOM_HEADERS` | (Experimental) Configure [custom HTTP headers](#custom-http-headers) to be sent by the client. Headers must be provided as a comma-separated list of `name=value` pairs. This is the equivalent to the `HttpHeaders` field in the configuration file. | | `DOCKER_DEFAULT_PLATFORM` | Default platform for commands that take the `--platform` flag. | diff --git a/docs/reference/commandline/image_pull.md b/docs/reference/commandline/image_pull.md index 3d390a294e49..aad73fe29ade 100644 --- a/docs/reference/commandline/image_pull.md +++ b/docs/reference/commandline/image_pull.md @@ -12,7 +12,6 @@ Download an image from a registry | Name | Type | Default | Description | |:---------------------------------------------|:---------|:--------|:-------------------------------------------------| | [`-a`](#all-tags), [`--all-tags`](#all-tags) | `bool` | | Download all tagged images in the repository | -| `--disable-content-trust` | `bool` | `true` | Skip image verification | | `--platform` | `string` | | Set platform if server is multi-platform capable | | `-q`, `--quiet` | `bool` | | Suppress verbose output | diff --git a/docs/reference/commandline/image_push.md b/docs/reference/commandline/image_push.md index 91f6a41be1f0..543563398d7a 100644 --- a/docs/reference/commandline/image_push.md +++ b/docs/reference/commandline/image_push.md @@ -12,7 +12,6 @@ Upload an image to a registry | Name | Type | Default | Description | |:---------------------------------------------|:---------|:--------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [`-a`](#all-tags), [`--all-tags`](#all-tags) | `bool` | | Push all tags of an image to the repository | -| `--disable-content-trust` | `bool` | `true` | Skip image signing | | `--platform` | `string` | | Push a platform-specific manifest as a single-platform image to the registry.
Image index won't be pushed, meaning that other manifests, including attestations won't be preserved.
'os[/arch[/variant]]': Explicit platform (eg. linux/amd64) | | `-q`, `--quiet` | `bool` | | Suppress verbose output | diff --git a/docs/reference/commandline/pull.md b/docs/reference/commandline/pull.md index 66acb611da1b..3cc2b0f94f93 100644 --- a/docs/reference/commandline/pull.md +++ b/docs/reference/commandline/pull.md @@ -9,12 +9,11 @@ Download an image from a registry ### Options -| Name | Type | Default | Description | -|:--------------------------|:---------|:--------|:-------------------------------------------------| -| `-a`, `--all-tags` | `bool` | | Download all tagged images in the repository | -| `--disable-content-trust` | `bool` | `true` | Skip image verification | -| `--platform` | `string` | | Set platform if server is multi-platform capable | -| `-q`, `--quiet` | `bool` | | Suppress verbose output | +| Name | Type | Default | Description | +|:-------------------|:---------|:--------|:-------------------------------------------------| +| `-a`, `--all-tags` | `bool` | | Download all tagged images in the repository | +| `--platform` | `string` | | Set platform if server is multi-platform capable | +| `-q`, `--quiet` | `bool` | | Suppress verbose output | diff --git a/docs/reference/commandline/push.md b/docs/reference/commandline/push.md index 9558d38e5ebc..61f48b22abfd 100644 --- a/docs/reference/commandline/push.md +++ b/docs/reference/commandline/push.md @@ -9,12 +9,11 @@ Upload an image to a registry ### Options -| Name | Type | Default | Description | -|:--------------------------|:---------|:--------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `-a`, `--all-tags` | `bool` | | Push all tags of an image to the repository | -| `--disable-content-trust` | `bool` | `true` | Skip image signing | -| `--platform` | `string` | | Push a platform-specific manifest as a single-platform image to the registry.
Image index won't be pushed, meaning that other manifests, including attestations won't be preserved.
'os[/arch[/variant]]': Explicit platform (eg. linux/amd64) | -| `-q`, `--quiet` | `bool` | | Suppress verbose output | +| Name | Type | Default | Description | +|:-------------------|:---------|:--------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `-a`, `--all-tags` | `bool` | | Push all tags of an image to the repository | +| `--platform` | `string` | | Push a platform-specific manifest as a single-platform image to the registry.
Image index won't be pushed, meaning that other manifests, including attestations won't be preserved.
'os[/arch[/variant]]': Explicit platform (eg. linux/amd64) | +| `-q`, `--quiet` | `bool` | | Suppress verbose output | diff --git a/docs/reference/commandline/run.md b/docs/reference/commandline/run.md index dcc5cd24bf67..d544a9cdf5fe 100644 --- a/docs/reference/commandline/run.md +++ b/docs/reference/commandline/run.md @@ -39,7 +39,6 @@ Create and run a new container from an image | `--device-read-iops` | `list` | | Limit read rate (IO per second) from a device | | `--device-write-bps` | `list` | | Limit write rate (bytes per second) to a device | | `--device-write-iops` | `list` | | Limit write rate (IO per second) to a device | -| `--disable-content-trust` | `bool` | `true` | Skip image verification | | `--dns` | `list` | | Set custom DNS servers | | `--dns-option` | `list` | | Set DNS options | | `--dns-search` | `list` | | Set custom DNS search domains | diff --git a/internal/registryclient/client.go b/internal/registryclient/client.go index 71d6b227cee4..20f0eda11d7f 100644 --- a/internal/registryclient/client.go +++ b/internal/registryclient/client.go @@ -34,7 +34,7 @@ func NewRegistryClient(resolver AuthConfigResolver, userAgent string, insecure b } // AuthConfigResolver returns Auth Configuration for an index -type AuthConfigResolver func(ctx context.Context, index *registrytypes.IndexInfo) registrytypes.AuthConfig +type AuthConfigResolver func(ctx context.Context, hostName string) registrytypes.AuthConfig type client struct { authConfigResolver AuthConfigResolver @@ -146,7 +146,7 @@ func (c *client) getRepositoryForReference(ctx context.Context, ref reference.Na func (c *client) getHTTPTransportForRepoEndpoint(ctx context.Context, repoEndpoint repositoryEndpoint) (http.RoundTripper, error) { httpTransport, err := getHTTPTransport( - c.authConfigResolver(ctx, repoEndpoint.indexInfo), + c.authConfigResolver(ctx, repoEndpoint.indexInfo.Name), repoEndpoint.endpoint, repoEndpoint.repoName, c.userAgent,