Skip to content

Commit 9b1df10

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 03ff54b commit 9b1df10

8 files changed

Lines changed: 56 additions & 27 deletions

File tree

cli/command/image/push.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"github.com/docker/docker/registry"
2121
"github.com/moby/moby/api/types/auxprogress"
2222
"github.com/moby/moby/api/types/image"
23-
registrytypes "github.com/moby/moby/api/types/registry"
2423
"github.com/morikuni/aec"
2524
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
2625
"github.com/pkg/errors"
@@ -104,12 +103,8 @@ 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
}
@@ -133,6 +128,9 @@ To push the complete multi-platform image, remove the --platform flag.
133128

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

cli/command/image/trust.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ 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

cli/command/plugin/install.go

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@ import (
1111
"github.com/docker/cli/cli/command/image"
1212
"github.com/docker/cli/internal/jsonstream"
1313
"github.com/docker/cli/internal/prompt"
14-
"github.com/docker/docker/registry"
1514
"github.com/moby/moby/api/types"
16-
registrytypes "github.com/moby/moby/api/types/registry"
1715
"github.com/pkg/errors"
1816
"github.com/spf13/cobra"
1917
"github.com/spf13/pflag"
@@ -65,7 +63,11 @@ 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+
encodedAuth, err := command.RetrieveAuthTokenFromImage(dockerCli.ConfigFile(), ref.String())
68+
if err != nil {
69+
return types.PluginInstallOptions{}, err
70+
}
6971

7072
remote := ref.String()
7173

@@ -84,12 +86,6 @@ func buildPullConfig(ctx context.Context, dockerCli command.Cli, opts pluginOpti
8486
remote = reference.FamiliarString(trusted)
8587
}
8688

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-
9389
options := types.PluginInstallOptions{
9490
RegistryAuth: encodedAuth,
9591
RemoteRef: remote,

cli/command/plugin/push.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,7 @@ func runPush(ctx context.Context, dockerCli command.Cli, opts pushOptions) error
4949

5050
named = reference.TagNameOnly(named)
5151

52-
repoInfo, _ := registry.ParseRepositoryInfo(named)
53-
authConfig := command.ResolveAuthConfig(dockerCli.ConfigFile(), repoInfo.Index)
54-
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
52+
encodedAuth, err := command.RetrieveAuthTokenFromImage(dockerCli.ConfigFile(), named.String())
5553
if err != nil {
5654
return err
5755
}
@@ -63,6 +61,8 @@ func runPush(ctx context.Context, dockerCli command.Cli, opts pushOptions) error
6361
defer responseBody.Close()
6462

6563
if !opts.untrusted {
64+
repoInfo, _ := registry.ParseRepositoryInfo(named)
65+
authConfig := command.ResolveAuthConfig(dockerCli.ConfigFile(), repoInfo.Index)
6666
return trust.PushTrustedReference(ctx, dockerCli, repoInfo, named, authConfig, responseBody, command.UserAgent())
6767
}
6868

cli/command/registry.go

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +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 to prompt the user for username and password.
3953
//
4054
// Deprecated: this function is no longer used and will be removed in the next release.
4155
func RegistryAuthenticationPrivilegedFunc(cli Cli, index *registrytypes.IndexInfo, cmdName string) registrytypes.RequestAuthConfig {
42-
configKey := getAuthConfigKey(index.Name)
43-
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 {
4466
return func(ctx context.Context) (string, error) {
45-
_, _ = fmt.Fprintf(cli.Out(), "\nLogin prior to %s:\n", cmdName)
46-
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)
4771
if err != nil {
4872
_, _ = fmt.Fprintf(cli.Err(), "Unable to retrieve stored credentials for %s, error: %s.\n", configKey, err)
4973
}
@@ -69,7 +93,8 @@ func RegistryAuthenticationPrivilegedFunc(cli Cli, index *registrytypes.IndexInf
6993
// It is similar to [registry.ResolveAuthConfig], but uses the credentials-
7094
// store, instead of looking up credentials from a map.
7195
func ResolveAuthConfig(cfg *configfile.ConfigFile, index *registrytypes.IndexInfo) registrytypes.AuthConfig {
72-
configKey := index.Name
96+
indexServer := index.Name
97+
configKey := getAuthConfigKey(indexServer)
7398
if index.Official {
7499
configKey = authConfigKey
75100
}
@@ -82,6 +107,7 @@ func ResolveAuthConfig(cfg *configfile.ConfigFile, index *registrytypes.IndexInf
82107
// If credentials for given serverAddress exists in the credential store, the configuration will be populated with values in it
83108
func GetDefaultAuthConfig(cfg *configfile.ConfigFile, checkCredStore bool, serverAddress string, isDefaultRegistry bool) (registrytypes.AuthConfig, error) {
84109
if !isDefaultRegistry {
110+
// FIXME(thaJeztah): should the same logic be used for getAuthConfigKey ?? Looks like we're normalizing things here, but not elsewhere? why?
85111
serverAddress = credentials.ConvertToHostname(serverAddress)
86112
}
87113
authconfig := configtypes.AuthConfig{}
@@ -125,6 +151,8 @@ func ConfigureAuth(ctx context.Context, cli Cli, flUser, flPassword string, auth
125151
// If defaultUsername is not empty, the username prompt includes that username
126152
// and the user can hit enter without inputting a username to use that default
127153
// username.
154+
//
155+
// TODO(thaJeztah): cli Cli could be a Streams if it was not for cli.SetIn to be needed?
128156
func PromptUserForCredentials(ctx context.Context, cli Cli, argUser, argPassword, defaultUsername, serverAddress string) (registrytypes.AuthConfig, error) {
129157
// On Windows, force the use of the regular OS stdin stream.
130158
//
@@ -217,12 +245,15 @@ func PromptUserForCredentials(ctx context.Context, cli Cli, argUser, argPassword
217245
//
218246
// For details on base64url encoding, see:
219247
// - 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?
220250
func RetrieveAuthTokenFromImage(cfg *configfile.ConfigFile, image string) (string, error) {
221251
// Retrieve encoded auth token from the image reference
222252
authConfig, err := resolveAuthConfigFromImage(cfg, image)
223253
if err != nil {
224254
return "", err
225255
}
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).
226257
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
227258
if err != nil {
228259
return "", err
@@ -231,6 +262,8 @@ func RetrieveAuthTokenFromImage(cfg *configfile.ConfigFile, image string) (strin
231262
}
232263

233264
// 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
234267
func resolveAuthConfigFromImage(cfg *configfile.ConfigFile, image string) (registrytypes.AuthConfig, error) {
235268
registryRef, err := reference.ParseNormalizedNamed(image)
236269
if err != nil {

cli/command/registry/search.go

Lines changed: 1 addition & 0 deletions
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

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)