From c11d2d543a0879f5cc17c7a65aaa4663a8bd2caa Mon Sep 17 00:00:00 2001 From: Martin Date: Mon, 11 May 2026 21:37:57 +0200 Subject: [PATCH] fix: Align different docker urls to fix authentication issues (#927) * fix: Align different docker urls to fix authentication issues * chore: Fix acc-test changed files parsing --- .github/workflows/acc-test.yaml | 5 +++ internal/provider/provider.go | 29 +++++++++++++++- .../provider/provider_auth_config_test.go | 28 ++++++++++++++++ .../resource_docker_registry_image_funcs.go | 7 ++++ ...source_docker_registry_image_funcs_test.go | 33 ++++++++++++++++++- .../provider/resource_docker_service_funcs.go | 6 ++++ 6 files changed, 106 insertions(+), 2 deletions(-) diff --git a/.github/workflows/acc-test.yaml b/.github/workflows/acc-test.yaml index 9e70d15a..3f081f82 100644 --- a/.github/workflows/acc-test.yaml +++ b/.github/workflows/acc-test.yaml @@ -59,8 +59,13 @@ jobs: continue if f.startswith('./'): f = f[2:] + # GitHub log rendering and some action outputs can present continued + # lines with a trailing backslash. Normalize that before matching. + f = f.rstrip('\\').rstrip() files.append(f) + print(f"Normalized changed files: {files}") + def snake_to_camel(s: str) -> str: return ''.join(part[:1].upper() + part[1:] for part in s.split('_') if part) diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 73c6d47c..ae8dee57 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -396,15 +396,42 @@ func loadConfigFile(configData io.Reader) (*configfile.ConfigFile, error) { } func isDockerHubRegistryHostname(registryHostname string) bool { - return registryHostname == "index.docker.io" || registryHostname == "docker.io" || registryHostname == "registry-1.docker.io" + for _, dockerHubHostname := range dockerHubRegistryHostnames() { + if registryHostname == dockerHubHostname { + return true + } + } + + return false +} + +func dockerHubRegistryHostnames() []string { + return []string{ + "registry-1.docker.io", + "index.docker.io", + "docker.io", + "registry.hub.docker.com", + } +} + +func getDockerHubAuthConfigFromMap(authConfigs map[string]registry.AuthConfig) (registry.AuthConfig, bool) { + for _, dockerHubHostname := range dockerHubRegistryHostnames() { + if authConfig, ok := authConfigs[dockerHubHostname]; ok { + return authConfig, true + } + } + + return registry.AuthConfig{}, false } func getAuthConfigFromConfigFile(c *configfile.ConfigFile, registryHostname string) (registry.AuthConfig, error) { if isDockerHubRegistryHostname(registryHostname) { preferredDockerHubKeys := []string{ "https://index.docker.io/v1/", + "registry-1.docker.io", "index.docker.io", "docker.io", + "registry.hub.docker.com", } for _, key := range preferredDockerHubKeys { diff --git a/internal/provider/provider_auth_config_test.go b/internal/provider/provider_auth_config_test.go index aa821ef7..e25f743b 100644 --- a/internal/provider/provider_auth_config_test.go +++ b/internal/provider/provider_auth_config_test.go @@ -38,3 +38,31 @@ func TestGetAuthConfigFromConfigFile_PrefersCanonicalDockerHubEntry(t *testing.T t.Fatalf("want canonical docker hub password dckr_pat_abc, got %s", auth.Password) } } + +func TestGetAuthConfigFromConfigFile_AllowsLegacyDockerHubHostname(t *testing.T) { + content := `{ + "auths": { + "registry.hub.docker.com": { + "auth": "bGVnYWN5LXVzZXI6bGVnYWN5LXRva2Vu" + } + } + }` + + cfg, err := loadConfigFile(strings.NewReader(content)) + if err != nil { + t.Fatalf("unexpected loadConfigFile error: %s", err) + } + + auth, err := getAuthConfigFromConfigFile(cfg, "registry-1.docker.io") + if err != nil { + t.Fatalf("unexpected getAuthConfigFromConfigFile error: %s", err) + } + + if auth.Username != "legacy-user" { + t.Fatalf("want username legacy-user, got %s", auth.Username) + } + + if auth.Password != "legacy-token" { + t.Fatalf("want password legacy-token, got %s", auth.Password) + } +} diff --git a/internal/provider/resource_docker_registry_image_funcs.go b/internal/provider/resource_docker_registry_image_funcs.go index 2d580381..5f427e5f 100644 --- a/internal/provider/resource_docker_registry_image_funcs.go +++ b/internal/provider/resource_docker_registry_image_funcs.go @@ -300,6 +300,13 @@ func getAuthConfigForRegistry( if authConfig, ok := providerConfig.AuthConfigs.Configs[registryWithoutProtocol]; ok { return authConfig, nil } + + if isDockerHubRegistryHostname(registryWithoutProtocol) { + if authConfig, ok := getDockerHubAuthConfigFromMap(providerConfig.AuthConfigs.Configs); ok { + return authConfig, nil + } + } + return registry.AuthConfig{}, fmt.Errorf("no auth config found for registry %s in auth configs: %#v", registryWithoutProtocol, providerConfig.AuthConfigs.Configs) } diff --git a/internal/provider/resource_docker_registry_image_funcs_test.go b/internal/provider/resource_docker_registry_image_funcs_test.go index e8f6014a..785061f0 100644 --- a/internal/provider/resource_docker_registry_image_funcs_test.go +++ b/internal/provider/resource_docker_registry_image_funcs_test.go @@ -1,6 +1,10 @@ package provider -import "testing" +import ( + "testing" + + "github.com/docker/docker/api/types/registry" +) func TestBuildAuthConfigFromResource_OptionalCredentials(t *testing.T) { authConfig := buildAuthConfigFromResource([]interface{}{ @@ -43,3 +47,30 @@ func TestBuildAuthConfigFromResource_WithCredentials(t *testing.T) { t.Fatalf("want password test-password, got %s", authConfig.Password) } } + +func TestGetAuthConfigForRegistry_DockerHubAliasLookup(t *testing.T) { + providerConfig := &ProviderConfig{ + AuthConfigs: &AuthConfigs{ + Configs: map[string]registry.AuthConfig{ + "index.docker.io": { + Username: "docker-user", + Password: "docker-pass", + ServerAddress: "https://index.docker.io/v1/", + }, + }, + }, + } + + authConfig, err := getAuthConfigForRegistry("registry-1.docker.io", providerConfig) + if err != nil { + t.Fatalf("unexpected getAuthConfigForRegistry error: %s", err) + } + + if authConfig.Username != "docker-user" { + t.Fatalf("want username docker-user, got %s", authConfig.Username) + } + + if authConfig.Password != "docker-pass" { + t.Fatalf("want password docker-pass, got %s", authConfig.Password) + } +} diff --git a/internal/provider/resource_docker_service_funcs.go b/internal/provider/resource_docker_service_funcs.go index 00f9947e..81f5697f 100644 --- a/internal/provider/resource_docker_service_funcs.go +++ b/internal/provider/resource_docker_service_funcs.go @@ -631,6 +631,12 @@ func fromRegistryAuth(image string, authConfigs map[string]registry.AuthConfig) if fromRegistryAuth, ok := authConfigs[serverAddress]; ok { return fromRegistryAuth } + + if isDockerHubRegistryHostname(serverAddress) { + if fromRegistryAuth, ok := getDockerHubAuthConfigFromMap(authConfigs); ok { + return fromRegistryAuth + } + } } return registry.AuthConfig{}