Add govulncheck analyzer pass#596
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new govulncheck analyzer pass to the plugin-validator to scan Go plugin backend source (when provided) and backend binaries for known vulnerabilities, and wires the tool into docs + container images.
Changes:
- Introduce
pkg/analysis/passes/govulncheckanalyzer that runsgovulncheck -jsonin source and-mode=binaryon detected backend binaries. - Add unit tests covering NDJSON parsing and analyzer behaviors using a fake
govulncheckshim. - Update README and Docker image to include/install
govulncheck(and installgoin the runtime image for source-mode scanning).
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| README.md | Documents govulncheck as an additional security tool + analyzer. |
| pkg/analysis/passes/govulncheck/types.go | Adds minimal structs for govulncheck -json NDJSON decoding. |
| pkg/analysis/passes/govulncheck/govulncheck.go | Implements the new analyzer, running source and binary scans and reporting findings. |
| pkg/analysis/passes/govulncheck/govulncheck_test.go | Adds tests for NDJSON parsing and analyzer reporting/scan behaviors. |
| pkg/analysis/passes/analysis.go | Registers the new analyzer in the global analyzer list. |
| Dockerfile | Installs/copies govulncheck into images and adds go to runtime for source scanning. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
bd423d1 to
536f050
Compare
733f6f4 to
529b068
Compare
| scansPerformed := 0 | ||
| scanFailures := 0 | ||
| findingsReported := 0 | ||
| hasBackend := hasBackendPlugin(pass) | ||
|
|
||
| sourceCodeDir, ok := pass.ResultOf[sourcecode.Analyzer].(string) | ||
| if !ok || sourceCodeDir == "" { |
| if hasBackend { | ||
| scanFailures++ | ||
| pass.ReportResult( | ||
| pass.AnalyzerName, | ||
| govulncheckScanFailed, | ||
| "govulncheck source scan skipped", | ||
| "Backend plugin source code was not provided, so govulncheck could not scan the source.", | ||
| ) |
| err := os.WriteFile(fakeGovulncheck, []byte(`#!/bin/sh | ||
| printf '{"config":{"protocol_version":"v1.0.0","scanner_name":"govulncheck"}}\n' | ||
| printf 'loading packages failed\n' >&2 | ||
| exit 1 | ||
| `), 0o755) |
| # govulncheck is distributed as a Go module — install with `go install` rather | ||
| # than a binary tarball. Pinned version is fixed via the ARG above. | ||
| RUN go install golang.org/x/vuln/cmd/govulncheck@${GOVULNCHECK_VERSION} && \ | ||
| mv "$(go env GOPATH)/bin/govulncheck" /usr/local/bin/govulncheck |
529b068 to
7b0f98c
Compare
| osvIDs, err := parseCalledFindings(bytes.NewReader(stdout)) | ||
| if err != nil { | ||
| logme.Errorln("Error parsing govulncheck source output", "error", err) | ||
| return nil, err |
There was a problem hiding this comment.
returning an error here will stop the whole validator and all other possible checks. only return errors from the validator if you want to break the whole pipeline from it.
| for _, moduleDir := range moduleDirs { | ||
| stdout, ok, failureDetail, err := runGovulncheckJSON(govulncheckBin, moduleDir, moduleDir, "-json", "./...") | ||
| if err != nil { | ||
| return nil, err |
There was a problem hiding this comment.
returning an error here will stop the whole validator and all other possible checks. only return errors from the validator if you want to break the whole pipeline from it.
| if ok && sourceCodeDir != "" { | ||
| moduleDirs, err := goModuleDirs(sourceCodeDir) | ||
| if err != nil { | ||
| return nil, err |
There was a problem hiding this comment.
returning an error here will stop the whole validator and all other possible checks. only return errors from the validator if you want to break the whole pipeline from it.
| for _, binaryPath := range binaryPaths { | ||
| stdout, ok, failureDetail, err := runGovulncheckJSON(govulncheckBin, "", filepath.Base(binaryPath), "-mode=binary", "-json", binaryPath) | ||
| if err != nil { | ||
| return nil, err |
There was a problem hiding this comment.
returning an error here will stop the whole validator and all other possible checks. only return errors from the validator if you want to break the whole pipeline from it.
| return moduleDirs, nil | ||
| } | ||
|
|
||
| func backendBinaries(pass *analysis.Pass) ([]string, error) { |
There was a problem hiding this comment.
should this be called getBackendBinaries instead?
| osvIDs, err := parseAllFindings(bytes.NewReader(stdout)) | ||
| if err != nil { | ||
| logme.Errorln("Error parsing govulncheck binary output", "error", err) | ||
| return nil, err |
There was a problem hiding this comment.
returning an error here will stop the whole validator and all other possible checks. only return errors from the validator if you want to break the whole pipeline from it.
Part of https://github.com/grafana/grafana-catalog-team/issues/945