From 7a8baa68e699f32bca671b192e54da919e84dac5 Mon Sep 17 00:00:00 2001 From: Nicholas Wiersma Date: Sun, 10 May 2026 13:22:40 +0200 Subject: [PATCH] fix: parsing to be actual findings --- internal/govulncheck/parse.go | 68 ++++++-------------- internal/govulncheck/testdata/multi.json | 4 ++ internal/modfix/testdata/apply/go.mod | 6 +- internal/modfix/testdata/apply/go.mod.golden | 5 +- internal/modfix/testdata/apply/go.sum | 3 + internal/modfix/testdata/apply/main.go | 6 +- 6 files changed, 40 insertions(+), 52 deletions(-) diff --git a/internal/govulncheck/parse.go b/internal/govulncheck/parse.go index 49db674..96b5779 100644 --- a/internal/govulncheck/parse.go +++ b/internal/govulncheck/parse.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "io" + "strings" "golang.org/x/mod/semver" ) @@ -16,31 +17,17 @@ import ( // golang.org/x/vuln/internal/osv, which are not importable externally. type message struct { - OSV *osvEntry `json:"osv,omitempty"` + Finding *finding `json:"finding"` } -type osvEntry struct { - Affected []affected `json:"affected"` +type finding struct { + OSV string `json:"osv"` + FixedVersion string `json:"fixed_version"` + Trace []frame `json:"trace"` } -type affected struct { - Package osvModule `json:"package"` - Ranges []rng `json:"ranges"` -} - -// osvModule is the package identifier in an OSV entry. -// The JSON field name is "name", not "path". -type osvModule struct { - Path string `json:"name"` -} - -type rng struct { - Events []rangeEvent `json:"events"` -} - -type rangeEvent struct { - Introduced string `json:"introduced,omitempty"` - Fixed string `json:"fixed,omitempty"` +type frame struct { + Module string `json:"module"` } const ( @@ -53,12 +40,11 @@ const ( GoToolchainPath = "toolchain" ) -// ParseFixed reads govulncheck -json output from r and returns a map of -// module path to the minimum version that fixes all known vulnerabilities -// for that module. When a module appears in multiple OSV entries the -// highest fix version wins. Versions have no leading "v". -// -//nolint:gocognit // Splitting this will not make it simpler. +// ParseFixed reads govulncheck -json output from r and returns a map of module +// path to the minimum version that fixes all reachable vulnerabilities. Only +// finding messages are considered, so modules that are imported but whose +// vulnerable symbols are never called are not included. When a module has +// multiple findings the highest fix version is used. Versions have no leading "v". func ParseFixed(r io.Reader) (map[string]string, error) { dec := json.NewDecoder(r) @@ -71,29 +57,17 @@ func ParseFixed(r io.Reader) (map[string]string, error) { } return nil, fmt.Errorf("parsing govulncheck JSON: %w", err) } - if msg.OSV == nil { + + if msg.Finding == nil || len(msg.Finding.Trace) == 0 { continue } - for _, aff := range msg.OSV.Affected { - mod := aff.Package.Path - if mod == "" { - continue - } - - for _, r := range aff.Ranges { - for _, ev := range r.Events { - if ev.Fixed == "" { - continue - } - - // semver.Compare expects a leading "v". - candidate := "v" + ev.Fixed - if existing, ok := fixed[mod]; !ok || semver.Compare(candidate, "v"+existing) > 0 { - fixed[mod] = ev.Fixed - } - } - } + mod := msg.Finding.Trace[0].Module + fixedVer := msg.Finding.FixedVersion + fixedVer = strings.TrimPrefix(fixedVer, "v") + fixedVer = strings.TrimPrefix(fixedVer, "go") + if existing, ok := fixed[mod]; !ok || semver.Compare("v"+fixedVer, "v"+existing) > 0 { + fixed[mod] = fixedVer } } return fixed, nil diff --git a/internal/govulncheck/testdata/multi.json b/internal/govulncheck/testdata/multi.json index cbe2414..383a4fc 100644 --- a/internal/govulncheck/testdata/multi.json +++ b/internal/govulncheck/testdata/multi.json @@ -3,4 +3,8 @@ {"osv":{"id":"GO-2024-0004","affected":[{"package":{"name":"example.com/foo","ecosystem":"Go"},"ranges":[{"type":"SEMVER","events":[{"introduced":"1.2.4"},{"fixed":"1.3.0"}]}]}]}} {"osv":{"id":"GO-2024-0002","affected":[{"package":{"name":"stdlib","ecosystem":"Go"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"1.22.3"}]}]}]}} {"osv":{"id":"GO-2024-0005","affected":[{"package":{"name":"example.com/bar","ecosystem":"Go"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"2.0.1"}]}]}]}} +{"finding":{"osv":"GO-2024-0001","fixed_version":"v1.2.3","trace":[{"module":"example.com/foo","version":"v1.0.0"}]}} +{"finding":{"osv":"GO-2024-0004","fixed_version":"v1.3.0","trace":[{"module":"example.com/foo","version":"v1.2.6"}]}} +{"finding":{"osv":"GO-2024-0002","fixed_version":"go1.22.3","trace":[{"module":"stdlib","version":"go1.21.0"}]}} +{"finding":{"osv":"GO-2024-0005","fixed_version":"v2.0.1","trace":[{"module":"example.com/bar","version":"v1.9.0"}]}} diff --git a/internal/modfix/testdata/apply/go.mod b/internal/modfix/testdata/apply/go.mod index db5965d..1954aaf 100644 --- a/internal/modfix/testdata/apply/go.mod +++ b/internal/modfix/testdata/apply/go.mod @@ -2,5 +2,7 @@ module vulnfixtest go 1.21.0 -require golang.org/x/mod v0.6.0 - +require ( + golang.org/x/mod v0.6.0 + golang.org/x/sync v0.11.0 +) diff --git a/internal/modfix/testdata/apply/go.mod.golden b/internal/modfix/testdata/apply/go.mod.golden index 0374c8a..82bc978 100644 --- a/internal/modfix/testdata/apply/go.mod.golden +++ b/internal/modfix/testdata/apply/go.mod.golden @@ -4,4 +4,7 @@ go 1.22.3 toolchain go1.23.0 -require golang.org/x/mod v0.8.0 +require ( + golang.org/x/mod v0.8.0 + golang.org/x/sync v0.11.0 +) diff --git a/internal/modfix/testdata/apply/go.sum b/internal/modfix/testdata/apply/go.sum index 802a862..674bc95 100644 --- a/internal/modfix/testdata/apply/go.sum +++ b/internal/modfix/testdata/apply/go.sum @@ -1 +1,4 @@ +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= diff --git a/internal/modfix/testdata/apply/main.go b/internal/modfix/testdata/apply/main.go index a428b85..4f565a0 100644 --- a/internal/modfix/testdata/apply/main.go +++ b/internal/modfix/testdata/apply/main.go @@ -1,6 +1,8 @@ package main -import _ "golang.org/x/mod/modfile" +import ( + _ "golang.org/x/mod/modfile" + _ "golang.org/x/sync/errgroup" +) func main() {} -