all: move triage-related code to its own package

Separate triage-related code to its own internal
package so it can be re-used throughout.

Change-Id: I1c143624d718b896edb64afa020875925210b094
Reviewed-on: https://go-review.googlesource.com/c/vulndb/+/601378
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Damien Neil <dneil@google.com>
This commit is contained in:
Tatiana Bradley 2024-07-09 11:29:36 -04:00
Родитель 225a63b295
Коммит 2b185852c9
20 изменённых файлов: 72 добавлений и 71 удалений

Просмотреть файл

@ -21,12 +21,12 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"golang.org/x/vulndb/cmd/vulnreport/priority"
"golang.org/x/vulndb/internal/cve5"
"golang.org/x/vulndb/internal/gitrepo"
"golang.org/x/vulndb/internal/osvutils"
"golang.org/x/vulndb/internal/proxy"
"golang.org/x/vulndb/internal/report"
"golang.org/x/vulndb/internal/triage/priority"
)
func TestChecksBash(t *testing.T) {

Просмотреть файл

@ -6,7 +6,7 @@
// code used by vulnreport triage.
// Prints the priority result for the given module(s).
// Can be used for experimentation / debugging.
// Usage: $ go run ./cmd/vulnreport/priority/priority <module_path>
// Usage: $ go run ./cmd/priority <module_path>
package main
import (
@ -15,8 +15,8 @@ import (
"os"
vlog "golang.org/x/vulndb/cmd/vulnreport/log"
"golang.org/x/vulndb/cmd/vulnreport/priority"
"golang.org/x/vulndb/internal/report"
"golang.org/x/vulndb/internal/triage/priority"
)
func main() {

Просмотреть файл

@ -13,12 +13,12 @@ import (
"golang.org/x/exp/slices"
"golang.org/x/vulndb/cmd/vulnreport/log"
"golang.org/x/vulndb/cmd/vulnreport/priority"
"golang.org/x/vulndb/internal/idstr"
"golang.org/x/vulndb/internal/issues"
"golang.org/x/vulndb/internal/osv"
"golang.org/x/vulndb/internal/report"
"golang.org/x/vulndb/internal/symbols"
"golang.org/x/vulndb/internal/triage/priority"
)
type creator struct {

Просмотреть файл

@ -11,12 +11,12 @@ import (
"os"
"github.com/go-git/go-git/v5"
"golang.org/x/vulndb/cmd/vulnreport/priority"
"golang.org/x/vulndb/internal/ghsa"
"golang.org/x/vulndb/internal/gitrepo"
"golang.org/x/vulndb/internal/issues"
"golang.org/x/vulndb/internal/pkgsite"
"golang.org/x/vulndb/internal/proxy"
"golang.org/x/vulndb/internal/triage/priority"
)
// environment stores fakes/mocks of external dependencies for testing.

Просмотреть файл

@ -21,11 +21,11 @@ import (
"golang.org/x/exp/maps"
"golang.org/x/tools/txtar"
"golang.org/x/vulndb/cmd/vulnreport/log"
"golang.org/x/vulndb/cmd/vulnreport/priority"
"golang.org/x/vulndb/internal/gitrepo"
"golang.org/x/vulndb/internal/pkgsite"
"golang.org/x/vulndb/internal/proxy"
"golang.org/x/vulndb/internal/test"
"golang.org/x/vulndb/internal/triage/priority"
)
// go test ./cmd/vulnreport -update-test -proxy -pkgsite

Просмотреть файл

@ -15,8 +15,8 @@ import (
"golang.org/x/exp/slices"
"golang.org/x/vulndb/cmd/vulnreport/log"
"golang.org/x/vulndb/cmd/vulnreport/priority"
"golang.org/x/vulndb/internal/issues"
"golang.org/x/vulndb/internal/triage/priority"
)
type triage struct {

Просмотреть файл

@ -11,8 +11,8 @@ import (
"golang.org/x/exp/constraints"
"golang.org/x/exp/slices"
"golang.org/x/vulndb/cmd/vulnreport/log"
"golang.org/x/vulndb/cmd/vulnreport/priority"
"golang.org/x/vulndb/internal/report"
"golang.org/x/vulndb/internal/triage/priority"
)
type xref struct {

Просмотреть файл

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package cveutils
package triage
import (
"context"
@ -31,13 +31,13 @@ var stdlibReferenceDataKeywords = []string{
const unknownPath = "Path is unknown"
// TriageCVE reports whether the CVE refers to a Go module.
func TriageCVE(ctx context.Context, c CVE, pc *pkgsite.Client) (_ *TriageResult, err error) {
defer derrors.Wrap(&err, "cveutils.TriageCVE(%q)", c.SourceID())
return triageCVE(ctx, c, pc)
// RefersToGoModule reports whether the vuln refers to a Go module or package in its references.
func RefersToGoModule(ctx context.Context, v Vuln, pc *pkgsite.Client) (_ *Result, err error) {
defer derrors.Wrap(&err, "triage.RefersToGoModule(%q)", v.SourceID())
return refersToGoModule(ctx, v, pc)
}
type TriageResult struct {
type Result struct {
ModulePath string
PackagePath string
Reason string
@ -68,25 +68,24 @@ var notGoModules = map[string]bool{
"github.com/gravitational/teleport": true,
}
type CVE interface {
type Vuln interface {
SourceID() string
ReferenceURLs() []string
}
// triageCVE triages a CVE and returns the result.
func triageCVE(ctx context.Context, c CVE, pc *pkgsite.Client) (result *TriageResult, err error) {
func refersToGoModule(ctx context.Context, v Vuln, pc *pkgsite.Client) (result *Result, err error) {
defer func() {
if err != nil {
return
}
msg := fmt.Sprintf("Triage result for %s", c.SourceID())
msg := fmt.Sprintf("Triage result for %s", v.SourceID())
if result == nil {
log.Debugf(ctx, "%s: not Go vuln", msg)
return
}
log.Debugf(ctx, "%s: is Go vuln:\n%s", msg, result.Reason)
}()
for _, rurl := range c.ReferenceURLs() {
for _, rurl := range v.ReferenceURLs() {
if rurl == "" {
continue
}
@ -96,7 +95,7 @@ func triageCVE(ctx context.Context, c CVE, pc *pkgsite.Client) (result *TriageRe
}
if strings.Contains(rurl, "golang.org/pkg") {
mp := strings.TrimPrefix(refURL.Path, "/pkg/")
return &TriageResult{
return &Result{
PackagePath: mp,
ModulePath: stdlib.ModulePath,
Reason: fmt.Sprintf("Reference data URL %q contains path %q", rurl, mp),
@ -105,13 +104,13 @@ func triageCVE(ctx context.Context, c CVE, pc *pkgsite.Client) (result *TriageRe
if gopkgHosts[refURL.Host] {
mp := strings.TrimPrefix(refURL.Path, "/")
if stdlib.Contains(mp) {
return &TriageResult{
return &Result{
PackagePath: mp,
ModulePath: stdlib.ModulePath,
Reason: fmt.Sprintf("Reference data URL %q contains path %q", rurl, mp),
}, nil
}
return &TriageResult{
return &Result{
ModulePath: mp,
Reason: fmt.Sprintf("Reference data URL %q contains path %q", rurl, mp),
}, nil
@ -127,7 +126,7 @@ func triageCVE(ctx context.Context, c CVE, pc *pkgsite.Client) (result *TriageRe
}
if known {
u := pc.URL() + "/" + mp
return &TriageResult{
return &Result{
ModulePath: mp,
Reason: fmt.Sprintf("Reference data URL %q contains path %q; %q returned a status 200", rurl, mp, u),
}, nil
@ -137,11 +136,11 @@ func triageCVE(ctx context.Context, c CVE, pc *pkgsite.Client) (result *TriageRe
// We didn't find a Go package or module path in the reference data. Check
// secondary heuristics to see if this is a Go related CVE.
for _, rurl := range c.ReferenceURLs() {
for _, rurl := range v.ReferenceURLs() {
// Example CVE containing snyk.io URL:
// https://github.com/CVEProject/cvelist/blob/899bba20d62eb73e04d1841a5ff04cd6225e1618/2020/7xxx/CVE-2020-7668.json#L52.
if strings.Contains(rurl, snykIdentifier) {
return &TriageResult{
return &Result{
ModulePath: unknownPath,
Reason: fmt.Sprintf("Reference data URL %q contains %q", rurl, snykIdentifier),
}, nil
@ -151,7 +150,7 @@ func triageCVE(ctx context.Context, c CVE, pc *pkgsite.Client) (result *TriageRe
// project.
for _, k := range stdlibReferenceDataKeywords {
if strings.Contains(rurl, k) {
return &TriageResult{
return &Result{
ModulePath: stdlib.ModulePath,
Reason: fmt.Sprintf("Reference data URL %q contains %q", rurl, k),
}, nil
@ -161,9 +160,11 @@ func triageCVE(ctx context.Context, c CVE, pc *pkgsite.Client) (result *TriageRe
return nil, nil
}
func GetAliasGHSAs(c CVE) []string {
// AliasGHSAs returns the list of GHSAs that are possibly aliases for this
// vuln, based on the references.
func AliasGHSAs(v Vuln) []string {
var ghsas []string
for _, rurl := range c.ReferenceURLs() {
for _, rurl := range v.ReferenceURLs() {
if ghsa := idstr.FindGHSA(rurl); ghsa != "" {
ghsas = append(ghsas, ghsa)
}

Просмотреть файл

@ -5,7 +5,7 @@
//go:build go1.17
// +build go1.17
package cveutils
package triage
import (
"context"
@ -22,7 +22,7 @@ import (
var usePkgsite = flag.Bool("pkgsite", false, "use pkg.go.dev for tests")
func TestTriageV4CVE(t *testing.T) {
func TestRefersToGoModuleV4CVE(t *testing.T) {
ctx := context.Background()
pc, err := pkgsite.TestClient(t, *usePkgsite)
if err != nil {
@ -32,8 +32,8 @@ func TestTriageV4CVE(t *testing.T) {
for _, test := range []struct {
name string
desc string
in CVE
want *TriageResult
in Vuln
want *Result
}{
{
name: "unknown_std",
@ -45,7 +45,7 @@ func TestTriageV4CVE(t *testing.T) {
},
},
},
want: &TriageResult{
want: &Result{
ModulePath: stdlib.ModulePath,
},
},
@ -59,7 +59,7 @@ func TestTriageV4CVE(t *testing.T) {
},
},
},
want: &TriageResult{
want: &Result{
ModulePath: stdlib.ModulePath,
PackagePath: "net/http",
},
@ -75,7 +75,7 @@ func TestTriageV4CVE(t *testing.T) {
},
},
},
want: &TriageResult{
want: &Result{
ModulePath: "golang.org/x/mod",
},
},
@ -89,7 +89,7 @@ func TestTriageV4CVE(t *testing.T) {
},
},
},
want: &TriageResult{
want: &Result{
ModulePath: "golang.org/x/mod",
},
},
@ -103,7 +103,7 @@ func TestTriageV4CVE(t *testing.T) {
},
},
},
want: &TriageResult{
want: &Result{
ModulePath: stdlib.ModulePath,
PackagePath: "net/http",
},
@ -130,7 +130,7 @@ func TestTriageV4CVE(t *testing.T) {
},
},
},
want: &TriageResult{
want: &Result{
ModulePath: "golang.org/x/exp/event",
},
},
@ -156,26 +156,26 @@ func TestTriageV4CVE(t *testing.T) {
},
},
},
want: &TriageResult{
want: &Result{
ModulePath: unknownPath,
},
},
} {
t.Run(test.name, func(t *testing.T) {
got, err := TriageCVE(ctx, test.in, pc)
got, err := RefersToGoModule(ctx, test.in, pc)
if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(test.want, got,
cmp.AllowUnexported(TriageResult{}),
cmpopts.IgnoreFields(TriageResult{}, "Reason")); diff != "" {
cmp.AllowUnexported(Result{}),
cmpopts.IgnoreFields(Result{}, "Reason")); diff != "" {
t.Errorf("mismatch (-want, +got):\n%s", diff)
}
})
}
}
func TestTriageV5CVE(t *testing.T) {
func TestRefersToGoModuleV5CVE(t *testing.T) {
ctx := context.Background()
pc, err := pkgsite.TestClient(t, *usePkgsite)
if err != nil {
@ -185,8 +185,8 @@ func TestTriageV5CVE(t *testing.T) {
for _, test := range []struct {
name string
desc string
in CVE
want *TriageResult
in Vuln
want *Result
}{
{
name: "unknown_std",
@ -200,7 +200,7 @@ func TestTriageV5CVE(t *testing.T) {
},
},
},
want: &TriageResult{
want: &Result{
ModulePath: stdlib.ModulePath,
},
},
@ -216,7 +216,7 @@ func TestTriageV5CVE(t *testing.T) {
},
},
},
want: &TriageResult{
want: &Result{
ModulePath: stdlib.ModulePath,
PackagePath: "net/http",
},
@ -234,7 +234,7 @@ func TestTriageV5CVE(t *testing.T) {
},
},
},
want: &TriageResult{
want: &Result{
ModulePath: "golang.org/x/mod",
},
},
@ -250,7 +250,7 @@ func TestTriageV5CVE(t *testing.T) {
},
},
},
want: &TriageResult{
want: &Result{
ModulePath: "golang.org/x/mod",
},
},
@ -266,7 +266,7 @@ func TestTriageV5CVE(t *testing.T) {
},
},
},
want: &TriageResult{
want: &Result{
ModulePath: stdlib.ModulePath,
PackagePath: "net/http",
},
@ -295,7 +295,7 @@ func TestTriageV5CVE(t *testing.T) {
},
},
},
want: &TriageResult{
want: &Result{
ModulePath: "golang.org/x/exp/event",
},
},
@ -325,26 +325,26 @@ func TestTriageV5CVE(t *testing.T) {
},
},
},
want: &TriageResult{
want: &Result{
ModulePath: unknownPath,
},
},
} {
t.Run(test.name, func(t *testing.T) {
got, err := TriageCVE(ctx, test.in, pc)
got, err := RefersToGoModule(ctx, test.in, pc)
if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(test.want, got,
cmp.AllowUnexported(TriageResult{}),
cmpopts.IgnoreFields(TriageResult{}, "Reason")); diff != "" {
cmp.AllowUnexported(Result{}),
cmpopts.IgnoreFields(Result{}, "Reason")); diff != "" {
t.Errorf("mismatch (-want, +got):\n%s", diff)
}
})
}
}
func TestGetAliasGHSAs(t *testing.T) {
func TestAliasGHSAs(t *testing.T) {
cve := &cve4.CVE{
References: cve4.References{
Data: []cve4.Reference{
@ -354,7 +354,7 @@ func TestGetAliasGHSAs(t *testing.T) {
},
}
want := "GHSA-xxxx-yyyy-0000"
if got := GetAliasGHSAs(cve); got[0] != want {
t.Errorf("getAliasGHSAs: got %s, want %s", got, want)
if got := AliasGHSAs(cve); got[0] != want {
t.Errorf("AliasGHSAs: got %s, want %s", got, want)
}
}

Просмотреть файл

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package cveutils
package triage
import (
"path"

Просмотреть файл

@ -5,7 +5,7 @@
//go:build go1.17
// +build go1.17
package cveutils
package triage
import (
"testing"

Просмотреть файл

Просмотреть файл

@ -16,12 +16,12 @@ import (
"github.com/go-git/go-git/v5/plumbing/object"
"golang.org/x/vulndb/internal/cve4"
"golang.org/x/vulndb/internal/cvelistrepo"
"golang.org/x/vulndb/internal/cveutils"
"golang.org/x/vulndb/internal/derrors"
"golang.org/x/vulndb/internal/ghsa"
"golang.org/x/vulndb/internal/gitrepo"
"golang.org/x/vulndb/internal/observe"
"golang.org/x/vulndb/internal/report"
"golang.org/x/vulndb/internal/triage"
"golang.org/x/vulndb/internal/worker/log"
"golang.org/x/vulndb/internal/worker/store"
)
@ -29,7 +29,7 @@ import (
// 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(*cve4.CVE) (*cveutils.TriageResult, error)
type triageFunc func(*cve4.CVE) (*triage.Result, error)
// A cveUpdater performs an update operation on the DB.
type cveUpdater struct {
@ -255,7 +255,7 @@ func (u *cveUpdater) updateBatch(ctx context.Context, batch []cvelistrepo.File)
// worker has already handled, and returns the appropriate triage state
// based on this.
func checkForAliases(cve *cve4.CVE, tx store.Transaction) (store.TriageState, error) {
for _, ghsaID := range cveutils.GetAliasGHSAs(cve) {
for _, ghsaID := range triage.AliasGHSAs(cve) {
ghsa, err := tx.GetRecord(ghsaID)
if err != nil {
return "", err
@ -277,7 +277,7 @@ func (u *cveUpdater) handleCVE(f cvelistrepo.File, old *store.CVE4Record, tx sto
if err != nil {
return nil, false, err
}
var result *cveutils.TriageResult
var result *triage.Result
if cve.State == cve4.StatePublic && !u.rc.AliasHasReport(cve.ID) {
c := cve
// If a false positive has changed, we only care about

Просмотреть файл

@ -19,11 +19,11 @@ import (
"github.com/google/go-cmp/cmp/cmpopts"
"golang.org/x/vulndb/internal/cve4"
"golang.org/x/vulndb/internal/cvelistrepo"
"golang.org/x/vulndb/internal/cveutils"
"golang.org/x/vulndb/internal/ghsa"
"golang.org/x/vulndb/internal/gitrepo"
"golang.org/x/vulndb/internal/pkgsite"
"golang.org/x/vulndb/internal/report"
"golang.org/x/vulndb/internal/triage"
"golang.org/x/vulndb/internal/worker/store"
)
@ -104,8 +104,8 @@ func TestDoUpdate(t *testing.T) {
if err != nil {
t.Fatal(err)
}
needsIssue := func(cve *cve4.CVE) (*cveutils.TriageResult, error) {
return cveutils.TriageCVE(ctx, cve, pc)
needsIssue := func(cve *cve4.CVE) (*triage.Result, error) {
return triage.RefersToGoModule(ctx, cve, pc)
}
commitHash := commit.Hash.String()
@ -399,7 +399,7 @@ func TestDoUpdateError(t *testing.T) {
if err != nil {
t.Fatal(err)
}
needsIssue := func(cve *cve4.CVE) (*cveutils.TriageResult, error) { return nil, nil }
needsIssue := func(cve *cve4.CVE) (*triage.Result, error) { return nil, nil }
for _, test := range []struct {
name string

Просмотреть файл

@ -20,7 +20,6 @@ import (
"github.com/go-git/go-git/v5/plumbing/object"
"golang.org/x/time/rate"
"golang.org/x/vulndb/internal/cve4"
"golang.org/x/vulndb/internal/cveutils"
"golang.org/x/vulndb/internal/derrors"
"golang.org/x/vulndb/internal/ghsa"
"golang.org/x/vulndb/internal/gitrepo"
@ -30,6 +29,7 @@ import (
"golang.org/x/vulndb/internal/pkgsite"
"golang.org/x/vulndb/internal/proxy"
"golang.org/x/vulndb/internal/report"
"golang.org/x/vulndb/internal/triage"
"golang.org/x/vulndb/internal/worker/log"
"golang.org/x/vulndb/internal/worker/store"
)
@ -67,8 +67,8 @@ func UpdateCVEsAtCommit(ctx context.Context, repoPath, commitHashString string,
return err
}
}
u := newCVEUpdater(repo, commit, st, rc, func(cve *cve4.CVE) (*cveutils.TriageResult, error) {
return cveutils.TriageCVE(ctx, cve, pc)
u := newCVEUpdater(repo, commit, st, rc, func(cve *cve4.CVE) (*triage.Result, error) {
return triage.RefersToGoModule(ctx, cve, pc)
})
return u.update(ctx)
}