Skip to content

Commit 5928b3f

Browse files
committed
WIP: don't require IndexInfo
Lots to do here; too many wrappers everywhere, which may become easier when content trust is removed (which adds another level of abstraction) Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
1 parent 8f71270 commit 5928b3f

File tree

8 files changed

+59
-24
lines changed

8 files changed

+59
-24
lines changed

cli/command/cli_deprecated.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ func (*DockerCli) ManifestStore() manifeststore.Store {
4949
//
5050
// Deprecated: use [registryclient.NewRegistryClient]. This method is no longer used and will be removed in the next release.
5151
func (cli *DockerCli) RegistryClient(allowInsecure bool) registryclient.RegistryClient {
52+
// FIXME(thaJezttah); this signature is problematic; we should also use a "resolver" everywhere (instead of passing around the creds?)
5253
resolver := func(ctx context.Context, index *registry.IndexInfo) registry.AuthConfig {
5354
return ResolveAuthConfig(cli.ConfigFile(), index)
5455
}

cli/command/image/push.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import (
1919
"github.com/docker/cli/internal/tui"
2020
"github.com/docker/docker/api/types/auxprogress"
2121
"github.com/docker/docker/api/types/image"
22-
registrytypes "github.com/docker/docker/api/types/registry"
2322
"github.com/docker/docker/registry"
2423
"github.com/morikuni/aec"
2524
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
@@ -112,13 +111,15 @@ To push the complete multi-platform image, remove the --platform flag.
112111
return err
113112
}
114113

115-
// Resolve the Auth config relevant for this server
114+
// FIXME(thaJeztah): this os only needed for docker content trust, which needs the raw, non-encoded authconfig
116115
authConfig := command.ResolveAuthConfig(dockerCli.ConfigFile(), repoInfo.Index)
117-
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
116+
117+
// Resolve the Auth config relevant for this server
118+
encodedAuth, err := command.RetrieveAuthTokenFromImage(dockerCli.ConfigFile(), ref.String())
118119
if err != nil {
119120
return err
120121
}
121-
requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(dockerCli, repoInfo.Index, "push")
122+
requestPrivilege := command.NewAuthRequester(dockerCli, reference.Domain(ref), "Login prior to push:")
122123
options := image.PushOptions{
123124
All: opts.all,
124125
RegistryAuth: encodedAuth,

cli/command/image/trust.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,13 +166,14 @@ func getTrustedPullTargets(cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth)
166166

167167
// imagePullPrivileged pulls the image and displays it to the output
168168
func imagePullPrivileged(ctx context.Context, cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth, opts PullOptions) error {
169+
// TODO(thaJeztah): get rid of this trust.ImageRefAndAuth monstrosity; we're wrapping wrappers around wrappers; all we need here is the image ref (or even less: the registry name)
169170
encodedAuth, err := registrytypes.EncodeAuthConfig(*imgRefAndAuth.AuthConfig())
170171
if err != nil {
171172
return err
172173
}
173-
requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(cli, imgRefAndAuth.RepoInfo().Index, "pull")
174+
requestPrivilege := command.NewAuthRequester(cli, reference.Domain(imgRefAndAuth.Reference()), "Login prior to pull:")
174175
responseBody, err := cli.Client().ImagePull(ctx, reference.FamiliarString(imgRefAndAuth.Reference()), image.PullOptions{
175-
RegistryAuth: encodedAuth,
176+
RegistryAuth: encodedAuth, // TODO: can we get rid of this one altogether, and always use PrivilegeFunc to lazily fetch creds? (maybe we need a way to tell it to either use "stored", or request login)
176177
PrivilegeFunc: requestPrivilege,
177178
All: opts.all,
178179
Platform: opts.platform,

cli/command/plugin/install.go

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ import (
1111
"github.com/docker/cli/cli/command/image"
1212
"github.com/docker/cli/cli/internal/jsonstream"
1313
"github.com/docker/docker/api/types"
14-
registrytypes "github.com/docker/docker/api/types/registry"
15-
"github.com/docker/docker/registry"
1614
"github.com/pkg/errors"
1715
"github.com/spf13/cobra"
1816
"github.com/spf13/pflag"
@@ -64,7 +62,9 @@ func buildPullConfig(ctx context.Context, dockerCli command.Cli, opts pluginOpti
6462
return types.PluginInstallOptions{}, err
6563
}
6664

67-
repoInfo, err := registry.ParseRepositoryInfo(ref)
65+
// TODO(thaJeztah): looks like we need to do this here, because "ref" is mutated further below? (because .. docker content trust?)
66+
privilegeFunc := command.NewAuthRequester(dockerCli, reference.Domain(ref), fmt.Sprintf("Login prior to %s:", cmdName))
67+
encodedAuth, err := command.RetrieveAuthTokenFromImage(dockerCli.ConfigFile(), ref.String())
6868
if err != nil {
6969
return types.PluginInstallOptions{}, err
7070
}
@@ -86,19 +86,13 @@ func buildPullConfig(ctx context.Context, dockerCli command.Cli, opts pluginOpti
8686
remote = reference.FamiliarString(trusted)
8787
}
8888

89-
authConfig := command.ResolveAuthConfig(dockerCli.ConfigFile(), repoInfo.Index)
90-
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
91-
if err != nil {
92-
return types.PluginInstallOptions{}, err
93-
}
94-
9589
options := types.PluginInstallOptions{
9690
RegistryAuth: encodedAuth,
9791
RemoteRef: remote,
9892
Disabled: opts.disable,
9993
AcceptAllPermissions: opts.grantPerms,
10094
AcceptPermissionsFunc: acceptPrivileges(dockerCli, opts.remote),
101-
PrivilegeFunc: command.RegistryAuthenticationPrivilegedFunc(dockerCli, repoInfo.Index, cmdName),
95+
PrivilegeFunc: privilegeFunc,
10296
Args: opts.args,
10397
}
10498
return options, nil

cli/command/plugin/push.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"github.com/docker/cli/cli/command"
99
"github.com/docker/cli/cli/internal/jsonstream"
1010
"github.com/docker/cli/cli/trust"
11-
registrytypes "github.com/docker/docker/api/types/registry"
1211
"github.com/docker/docker/registry"
1312
"github.com/pkg/errors"
1413
"github.com/spf13/cobra"
@@ -53,8 +52,10 @@ func runPush(ctx context.Context, dockerCli command.Cli, opts pushOptions) error
5352
if err != nil {
5453
return err
5554
}
55+
56+
// FIXME(thaJeztah): this is now only used by docker content trust below
5657
authConfig := command.ResolveAuthConfig(dockerCli.ConfigFile(), repoInfo.Index)
57-
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
58+
encodedAuth, err := command.RetrieveAuthTokenFromImage(dockerCli.ConfigFile(), named.String())
5859
if err != nil {
5960
return err
6061
}

cli/command/registry.go

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,39 @@ const (
3333
// [registry.IndexServer]: https://pkg.go.dev/github.com/docker/docker/registry#IndexServer
3434
const authConfigKey = "https:/index.docker.io/v1/"
3535

36+
// NewAuthRequester returns a RequestPrivilegeFunc for the specified registry
37+
// and the given cmdName (used as informational message to the user).
38+
//
39+
// The returned function is a [registrytypes.RequestAuthConfig] to prompt the user
40+
// for credentials if needed. It is called as fallback if the credentials (if any)
41+
// used for the initial operation did not work.
42+
//
43+
// TODO(thaJeztah): cli Cli could be a Streams if it was not for cli.SetIn to be needed?
44+
// TODO(thaJeztah): ideally, this would accept reposName / imageRef as a regular string (we can parse it if needed!), or .. maybe generics and accept either?
45+
func NewAuthRequester(cli Cli, indexServer string, promptMsg string) registrytypes.RequestAuthConfig {
46+
configKey := getAuthConfigKey(indexServer)
47+
return newPrivilegeFunc(cli, configKey, promptMsg)
48+
}
49+
3650
// RegistryAuthenticationPrivilegedFunc returns a RequestPrivilegeFunc from the specified registry index info
3751
// for the given command.
52+
//
53+
// Deprecated: this function was only used internally and will be removed in the next release. Use
3854
func RegistryAuthenticationPrivilegedFunc(cli Cli, index *registrytypes.IndexInfo, cmdName string) registrytypes.RequestAuthConfig {
39-
indexServer := getAuthConfigKey(index.Name)
40-
isDefaultRegistry := indexServer == authConfigKey || index.Official
55+
indexServer := index.Name
56+
configKey := getAuthConfigKey(indexServer)
57+
if index.Official {
58+
configKey = authConfigKey
59+
}
60+
promptMsg := fmt.Sprintf("Login prior to %s:", cmdName)
61+
return newPrivilegeFunc(cli, configKey, promptMsg)
62+
}
63+
64+
func newPrivilegeFunc(cli Cli, indexServer string, promptMsg string) registrytypes.RequestAuthConfig {
4165
return func(ctx context.Context) (string, error) {
42-
_, _ = fmt.Fprintf(cli.Out(), "\nLogin prior to %s:\n", cmdName)
66+
// TODO(thaJeztah): can we make the prompt an argument? ("prompt func()" or "prompt func()?
67+
_, _ = fmt.Fprintf(cli.Out(), "\n"+promptMsg+"\n")
68+
isDefaultRegistry := indexServer == authConfigKey
4369
authConfig, err := GetDefaultAuthConfig(cli.ConfigFile(), true, indexServer, isDefaultRegistry)
4470
if err != nil {
4571
_, _ = fmt.Fprintf(cli.Err(), "Unable to retrieve stored credentials for %s, error: %s.\n", authConfigKey, err)
@@ -66,7 +92,8 @@ func RegistryAuthenticationPrivilegedFunc(cli Cli, index *registrytypes.IndexInf
6692
// It is similar to [registry.ResolveAuthConfig], but uses the credentials-
6793
// store, instead of looking up credentials from a map.
6894
func ResolveAuthConfig(cfg *configfile.ConfigFile, index *registrytypes.IndexInfo) registrytypes.AuthConfig {
69-
configKey := index.Name
95+
indexServer := index.Name
96+
configKey := getAuthConfigKey(indexServer)
7097
if index.Official {
7198
configKey = authConfigKey
7299
}
@@ -79,6 +106,7 @@ func ResolveAuthConfig(cfg *configfile.ConfigFile, index *registrytypes.IndexInf
79106
// If credentials for given serverAddress exists in the credential store, the configuration will be populated with values in it
80107
func GetDefaultAuthConfig(cfg *configfile.ConfigFile, checkCredStore bool, serverAddress string, isDefaultRegistry bool) (registrytypes.AuthConfig, error) {
81108
if !isDefaultRegistry {
109+
// FIXME(thaJeztah): should the same logic be used for getAuthConfigKey ?? Looks like we're normalizing things here, but not elsewhere? why?
82110
serverAddress = credentials.ConvertToHostname(serverAddress)
83111
}
84112
authconfig := configtypes.AuthConfig{}
@@ -122,6 +150,8 @@ func ConfigureAuth(ctx context.Context, cli Cli, flUser, flPassword string, auth
122150
// If defaultUsername is not empty, the username prompt includes that username
123151
// and the user can hit enter without inputting a username to use that default
124152
// username.
153+
//
154+
// TODO(thaJeztah): cli Cli could be a Streams if it was not for cli.SetIn to be needed?
125155
func PromptUserForCredentials(ctx context.Context, cli Cli, argUser, argPassword, defaultUsername, serverAddress string) (registrytypes.AuthConfig, error) {
126156
// On Windows, force the use of the regular OS stdin stream.
127157
//
@@ -211,12 +241,15 @@ func PromptUserForCredentials(ctx context.Context, cli Cli, argUser, argPassword
211241
//
212242
// For details on base64url encoding, see:
213243
// - RFC4648, section 5: https://tools.ietf.org/html/rfc4648#section-5
244+
//
245+
// FIXME(thaJeztah): do we need a variant like this, but with "indexServer" (domainName) as input?
214246
func RetrieveAuthTokenFromImage(cfg *configfile.ConfigFile, image string) (string, error) {
215247
// Retrieve encoded auth token from the image reference
216248
authConfig, err := resolveAuthConfigFromImage(cfg, image)
217249
if err != nil {
218250
return "", err
219251
}
252+
// FIXME(thaJeztah); implement stringer (.String()) or "MarshalText / UnmarshalText" on AuthConfig, so that we can pass it around as-is, and encode where it needs to be encoded (when making requests).
220253
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
221254
if err != nil {
222255
return "", err
@@ -225,6 +258,8 @@ func RetrieveAuthTokenFromImage(cfg *configfile.ConfigFile, image string) (strin
225258
}
226259

227260
// resolveAuthConfigFromImage retrieves that AuthConfig using the image string
261+
//
262+
// TODO(thaJeztah): export this and/or accept an image ref-type, and use instead of ResolveAuthConfig
228263
func resolveAuthConfigFromImage(cfg *configfile.ConfigFile, image string) (registrytypes.AuthConfig, error) {
229264
registryRef, err := reference.ParseNormalizedNamed(image)
230265
if err != nil {

cli/command/registry/search.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ func runSearch(ctx context.Context, dockerCli command.Cli, options searchOptions
5252
if options.filter.Value().Contains("is-automated") {
5353
_, _ = fmt.Fprintln(dockerCli.Err(), `WARNING: the "is-automated" filter is deprecated, and searching for "is-automated=true" will not yield any results in future.`)
5454
}
55+
// FIXME(thaJeztah): we need some equivalent of "splitReposSearchTerm" to get the registry hostname from the search term.
5556
indexInfo, err := registry.ParseSearchIndexInfo(options.term)
5657
if err != nil {
5758
return err
@@ -63,7 +64,8 @@ func runSearch(ctx context.Context, dockerCli command.Cli, options searchOptions
6364
return err
6465
}
6566

66-
requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(dockerCli, indexInfo, "search")
67+
indexServer := indexInfo.Name
68+
requestPrivilege := command.NewAuthRequester(dockerCli, indexServer, "Login prior to search:")
6769
results, err := dockerCli.Client().ImageSearch(ctx, options.term, registrytypes.SearchOptions{
6870
RegistryAuth: encodedAuth,
6971
PrivilegeFunc: requestPrivilege,

cli/command/trust/sign.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ func runSignImage(ctx context.Context, dockerCLI command.Cli, options signOption
8282
return trust.NotaryError(imgRefAndAuth.RepoInfo().Name.Name(), err)
8383
}
8484
}
85-
requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(dockerCLI, imgRefAndAuth.RepoInfo().Index, "push")
85+
requestPrivilege := command.NewAuthRequester(dockerCLI, reference.Domain(imgRefAndAuth.Reference()), "Login prior to push:")
8686
target, err := createTarget(notaryRepo, imgRefAndAuth.Tag())
8787
if err != nil || options.local {
8888
switch err := err.(type) {

0 commit comments

Comments
 (0)