-
Notifications
You must be signed in to change notification settings - Fork 7k
fix: support relative links in OCI tags query response #11708
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
Changes from all commits
54d039b
29d0bd7
4398bf8
526526d
7504365
9c0a477
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 |
|---|---|---|
|
|
@@ -390,10 +390,10 @@ func getTagsListURL(rawURL string, chart string) (string, error) { | |
| if err != nil { | ||
| return "", fmt.Errorf("unable to parse repo url: %v", err) | ||
| } | ||
| tagsPathFormat := "%s/v2/%s/tags/list" | ||
| repoURL.Scheme = "https" | ||
| tagsList := strings.Join([]string{"v2", url.PathEscape(chart), "tags/list"}, "/") | ||
| repoURL.Path = strings.Join([]string{repoURL.Path, tagsList}, "/") | ||
| repoURL.RawPath = strings.Join([]string{repoURL.RawPath, tagsList}, "/") | ||
| repoURL.Path = fmt.Sprintf(tagsPathFormat, repoURL.Path, chart) | ||
| repoURL.RawPath = fmt.Sprintf(tagsPathFormat, repoURL.RawPath, url.PathEscape(chart)) | ||
| return repoURL.String(), nil | ||
| } | ||
|
|
||
|
|
@@ -406,7 +406,7 @@ func (c *nativeHelmChart) getTags(chart string) ([]byte, error) { | |
| allTags := &TagsList{} | ||
| var data []byte | ||
| for nextURL != "" { | ||
| log.Debugf("fetching %s tags from %s", chart, text.Trunc(nextURL, 100)) | ||
| log.Debugf("fetching %s tags from %s", chart, sanitizeLog(text.Trunc(nextURL, 100))) | ||
| data, nextURL, err = c.getTagsFromUrl(nextURL) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("failed tags part: %v", err) | ||
|
|
@@ -426,14 +426,30 @@ func (c *nativeHelmChart) getTags(chart string) ([]byte, error) { | |
| return data, nil | ||
| } | ||
|
|
||
| func getNextUrl(linkHeader string) string { | ||
| nextUrl := "" | ||
| if linkHeader != "" { | ||
| // drop < >; ref= from the Link header, see: https://docs.docker.com/registry/spec/api/#pagination | ||
| nextUrl = strings.Split(linkHeader, ";")[0][1:] | ||
| nextUrl = nextUrl[:len(nextUrl)-1] | ||
| func getNextUrl(resp *http.Response) (string, error) { | ||
| link := resp.Header.Get("Link") | ||
| if link == "" { | ||
| return "", nil | ||
| } | ||
| return nextUrl | ||
| if link[0] != '<' { | ||
| return "", fmt.Errorf("invalid next link %q: missing '<'", link) | ||
| } | ||
| if i := strings.IndexByte(link, '>'); i == -1 { | ||
| return "", fmt.Errorf("invalid next link %q: missing '>'", link) | ||
| } else { | ||
| link = link[1:i] | ||
| } | ||
| linkURL, err := resp.Request.URL.Parse(link) | ||
|
Member
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. Is this the place where you convert from relative link to absolute?
Contributor
Author
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. yes, more precisely just the Granted, this code was inspired a great deal by https://github.com/oras-project/oras-go/blob/main/registry/remote/utils.go#L40 which also begs the question: shouldn't we use the oras-go project for this OCI functionality? Helm itself is using it internally
Member
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. @detvdl as I'm new to the project, I was reluctant to introduce new dependencies in my pr. But I agree, it makes sense to use the library rather than copying the code. As 2.6RC is just around the corner, it probably makes sense to merge this fix as is, and then replace the code with oras in a separate PR? Will let @crenshaw-dev / @alexmt decide.
Contributor
Author
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. I would agree with that, let's wait for their decision indeed
Member
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. In general, I'm cool w/ Oras if it saves, say, 30 lines of code that they're more likely to get correct. But I think that can wait for a follow-up PR. :-) |
||
| if err != nil { | ||
| return "", err | ||
| } | ||
| return linkURL.String(), nil | ||
| } | ||
|
|
||
| func sanitizeLog(input string) string { | ||
| sanitized := strings.ReplaceAll(input, "\r", "") | ||
| sanitized = strings.ReplaceAll(sanitized, "\n", "") | ||
| return sanitized | ||
| } | ||
|
|
||
| func (c *nativeHelmChart) getTagsFromUrl(tagsURL string) ([]byte, string, error) { | ||
|
|
@@ -484,8 +500,8 @@ func (c *nativeHelmChart) getTagsFromUrl(tagsURL string) ([]byte, string, error) | |
| if err != nil { | ||
| return nil, "", fmt.Errorf("failed to read body: %v", err) | ||
| } | ||
| nextUrl := getNextUrl(resp.Header.Get("Link")) | ||
| return data, nextUrl, nil | ||
| nextUrl, err := getNextUrl(resp) | ||
| return data, nextUrl, err | ||
| } | ||
|
|
||
| func (c *nativeHelmChart) GetTags(chart string, noCache bool) (*TagsList, error) { | ||
|
|
||
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.
As per the documentation on
url.String()andurl.EscapedPath():This means that
repoURL.RawPathshould contain a valid escaping.In the case of a
chartwith a/in its name, the following occurred:url.PathEscape("chart/name")generatedchart%2FnamerepoURL.PathandrepoURL.RawPathboth containchart%2FnamerepoURL.String()invokesrepoURL.EscapedPath()repoURL.EscapedPath()does not recognizechart%2Fnameas a valid escaping ofchart%2FnamerepoURL.EscapedPath()escapes again, resulting inchart%252Fnameand the resulting URL is not correct and results in 404 responses