From ffc5042caea701a2947130a07df8f83699026c66 Mon Sep 17 00:00:00 2001 From: Rudy Celekli Date: Sat, 24 Oct 2026 18:10:27 -0400 Subject: [PATCH] fix(registry): derive the add-source id from the full IPv6 host deriveRegistryID dropped a port by cutting the host at the first ':'. For an IPv6 literal URL such as https://[2606:4700:4700::1111]/ that left only the first group, so the id became "2606" and a second registry in the same /16 was refused as a duplicate id. Pass u.Hostname(), which already strips the port and brackets, and drop the cut. --- internal/server/add_registry_source.go | 10 +++----- .../server/add_registry_source_ipv6_test.go | 25 +++++++++++++++++++ 2 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 internal/server/add_registry_source_ipv6_test.go diff --git a/internal/server/add_registry_source.go b/internal/server/add_registry_source.go index 5b22b78a7..b0d62f334 100644 --- a/internal/server/add_registry_source.go +++ b/internal/server/add_registry_source.go @@ -226,7 +226,7 @@ func buildRegistrySourceEntry(rawURL, protocol, id, name string) (config.Registr ErrUnsupportedRegistryProtocol, protocol, defaultRegistryProtocol) } if id == "" { - id = deriveRegistryID(u.Host) + id = deriveRegistryID(u.Hostname()) } if name == "" { name = id @@ -272,13 +272,11 @@ func validateNewRegistrySource(cfg *config.Config, entry config.RegistryEntry) e return nil } -// deriveRegistryID slugifies a host into a stable registry id, dropping a -// leading "www." and a trailing port, and replacing non-alphanumerics with "-". +// deriveRegistryID slugifies a hostname (no port, no IPv6 brackets) into a +// stable registry id, dropping a leading "www." and replacing non-alphanumerics +// with "-". func deriveRegistryID(host string) string { host = strings.ToLower(host) - if h, _, ok := strings.Cut(host, ":"); ok { - host = h - } host = strings.TrimPrefix(host, "www.") var b strings.Builder for _, r := range host { diff --git a/internal/server/add_registry_source_ipv6_test.go b/internal/server/add_registry_source_ipv6_test.go new file mode 100644 index 000000000..204820379 --- /dev/null +++ b/internal/server/add_registry_source_ipv6_test.go @@ -0,0 +1,25 @@ +package server + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// An IPv6 literal host contains colons. Cutting at the first ':' to drop a port +// reduced every such host to its first group, so distinct registries collided +// on the same derived id and the second one was refused as a duplicate. +func TestBuildRegistrySourceEntry_IPv6HostID(t *testing.T) { + cases := map[string]string{ + "https://[2606:4700:4700::1111]/": "2606-4700-4700--1111", + "https://[2606:4700::64]:8443/": "2606-4700--64", + "https://www.Registry.Example:8443/": "registry-example", + "https://registry.acme.example/v0.1/": "registry-acme-example", + } + for raw, want := range cases { + entry, err := buildRegistrySourceEntry(raw, "", "", "") + require.NoError(t, err, raw) + assert.Equal(t, want, entry.ID, raw) + } +}