diff --git a/pkg/auth/auth.go b/pkg/auth/auth.go index cfb006743..25935b09c 100644 --- a/pkg/auth/auth.go +++ b/pkg/auth/auth.go @@ -75,10 +75,10 @@ func CheckAuthFile(pathOption string) error { } // systemContextWithOptions returns a version of sys -// updated with authFile and certDir values (if they are not ""). +// updated with authFile, dockerCompatAuthFile and certDir values (if they are not ""). // NOTE: this is a shallow copy that can be used and updated, but may share // data with the original parameter. -func systemContextWithOptions(sys *types.SystemContext, authFile, certDir string) *types.SystemContext { +func systemContextWithOptions(sys *types.SystemContext, authFile, dockerCompatAuthFile, certDir string) (*types.SystemContext, error) { if sys != nil { sysCopy := *sys sys = &sysCopy @@ -86,9 +86,14 @@ func systemContextWithOptions(sys *types.SystemContext, authFile, certDir string sys = &types.SystemContext{} } - if authFile != "" { + switch { + case authFile != "" && dockerCompatAuthFile != "": + return nil, errors.New("options for paths to the credential file and to the Docker-compatible credential file can not be set simultaneously") + case authFile != "": sys.AuthFilePath = authFile - } else { + case dockerCompatAuthFile != "": + sys.DockerCompatAuthFilePath = dockerCompatAuthFile + default: // Keep this in sync with GetDefaultAuthFile()! // // Note that c/image does not natively implement the REGISTRY_AUTH_FILE @@ -100,24 +105,24 @@ func systemContextWithOptions(sys *types.SystemContext, authFile, certDir string // If the Docker configuration exists in the default ~/.docker/config.json location, // we DO NOT write to it; instead, we update auth.json in the default path. // Only if the user explicitly sets DOCKER_CONFIG, we write to that config.json. - sys.AuthFilePath = filepath.Join(dockerConfig, "config.json") + sys.DockerCompatAuthFilePath = filepath.Join(dockerConfig, "config.json") } } if certDir != "" { sys.DockerCertPath = certDir } - return sys + return sys, nil } // Login implements a “log in” command with the provided opts and args // reading the password from opts.Stdin or the options in opts. func Login(ctx context.Context, systemContext *types.SystemContext, opts *LoginOptions, args []string) error { - systemContext = systemContextWithOptions(systemContext, opts.AuthFile, opts.CertDir) + systemContext, err := systemContextWithOptions(systemContext, opts.AuthFile, opts.DockerCompatAuthFile, opts.CertDir) + if err != nil { + return err + } - var ( - key, registry string - err error - ) + var key, registry string switch len(args) { case 0: if !opts.AcceptUnspecifiedRegistry { @@ -311,7 +316,13 @@ func Logout(systemContext *types.SystemContext, opts *LogoutOptions, args []stri if err := CheckAuthFile(opts.AuthFile); err != nil { return err } - systemContext = systemContextWithOptions(systemContext, opts.AuthFile, "") + if err := CheckAuthFile(opts.DockerCompatAuthFile); err != nil { + return err + } + systemContext, err := systemContextWithOptions(systemContext, opts.AuthFile, opts.DockerCompatAuthFile, "") + if err != nil { + return err + } if opts.All { if len(args) != 0 { @@ -324,10 +335,7 @@ func Logout(systemContext *types.SystemContext, opts *LogoutOptions, args []stri return nil } - var ( - key, registry string - err error - ) + var key, registry string switch len(args) { case 0: if !opts.AcceptUnspecifiedRegistry { diff --git a/pkg/auth/cli.go b/pkg/auth/cli.go index 1eeb6f9dd..60e02e51e 100644 --- a/pkg/auth/cli.go +++ b/pkg/auth/cli.go @@ -14,14 +14,15 @@ type LoginOptions struct { // CLI flags managed by the FlagSet returned by GetLoginFlags // Callers that use GetLoginFlags should not need to touch these values at all; callers that use // other CLI frameworks should set them based on user input. - AuthFile string - CertDir string - Password string - Username string - StdinPassword bool - GetLoginSet bool - Verbose bool // set to true for verbose output - AcceptRepositories bool // set to true to allow namespaces or repositories rather than just registries + AuthFile string + DockerCompatAuthFile string + CertDir string + Password string + Username string + StdinPassword bool + GetLoginSet bool + Verbose bool // set to true for verbose output + AcceptRepositories bool // set to true to allow namespaces or repositories rather than just registries // Options caller can set Stdin io.Reader // set to os.Stdin Stdout io.Writer // set to os.Stdout @@ -34,9 +35,10 @@ type LogoutOptions struct { // CLI flags managed by the FlagSet returned by GetLogoutFlags // Callers that use GetLogoutFlags should not need to touch these values at all; callers that use // other CLI frameworks should set them based on user input. - AuthFile string - All bool - AcceptRepositories bool // set to true to allow namespaces or repositories rather than just registries + AuthFile string + DockerCompatAuthFile string + All bool + AcceptRepositories bool // set to true to allow namespaces or repositories rather than just registries // Options caller can set Stdout io.Writer // set to os.Stdout AcceptUnspecifiedRegistry bool // set to true if allows logout with unspecified registry @@ -46,6 +48,7 @@ type LogoutOptions struct { func GetLoginFlags(flags *LoginOptions) *pflag.FlagSet { fs := pflag.FlagSet{} fs.StringVar(&flags.AuthFile, "authfile", "", "path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override") + fs.StringVar(&flags.DockerCompatAuthFile, "compat-auth-file", "", "path of a Docker-compatible config file to update instead") fs.StringVar(&flags.CertDir, "cert-dir", "", "use certificates at the specified path to access the registry") fs.StringVarP(&flags.Password, "password", "p", "", "Password for registry") fs.StringVarP(&flags.Username, "username", "u", "", "Username for registry") @@ -59,6 +62,7 @@ func GetLoginFlags(flags *LoginOptions) *pflag.FlagSet { func GetLoginFlagsCompletions() completion.FlagCompletions { flagCompletion := completion.FlagCompletions{} flagCompletion["authfile"] = completion.AutocompleteDefault + flagCompletion["compat-auth-file"] = completion.AutocompleteDefault flagCompletion["cert-dir"] = completion.AutocompleteDefault flagCompletion["password"] = completion.AutocompleteNone flagCompletion["username"] = completion.AutocompleteNone @@ -69,6 +73,7 @@ func GetLoginFlagsCompletions() completion.FlagCompletions { func GetLogoutFlags(flags *LogoutOptions) *pflag.FlagSet { fs := pflag.FlagSet{} fs.StringVar(&flags.AuthFile, "authfile", "", "path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override") + fs.StringVar(&flags.DockerCompatAuthFile, "compat-auth-file", "", "path of a Docker-compatible config file to update instead") fs.BoolVarP(&flags.All, "all", "a", false, "Remove the cached credentials for all registries in the auth file") return &fs } @@ -77,5 +82,6 @@ func GetLogoutFlags(flags *LogoutOptions) *pflag.FlagSet { func GetLogoutFlagsCompletions() completion.FlagCompletions { flagCompletion := completion.FlagCompletions{} flagCompletion["authfile"] = completion.AutocompleteDefault + flagCompletion["compat-auth-file"] = completion.AutocompleteDefault return flagCompletion }