Skip to content

Commit

Permalink
Ignore docker config if it's a directory (#1420)
Browse files Browse the repository at this point in the history
In a kubernetes environment, a volume from a Secret can be optionally
mounted. If the Secret does not exist, the mounted path is always a
directory.

This change modifies auth.DefaultKeychain to ignore the case where the
docker config file is unexpectedly a directory.

Signed-off-by: Luiz Carvalho <lucarval@redhat.com>
  • Loading branch information
lcarva committed Jul 28, 2022
1 parent 49cdb8b commit 24a1c33
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 8 deletions.
14 changes: 8 additions & 6 deletions pkg/authn/keychain.go
Expand Up @@ -75,15 +75,11 @@ func (dk *defaultKeychain) Resolve(target Resource) (Authenticator, error) {
foundDockerConfig := false
home, err := homedir.Dir()
if err == nil {
if _, err := os.Stat(filepath.Join(home, ".docker/config.json")); err == nil {
foundDockerConfig = true
}
foundDockerConfig = fileExists(filepath.Join(home, ".docker/config.json"))
}
// If $HOME/.docker/config.json isn't found, check $DOCKER_CONFIG (if set)
if !foundDockerConfig && os.Getenv("DOCKER_CONFIG") != "" {
if _, err := os.Stat(filepath.Join(os.Getenv("DOCKER_CONFIG"), "config.json")); err == nil {
foundDockerConfig = true
}
foundDockerConfig = fileExists(filepath.Join(os.Getenv("DOCKER_CONFIG"), "config.json"))
}
// If either of those locations are found, load it using Docker's
// config.Load, which may fail if the config can't be parsed.
Expand Down Expand Up @@ -144,6 +140,12 @@ func (dk *defaultKeychain) Resolve(target Resource) (Authenticator, error) {
}), nil
}

// fileExists returns true if the given path exists and is not a directory.
func fileExists(path string) bool {
fi, err := os.Stat(path)
return err == nil && !fi.IsDir()
}

// Helper is a subset of the Docker credential helper credentials.Helper
// interface used by NewKeychainFromHelper.
//
Expand Down
24 changes: 22 additions & 2 deletions pkg/authn/keychain_test.go
Expand Up @@ -21,6 +21,7 @@ import (
"io/ioutil"
"log"
"os"
"path"
"path/filepath"
"reflect"
"testing"
Expand Down Expand Up @@ -63,7 +64,7 @@ func setupConfigDir(t *testing.T) string {
fresh++
p := filepath.Join(tmpdir, fmt.Sprintf("%d", fresh))
t.Logf("DOCKER_CONFIG=%s", p)
os.Setenv("DOCKER_CONFIG", p)
t.Setenv("DOCKER_CONFIG", p)
if err := os.Mkdir(p, 0777); err != nil {
t.Fatalf("mkdir %q: %v", p, err)
}
Expand Down Expand Up @@ -106,7 +107,7 @@ func TestPodmanConfig(t *testing.T) {
}
fresh++
p := filepath.Join(tmpdir, fmt.Sprintf("%d", fresh))
os.Setenv("XDG_RUNTIME_DIR", p)
t.Setenv("XDG_RUNTIME_DIR", p)
os.Unsetenv("DOCKER_CONFIG")
if err := os.MkdirAll(filepath.Join(p, "containers"), 0777); err != nil {
t.Fatalf("mkdir %s/containers: %v", p, err)
Expand Down Expand Up @@ -146,6 +147,7 @@ func TestPodmanConfig(t *testing.T) {
if err := ioutil.WriteFile(cfg, []byte(content), 0600); err != nil {
t.Fatalf("write %q: %v", cfg, err)
}
defer func() { os.Remove(cfg) }()
auth, err = DefaultKeychain.Resolve(testRegistry)
if err != nil {
t.Fatalf("Resolve() = %v", err)
Expand Down Expand Up @@ -363,3 +365,21 @@ func TestNewKeychainFromHelper(t *testing.T) {
}
})
}

func TestConfigFileIsADir(t *testing.T) {
tmpdir := setupConfigDir(t)
// Create "config.json" as a directory, not a file to simulate optional
// secrets in Kubernetes.
err := os.Mkdir(path.Join(tmpdir, "config.json"), 0777)
if err != nil {
t.Fatal(err)
}

auth, err := DefaultKeychain.Resolve(testRegistry)
if err != nil {
t.Fatalf("Resolve() = %v", err)
}
if auth != Anonymous {
t.Errorf("expected Anonymous, got %v", auth)
}
}

0 comments on commit 24a1c33

Please sign in to comment.