mirror of https://github.com/docker/cli.git
config: print deprecation warning when falling back to ~/.dockercfg
Relates to the deprecation, added in3c0a167ed5
The docker CLI up until v1.7.0 used the `~/.dockercfg` file to store credentials after authenticating to a registry (`docker login`). Docker v1.7.0 replaced this file with a new CLI configuration file, located in `~/.docker/config.json`. When implementing the new configuration file, the old file (and file-format) was kept as a fall-back, to assist existing users with migrating to the new file. Given that the old file format encourages insecure storage of credentials (credentials are stored unencrypted), and that no version of the CLI since Docker v1.7.0 has created this file, the file is marked deprecated, and support for this file will be removed in a future release. This patch adds a deprecation warning, which is printed if the CLI falls back to using the deprecated ~/.dockercfg file. Signed-off-by: Sebastiaan van Stijn <github@gone.nl> (cherry picked from commitb83bc67136
) Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
parent
55c4c88966
commit
4571d90f20
|
@ -24,12 +24,12 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
initConfigDir sync.Once
|
initConfigDir = new(sync.Once)
|
||||||
configDir string
|
configDir string
|
||||||
homeDir string
|
homeDir string
|
||||||
)
|
)
|
||||||
|
|
||||||
// resetHomeDir is used in testing to resets the "homeDir" package variable to
|
// resetHomeDir is used in testing to reset the "homeDir" package variable to
|
||||||
// force re-lookup of the home directory between tests.
|
// force re-lookup of the home directory between tests.
|
||||||
func resetHomeDir() {
|
func resetHomeDir() {
|
||||||
homeDir = ""
|
homeDir = ""
|
||||||
|
@ -42,6 +42,13 @@ func getHomeDir() string {
|
||||||
return homeDir
|
return homeDir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// resetConfigDir is used in testing to reset the "configDir" package variable
|
||||||
|
// and its sync.Once to force re-lookup between tests.
|
||||||
|
func resetConfigDir() {
|
||||||
|
configDir = ""
|
||||||
|
initConfigDir = new(sync.Once)
|
||||||
|
}
|
||||||
|
|
||||||
func setConfigDir() {
|
func setConfigDir() {
|
||||||
if configDir != "" {
|
if configDir != "" {
|
||||||
return
|
return
|
||||||
|
@ -97,10 +104,20 @@ func LoadFromReader(configData io.Reader) (*configfile.ConfigFile, error) {
|
||||||
return &configFile, err
|
return &configFile, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO remove this temporary hack, which is used to warn about the deprecated ~/.dockercfg file
|
||||||
|
var (
|
||||||
|
mutex sync.RWMutex
|
||||||
|
printLegacyFileWarning bool
|
||||||
|
)
|
||||||
|
|
||||||
// Load reads the configuration files in the given directory, and sets up
|
// Load reads the configuration files in the given directory, and sets up
|
||||||
// the auth config information and returns values.
|
// the auth config information and returns values.
|
||||||
// FIXME: use the internal golang config parser
|
// FIXME: use the internal golang config parser
|
||||||
func Load(configDir string) (*configfile.ConfigFile, error) {
|
func Load(configDir string) (*configfile.ConfigFile, error) {
|
||||||
|
mutex.Lock()
|
||||||
|
printLegacyFileWarning = false
|
||||||
|
mutex.Unlock()
|
||||||
|
|
||||||
if configDir == "" {
|
if configDir == "" {
|
||||||
configDir = Dir()
|
configDir = Dir()
|
||||||
}
|
}
|
||||||
|
@ -125,6 +142,9 @@ func Load(configDir string) (*configfile.ConfigFile, error) {
|
||||||
// Can't find latest config file so check for the old one
|
// Can't find latest config file so check for the old one
|
||||||
filename = filepath.Join(getHomeDir(), oldConfigfile)
|
filename = filepath.Join(getHomeDir(), oldConfigfile)
|
||||||
if file, err := os.Open(filename); err == nil {
|
if file, err := os.Open(filename); err == nil {
|
||||||
|
mutex.Lock()
|
||||||
|
printLegacyFileWarning = true
|
||||||
|
mutex.Unlock()
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
if err := configFile.LegacyLoadFromReader(file); err != nil {
|
if err := configFile.LegacyLoadFromReader(file); err != nil {
|
||||||
return configFile, errors.Wrap(err, filename)
|
return configFile, errors.Wrap(err, filename)
|
||||||
|
@ -140,6 +160,11 @@ func LoadDefaultConfigFile(stderr io.Writer) *configfile.ConfigFile {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(stderr, "WARNING: Error loading config file: %v\n", err)
|
fmt.Fprintf(stderr, "WARNING: Error loading config file: %v\n", err)
|
||||||
}
|
}
|
||||||
|
mutex.RLock()
|
||||||
|
defer mutex.RUnlock()
|
||||||
|
if printLegacyFileWarning {
|
||||||
|
_, _ = fmt.Fprintln(stderr, "WARNING: Support for the legacy ~/.dockercfg configuration file and file-format is deprecated and will be removed in an upcoming release")
|
||||||
|
}
|
||||||
if !configFile.ContainsAuth() {
|
if !configFile.ContainsAuth() {
|
||||||
configFile.CredentialsStore = credentials.DetectDefaultStore(configFile.CredentialsStore)
|
configFile.CredentialsStore = credentials.DetectDefaultStore(configFile.CredentialsStore)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,9 +12,11 @@ import (
|
||||||
|
|
||||||
"github.com/docker/cli/cli/config/configfile"
|
"github.com/docker/cli/cli/config/configfile"
|
||||||
"github.com/docker/cli/cli/config/credentials"
|
"github.com/docker/cli/cli/config/credentials"
|
||||||
|
"github.com/docker/cli/cli/config/types"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
is "gotest.tools/v3/assert/cmp"
|
is "gotest.tools/v3/assert/cmp"
|
||||||
"gotest.tools/v3/env"
|
"gotest.tools/v3/env"
|
||||||
|
"gotest.tools/v3/fs"
|
||||||
)
|
)
|
||||||
|
|
||||||
var homeKey = "HOME"
|
var homeKey = "HOME"
|
||||||
|
@ -223,6 +225,31 @@ func TestOldJSON(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestOldJSONFallbackDeprecationWarning(t *testing.T) {
|
||||||
|
js := `{"https://index.docker.io/v1/":{"auth":"am9lam9lOmhlbGxv","email":"user@example.com"}}`
|
||||||
|
tmpHome := fs.NewDir(t, t.Name(), fs.WithFile(oldConfigfile, js))
|
||||||
|
defer tmpHome.Remove()
|
||||||
|
defer env.PatchAll(t, map[string]string{homeKey: tmpHome.Path(), "DOCKER_CONFIG": ""})()
|
||||||
|
|
||||||
|
// reset the homeDir, configDir, and its sync.Once, to force them being resolved again
|
||||||
|
resetHomeDir()
|
||||||
|
resetConfigDir()
|
||||||
|
|
||||||
|
buffer := new(bytes.Buffer)
|
||||||
|
configFile := LoadDefaultConfigFile(buffer)
|
||||||
|
expected := configfile.New(tmpHome.Join(configFileDir, ConfigFileName))
|
||||||
|
expected.AuthConfigs = map[string]types.AuthConfig{
|
||||||
|
"https://index.docker.io/v1/": {
|
||||||
|
Username: "joejoe",
|
||||||
|
Password: "hello",
|
||||||
|
Email: "user@example.com",
|
||||||
|
ServerAddress: "https://index.docker.io/v1/",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.Assert(t, strings.Contains(buffer.String(), "WARNING: Support for the legacy ~/.dockercfg configuration file and file-format is deprecated and will be removed in an upcoming release"))
|
||||||
|
assert.Check(t, is.DeepEqual(expected, configFile))
|
||||||
|
}
|
||||||
|
|
||||||
func TestNewJSON(t *testing.T) {
|
func TestNewJSON(t *testing.T) {
|
||||||
tmpHome, err := ioutil.TempDir("", "config-test")
|
tmpHome, err := ioutil.TempDir("", "config-test")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
|
@ -17,7 +17,9 @@ import (
|
||||||
func TestClientDebugEnabled(t *testing.T) {
|
func TestClientDebugEnabled(t *testing.T) {
|
||||||
defer debug.Disable()
|
defer debug.Disable()
|
||||||
|
|
||||||
tcmd := newDockerCommand(&command.DockerCli{})
|
cli, err := command.NewDockerCli()
|
||||||
|
assert.NilError(t, err)
|
||||||
|
tcmd := newDockerCommand(cli)
|
||||||
tcmd.SetFlag("debug", "true")
|
tcmd.SetFlag("debug", "true")
|
||||||
cmd, _, err := tcmd.HandleGlobalFlags()
|
cmd, _, err := tcmd.HandleGlobalFlags()
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
Loading…
Reference in New Issue