Skip to content

Commit df692c7

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 8977c3c commit df692c7

File tree

11 files changed

+78
-36
lines changed

11 files changed

+78
-36
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 & 7 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"
@@ -104,16 +103,12 @@ To push the complete multi-platform image, remove the --platform flag.
104103
}
105104
}
106105

107-
// Resolve the Repository name from fqn to RepositoryInfo
108-
repoInfo, _ := registry.ParseRepositoryInfo(ref)
109-
110106
// Resolve the Auth config relevant for this server
111-
authConfig := command.ResolveAuthConfig(dockerCli.ConfigFile(), repoInfo.Index)
112-
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
107+
encodedAuth, err := command.RetrieveAuthTokenFromImage(dockerCli.ConfigFile(), ref.String())
113108
if err != nil {
114109
return err
115110
}
116-
requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(dockerCli, repoInfo.Index, "push")
111+
requestPrivilege := command.NewAuthRequester(dockerCli, reference.Domain(ref), "Login prior to push:")
117112
options := image.PushOptions{
118113
All: opts.all,
119114
RegistryAuth: encodedAuth,
@@ -134,6 +129,9 @@ To push the complete multi-platform image, remove the --platform flag.
134129

135130
defer responseBody.Close()
136131
if !opts.untrusted {
132+
repoInfo, _ := registry.ParseRepositoryInfo(ref)
133+
authConfig := command.ResolveAuthConfig(dockerCli.ConfigFile(), repoInfo.Index)
134+
137135
// TODO pushTrustedReference currently doesn't respect `--quiet`
138136
return pushTrustedReference(ctx, dockerCli, repoInfo, ref, authConfig, responseBody)
139137
}

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 wee always use PrivilegeFunc; 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: 7 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,12 @@ func buildPullConfig(ctx context.Context, dockerCli command.Cli, opts pluginOpti
6462
return types.PluginInstallOptions{}, err
6563
}
6664

67-
repoInfo, _ := 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())
68+
if err != nil {
69+
return types.PluginInstallOptions{}, err
70+
}
6871

6972
remote := ref.String()
7073

@@ -83,19 +86,13 @@ func buildPullConfig(ctx context.Context, dockerCli command.Cli, opts pluginOpti
8386
remote = reference.FamiliarString(trusted)
8487
}
8588

86-
authConfig := command.ResolveAuthConfig(dockerCli.ConfigFile(), repoInfo.Index)
87-
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
88-
if err != nil {
89-
return types.PluginInstallOptions{}, err
90-
}
91-
9289
options := types.PluginInstallOptions{
9390
RegistryAuth: encodedAuth,
9491
RemoteRef: remote,
9592
Disabled: opts.disable,
9693
AcceptAllPermissions: opts.grantPerms,
9794
AcceptPermissionsFunc: acceptPrivileges(dockerCli, opts.remote),
98-
PrivilegeFunc: command.RegistryAuthenticationPrivilegedFunc(dockerCli, repoInfo.Index, cmdName),
95+
PrivilegeFunc: privilegeFunc,
9996
Args: opts.args,
10097
}
10198
return options, nil

cli/command/plugin/push.go

Lines changed: 3 additions & 4 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"
@@ -49,9 +48,7 @@ func runPush(ctx context.Context, dockerCli command.Cli, opts pushOptions) error
4948

5049
named = reference.TagNameOnly(named)
5150

52-
repoInfo, _ := registry.ParseRepositoryInfo(named)
53-
authConfig := command.ResolveAuthConfig(dockerCli.ConfigFile(), repoInfo.Index)
54-
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
51+
encodedAuth, err := command.RetrieveAuthTokenFromImage(dockerCli.ConfigFile(), named.String())
5552
if err != nil {
5653
return err
5754
}
@@ -63,6 +60,8 @@ func runPush(ctx context.Context, dockerCli command.Cli, opts pushOptions) error
6360
defer responseBody.Close()
6461

6562
if !opts.untrusted {
63+
repoInfo, _ := registry.ParseRepositoryInfo(named)
64+
authConfig := command.ResolveAuthConfig(dockerCli.ConfigFile(), repoInfo.Index)
6665
return trust.PushTrustedReference(ctx, dockerCli, repoInfo, named, authConfig, responseBody, command.UserAgent())
6766
}
6867

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.Fprint(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 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) {

cli/registry/client/client.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ func (c *client) getRepositoryForReference(ctx context.Context, ref reference.Na
147147

148148
func (c *client) getHTTPTransportForRepoEndpoint(ctx context.Context, repoEndpoint repositoryEndpoint) (http.RoundTripper, error) {
149149
httpTransport, err := getHTTPTransport(
150-
c.authConfigResolver(ctx, repoEndpoint.info.Index),
150+
c.authConfigResolver(ctx, repoEndpoint.indexInfo),
151151
repoEndpoint.endpoint,
152152
repoEndpoint.Name(),
153153
c.userAgent,

cli/registry/client/endpoint.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,15 @@ import (
1414
)
1515

1616
type repositoryEndpoint struct {
17-
info *registry.RepositoryInfo
18-
endpoint registry.APIEndpoint
19-
actions []string
17+
name string
18+
indexInfo *registrytypes.IndexInfo
19+
endpoint registry.APIEndpoint
20+
actions []string
2021
}
2122

2223
// Name returns the repository name
2324
func (r repositoryEndpoint) Name() string {
24-
return reference.Path(r.info.Name)
25+
return r.name
2526
}
2627

2728
// BaseURL returns the endpoint url
@@ -38,7 +39,11 @@ func newDefaultRepositoryEndpoint(ref reference.Named, insecure bool) (repositor
3839
if insecure {
3940
endpoint.TLSConfig.InsecureSkipVerify = true
4041
}
41-
return repositoryEndpoint{info: repoInfo, endpoint: endpoint}, nil
42+
return repositoryEndpoint{
43+
name: reference.Path(repoInfo.Name),
44+
indexInfo: repoInfo.Index,
45+
endpoint: endpoint,
46+
}, nil
4247
}
4348

4449
func getDefaultEndpointFromRepoInfo(repoInfo *registry.RepositoryInfo) (registry.APIEndpoint, error) {

0 commit comments

Comments
 (0)