Skip to content

Commit

Permalink
config: print deprecation warning when falling back to ~/.dockercfg
Browse files Browse the repository at this point in the history
Relates to the deprecation, added in 3c0a167

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 <[email protected]>
  • Loading branch information
thaJeztah committed Mar 8, 2021
1 parent 70a0015 commit b83bc67
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 3 deletions.
29 changes: 27 additions & 2 deletions cli/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ const (
)

var (
initConfigDir sync.Once
initConfigDir = new(sync.Once)
configDir 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.
func resetHomeDir() {
homeDir = ""
Expand All @@ -42,6 +42,13 @@ func getHomeDir() string {
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() {
if configDir != "" {
return
Expand Down Expand Up @@ -97,10 +104,20 @@ func LoadFromReader(configData io.Reader) (*configfile.ConfigFile, error) {
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
// the auth config information and returns values.
// FIXME: use the internal golang config parser
func Load(configDir string) (*configfile.ConfigFile, error) {
mutex.Lock()
printLegacyFileWarning = false
mutex.Unlock()

if configDir == "" {
configDir = Dir()
}
Expand All @@ -125,6 +142,9 @@ func Load(configDir string) (*configfile.ConfigFile, error) {
// Can't find latest config file so check for the old one
filename = filepath.Join(getHomeDir(), oldConfigfile)
if file, err := os.Open(filename); err == nil {
mutex.Lock()
printLegacyFileWarning = true
mutex.Unlock()
defer file.Close()
if err := configFile.LegacyLoadFromReader(file); err != nil {
return configFile, errors.Wrap(err, filename)
Expand All @@ -140,6 +160,11 @@ func LoadDefaultConfigFile(stderr io.Writer) *configfile.ConfigFile {
if err != nil {
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() {
configFile.CredentialsStore = credentials.DetectDefaultStore(configFile.CredentialsStore)
}
Expand Down
27 changes: 27 additions & 0 deletions cli/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ import (

"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/cli/config/credentials"
"github.com/docker/cli/cli/config/types"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
"gotest.tools/v3/env"
"gotest.tools/v3/fs"
)

var homeKey = "HOME"
Expand Down Expand Up @@ -223,6 +225,31 @@ func TestOldJSON(t *testing.T) {
}
}

func TestOldJSONFallbackDeprecationWarning(t *testing.T) {
js := `{"https://index.docker.io/v1/":{"auth":"am9lam9lOmhlbGxv","email":"[email protected]"}}`
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: "[email protected]",
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) {
tmpHome, err := ioutil.TempDir("", "config-test")
assert.NilError(t, err)
Expand Down
4 changes: 3 additions & 1 deletion cmd/docker/docker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ import (
func TestClientDebugEnabled(t *testing.T) {
defer debug.Disable()

tcmd := newDockerCommand(&command.DockerCli{})
cli, err := command.NewDockerCli()
assert.NilError(t, err)
tcmd := newDockerCommand(cli)
tcmd.SetFlag("debug", "true")
cmd, _, err := tcmd.HandleGlobalFlags()
assert.NilError(t, err)
Expand Down

0 comments on commit b83bc67

Please sign in to comment.