diff --git a/cli/config/configfile/file.go b/cli/config/configfile/file.go index 37e1533f42..7fa9b734b9 100644 --- a/cli/config/configfile/file.go +++ b/cli/config/configfile/file.go @@ -175,15 +175,21 @@ func (configFile *ConfigFile) Save() error { return errors.Errorf("Can't save config with empty filename") } - if err := os.MkdirAll(filepath.Dir(configFile.Filename), 0700); err != nil { + dir := filepath.Dir(configFile.Filename) + if err := os.MkdirAll(dir, 0700); err != nil { return err } - f, err := os.OpenFile(configFile.Filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) + temp, err := ioutil.TempFile(dir, filepath.Base(configFile.Filename)) if err != nil { return err } - defer f.Close() - return configFile.SaveToWriter(f) + err = configFile.SaveToWriter(temp) + temp.Close() + if err != nil { + os.Remove(temp.Name()) + return err + } + return os.Rename(temp.Name(), configFile.Filename) } // ParseProxyConfig computes proxy configuration by retrieving the config for the provided host and diff --git a/cli/config/configfile/file_test.go b/cli/config/configfile/file_test.go index f0704cef3f..765a9f9cd9 100644 --- a/cli/config/configfile/file_test.go +++ b/cli/config/configfile/file_test.go @@ -2,6 +2,8 @@ package configfile import ( "fmt" + "io/ioutil" + "os" "testing" "github.com/docker/cli/cli/config/credentials" @@ -413,3 +415,13 @@ func TestCheckKubernetesConfigurationRaiseAnErrorOnInvalidValue(t *testing.T) { } } } + +func TestSave(t *testing.T) { + configFile := New("test-save") + defer os.Remove("test-save") + err := configFile.Save() + assert.NilError(t, err) + cfg, err := ioutil.ReadFile("test-save") + assert.NilError(t, err) + assert.Check(t, is.Equal(string(cfg), "{\n \"auths\": {}\n}")) +}