diff --git a/cli/command/cli.go b/cli/command/cli.go index a000bcc246..dfc22b701f 100644 --- a/cli/command/cli.go +++ b/cli/command/cli.go @@ -189,7 +189,7 @@ func (cli *DockerCli) ManifestStore() manifeststore.Store { // registry func (cli *DockerCli) RegistryClient(allowInsecure bool) registryclient.RegistryClient { resolver := func(ctx context.Context, index *registry.IndexInfo) registry.AuthConfig { - return ResolveAuthConfig(ctx, cli, index) + return ResolveAuthConfig(cli.ConfigFile(), index) } return registryclient.NewRegistryClient(resolver, UserAgent(), allowInsecure) } diff --git a/cli/command/container/create.go b/cli/command/container/create.go index bd594124d0..89273b8d99 100644 --- a/cli/command/container/create.go +++ b/cli/command/container/create.go @@ -114,7 +114,7 @@ func runCreate(dockerCli command.Cli, flags *pflag.FlagSet, options *createOptio // FIXME(thaJeztah): this is the only code-path that uses APIClient.ImageCreate. Rewrite this to use the regular "pull" code (or vice-versa). func pullImage(ctx context.Context, dockerCli command.Cli, image string, opts *createOptions) error { - encodedAuth, err := command.RetrieveAuthTokenFromImage(ctx, dockerCli, image) + encodedAuth, err := command.RetrieveAuthTokenFromImage(dockerCli.ConfigFile(), image) if err != nil { return err } diff --git a/cli/command/image/push.go b/cli/command/image/push.go index f60a92c33c..de8a79530b 100644 --- a/cli/command/image/push.go +++ b/cli/command/image/push.go @@ -76,7 +76,7 @@ func RunPush(dockerCli command.Cli, opts pushOptions) error { ctx := context.Background() // Resolve the Auth config relevant for this server - authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index) + authConfig := command.ResolveAuthConfig(dockerCli.ConfigFile(), repoInfo.Index) encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig) if err != nil { return err diff --git a/cli/command/image/trust.go b/cli/command/image/trust.go index 3da1e8032e..a02c50dfc3 100644 --- a/cli/command/image/trust.go +++ b/cli/command/image/trust.go @@ -339,6 +339,6 @@ func TagTrusted(ctx context.Context, cli command.Cli, trustedRef reference.Canon // AuthResolver returns an auth resolver function from a command.Cli func AuthResolver(cli command.Cli) func(ctx context.Context, index *registrytypes.IndexInfo) registrytypes.AuthConfig { return func(ctx context.Context, index *registrytypes.IndexInfo) registrytypes.AuthConfig { - return command.ResolveAuthConfig(ctx, cli, index) + return command.ResolveAuthConfig(cli.ConfigFile(), index) } } diff --git a/cli/command/plugin/install.go b/cli/command/plugin/install.go index 2b6d3040cf..fbd0c5dbdd 100644 --- a/cli/command/plugin/install.go +++ b/cli/command/plugin/install.go @@ -79,19 +79,18 @@ func buildPullConfig(ctx context.Context, dockerCli command.Cli, opts pluginOpti return types.PluginInstallOptions{}, errors.Errorf("invalid name: %s", ref.String()) } - trusted, err := image.TrustedReference(context.Background(), dockerCli, nt) + trusted, err := image.TrustedReference(ctx, dockerCli, nt) if err != nil { return types.PluginInstallOptions{}, err } remote = reference.FamiliarString(trusted) } - authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index) + authConfig := command.ResolveAuthConfig(dockerCli.ConfigFile(), repoInfo.Index) encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig) if err != nil { return types.PluginInstallOptions{}, err } - registryAuthFunc := command.RegistryAuthenticationPrivilegedFunc(dockerCli, repoInfo.Index, cmdName) options := types.PluginInstallOptions{ RegistryAuth: encodedAuth, @@ -99,7 +98,7 @@ func buildPullConfig(ctx context.Context, dockerCli command.Cli, opts pluginOpti Disabled: opts.disable, AcceptAllPermissions: opts.grantPerms, AcceptPermissionsFunc: acceptPrivileges(dockerCli, opts.remote), - PrivilegeFunc: registryAuthFunc, + PrivilegeFunc: command.RegistryAuthenticationPrivilegedFunc(dockerCli, repoInfo.Index, cmdName), Args: opts.args, } return options, nil diff --git a/cli/command/plugin/push.go b/cli/command/plugin/push.go index bb03bcfc11..f6973d4323 100644 --- a/cli/command/plugin/push.go +++ b/cli/command/plugin/push.go @@ -55,7 +55,7 @@ func runPush(dockerCli command.Cli, opts pushOptions) error { if err != nil { return err } - authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index) + authConfig := command.ResolveAuthConfig(dockerCli.ConfigFile(), repoInfo.Index) encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig) if err != nil { return err diff --git a/cli/command/registry.go b/cli/command/registry.go index 94f58fe541..c3ee03f998 100644 --- a/cli/command/registry.go +++ b/cli/command/registry.go @@ -2,13 +2,13 @@ package command import ( "bufio" - "context" "fmt" "io" "os" "runtime" "strings" + "github.com/docker/cli/cli/config/configfile" configtypes "github.com/docker/cli/cli/config/types" "github.com/docker/cli/cli/streams" "github.com/docker/distribution/reference" @@ -26,7 +26,7 @@ func RegistryAuthenticationPrivilegedFunc(cli Cli, index *registrytypes.IndexInf fmt.Fprintf(cli.Out(), "\nPlease login prior to %s:\n", cmdName) indexServer := registry.GetAuthConfigKey(index) isDefaultRegistry := indexServer == registry.IndexServer - authConfig, err := GetDefaultAuthConfig(cli, true, indexServer, isDefaultRegistry) + authConfig, err := GetDefaultAuthConfig(cli.ConfigFile(), true, indexServer, isDefaultRegistry) if err != nil { fmt.Fprintf(cli.Err(), "Unable to retrieve stored credentials for %s, error: %s.\n", indexServer, err) } @@ -44,26 +44,26 @@ func RegistryAuthenticationPrivilegedFunc(cli Cli, index *registrytypes.IndexInf // // It is similar to [registry.ResolveAuthConfig], but uses the credentials- // store, instead of looking up credentials from a map. -func ResolveAuthConfig(_ context.Context, cli Cli, index *registrytypes.IndexInfo) registrytypes.AuthConfig { +func ResolveAuthConfig(cfg *configfile.ConfigFile, index *registrytypes.IndexInfo) registrytypes.AuthConfig { configKey := index.Name if index.Official { configKey = registry.IndexServer } - a, _ := cli.ConfigFile().GetAuthConfig(configKey) + a, _ := cfg.GetAuthConfig(configKey) return registrytypes.AuthConfig(a) } // GetDefaultAuthConfig gets the default auth config given a serverAddress // If credentials for given serverAddress exists in the credential store, the configuration will be populated with values in it -func GetDefaultAuthConfig(cli Cli, checkCredStore bool, serverAddress string, isDefaultRegistry bool) (registrytypes.AuthConfig, error) { +func GetDefaultAuthConfig(cfg *configfile.ConfigFile, checkCredStore bool, serverAddress string, isDefaultRegistry bool) (registrytypes.AuthConfig, error) { if !isDefaultRegistry { serverAddress = registry.ConvertToHostname(serverAddress) } authconfig := configtypes.AuthConfig{} var err error if checkCredStore { - authconfig, err = cli.ConfigFile().GetAuthConfig(serverAddress) + authconfig, err = cfg.GetAuthConfig(serverAddress) if err != nil { return registrytypes.AuthConfig{ ServerAddress: serverAddress, @@ -72,8 +72,7 @@ func GetDefaultAuthConfig(cli Cli, checkCredStore bool, serverAddress string, is } authconfig.ServerAddress = serverAddress authconfig.IdentityToken = "" - res := registrytypes.AuthConfig(authconfig) - return res, nil + return registrytypes.AuthConfig(authconfig), nil } // ConfigureAuth handles prompting of user's username and password if needed @@ -172,9 +171,9 @@ func promptWithDefault(out io.Writer, prompt string, configDefault string) { // // For details on base64url encoding, see: // - RFC4648, section 5: https://tools.ietf.org/html/rfc4648#section-5 -func RetrieveAuthTokenFromImage(ctx context.Context, cli Cli, image string) (string, error) { +func RetrieveAuthTokenFromImage(cfg *configfile.ConfigFile, image string) (string, error) { // Retrieve encoded auth token from the image reference - authConfig, err := resolveAuthConfigFromImage(ctx, cli, image) + authConfig, err := resolveAuthConfigFromImage(cfg, image) if err != nil { return "", err } @@ -186,7 +185,7 @@ func RetrieveAuthTokenFromImage(ctx context.Context, cli Cli, image string) (str } // resolveAuthConfigFromImage retrieves that AuthConfig using the image string -func resolveAuthConfigFromImage(ctx context.Context, cli Cli, image string) (registrytypes.AuthConfig, error) { +func resolveAuthConfigFromImage(cfg *configfile.ConfigFile, image string) (registrytypes.AuthConfig, error) { registryRef, err := reference.ParseNormalizedNamed(image) if err != nil { return registrytypes.AuthConfig{}, err @@ -195,5 +194,5 @@ func resolveAuthConfigFromImage(ctx context.Context, cli Cli, image string) (reg if err != nil { return registrytypes.AuthConfig{}, err } - return ResolveAuthConfig(ctx, cli, repoInfo.Index), nil + return ResolveAuthConfig(cfg, repoInfo.Index), nil } diff --git a/cli/command/registry/login.go b/cli/command/registry/login.go index 7ddfccca20..6098c1863e 100644 --- a/cli/command/registry/login.go +++ b/cli/command/registry/login.go @@ -117,7 +117,7 @@ func runLogin(dockerCli command.Cli, opts loginOptions) error { //nolint:gocyclo } isDefaultRegistry := serverAddress == registry.IndexServer - authConfig, err := command.GetDefaultAuthConfig(dockerCli, opts.user == "" && opts.password == "", serverAddress, isDefaultRegistry) + authConfig, err := command.GetDefaultAuthConfig(dockerCli.ConfigFile(), opts.user == "" && opts.password == "", serverAddress, isDefaultRegistry) if err == nil && authConfig.Username != "" && authConfig.Password != "" { response, err = loginWithCredStoreCreds(ctx, dockerCli, &authConfig) } diff --git a/cli/command/registry/search.go b/cli/command/registry/search.go index 6ba00b5236..86e3ae91e5 100644 --- a/cli/command/registry/search.go +++ b/cli/command/registry/search.go @@ -54,13 +54,13 @@ func runSearch(dockerCli command.Cli, options searchOptions) error { return err } - ctx := context.Background() - authConfig := command.ResolveAuthConfig(ctx, dockerCli, indexInfo) + authConfig := command.ResolveAuthConfig(dockerCli.ConfigFile(), indexInfo) encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig) if err != nil { return err } + ctx := context.Background() requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(dockerCli, indexInfo, "search") results, err := dockerCli.Client().ImageSearch(ctx, options.term, types.ImageSearchOptions{ RegistryAuth: encodedAuth, diff --git a/cli/command/registry_test.go b/cli/command/registry_test.go index 4fa8658ebc..1099dfd05b 100644 --- a/cli/command/registry_test.go +++ b/cli/command/registry_test.go @@ -1,26 +1,17 @@ package command_test import ( - "bytes" - "context" "fmt" "testing" . "github.com/docker/cli/cli/command" // Prevents a circular import with "github.com/docker/cli/internal/test" + "github.com/docker/cli/cli/config/configfile" configtypes "github.com/docker/cli/cli/config/types" - "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types/registry" - "github.com/docker/docker/api/types/system" - "github.com/docker/docker/client" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" ) -type fakeClient struct { - client.Client - infoFunc func() (system.Info, error) -} - var testAuthConfigs = []registry.AuthConfig{ { ServerAddress: "https://index.docker.io/v1/", @@ -34,13 +25,6 @@ var testAuthConfigs = []registry.AuthConfig{ }, } -func (cli *fakeClient) Info(_ context.Context) (system.Info, error) { - if cli.infoFunc != nil { - return cli.infoFunc() - } - return system.Info{}, nil -} - func TestGetDefaultAuthConfig(t *testing.T) { testCases := []struct { checkCredStore bool @@ -77,15 +61,13 @@ func TestGetDefaultAuthConfig(t *testing.T) { expectedAuthConfig: testAuthConfigs[1], }, } - cli := test.NewFakeCli(&fakeClient{}) - errBuf := new(bytes.Buffer) - cli.SetErr(errBuf) + cfg := configfile.New("filename") for _, authconfig := range testAuthConfigs { - cli.ConfigFile().GetCredentialsStore(authconfig.ServerAddress).Store(configtypes.AuthConfig(authconfig)) + cfg.GetCredentialsStore(authconfig.ServerAddress).Store(configtypes.AuthConfig(authconfig)) } for _, tc := range testCases { serverAddress := tc.inputServerAddress - authconfig, err := GetDefaultAuthConfig(cli, tc.checkCredStore, serverAddress, serverAddress == "https://index.docker.io/v1/") + authconfig, err := GetDefaultAuthConfig(cfg, tc.checkCredStore, serverAddress, serverAddress == "https://index.docker.io/v1/") if tc.expectedErr != "" { assert.Check(t, err != nil) assert.Check(t, is.Equal(tc.expectedErr, err.Error())) @@ -97,15 +79,14 @@ func TestGetDefaultAuthConfig(t *testing.T) { } func TestGetDefaultAuthConfig_HelperError(t *testing.T) { - cli := test.NewFakeCli(&fakeClient{}) - errBuf := new(bytes.Buffer) - cli.SetErr(errBuf) - cli.ConfigFile().CredentialsStore = "fake-does-not-exist" - serverAddress := "test-server-address" + cfg := configfile.New("filename") + cfg.CredentialsStore = "fake-does-not-exist" + + const serverAddress = "test-server-address" expectedAuthConfig := registry.AuthConfig{ ServerAddress: serverAddress, } - authconfig, err := GetDefaultAuthConfig(cli, true, serverAddress, serverAddress == "https://index.docker.io/v1/") + authconfig, err := GetDefaultAuthConfig(cfg, true, serverAddress, serverAddress == "https://index.docker.io/v1/") assert.Check(t, is.DeepEqual(expectedAuthConfig, authconfig)) assert.Check(t, is.ErrorContains(err, "docker-credential-fake-does-not-exist")) } diff --git a/cli/command/service/create.go b/cli/command/service/create.go index 8d4bc76cdd..d5b8fec087 100644 --- a/cli/command/service/create.go +++ b/cli/command/service/create.go @@ -112,7 +112,7 @@ func runCreate(dockerCli command.Cli, flags *pflag.FlagSet, opts *serviceOptions // only send auth if flag was set if opts.registryAuth { // Retrieve encoded auth token from the image reference - encodedAuth, err := command.RetrieveAuthTokenFromImage(ctx, dockerCli, opts.image) + encodedAuth, err := command.RetrieveAuthTokenFromImage(dockerCli.ConfigFile(), opts.image) if err != nil { return err } diff --git a/cli/command/service/trust.go b/cli/command/service/trust.go index b7453ccbb9..75b8fad124 100644 --- a/cli/command/service/trust.go +++ b/cli/command/service/trust.go @@ -1,7 +1,6 @@ package service import ( - "context" "encoding/hex" "github.com/docker/cli/cli/command" @@ -39,7 +38,7 @@ func resolveServiceImageDigestContentTrust(dockerCli command.Cli, service *swarm return errors.New("failed to resolve image digest using content trust: reference is not tagged") } - resolvedImage, err := trustedResolveDigest(context.Background(), dockerCli, taggedRef) + resolvedImage, err := trustedResolveDigest(dockerCli, taggedRef) if err != nil { return errors.Wrap(err, "failed to resolve image digest using content trust") } @@ -51,13 +50,13 @@ func resolveServiceImageDigestContentTrust(dockerCli command.Cli, service *swarm return nil } -func trustedResolveDigest(ctx context.Context, cli command.Cli, ref reference.NamedTagged) (reference.Canonical, error) { +func trustedResolveDigest(cli command.Cli, ref reference.NamedTagged) (reference.Canonical, error) { repoInfo, err := registry.ParseRepositoryInfo(ref) if err != nil { return nil, err } - authConfig := command.ResolveAuthConfig(ctx, cli, repoInfo.Index) + authConfig := command.ResolveAuthConfig(cli.ConfigFile(), repoInfo.Index) notaryRepo, err := trust.GetNotaryRepository(cli.In(), cli.Out(), command.UserAgent(), repoInfo, &authConfig, "pull") if err != nil { diff --git a/cli/command/service/update.go b/cli/command/service/update.go index 2ef9014cab..c087224ba4 100644 --- a/cli/command/service/update.go +++ b/cli/command/service/update.go @@ -223,7 +223,7 @@ func runUpdate(dockerCli command.Cli, flags *pflag.FlagSet, options *serviceOpti // Retrieve encoded auth token from the image reference // This would be the old image if it didn't change in this update image := spec.TaskTemplate.ContainerSpec.Image - encodedAuth, err := command.RetrieveAuthTokenFromImage(ctx, dockerCli, image) + encodedAuth, err := command.RetrieveAuthTokenFromImage(dockerCli.ConfigFile(), image) if err != nil { return err } diff --git a/cli/command/stack/swarm/deploy_composefile.go b/cli/command/stack/swarm/deploy_composefile.go index 778cdd9757..2d8a46639c 100644 --- a/cli/command/stack/swarm/deploy_composefile.go +++ b/cli/command/stack/swarm/deploy_composefile.go @@ -198,7 +198,7 @@ func deployServices(ctx context.Context, dockerCli command.Cli, services map[str if sendAuth { // Retrieve encoded auth token from the image reference - encodedAuth, err = command.RetrieveAuthTokenFromImage(ctx, dockerCli, image) + encodedAuth, err = command.RetrieveAuthTokenFromImage(dockerCli.ConfigFile(), image) if err != nil { return err } diff --git a/cli/command/trust/sign.go b/cli/command/trust/sign.go index 5f8f3c1014..7679b38f7c 100644 --- a/cli/command/trust/sign.go +++ b/cli/command/trust/sign.go @@ -93,7 +93,7 @@ func runSignImage(cli command.Cli, options signOptions) error { } fmt.Fprintf(cli.Err(), "Signing and pushing trust data for local image %s, may overwrite remote trust data\n", imageName) - authConfig := command.ResolveAuthConfig(ctx, cli, imgRefAndAuth.RepoInfo().Index) + authConfig := command.ResolveAuthConfig(cli.ConfigFile(), imgRefAndAuth.RepoInfo().Index) encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig) if err != nil { return err