Summary
normalizeEndpoint() in pkg/commands/talosctl_wrapper.go:225-239 produces a malformed URL for IPv6 inputs. Square brackets that delimit the host literal in URI authority syntax (RFC 3986, Go net/url) are dropped, leaving an unparseable https://2001:db8::1:6443 instead of the canonical https://[2001:db8::1]:6443.
Reproduction
got := normalizeEndpoint("[2001:db8::1]:6443")
// got == "https://2001:db8::1:6443" <- malformed
url.Parse(got) rejects this URL: per Go's net/url documentation, when the host is an IPv6 address it must be enclosed in square brackets. Any HTTP client or kubeconfig dialer that re-parses the value (e.g. through clientcmd.LoadFromFile followed by a real connect attempt) will fail.
Root cause
// pkg/commands/talosctl_wrapper.go:225-239
func normalizeEndpoint(endpoint string) string {
endpoint = strings.TrimPrefix(endpoint, "https://")
endpoint = strings.TrimPrefix(endpoint, "http://")
host, _, err := net.SplitHostPort(endpoint)
if err != nil {
host = endpoint
}
return fmt.Sprintf("https://%s:6443", host) // <-- no bracket re-add
}
net.SplitHostPort strips the brackets from [2001:db8::1]:6443, returning host == "2001:db8::1". The final fmt.Sprintf does NOT re-add them, producing the malformed string.
Suggested fix
Use net.JoinHostPort for the assembly step — it adds brackets back automatically when the host contains a colon:
return "https://" + net.JoinHostPort(host, "6443")
This is the recommended pattern in net/url documentation and works correctly for both IPv4 and IPv6 inputs.
Notes
Discovered by CodeRabbit on PR #154 while reviewing the contract test that pinned the current (broken) output. The contract test on test/chart-contract keeps the broken case with a FIXME pointing at this issue, so the test can be tightened once the fix lands.
Impact
updateKubeconfigServer() calls normalizeEndpoint() to rewrite the server: field of a managed kubeconfig. An operator running a single-node Talos on an IPv6 cluster endpoint would end up with a kubeconfig that kubectl cannot parse. Likely undiscovered today only because the IPv6-only Talos install path is uncommon in the user base.
Summary
normalizeEndpoint()inpkg/commands/talosctl_wrapper.go:225-239produces a malformed URL for IPv6 inputs. Square brackets that delimit the host literal in URI authority syntax (RFC 3986, Gonet/url) are dropped, leaving an unparseablehttps://2001:db8::1:6443instead of the canonicalhttps://[2001:db8::1]:6443.Reproduction
url.Parse(got)rejects this URL: per Go'snet/urldocumentation, when the host is an IPv6 address it must be enclosed in square brackets. Any HTTP client or kubeconfig dialer that re-parses the value (e.g. throughclientcmd.LoadFromFilefollowed by a real connect attempt) will fail.Root cause
net.SplitHostPortstrips the brackets from[2001:db8::1]:6443, returninghost == "2001:db8::1". The finalfmt.Sprintfdoes NOT re-add them, producing the malformed string.Suggested fix
Use
net.JoinHostPortfor the assembly step — it adds brackets back automatically when the host contains a colon:This is the recommended pattern in
net/urldocumentation and works correctly for both IPv4 and IPv6 inputs.Notes
Discovered by CodeRabbit on PR #154 while reviewing the contract test that pinned the current (broken) output. The contract test on
test/chart-contractkeeps the broken case with a FIXME pointing at this issue, so the test can be tightened once the fix lands.Impact
updateKubeconfigServer()callsnormalizeEndpoint()to rewrite theserver:field of a managed kubeconfig. An operator running a single-node Talos on an IPv6 cluster endpoint would end up with a kubeconfig thatkubectlcannot parse. Likely undiscovered today only because the IPv6-only Talos install path is uncommon in the user base.