From 961d487c399448c2fd98fcffbb846b38ad59c303 Mon Sep 17 00:00:00 2001 From: Rafael Matias Date: Wed, 2 Oct 2024 16:41:12 +0200 Subject: [PATCH] add tests --- .../docker/docker_manager/docker_auth.go | 32 +++++-- .../docker/docker_manager/docker_auth_test.go | 83 +++++++++++++++++++ .../docker/docker_manager/docker_manager.go | 2 +- 3 files changed, 111 insertions(+), 6 deletions(-) create mode 100644 container-engine-lib/lib/backend_impls/docker/docker_manager/docker_auth_test.go diff --git a/container-engine-lib/lib/backend_impls/docker/docker_manager/docker_auth.go b/container-engine-lib/lib/backend_impls/docker/docker_manager/docker_auth.go index 2c96910ed1..571949a264 100644 --- a/container-engine-lib/lib/backend_impls/docker/docker_manager/docker_auth.go +++ b/container-engine-lib/lib/backend_impls/docker/docker_manager/docker_auth.go @@ -8,6 +8,7 @@ import ( "os/exec" "strings" + "github.com/davecgh/go-spew/spew" "github.com/docker/docker/api/types/registry" dockerregistry "github.com/docker/docker/registry" ) @@ -59,17 +60,28 @@ func getCredentialsFromStore(credHelper string, registryURL string) (*registry.A return nil, fmt.Errorf("error executing credential helper %s: %v, %s", credHelperCmd, err, stderr.String()) } - // Parse the output (it should return JSON containing "Username" and "Secret") - var creds registry.AuthConfig + // Parse the output (it should return JSON containing "Username", "Secret" and "ServerURL") + creds := struct { + Username string `json:"Username"` + Secret string `json:"Secret"` + ServerURL string `json:"ServerURL"` + }{} + if err := json.Unmarshal(out.Bytes(), &creds); err != nil { return nil, fmt.Errorf("error parsing credentials from store: %v", err) } - return &creds, nil + return ®istry.AuthConfig{ + Username: creds.Username, + Password: creds.Secret, + ServerAddress: creds.ServerURL, + }, nil } -// getAuthFromDockerConfig retrieves the auth configuration for a given repository -func getAuthFromDockerConfig(repo string) (*registry.AuthConfig, error) { +// GetAuthFromDockerConfig retrieves the auth configuration for a given repository +// by checking the Docker config.json file and Docker credential helpers. +// Returns nil if no credentials were found. +func GetAuthFromDockerConfig(repo string) (*registry.AuthConfig, error) { authConfig, err := loadDockerAuth() if err != nil { return nil, err @@ -77,6 +89,16 @@ func getAuthFromDockerConfig(repo string) (*registry.AuthConfig, error) { registryHost := dockerregistry.ConvertToHostname(repo) + spew.Dump(registryHost) + if !strings.Contains(registryHost, ".") || registryHost == "docker.io" || registryHost == "registry-1.docker.io" { + registryHost = "https://index.docker.io/v1/" + } + + // Check if the URL contains "://", meaning it already has a protocol + if !strings.Contains(registryHost, "://") { + registryHost = "https://" + registryHost + } + // 1. Check if there is a credHelper for this specific registry if credHelper, exists := authConfig.CredHelpers[registryHost]; exists { return getCredentialsFromStore(credHelper, registryHost) diff --git a/container-engine-lib/lib/backend_impls/docker/docker_manager/docker_auth_test.go b/container-engine-lib/lib/backend_impls/docker/docker_manager/docker_auth_test.go new file mode 100644 index 0000000000..3f6904453e --- /dev/null +++ b/container-engine-lib/lib/backend_impls/docker/docker_manager/docker_auth_test.go @@ -0,0 +1,83 @@ +package docker_manager + +import ( + "encoding/base64" + "fmt" + "io/ioutil" + "os" + "testing" + + "github.com/docker/docker/api/types/registry" + "github.com/stretchr/testify/assert" +) + +// WriteStaticConfig writes a static Docker config.json file to a temporary directory +func WriteStaticConfig(t *testing.T, configContent string) string { + tmpDir, err := os.MkdirTemp("", "docker-config") + if err != nil { + t.Fatalf("Failed to create temp directory: %v", err) + } + + configPath := tmpDir + "/config.json" + err = ioutil.WriteFile(configPath, []byte(configContent), 0600) + if err != nil { + t.Fatalf("Failed to write config.json: %v", err) + } + + // Set the DOCKER_CONFIG environment variable to the temp directory + os.Setenv("DOCKER_CONFIG", tmpDir) + return tmpDir +} + +func TestGetAuthConfigForRepoPlain(t *testing.T) { + cfg := ` + { + "auths": { + "https://index.docker.io/v1/": { + "auth": "dXNlcjpwYXNzd29yZA==" + } + } + } + ` + tmpDir := WriteStaticConfig(t, cfg) + defer os.RemoveAll(tmpDir) + + expectedAuth := registry.AuthConfig{ + Username: "user", + Password: "password", + } + encodedAuth := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", expectedAuth.Username, expectedAuth.Password))) + + // Test 1: Retrieve auth config for Docker Hub using docker.io domain + authConfig, err := GetAuthFromDockerConfig("docker.io/my-repo/my-image:latest") + assert.NoError(t, err) + assert.Equal(t, encodedAuth, authConfig.Auth, "Auth for Docker Hub should match") + + // Test 2: Retrieve auth config for Docker Hub using no domain + authConfig, err = GetAuthFromDockerConfig("my-repo/my-image:latest") + assert.NoError(t, err) + assert.Equal(t, encodedAuth, authConfig.Auth, "Auth for Docker Hub should match when using no host prefix") + + // Test 3: Retrieve auth config for Docker Hub using full domain and https:// prefix + authConfig, err = GetAuthFromDockerConfig("https://registry-1.docker.io/my-repo/my-image:latest") + assert.NoError(t, err) + assert.Equal(t, encodedAuth, authConfig.Auth, "Auth for Docker Hub should match when using no host prefix") + +} + +func TestGetAuthConfigForRepoOSX(t *testing.T) { + t.Skip("Skipping test that requires macOS keychain") + + cfg := `{ + "auths": { + "https://index.docker.io/v1/": {} + }, + "credsStore": "osxkeychain" + }` + tmpDir := WriteStaticConfig(t, cfg) + defer os.RemoveAll(tmpDir) + + authConfig, err := GetAuthFromDockerConfig("my-repo/my-image:latest") + assert.NoError(t, err) + assert.NotNil(t, authConfig, "Auth config should not be nil") +} diff --git a/container-engine-lib/lib/backend_impls/docker/docker_manager/docker_manager.go b/container-engine-lib/lib/backend_impls/docker/docker_manager/docker_manager.go index dd8dac1ef5..cad0cbc6d9 100644 --- a/container-engine-lib/lib/backend_impls/docker/docker_manager/docker_manager.go +++ b/container-engine-lib/lib/backend_impls/docker/docker_manager/docker_manager.go @@ -2281,7 +2281,7 @@ func pullImage(dockerClient *client.Client, imageName string, registrySpec *imag } // Try to obtain the auth configuration from the docker config file - authConfig, err := getAuthFromDockerConfig(imageName) + authConfig, err := GetAuthFromDockerConfig(imageName) if err != nil { logrus.Errorf("An error occurred while getting auth config for image: %s: %s", imageName, err.Error()) }