-
Notifications
You must be signed in to change notification settings - Fork 2.1k
cli/file_store: Go 1.26 compatibility #7026
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -104,7 +104,7 @@ func (c *fileStore) Store(authConfig types.AuthConfig) error { | |
| // stored as hostname or as hostname including scheme (in legacy configuration | ||
| // files). | ||
| // | ||
| // It's the equivalent to [registry.ConvertToHostname] in the daemon. | ||
| // It's based on [registry.ConvertToHostname] from Moby daemon. | ||
| // | ||
| // [registry.ConvertToHostname]: https://pkg.go.dev/github.com/moby/moby/v2@v2.0.0-beta.7/daemon/pkg/registry#ConvertToHostname | ||
| func ConvertToHostname(maybeURL string) string { | ||
|
|
@@ -117,7 +117,48 @@ func ConvertToHostname(maybeURL string) string { | |
| } | ||
| return net.JoinHostPort(u.Hostname(), u.Port()) | ||
| } | ||
|
|
||
| if hostName := hostFromURLFallback(stripped); hostName != "" { | ||
| return hostName | ||
| } | ||
| } | ||
| hostName, _, _ := strings.Cut(stripped, "/") | ||
| return hostName | ||
| } | ||
|
|
||
| // hostFromURLFallback extracts a host from scheme URLs that net/url rejects. | ||
| // Go rejects unbracketed IPv6 literals in URL hosts since | ||
| // https://github.com/golang/go/commit/0c28789bd7dfc55099cac86a3212dda0d6c091f6 | ||
| func hostFromURLFallback(maybeURL string) string { | ||
| _, rest, ok := strings.Cut(maybeURL, "://") | ||
| if !ok { | ||
| return "" | ||
| } | ||
|
|
||
| hostName, _, _ := strings.Cut(rest, "/") | ||
| if hostName == "" { | ||
| return "" | ||
| } | ||
|
|
||
| if strings.Count(hostName, ":") > 1 && !strings.HasPrefix(hostName, "[") { | ||
| portStart := strings.LastIndex(hostName, ":") | ||
| addr, port := hostName[:portStart], hostName[portStart+1:] | ||
| if addr != "" && isPort(port) { | ||
| return net.JoinHostPort(addr, port) | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [LOW] Non-numeric-port branch falls through and returns unbracketed IPv6 string When All other code paths that handle IPv6 addresses produce bracketed output ( In practice, credentials with non-numeric ports are not realistic, so the real-world impact is near zero. But the fall-through behaviour is worth documenting (or guarding) for correctness. |
||
| } | ||
|
|
||
| return hostName | ||
| } | ||
|
|
||
| func isPort(port string) bool { | ||
| if port == "" { | ||
| return false | ||
| } | ||
| for _, r := range port { | ||
| if r < '0' || r > '9' { | ||
| return false | ||
| } | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [LOW] isPort accepts values > 65535 — no upper-bound validation
In practice this mirrors whatever was stored under old Go (which also had no port-range enforcement in |
||
| return true | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[MEDIUM] hostFromURLFallback misidentifies last IPv6 segment as port, producing a malformed address
For any unbracketed IPv6 address without an explicit port — e.g. a legacy credential stored as
"https://2001:db8::1/path"— the fallback parser splits on the last:and misidentifies the final group of the IPv6 address as a port number.Trace for
"https://2001:db8::1/path":url.Parsefails (Go 1.26 rejects unbracketed IPv6), so the fallback is invoked.hostName = "2001:db8::1".strings.Count("2001:db8::1", ":") = 3 > 1→ enters the branch.portStart = strings.LastIndex("2001:db8::1", ":") = 9→addr = "2001:db8:",port = "1".isPort("1") = true→ returnsnet.JoinHostPort("2001:db8:", "1")="[2001:db8:]:1".The
addrvalue"2001:db8:"has a trailing colon and is not a valid IPv6 address. Any credential previously stored under"https://2001:db8::1"would fail to match after normalization because the key becomes"[2001:db8:]:1"instead of"2001:db8::1".Fix suggestion: Before splitting on the last
:, check whether the suffix after the last:is also a valid hex IPv6 group — or, more robustly, attemptnet.ParseIP(hostName)first. If it parses as a valid IP (no port), returnnet.JoinHostPort(hostName, "")(i.e. bracket but no port) or justhostNameunchanged.