Skip to content

Commit 001dc47

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 <[email protected]>
1 parent 6bc7ed8 commit 001dc47

File tree

3 files changed

+51
-7
lines changed

3 files changed

+51
-7
lines changed

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/cli/internal/tui"
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"
@@ -106,12 +105,8 @@ To push the complete multi-platform image, remove the --platform flag.
106105
}
107106
}
108107

109-
// Resolve the Repository name from fqn to RepositoryInfo
110-
indexInfo := registry.NewIndexInfo(ref)
111-
112108
// Resolve the Auth config relevant for this server
113-
authConfig := command.ResolveAuthConfig(dockerCli.ConfigFile(), indexInfo)
114-
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
109+
encodedAuth, err := command.RetrieveAuthTokenFromImage(dockerCli.ConfigFile(), ref.String())
115110
if err != nil {
116111
return err
117112
}
@@ -134,6 +129,9 @@ To push the complete multi-platform image, remove the --platform flag.
134129
}()
135130

136131
if !opts.untrusted {
132+
// Resolve the Repository name from fqn to RepositoryInfo
133+
indexInfo := registry.NewIndexInfo(ref)
134+
authConfig := command.ResolveAuthConfig(dockerCli.ConfigFile(), indexInfo)
137135
return pushTrustedReference(ctx, dockerCli, indexInfo, ref, authConfig, responseBody)
138136
}
139137

cli/command/image/trust.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ func getTrustedPullTargets(cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth)
149149

150150
// imagePullPrivileged pulls the image and displays it to the output
151151
func imagePullPrivileged(ctx context.Context, cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth, opts pullOptions) error {
152+
// 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)
152153
encodedAuth, err := registrytypes.EncodeAuthConfig(*imgRefAndAuth.AuthConfig())
153154
if err != nil {
154155
return err

cli/command/registry.go

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,44 @@ const (
3434
// [registry.IndexServer]: https://pkg.go.dev/github.com/docker/[email protected]+incompatible/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+
51+
func newPrivilegeFunc(cli Cli, indexServer string, promptMsg string) registrytypes.RequestAuthConfig {
52+
return func(ctx context.Context) (string, error) {
53+
// TODO(thaJeztah): can we make the prompt an argument? ("prompt func()" or "prompt func()?
54+
_, _ = fmt.Fprint(cli.Out(), "\n"+promptMsg+"\n")
55+
isDefaultRegistry := indexServer == authConfigKey
56+
authConfig, err := GetDefaultAuthConfig(cli.ConfigFile(), true, indexServer, isDefaultRegistry)
57+
if err != nil {
58+
_, _ = fmt.Fprintf(cli.Err(), "Unable to retrieve stored credentials for %s, error: %s.\n", indexServer, err)
59+
}
60+
61+
select {
62+
case <-ctx.Done():
63+
return "", ctx.Err()
64+
default:
65+
}
66+
67+
authConfig, err = PromptUserForCredentials(ctx, cli, "", "", authConfig.Username, indexServer)
68+
if err != nil {
69+
return "", err
70+
}
71+
return registrytypes.EncodeAuthConfig(authConfig)
72+
}
73+
}
74+
3775
// ResolveAuthConfig returns auth-config for the given registry from the
3876
// credential-store. It returns an empty AuthConfig if no credentials were
3977
// found.
@@ -43,7 +81,8 @@ const authConfigKey = "https://index.docker.io/v1/"
4381
//
4482
// [registry.ResolveAuthConfig]: https://pkg.go.dev/github.com/docker/[email protected]+incompatible/registry#ResolveAuthConfig
4583
func ResolveAuthConfig(cfg *configfile.ConfigFile, index *registrytypes.IndexInfo) registrytypes.AuthConfig {
46-
configKey := index.Name
84+
indexServer := index.Name
85+
configKey := getAuthConfigKey(indexServer)
4786
if index.Official {
4887
configKey = authConfigKey
4988
}
@@ -56,6 +95,7 @@ func ResolveAuthConfig(cfg *configfile.ConfigFile, index *registrytypes.IndexInf
5695
// If credentials for given serverAddress exists in the credential store, the configuration will be populated with values in it
5796
func GetDefaultAuthConfig(cfg *configfile.ConfigFile, checkCredStore bool, serverAddress string, isDefaultRegistry bool) (registrytypes.AuthConfig, error) {
5897
if !isDefaultRegistry {
98+
// FIXME(thaJeztah): should the same logic be used for getAuthConfigKey ?? Looks like we're normalizing things here, but not elsewhere? why?
5999
serverAddress = credentials.ConvertToHostname(serverAddress)
60100
}
61101
authconfig := configtypes.AuthConfig{}
@@ -82,6 +122,8 @@ func GetDefaultAuthConfig(cfg *configfile.ConfigFile, checkCredStore bool, serve
82122
// If defaultUsername is not empty, the username prompt includes that username
83123
// and the user can hit enter without inputting a username to use that default
84124
// username.
125+
//
126+
// TODO(thaJeztah): cli Cli could be a Streams if it was not for cli.SetIn to be needed?
85127
func PromptUserForCredentials(ctx context.Context, cli Cli, argUser, argPassword, defaultUsername, serverAddress string) (registrytypes.AuthConfig, error) {
86128
// On Windows, force the use of the regular OS stdin stream.
87129
//
@@ -173,6 +215,9 @@ func PromptUserForCredentials(ctx context.Context, cli Cli, argUser, argPassword
173215
// base64url encoded ([RFC 4648, Section 5]) JSON string for sending through
174216
// the "X-Registry-Auth" header.
175217
//
218+
// FIXME(thaJeztah): do we need a variant like this, but with "indexServer" (domainName) as input?
219+
// TODO(thaJeztah): should this accept an image ref-type, and use instead of ResolveAuthConfig
220+
//
176221
// [RFC 4648, Section 5]: https://tools.ietf.org/html/rfc4648#section-5
177222
func RetrieveAuthTokenFromImage(cfg *configfile.ConfigFile, image string) (string, error) {
178223
registryRef, err := reference.ParseNormalizedNamed(image)

0 commit comments

Comments
 (0)