internal/worker: add triageResult
TriageCVE now returns a triageResult instead of just the module path.
Change-Id: Ie7359ab97d4505e05ebf8b26fcbad80b09ff96f9
Reviewed-on: https://go-review.googlesource.com/c/vuln/+/369874
Reviewed-by: Jonathan Amsterdam <jba@google.com>
Trust: Julie Qiu <julie@golang.org>
Run-TryBot: Julie Qiu <julie@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
diff --git a/internal/worker/triage.go b/internal/worker/triage.go
index 1d9a0d0..e4f67bf 100644
--- a/internal/worker/triage.go
+++ b/internal/worker/triage.go
@@ -31,50 +31,59 @@
}
// TriageCVE reports whether the CVE refers to a Go module.
-func TriageCVE(ctx context.Context, c *cveschema.CVE, pkgsiteURL string) (module string, err error) {
+func TriageCVE(ctx context.Context, c *cveschema.CVE, pkgsiteURL string) (_ *triageResult, err error) {
defer derrors.Wrap(&err, "triageCVE(%q)", c.ID)
switch c.DataVersion {
case "4.0":
- mp, err := cveModulePath(ctx, c, pkgsiteURL)
- if err != nil {
- return "", err
- }
- return mp, nil
+ return triageV4CVE(ctx, c, pkgsiteURL)
default:
// TODO(https://golang.org/issue/49289): Add support for v5.0.
- return "", fmt.Errorf("CVE %q has DataVersion %q: %w", c.ID, c.DataVersion, errCVEVersionUnsupported)
+ return nil, fmt.Errorf("CVE %q has DataVersion %q: %w", c.ID, c.DataVersion, errCVEVersionUnsupported)
}
}
-// cveModulePath returns a Go module path for a CVE, if we can determine what
-// it is.
-func cveModulePath(ctx context.Context, c *cveschema.CVE, pkgsiteURL string) (_ string, err error) {
- defer derrors.Wrap(&err, "cveModulePath(%q)", c.ID)
+type triageResult struct {
+ modulePath string
+ stdlib bool
+ reason string
+}
+
+// triageV4CVE triages a CVE following schema v4.0 and returns the result.
+func triageV4CVE(ctx context.Context, c *cveschema.CVE, pkgsiteURL string) (_ *triageResult, err error) {
+ defer derrors.Wrap(&err, "triageV4CVE(ctx, %q, %q)", c.ID, pkgsiteURL)
for _, r := range c.References.Data {
if r.URL == "" {
continue
}
for k := range stdlibKeywords {
if strings.Contains(r.URL, k) && !strings.Contains(r.URL, "golang.org/x/") {
- return "Go Standard Library", nil
+ return &triageResult{
+ modulePath: "Go Standard Library",
+ stdlib: true,
+ reason: fmt.Sprintf("Reference data URL %q contains %q", r.URL, k),
+ }, nil
}
}
refURL, err := url.Parse(r.URL)
if err != nil {
- return "", fmt.Errorf("url.Parse(%q): %v", r.URL, err)
+ return nil, fmt.Errorf("url.Parse(%q): %v", r.URL, err)
}
modpaths := candidateModulePaths(refURL.Host + refURL.Path)
for _, mp := range modpaths {
known, err := knownToPkgsite(ctx, pkgsiteURL, mp)
if err != nil {
- return "", err
+ return nil, err
}
if known {
- return mp, nil
+ u := pkgsiteURL + "/" + mp
+ return &triageResult{
+ modulePath: mp,
+ reason: fmt.Sprintf("Reference data URL %q contains path %q; %q returned a status 200", r.URL, mp, u),
+ }, nil
}
}
}
- return "", nil
+ return nil, nil
}
// Limit pkgsite calls to 2 qps (once every 500ms).
diff --git a/internal/worker/triage_test.go b/internal/worker/triage_test.go
index 8d5a367..43a8cb5 100644
--- a/internal/worker/triage_test.go
+++ b/internal/worker/triage_test.go
@@ -18,7 +18,7 @@
var usePkgsite = flag.Bool("pkgsite", false, "use pkg.go.dev for tests")
-func TestCVEModulePath(t *testing.T) {
+func TestTriageV4CVE(t *testing.T) {
ctx := log.WithLineLogger(context.Background())
url := pkgsiteURL(t)
@@ -84,12 +84,19 @@
},
} {
t.Run(test.name, func(t *testing.T) {
- got, err := cveModulePath(ctx, test.in, url)
+ test.in.DataVersion = "4.0"
+ got, err := TriageCVE(ctx, test.in, url)
if err != nil {
t.Fatal(err)
}
- if got != test.want {
- t.Errorf("got %q, want %q", got, test.want)
+ if got == nil {
+ if test.want != "" {
+ t.Fatalf("got empty string, want %q", test.want)
+ }
+ return
+ }
+ if got.modulePath != test.want {
+ t.Errorf("got %q, want %q", got.modulePath, test.want)
}
})
}
diff --git a/internal/worker/update.go b/internal/worker/update.go
index c844978..2c9739f 100644
--- a/internal/worker/update.go
+++ b/internal/worker/update.go
@@ -29,7 +29,7 @@
// A triageFunc triages a CVE: it decides whether an issue needs to be filed.
// If so, it returns a non-empty string indicating the possibly
// affected module.
-type triageFunc func(*cveschema.CVE) (string, error)
+type triageFunc func(*cveschema.CVE) (*triageResult, error)
// An updater performs an update operation on the DB.
type updater struct {
@@ -256,9 +256,9 @@
if err := json.NewDecoder(r).Decode(cve); err != nil {
return false, err
}
- module := ""
+ var result *triageResult
if cve.State == cveschema.StatePublic && !u.knownIDs[cve.ID] {
- module, err = u.affectedModule(cve)
+ result, err = u.affectedModule(cve)
if err != nil {
return false, err
}
@@ -268,9 +268,9 @@
if old == nil {
cr := store.NewCVERecord(cve, pathname, f.blobHash.String())
cr.CommitHash = u.commitHash.String()
- if module != "" {
+ if result != nil {
cr.TriageState = store.TriageStateNeedsIssue
- cr.Module = module
+ cr.Module = result.modulePath
cr.CVE = cve
} else {
cr.TriageState = store.TriageStateNoActionNeeded
@@ -291,15 +291,15 @@
mod.CommitHash = u.commitHash.String()
switch old.TriageState {
case store.TriageStateNoActionNeeded:
- if module != "" {
+ if result != nil {
// Didn't need an issue before, does now.
mod.TriageState = store.TriageStateNeedsIssue
- mod.Module = module
+ mod.Module = result.modulePath
}
// Else don't change the triage state, but we still want
// to update the other changed fields.
case store.TriageStateNeedsIssue:
- if module == "" {
+ if result == nil {
// Needed an issue, no longer does.
mod.TriageState = store.TriageStateNoActionNeeded
mod.Module = ""
@@ -310,7 +310,11 @@
case store.TriageStateIssueCreated, store.TriageStateUpdatedSinceIssueCreation:
// An issue was filed, so a person should revisit this CVE.
mod.TriageState = store.TriageStateUpdatedSinceIssueCreation
- mod.TriageStateReason = fmt.Sprintf("CVE changed; affected module = %q", module)
+ var mp string
+ if result != nil {
+ mp = result.modulePath
+ }
+ mod.TriageStateReason = fmt.Sprintf("CVE changed; affected module = %q", mp)
// TODO(golang/go#49733): keep a history of the previous states and their commits.
default:
return false, fmt.Errorf("unknown TriageState: %q", old.TriageState)
diff --git a/internal/worker/update_test.go b/internal/worker/update_test.go
index 5d50f31..b394241 100644
--- a/internal/worker/update_test.go
+++ b/internal/worker/update_test.go
@@ -58,7 +58,7 @@
}
purl := pkgsiteURL(t)
- needsIssue := func(cve *cveschema.CVE) (string, error) {
+ needsIssue := func(cve *cveschema.CVE) (*triageResult, error) {
return TriageCVE(ctx, cve, purl)
}
diff --git a/internal/worker/worker.go b/internal/worker/worker.go
index 2535e32..c6e0899 100644
--- a/internal/worker/worker.go
+++ b/internal/worker/worker.go
@@ -46,7 +46,7 @@
if err != nil {
return err
}
- u := newUpdater(repo, ch, st, knownVulnIDs, func(cve *cveschema.CVE) (string, error) {
+ u := newUpdater(repo, ch, st, knownVulnIDs, func(cve *cveschema.CVE) (*triageResult, error) {
return TriageCVE(ctx, cve, pkgsiteURL)
})
_, err = u.update(ctx)