diff --git a/internal/registry/desktop.go b/internal/registry/desktop.go index f6f5cc90b..718d08da8 100644 --- a/internal/registry/desktop.go +++ b/internal/registry/desktop.go @@ -103,6 +103,9 @@ type desktopAuthProvider struct { func (p *desktopAuthProvider) GetAuthConfig(registryHostname string) (clitypes.AuthConfig, error) { if session := p.sessionFor(registryHostname); session != nil { if auth, ok := session.auth(); ok { + if registryHost(registryHostname) == DHIRegistryHost { + auth.ServerAddress = DHIRegistryHost + } return auth, nil } } @@ -111,18 +114,19 @@ func (p *desktopAuthProvider) GetAuthConfig(registryHostname string) (clitypes.A func (p *desktopAuthProvider) sessionFor(registryHostname string) *desktopSession { switch { - case GetAuthConfigKey(registryHostname) == IndexServer: + case GetAuthConfigKey(registryHostname) == IndexServer, registryHost(registryHostname) == DHIRegistryHost: return p.hub - case isStagingRegistry(registryHostname): + case registryHost(registryHostname) == StagingRegistryHost: return p.stagingHub default: return nil } } -func isStagingRegistry(registryHostname string) bool { +// registryHost strips the scheme and trailing slash from a registry address. +func registryHost(registryHostname string) string { host := strings.TrimPrefix(strings.TrimPrefix(registryHostname, "https://"), "http://") - return strings.TrimSuffix(host, "/") == StagingRegistryHost + return strings.TrimSuffix(host, "/") } // desktopSession caches the Desktop session of one Docker Hub environment. diff --git a/internal/registry/desktop_test.go b/internal/registry/desktop_test.go index 264dff62b..5a4b39d8d 100644 --- a/internal/registry/desktop_test.go +++ b/internal/registry/desktop_test.go @@ -194,8 +194,9 @@ func TestDesktopAuthProvider_DockerHubUsesDesktopSession(t *testing.T) { func TestDesktopAuthProvider_OtherRegistriesUseFallback(t *testing.T) { hosts := []string{ "ghcr.io", "localhost:5000", "registry.example.com", - // look-alikes of the staging registry + // look-alikes of the staging and DHI registries StagingRegistryHost + ".example.com", "example.com/" + StagingRegistryHost, + DHIRegistryHost + ".example.com", "example.com/" + DHIRegistryHost, "registry." + DHIRegistryHost, } for _, host := range hosts { t.Run(host, func(t *testing.T) { @@ -212,6 +213,30 @@ func TestDesktopAuthProvider_OtherRegistriesUseFallback(t *testing.T) { } } +func TestDesktopAuthProvider_DHIUsesDockerHubSession(t *testing.T) { + for _, host := range []string{DHIRegistryHost, "https://" + DHIRegistryHost, "https://" + DHIRegistryHost + "/"} { + t.Run(host, func(t *testing.T) { + hub := &fakeHub{session: hubSession("hubuser", testNow.Add(time.Hour))} + p := newTestProvider(hub, nil) + p.signInToStaging() + + want := desktopCredentials() + want.ServerAddress = DHIRegistryHost + got, err := p.GetAuthConfig(host) + assert.NilError(t, err) + assert.DeepEqual(t, got, want) + assert.Equal(t, len(p.fallback.hosts), 0) + assert.Equal(t, p.staging.sessionCalls.Load(), int32(0), "the staging session must not be read for DHI") + + // DHI shares the cached Docker Hub session without changing it. + got, err = p.GetAuthConfig("docker.io") + assert.NilError(t, err) + assert.DeepEqual(t, got, desktopCredentials()) + assert.Equal(t, hub.sessionCalls.Load(), int32(1)) + }) + } +} + func TestDesktopAuthProvider_StagingRegistryUsesStagingSession(t *testing.T) { for _, host := range []string{StagingRegistryHost, StagingIndexServer, "https://" + StagingRegistryHost} { t.Run(host, func(t *testing.T) { diff --git a/internal/registry/registry.go b/internal/registry/registry.go index eee9fff9b..079e857c2 100644 --- a/internal/registry/registry.go +++ b/internal/registry/registry.go @@ -43,6 +43,8 @@ const ( StagingRegistryHost = "registry-1-stage.docker.io" // StagingIndexServer is the credentials key for StagingRegistryHost. StagingIndexServer = "https://" + StagingRegistryHost + "/" + // DHIRegistryHost is the Docker Hardened Images registry. + DHIRegistryHost = "dhi.io" ) // GetAuthConfigKey special-cases using the full index address of the official