Skip to content

Commit 3fac046

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 8e5fb5b commit 3fac046

File tree

9 files changed

+66
-34
lines changed

9 files changed

+66
-34
lines changed

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
@@ -145,13 +145,14 @@ func getTrustedPullTargets(cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth)
145145

146146
// imagePullPrivileged pulls the image and displays it to the output
147147
func imagePullPrivileged(ctx context.Context, cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth, opts pullOptions) error {
148+
// 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)
148149
encodedAuth, err := registrytypes.EncodeAuthConfig(*imgRefAndAuth.AuthConfig())
149150
if err != nil {
150151
return err
151152
}
152-
requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(cli, imgRefAndAuth.RepoInfo().Index, "pull")
153+
requestPrivilege := command.NewAuthRequester(cli, reference.Domain(imgRefAndAuth.Reference()), "Login prior to pull:")
153154
responseBody, err := cli.Client().ImagePull(ctx, reference.FamiliarString(imgRefAndAuth.Reference()), image.PullOptions{
154-
RegistryAuth: encodedAuth,
155+
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)
155156
PrivilegeFunc: requestPrivilege,
156157
All: opts.all,
157158
Platform: opts.platform,

cli/command/plugin/install.go

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ import (
1212
"github.com/docker/cli/internal/jsonstream"
1313
"github.com/docker/cli/internal/prompt"
1414
"github.com/docker/docker/api/types"
15-
registrytypes "github.com/docker/docker/api/types/registry"
16-
"github.com/docker/docker/registry"
1715
"github.com/pkg/errors"
1816
"github.com/spf13/cobra"
1917
"github.com/spf13/pflag"
@@ -65,7 +63,12 @@ func buildPullConfig(ctx context.Context, dockerCli command.Cli, opts pluginOpti
6563
return types.PluginInstallOptions{}, err
6664
}
6765

68-
repoInfo, _ := registry.ParseRepositoryInfo(ref)
66+
// TODO(thaJeztah): looks like we need to do this here, because "ref" is mutated further below? (because .. docker content trust?)
67+
privilegeFunc := command.NewAuthRequester(dockerCli, reference.Domain(ref), fmt.Sprintf("Login prior to %s:", cmdName))
68+
encodedAuth, err := command.RetrieveAuthTokenFromImage(dockerCli.ConfigFile(), ref.String())
69+
if err != nil {
70+
return types.PluginInstallOptions{}, err
71+
}
6972

7073
remote := ref.String()
7174

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

87-
authConfig := command.ResolveAuthConfig(dockerCli.ConfigFile(), repoInfo.Index)
88-
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
89-
if err != nil {
90-
return types.PluginInstallOptions{}, err
91-
}
92-
9390
options := types.PluginInstallOptions{
9491
RegistryAuth: encodedAuth,
9592
RemoteRef: remote,
9693
Disabled: opts.disable,
9794
AcceptAllPermissions: opts.grantPerms,
9895
AcceptPermissionsFunc: acceptPrivileges(dockerCli, opts.remote),
99-
PrivilegeFunc: command.RegistryAuthenticationPrivilegedFunc(dockerCli, repoInfo.Index, cmdName),
96+
PrivilegeFunc: privilegeFunc,
10097
Args: opts.args,
10198
}
10299
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/trust"
1010
"github.com/docker/cli/internal/jsonstream"
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: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,40 @@ const (
3434
// [registry.IndexServer]: https://pkg.go.dev/github.com/docker/docker/registry#IndexServer
3535
const authConfigKey = "https://index.docker.io/v1/"
3636

37+
// NewAuthRequester returns a RequestPrivilegeFunc for the specified registry
38+
// and the given cmdName (used as informational message to the user).
39+
//
40+
// The returned function is a [registrytypes.RequestAuthConfig] to prompt the user
41+
// for credentials if needed. It is called as fallback if the credentials (if any)
42+
// used for the initial operation did not work.
43+
//
44+
// TODO(thaJeztah): cli Cli could be a Streams if it was not for cli.SetIn to be needed?
45+
// TODO(thaJeztah): ideally, this would accept reposName / imageRef as a regular string (we can parse it if needed!), or .. maybe generics and accept either?
46+
func NewAuthRequester(cli Cli, indexServer string, promptMsg string) registrytypes.RequestAuthConfig {
47+
configKey := getAuthConfigKey(indexServer)
48+
return newPrivilegeFunc(cli, configKey, promptMsg)
49+
}
50+
3751
// RegistryAuthenticationPrivilegedFunc returns a RequestPrivilegeFunc from the specified registry index info
3852
// for the given command.
53+
//
54+
// Deprecated: this function was only used internally and will be removed in the next release. Use
3955
func RegistryAuthenticationPrivilegedFunc(cli Cli, index *registrytypes.IndexInfo, cmdName string) registrytypes.RequestAuthConfig {
40-
configKey := getAuthConfigKey(index.Name)
41-
isDefaultRegistry := configKey == authConfigKey || index.Official
56+
indexServer := index.Name
57+
configKey := getAuthConfigKey(indexServer)
58+
if index.Official {
59+
configKey = authConfigKey
60+
}
61+
promptMsg := fmt.Sprintf("Login prior to %s:", cmdName)
62+
return newPrivilegeFunc(cli, configKey, promptMsg)
63+
}
64+
65+
func newPrivilegeFunc(cli Cli, indexServer string, promptMsg string) registrytypes.RequestAuthConfig {
4266
return func(ctx context.Context) (string, error) {
43-
_, _ = fmt.Fprintf(cli.Out(), "\nLogin prior to %s:\n", cmdName)
44-
authConfig, err := GetDefaultAuthConfig(cli.ConfigFile(), true, configKey, isDefaultRegistry)
67+
// TODO(thaJeztah): can we make the prompt an argument? ("prompt func()" or "prompt func()?
68+
_, _ = fmt.Fprint(cli.Out(), "\n"+promptMsg+"\n")
69+
isDefaultRegistry := indexServer == authConfigKey
70+
authConfig, err := GetDefaultAuthConfig(cli.ConfigFile(), true, indexServer, isDefaultRegistry)
4571
if err != nil {
4672
_, _ = fmt.Fprintf(cli.Err(), "Unable to retrieve stored credentials for %s, error: %s.\n", authConfigKey, err)
4773
}
@@ -67,7 +93,8 @@ func RegistryAuthenticationPrivilegedFunc(cli Cli, index *registrytypes.IndexInf
6793
// It is similar to [registry.ResolveAuthConfig], but uses the credentials-
6894
// store, instead of looking up credentials from a map.
6995
func ResolveAuthConfig(cfg *configfile.ConfigFile, index *registrytypes.IndexInfo) registrytypes.AuthConfig {
70-
configKey := index.Name
96+
indexServer := index.Name
97+
configKey := getAuthConfigKey(indexServer)
7198
if index.Official {
7299
configKey = authConfigKey
73100
}
@@ -80,6 +107,7 @@ func ResolveAuthConfig(cfg *configfile.ConfigFile, index *registrytypes.IndexInf
80107
// If credentials for given serverAddress exists in the credential store, the configuration will be populated with values in it
81108
func GetDefaultAuthConfig(cfg *configfile.ConfigFile, checkCredStore bool, serverAddress string, isDefaultRegistry bool) (registrytypes.AuthConfig, error) {
82109
if !isDefaultRegistry {
110+
// FIXME(thaJeztah): should the same logic be used for getAuthConfigKey ?? Looks like we're normalizing things here, but not elsewhere? why?
83111
serverAddress = credentials.ConvertToHostname(serverAddress)
84112
}
85113
authconfig := configtypes.AuthConfig{}
@@ -123,6 +151,8 @@ func ConfigureAuth(ctx context.Context, cli Cli, flUser, flPassword string, auth
123151
// If defaultUsername is not empty, the username prompt includes that username
124152
// and the user can hit enter without inputting a username to use that default
125153
// username.
154+
//
155+
// TODO(thaJeztah): cli Cli could be a Streams if it was not for cli.SetIn to be needed?
126156
func PromptUserForCredentials(ctx context.Context, cli Cli, argUser, argPassword, defaultUsername, serverAddress string) (registrytypes.AuthConfig, error) {
127157
// On Windows, force the use of the regular OS stdin stream.
128158
//
@@ -215,12 +245,15 @@ func PromptUserForCredentials(ctx context.Context, cli Cli, argUser, argPassword
215245
//
216246
// For details on base64url encoding, see:
217247
// - RFC4648, section 5: https://tools.ietf.org/html/rfc4648#section-5
248+
//
249+
// FIXME(thaJeztah): do we need a variant like this, but with "indexServer" (domainName) as input?
218250
func RetrieveAuthTokenFromImage(cfg *configfile.ConfigFile, image string) (string, error) {
219251
// Retrieve encoded auth token from the image reference
220252
authConfig, err := resolveAuthConfigFromImage(cfg, image)
221253
if err != nil {
222254
return "", err
223255
}
256+
// 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).
224257
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
225258
if err != nil {
226259
return "", err
@@ -229,6 +262,8 @@ func RetrieveAuthTokenFromImage(cfg *configfile.ConfigFile, image string) (strin
229262
}
230263

231264
// resolveAuthConfigFromImage retrieves that AuthConfig using the image string
265+
//
266+
// TODO(thaJeztah): export this and/or accept an image ref-type, and use instead of ResolveAuthConfig
232267
func resolveAuthConfigFromImage(cfg *configfile.ConfigFile, image string) (registrytypes.AuthConfig, error) {
233268
registryRef, err := reference.ParseNormalizedNamed(image)
234269
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/endpoint.go

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

1616
type repositoryEndpoint struct {
17-
repoName reference.Named
17+
repoName string
1818
indexInfo *registrytypes.IndexInfo
1919
endpoint registry.APIEndpoint
2020
actions []string
2121
}
2222

2323
// Name returns the repository name
2424
func (r repositoryEndpoint) Name() string {
25-
return reference.Path(r.repoName)
25+
return r.repoName
2626
}
2727

2828
// BaseURL returns the endpoint url
@@ -43,7 +43,7 @@ func newDefaultRepositoryEndpoint(ref reference.Named, insecure bool) (repositor
4343
endpoint.TLSConfig.InsecureSkipVerify = true
4444
}
4545
return repositoryEndpoint{
46-
repoName: repoName,
46+
repoName: reference.Path(repoName),
4747
indexInfo: indexInfo,
4848
endpoint: endpoint,
4949
}, nil

cli/registry/client/fetcher.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ func (c *client) iterateEndpoints(ctx context.Context, namedRef reference.Named,
237237
endpoint.TLSConfig.InsecureSkipVerify = true
238238
}
239239
repoEndpoint := repositoryEndpoint{
240-
repoName: repoName,
240+
repoName: reference.Path(repoName),
241241
indexInfo: indexInfo,
242242
endpoint: endpoint,
243243
}

0 commit comments

Comments
 (0)