feat: golang module support pseudo version#8293
feat: golang module support pseudo version#8293olblak wants to merge 1 commit intoupdatecli:mainfrom
Conversation
Signed-off-by: Olblak <me@olblak.com>
There was a problem hiding this comment.
Pull request overview
This PR extends the Go module resource to better handle modules that don’t publish tagged versions by falling back to Go proxy pseudo-versions (via @latest) when using “latest”-style filters, and updates the condition check to query specific versions via the Go proxy .info endpoint.
Changes:
- Refactors proxy version retrieval into helper functions and trims/normalizes list responses.
- Adds
@latestJSON parsing to support pseudo-version fallback when no versions are published. - Updates
Conditionto check for a specific version using@v/<version>.infoinstead of scanning the full version list.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 10 comments.
| File | Description |
|---|---|
| pkg/plugins/resources/go/module/version.go | Adds proxy helpers and @latest fallback logic to return pseudo-versions when no tagged versions exist. |
| pkg/plugins/resources/go/module/condition.go | Switches condition checks to use the proxy .info endpoint per version and aligns GOPROXY resolution logic. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| req, err := http.NewRequestWithContext(ctx, "GET", URL, nil) | ||
| if err != nil { | ||
| logrus.Errorf("something went wrong while getting go module api data %q\n", err) | ||
| return "", err | ||
| } |
There was a problem hiding this comment.
getLatestVersionFromProxy uses http.NewRequestWithContext with a variable URL but doesn't include the gosec suppression used elsewhere in this file. With golangci-lint enabling gosec, this is likely to raise G107 and fail CI unless the URL is validated/whitelisted or an explicit suppression with justification is added (as done in getVersionsFromProxy).
| req, err := http.NewRequestWithContext(ctx, "GET", URL, nil) | ||
| if err != nil { | ||
| logrus.Errorf("something went wrong while getting go module api data %q\n", err) | ||
| return "", err | ||
| } |
There was a problem hiding this comment.
getVersionInfoFromProxy also builds a request with a variable URL and is missing the gosec G107 suppression / validation approach used above. Please either validate the proxy URL input (Spec.Proxy / GOPROXY) before use or add an explicit, justified suppression so golangci-lint doesn't fail.
| return "", nil, fmt.Errorf("GO module %q not found on proxy %q", g.Spec.Module, GOPROXY) | ||
| } | ||
|
|
||
| // getVersionInfoFromProxy returns all versions of a Golang module from a proxy |
There was a problem hiding this comment.
The doc comment above getVersionsFromProxy is incorrect (it says "getVersionInfoFromProxy returns..."). This makes the helper harder to discover/understand; please update the comment to match the actual function name and behavior.
| // getVersionInfoFromProxy returns all versions of a Golang module from a proxy | |
| // getVersionsFromProxy returns all versions of a Golang module from a proxy |
|
|
||
| data, err := io.ReadAll(res.Body) | ||
| if err != nil { | ||
| logrus.Errorf("something went wrong while getting npm api data%q\n", err) |
There was a problem hiding this comment.
This error log refers to the "npm api" in a Go module proxy codepath. Please fix the message to reference the Go module/proxy request to avoid confusion when debugging.
| logrus.Errorf("something went wrong while getting npm api data%q\n", err) | |
| logrus.Errorf("something went wrong while reading go module proxy response %q\n", err) |
|
|
||
| data, err := io.ReadAll(res.Body) | ||
| if err != nil { | ||
| logrus.Errorf("something went wrong while getting npm api data%q\n", err) |
There was a problem hiding this comment.
This error log refers to the "npm api" in a Go module proxy codepath. Please fix the message to reference the Go module/proxy request to avoid confusion when debugging.
| logrus.Errorf("something went wrong while getting npm api data%q\n", err) | |
| logrus.Errorf("something went wrong while reading go module proxy response data %q\n", err) |
| body, err := httputil.DumpResponse(res, false) | ||
| logrus.Errorf("something went wrong while getting golang module data %q\n", err) | ||
| logrus.Debugf("skipping proxy %q due to %q\n", proxy, err) | ||
| logrus.Debugf("\n%v\n", string(body)) |
There was a problem hiding this comment.
When res.StatusCode >= 400, the code logs err from httputil.DumpResponse, not the actual HTTP failure context (status code/status). This can emit misleading "something went wrong" errors even when the dump succeeds (err=nil). Consider logging res.Status/res.StatusCode and only logging the dump error if it occurs.
| body, err := httputil.DumpResponse(res, false) | |
| logrus.Errorf("something went wrong while getting golang module data %q\n", err) | |
| logrus.Debugf("skipping proxy %q due to %q\n", proxy, err) | |
| logrus.Debugf("\n%v\n", string(body)) | |
| logrus.Errorf("something went wrong while getting golang module data: proxy %q returned HTTP %d (%s)\n", proxy, res.StatusCode, res.Status) | |
| logrus.Debugf("skipping proxy %q due to HTTP %d (%s)\n", proxy, res.StatusCode, res.Status) | |
| body, err := httputil.DumpResponse(res, false) | |
| if err != nil { | |
| logrus.Debugf("failed to dump proxy response for %q: %q\n", proxy, err) | |
| } else { | |
| logrus.Debugf("\n%v\n", string(body)) | |
| } |
| if proxyVersions == nil && isLatestVersionFilter(g.versionFilter) { | ||
| pseudoVersion, err := getLatestVersionFromProxy(ctx, g.webClient, proxy, g.Spec.Module) | ||
| if err != nil { | ||
| logrus.Debugf("skipping proxy %q due to %q\n", proxy, err) | ||
| continue | ||
| } | ||
|
|
||
| data, err := io.ReadAll(res.Body) | ||
| if err != nil { | ||
| logrus.Errorf("something went wrong while getting npm api data%q\n", err) | ||
| return "", []string{}, err | ||
| if pseudoVersion != "" { | ||
| versions = append(versions, pseudoVersion) | ||
| } | ||
|
|
||
| logrus.Debugf("no version published for module %q on proxy %q, fallback to pseudo version %q\n", g.Spec.Module, proxy, pseudoVersion) | ||
|
|
||
| return pseudoVersion, versions, nil | ||
| } |
There was a problem hiding this comment.
The pseudo-version fallback behavior (empty @v/list => use @latest when the filter is effectively "latest") is new and currently untested. Please add unit/integration coverage that exercises this path (ideally with a mocked HTTPClient) to prevent regressions and flaky behavior changes in version selection.
| type JSONData struct { | ||
| Version string `json:"Version"` | ||
| Time string `json:"Time"` | ||
| } | ||
|
|
||
| jsonData := JSONData{} | ||
| err = json.Unmarshal(data, &jsonData) |
There was a problem hiding this comment.
JSONData duplicates the same Version/Time shape defined again later (Info). Consider reusing a single struct type for both JSON decodes to reduce duplication and the risk of the two drifting over time.
| for _, proxy := range strings.Split(GOPROXY, ",") { | ||
| if !isSupportedGoProxy(proxy) { | ||
| continue | ||
| } | ||
| version, err := getVersionInfoFromProxy(ctx, g.webClient, proxy, g.Spec.Module, versionToCheck) |
There was a problem hiding this comment.
When iterating over strings.Split(GOPROXY, ","), entries may include leading/trailing whitespace (e.g., from env var formatting). Consider strings.TrimSpace(proxy) before isSupportedGoProxy / URL building to avoid generating invalid proxy URLs like "https:// proxy.golang.org".
| for _, proxy := range strings.Split(GOPROXY, ",") { | ||
| if !isSupportedGoProxy(proxy) { | ||
| continue | ||
| } | ||
|
|
There was a problem hiding this comment.
Like Condition, this loop splits GOPROXY on commas but doesn't trim whitespace for each entry. Trimming each proxy before validation and URL construction would make GOPROXY parsing more robust (e.g., handling "direct, proxy.golang.org").
Support pseudo version such as
github.com/shurcooL/githubv4 v0.0.0-20230215024106-420ad0987b9bfor golang moduleTest
To test this pull request, you can run the following commands:
pkg/plugins/resources/go/module/ go testAdditional Information
Checklist
Tradeoff
Potential improvement