internal/worker: refactor CVE parsing logic
Logic for parsing data from a CVE is refactored and moved to various
helper functions.
Change-Id: Idd0162c6240a8ae2b1a63d3faf4d32e29e00a40c
Reviewed-on: https://go-review.googlesource.com/c/vuln/+/362239
Trust: Julie Qiu <julie@golang.org>
Run-TryBot: Julie Qiu <julie@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
diff --git a/internal/worker/cve.go b/internal/worker/cve.go
index 88faac3..1272070 100644
--- a/internal/worker/cve.go
+++ b/internal/worker/cve.go
@@ -5,8 +5,8 @@
package worker
import (
+ "errors"
"fmt"
- "log"
"net/http"
"net/url"
"strings"
@@ -16,66 +16,58 @@
"golang.org/x/vuln/internal/report"
)
-const goGitHubRepo = "github.com/golang/go"
+const (
+ stateReserved = "Reserved"
+ statePublicNotGoVuln = "Public - Not Go Vuln"
+ statePublicGoVuln = "Public - Go Vuln"
+)
-// cveToIssue creates a cveRecord from a c *cveschema.CVE.
-func cveToIssue(c *cveschema.CVE) (_ *cve, err error) {
+var errCVEVersionUnsupported = errors.New("unsupported CVE version")
+
+// triageCVE triages the CVE and creates a cve record state.
+func triageCVE(c *cveschema.CVE) (_ *cve, err error) {
defer derrors.Wrap(&err, "cveToIssue(%q)", c.CVEDataMeta.ID)
- if isPendingCVE(c) {
- return nil, nil
+ if isReservedCVE(c) {
+ return createCVE(c, stateReserved, "", false), nil
}
switch c.DataVersion {
case "4.0":
- return cveToIssueV4(c)
+ mp, err := cveModulePath(c)
+ if err != nil {
+ return nil, err
+ }
+ if mp == "" {
+ return createCVE(c, statePublicNotGoVuln, "", false), nil
+ }
+ return createCVE(c, statePublicGoVuln, mp, true), nil
default:
// TODO(https://golang.org/issue/49289): Add support for v5.0.
- log.Printf("Unxpected data_version for CVE %q: %q (skipping)", c.CVEDataMeta.ID, c.DataVersion)
- return nil, nil
+ return nil, fmt.Errorf("CVE %q has DataVersion %q: %w", c.CVEDataMeta.ID, c.DataVersion, errCVEVersionUnsupported)
}
}
-func cveToIssueV4(c *cveschema.CVE) (_ *cve, err error) {
- mp, err := modulePathFromCVE(c)
- if err != nil {
- return nil, err
- }
- if mp == "" {
- return nil, nil
- }
- var links report.Links
- for _, r := range c.References.ReferenceData {
- if links.Commit == "" && strings.Contains(r.URL, "/commit/") {
- links.Commit = r.URL
- } else if links.PR == "" && strings.Contains(r.URL, "/pull/") {
- links.PR = r.URL
- } else {
- links.Context = append(links.Context, r.URL)
- }
- }
- var cwe string
- for _, pt := range c.Problemtype.ProblemtypeData {
- for _, d := range pt.Description {
- if strings.Contains(d.Value, "CWE") {
- cwe = d.Value
- }
- }
- }
+const goGitHubRepo = "github.com/golang/go"
+
+// createCVE creates a cve record state from the data provided.
+func createCVE(c *cveschema.CVE, state string, mp string, isGoVuln bool) *cve {
r := &cve{
CVE: *c,
- cwe: cwe,
+ state: state,
+ cwe: cveCWE(c),
modulePath: mp,
- links: links,
+ links: cveLinks(c),
description: description(c),
+ isGoVuln: isGoVuln,
}
if mp == goGitHubRepo {
r.modulePath = "Standard Library"
}
- return r, nil
+ return r
}
// isPendingCVE reports if the CVE is still waiting on information and not
// ready to be triaged.
-func isPendingCVE(c *cveschema.CVE) bool {
+func isReservedCVE(c *cveschema.CVE) bool {
return c.CVEDataMeta.STATE == cveschema.StateReserved
}
@@ -88,10 +80,10 @@
"golang.org": true,
}
-// modulePathFromCVE returns a Go module path for a CVE, if we can determine
-// what it is.
-func modulePathFromCVE(c *cveschema.CVE) (_ string, err error) {
- defer derrors.Wrap(&err, "modulePathFromCVE(c)")
+// cveModulePath returns a Go module path for a CVE, if we can determine what
+// it is.
+func cveModulePath(c *cveschema.CVE) (_ string, err error) {
+ defer derrors.Wrap(&err, "cveModulePath(%q)", c.CVEDataMeta.ID)
for _, r := range c.References.ReferenceData {
if r.URL == "" {
continue
@@ -122,6 +114,32 @@
return "", nil
}
+func cveLinks(c *cveschema.CVE) report.Links {
+ var links report.Links
+ for _, r := range c.References.ReferenceData {
+ if links.Commit == "" && strings.Contains(r.URL, "/commit/") {
+ links.Commit = r.URL
+ } else if links.PR == "" && strings.Contains(r.URL, "/pull/") {
+ links.PR = r.URL
+ } else {
+ links.Context = append(links.Context, r.URL)
+ }
+ }
+ return links
+}
+
+func cveCWE(c *cveschema.CVE) string {
+ var cwe string
+ for _, pt := range c.Problemtype.ProblemtypeData {
+ for _, d := range pt.Description {
+ if strings.Contains(d.Value, "CWE") {
+ cwe = d.Value
+ }
+ }
+ }
+ return cwe
+}
+
func description(c *cveschema.CVE) string {
var ds []string
for _, d := range c.Description.DescriptionData {
diff --git a/internal/worker/worker.go b/internal/worker/worker.go
index 8fff940..7aa150c 100644
--- a/internal/worker/worker.go
+++ b/internal/worker/worker.go
@@ -11,6 +11,7 @@
"fmt"
"log"
"path"
+ "sort"
"strings"
"github.com/go-git/go-git/v5"
@@ -42,12 +43,17 @@
if err := walkRepo(repo, root, "", t); err != nil {
return err
}
+ var newVulns []string
for cveID, r := range t {
if r.isGoVuln {
- fmt.Println(cveID)
+ newVulns = append(newVulns, fmt.Sprintf("%s (%s)", cveID, r.modulePath))
}
}
+ sort.Strings(newVulns)
log.Printf("Found %d new issues from %d CVEs", t.totalVulns(), t.totalCVEs())
+ for _, v := range newVulns {
+ fmt.Println(v)
+ }
return nil
}
@@ -81,7 +87,7 @@
if err != nil {
return err
}
- issue, err := cveToIssue(c)
+ issue, err := triageCVE(c)
if err != nil {
return err
}