internal/worker: (WIP) add logic to convert from govulncheck.Vuln to bigquerry vuln
Adds the convertGovulncheckVuln func to vulncheck_scan.go (see b/264852628)
Change-Id: Icac4f40fb2394de987f61d6cc053c9e26ee9068e
Reviewed-on: https://go-review.googlesource.com/c/pkgsite-metrics/+/466656
Run-TryBot: Maceo Thompson <maceothompson@google.com>
Reviewed-by: Zvonimir Pavlinovic <zpavlinovic@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
diff --git a/internal/worker/vulncheck_scan.go b/internal/worker/vulncheck_scan.go
index db94733..4d288e6 100644
--- a/internal/worker/vulncheck_scan.go
+++ b/internal/worker/vulncheck_scan.go
@@ -34,6 +34,7 @@
"golang.org/x/pkgsite-metrics/internal/scan"
"golang.org/x/pkgsite-metrics/internal/version"
vulnc "golang.org/x/vuln/client"
+ "golang.org/x/vuln/exp/govulncheck"
"golang.org/x/vuln/vulncheck"
)
@@ -612,6 +613,50 @@
}
}
+func convertGoVulncheckOutput(v *govulncheck.Vuln) (vulns []*bigquery.Vuln) {
+ for _, module := range v.Modules {
+ for pkgNum, pkg := range module.Packages {
+ addedSymbols := make(map[string]bool)
+ baseVuln := &bigquery.Vuln{
+ ID: v.OSV.ID,
+ ModulePath: module.Path,
+ PackagePath: pkg.Path,
+ CallSink: bigquery.NullInt(0),
+ ImportSink: bigquery.NullInt(pkgNum + 1),
+ RequireSink: bigquery.NullInt(pkgNum + 1),
+ }
+
+ // For each called symbol, reconstruct sinks and create the corresponding bigquery vuln
+ for symbolNum, cs := range pkg.CallStacks {
+ addedSymbols[cs.Symbol] = true
+ toAdd := *baseVuln
+ toAdd.Symbol = cs.Symbol
+ toAdd.CallSink = bigquery.NullInt(symbolNum + 1)
+ vulns = append(vulns, &toAdd)
+ }
+
+ // Find the rest of the vulnerable imported symbols that haven't been called
+ // and create corresponding bigquery vulns
+ for _, affected := range v.OSV.Affected {
+ if affected.Package.Name == module.Path {
+ for _, imp := range affected.EcosystemSpecific.Imports {
+ if imp.Path == pkg.Path {
+ for _, symbol := range imp.Symbols {
+ if !addedSymbols[symbol] {
+ toAdd := *baseVuln
+ toAdd.Symbol = symbol
+ vulns = append(vulns, &toAdd)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return vulns
+}
+
// currHeapUsage computes currently allocate heap bytes.
func currHeapUsage() uint64 {
var stats runtime.MemStats
diff --git a/internal/worker/vulncheck_scan_test.go b/internal/worker/vulncheck_scan_test.go
index ccd488d..794fcc7 100644
--- a/internal/worker/vulncheck_scan_test.go
+++ b/internal/worker/vulncheck_scan_test.go
@@ -14,10 +14,14 @@
"cloud.google.com/go/storage"
"github.com/google/go-cmp/cmp"
+ "github.com/google/go-cmp/cmp/cmpopts"
+ "golang.org/x/pkgsite-metrics/internal/bigquery"
"golang.org/x/pkgsite-metrics/internal/config"
"golang.org/x/pkgsite-metrics/internal/derrors"
"golang.org/x/pkgsite-metrics/internal/proxy"
vulnc "golang.org/x/vuln/client"
+ "golang.org/x/vuln/exp/govulncheck"
+ "golang.org/x/vuln/osv"
"golang.org/x/vuln/vulncheck"
)
@@ -144,3 +148,126 @@
t.Errorf("got %+v, want %+v", got, want)
}
}
+
+func TestConvertGoVulncheckOutput(t *testing.T) {
+ var (
+ osvEntry = &osv.Entry{
+ ID: "GO-YYYY-1234",
+ Affected: []osv.Affected{
+ {
+ Package: osv.Package{
+ Name: "example.com/repo/module",
+ Ecosystem: "Go",
+ },
+ EcosystemSpecific: osv.EcosystemSpecific{
+ Imports: []osv.EcosystemSpecificImport{
+ {
+ Path: "example.com/repo/module/package",
+ Symbols: []string{
+ "Symbol",
+ "Another",
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+
+ vuln1 = &govulncheck.Vuln{
+ OSV: osvEntry,
+ Modules: []*govulncheck.Module{
+ {
+ Path: "example.com/repo/module",
+ Packages: []*govulncheck.Package{
+ {
+ Path: "example.com/repo/module/package",
+ CallStacks: []govulncheck.CallStack{
+ {
+ Symbol: "Symbol",
+ Summary: "example.go:1:1 xyz.func calls pkgPath.Symbol",
+ Frames: []*govulncheck.StackFrame{},
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+
+ vuln2 = &govulncheck.Vuln{
+ OSV: osvEntry,
+ Modules: []*govulncheck.Module{
+ {
+ Path: "example.com/repo/module",
+ Packages: []*govulncheck.Package{
+ {
+ Path: "example.com/repo/module/package",
+ },
+ },
+ },
+ },
+ }
+ )
+ tests := []struct {
+ name string
+ vuln *govulncheck.Vuln
+ wantVulns []*bigquery.Vuln
+ }{
+ {
+ name: "Call One Symbol",
+ vuln: vuln1,
+ wantVulns: []*bigquery.Vuln{
+ {
+ ID: "GO-YYYY-1234",
+ Symbol: "Symbol",
+ PackagePath: "example.com/repo/module/package",
+ ModulePath: "example.com/repo/module",
+ CallSink: bigquery.NullInt(1),
+ ImportSink: bigquery.NullInt(1),
+ RequireSink: bigquery.NullInt(1),
+ },
+ {
+ ID: "GO-YYYY-1234",
+ Symbol: "Another",
+ PackagePath: "example.com/repo/module/package",
+ ModulePath: "example.com/repo/module",
+ CallSink: bigquery.NullInt(0),
+ ImportSink: bigquery.NullInt(1),
+ RequireSink: bigquery.NullInt(1),
+ },
+ },
+ },
+ {
+ name: "Call no symbols",
+ vuln: vuln2,
+ wantVulns: []*bigquery.Vuln{
+ {
+ ID: "GO-YYYY-1234",
+ PackagePath: "example.com/repo/module/package",
+ ModulePath: "example.com/repo/module",
+ Symbol: "Symbol",
+ CallSink: bigquery.NullInt(0),
+ ImportSink: bigquery.NullInt(1),
+ RequireSink: bigquery.NullInt(1),
+ },
+ {
+ ID: "GO-YYYY-1234",
+ PackagePath: "example.com/repo/module/package",
+ ModulePath: "example.com/repo/module",
+ Symbol: "Another",
+ CallSink: bigquery.NullInt(0),
+ ImportSink: bigquery.NullInt(1),
+ RequireSink: bigquery.NullInt(1),
+ },
+ },
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if diff := cmp.Diff(convertGoVulncheckOutput(tt.vuln), tt.wantVulns, cmpopts.EquateEmpty()); diff != "" {
+ t.Errorf("mismatch (-got, +want): %s", diff)
+ }
+ })
+ }
+}