Skip to content

Commit 6a3e504

Browse files
committed
cmd/vulnreport: fix bug in duplicate-finding for triage
Fix a bug in which the "likely duplicate" label was applied to all issues that have duplicates on the tracker. (For example, if #1 and #2 both refer to GHSA-xxxx-yyyy-zzzz, only one of these should be marked as a duplicate). This also revealed some bugs in the fake in-memory implementation of the GHSA API, which are now fixed. Change-Id: Ifd98befdf3e23f1fc95df38533107de9c921b195 Reviewed-on: https://go-review.googlesource.com/c/vulndb/+/599456 Reviewed-by: Damien Neil <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent ebcb244 commit 6a3e504

File tree

8 files changed

+95
-31
lines changed

8 files changed

+95
-31
lines changed

cmd/vulnreport/find_aliases.go

+15-9
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package main
66

77
import (
8+
"bytes"
89
"context"
910
"fmt"
1011

@@ -172,19 +173,31 @@ type ghsaClient interface {
172173

173174
type memGC struct {
174175
ghsas map[string]ghsa.SecurityAdvisory
176+
byCVE map[string][]*ghsa.SecurityAdvisory
175177
}
176178

177179
func newMemGC(archive []byte) (*memGC, error) {
178180
ar := txtar.Parse(archive)
179181
m := &memGC{
180182
ghsas: make(map[string]ghsa.SecurityAdvisory),
183+
byCVE: make(map[string][]*ghsa.SecurityAdvisory),
181184
}
182185
for _, f := range ar.Files {
183186
var g ghsa.SecurityAdvisory
184-
if err := yaml.Unmarshal(f.Data, &g); err != nil {
187+
d := yaml.NewDecoder(bytes.NewBuffer(f.Data))
188+
d.KnownFields(true)
189+
if err := d.Decode(&g); err != nil {
185190
return nil, err
186191
}
192+
if f.Name != g.ID {
193+
return nil, fmt.Errorf("filename (%s) != ID (%s)", f.Name, g.ID)
194+
}
187195
m.ghsas[f.Name] = g
196+
for _, id := range g.Identifiers {
197+
if id.Type == "CVE" {
198+
m.byCVE[id.Value] = append(m.byCVE[id.Value], &g)
199+
}
200+
}
188201
}
189202
return m, nil
190203
}
@@ -197,12 +210,5 @@ func (m *memGC) FetchGHSA(_ context.Context, id string) (*ghsa.SecurityAdvisory,
197210
}
198211

199212
func (m *memGC) ListForCVE(_ context.Context, cid string) (result []*ghsa.SecurityAdvisory, _ error) {
200-
for _, sa := range m.ghsas {
201-
for _, id := range sa.Identifiers {
202-
if id.Type == "CVE" || id.Value == cid {
203-
result = append(result, &sa)
204-
}
205-
}
206-
}
207-
return result, nil
213+
return m.byCVE[cid], nil
208214
}

cmd/vulnreport/lint.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,10 @@ func (l *linter) lint(r *yamlReport) error {
5555
}
5656

5757
func (l *linter) canonicalModule(mp string) string {
58-
if module, err := l.pxc.FindModule(mp); err == nil { // no error
58+
if module, err := l.pxc.FindModule(mp); module != "" && err == nil { // no error
5959
mp = module
6060
}
61-
if module, err := l.pxc.CanonicalAtLatest(mp); err == nil { // no error
61+
if module, err := l.pxc.CanonicalAtLatest(mp); module != "" && err == nil { // no error
6262
mp = module
6363
}
6464
return mp

cmd/vulnreport/run_test.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@ import (
1212
"fmt"
1313
"io/fs"
1414
"path/filepath"
15+
"slices"
1516
"strings"
1617
"testing"
1718
"time"
1819

1920
"github.com/google/go-cmp/cmp"
21+
"golang.org/x/exp/maps"
2022
"golang.org/x/tools/txtar"
2123
"golang.org/x/vulndb/cmd/vulnreport/log"
2224
"golang.org/x/vulndb/cmd/vulnreport/priority"
@@ -206,8 +208,10 @@ func writeGolden(t *testing.T, g *golden, comment string, written map[string][]b
206208
{Name: "out", Data: g.out},
207209
{Name: "logs", Data: g.logs},
208210
}
209-
for fname, b := range written {
210-
files = append(files, txtar.File{Name: fname, Data: b})
211+
sortedFilenames := maps.Keys(written)
212+
slices.Sort(sortedFilenames)
213+
for _, fname := range sortedFilenames {
214+
files = append(files, txtar.File{Name: fname, Data: written[fname]})
211215
}
212216

213217
return test.WriteTxtar(testFilename(t), files, comment)

cmd/vulnreport/testdata/TestFix/no_change.txtar

+10-10
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,6 @@ info: GO-9999-0001: skipping symbol checks for package golang.org/x/vulndb/cmd/v
1717
info: GO-9999-0001: checking for missing GHSAs and CVEs (use -skip-alias to skip this)
1818
info: GO-9999-0001: checking that all references are reachable
1919
info: fix: processed 1 report(s) (success=1; skip=0; error=0)
20-
-- data/reports/GO-9999-0001.yaml --
21-
id: GO-9999-0001
22-
modules:
23-
- module: golang.org/x/vulndb
24-
vulnerable_at: 0.0.0-20240716161253-dd7900b89e20
25-
packages:
26-
- package: golang.org/x/vulndb/cmd/vulnreport
27-
summary: A problem with golang.org/x/vulndb
28-
description: A description of the issue
29-
review_status: REVIEWED
3020
-- data/osv/GO-9999-0001.json --
3121
{
3222
"schema_version": "1.3.1",
@@ -65,3 +55,13 @@ review_status: REVIEWED
6555
"review_status": "REVIEWED"
6656
}
6757
}
58+
-- data/reports/GO-9999-0001.yaml --
59+
id: GO-9999-0001
60+
modules:
61+
- module: golang.org/x/vulndb
62+
vulnerable_at: 0.0.0-20240716161253-dd7900b89e20
63+
packages:
64+
- package: golang.org/x/vulndb/cmd/vulnreport
65+
summary: A problem with golang.org/x/vulndb
66+
description: A description of the issue
67+
review_status: REVIEWED

cmd/vulnreport/testdata/TestTriage/all.txtar

+19-5
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,22 @@ issue test-issue-tracker/10 is high priority
1212
- golang.org/x/vuln has 101 importers (>= 100) and as many reviewed (0) as likely-binary reports (0)
1313
issue test-issue-tracker/11 is possibly not Go
1414
- more than 20 percent of reports (1 of 1) with this module are NOT_GO_CODE
15-
triaged 3 issues:
15+
issue test-issue-tracker/12 is likely duplicate
16+
- #12 shares alias(es) CVE-1999-0002, GHSA-xxxx-yyyy-0002, GHSA-xxxx-yyyy-0003 with test-issue-tracker/13
17+
- #12 shares alias(es) CVE-1999-0002, GHSA-xxxx-yyyy-0002, GHSA-xxxx-yyyy-0003 with test-issue-tracker/14
18+
issue test-issue-tracker/13 is likely duplicate
19+
- #13 shares alias(es) CVE-1999-0002, GHSA-xxxx-yyyy-0002, GHSA-xxxx-yyyy-0003 with test-issue-tracker/14
20+
triaged 6 issues:
1621
- 1 high priority
17-
- 2 low priority
22+
- 5 low priority
1823
- 0 unknown priority
19-
- 1 likely duplicate
24+
- 3 likely duplicate
2025
- 1 possibly not Go
2126
helpful commands:
2227
$ vulnreport create 10
2328
-- logs --
2429
info: creating alias map for open issues
25-
info: triage: operating on 4 issue(s)
30+
info: triage: operating on 7 issue(s)
2631
info: triage: skipping issue #1 (already has report)
2732
info: triage 7
2833
info: issue test-issue-tracker/7 is low priority
@@ -31,4 +36,13 @@ info: triage 10
3136
info: triage 11
3237
info: issue test-issue-tracker/11 is low priority
3338
- collectd.org has 0 importers (< 100)
34-
info: triage: processed 4 issue(s) (success=3; skip=1; error=0)
39+
info: triage 12
40+
info: issue test-issue-tracker/12 is low priority
41+
- golang.org/x/tools has 50 importers (< 100)
42+
info: triage 13
43+
info: issue test-issue-tracker/13 is low priority
44+
- golang.org/x/tools has 50 importers (< 100)
45+
info: triage 14
46+
info: issue test-issue-tracker/14 is low priority
47+
- golang.org/x/tools has 50 importers (< 100)
48+
info: triage: processed 7 issue(s) (success=6; skip=1; error=0)

cmd/vulnreport/testdata/issue_tracker.txtar

+15
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,18 @@ number: 11
2626
title: "x/vulndb: potential Go vuln in collectd.org: CVE-2021-0000"
2727
state: open
2828

29+
-- 12 --
30+
number: 12
31+
title: "x/vulndb: potential Go vuln in golang.org/x/tools: GHSA-xxxx-yyyy-0002"
32+
state: open
33+
34+
-- 13 --
35+
number: 13
36+
title: "x/vulndb: potential Go vuln in golang.org/x/tools: CVE-1999-0002"
37+
state: open
38+
39+
-- 14 --
40+
number: 14
41+
title: "x/vulndb: potential Go vuln in golang.org/x/tools: GHSA-xxxx-yyyy-0003"
42+
state: open
43+

cmd/vulnreport/testdata/legacy_ghsas.txtar

+14-3
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,20 @@
77
-- GHSA-xxxx-yyyy-zzzz --
88
id: GHSA-xxxx-yyyy-zzzz
99
identifiers:
10-
- identifier:
11-
- type: CVE
12-
id: CVE-1999-0005
10+
- type: CVE
11+
value: CVE-1999-0005
1312

1413
-- GHSA-xxxx-yyyy-0001 --
1514
id: GHSA-xxxx-yyyy-0001
15+
16+
-- GHSA-xxxx-yyyy-0002 --
17+
id: GHSA-xxxx-yyyy-0002
18+
identifiers:
19+
- type: CVE
20+
value: CVE-1999-0002
21+
22+
-- GHSA-xxxx-yyyy-0003 --
23+
id: GHSA-xxxx-yyyy-0003
24+
identifiers:
25+
- type: CVE
26+
value: CVE-1999-0002

cmd/vulnreport/triage.go

+14
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ type triage struct {
2727
mu sync.Mutex // protects aliasesToIssues and stats
2828
aliasesToIssues map[string][]int
2929
stats []issuesList
30+
31+
// issues that have already been marked as duplicate
32+
duplicates map[int]bool
3033
}
3134

3235
func (*triage) name() string { return "triage" }
@@ -65,6 +68,7 @@ func (t *triage) setup(ctx context.Context, env environment) error {
6568
}
6669

6770
log.Info("creating alias map for open issues")
71+
t.duplicates = make(map[int]bool)
6872
open, err := t.openIssues(ctx)
6973
if err != nil {
7074
return err
@@ -74,6 +78,9 @@ func (t *triage) setup(ctx context.Context, env environment) error {
7478
for _, a := range aliases {
7579
t.addAlias(a, iss.Number)
7680
}
81+
if iss.HasLabel(labelPossibleDuplicate) || iss.HasLabel(labelDuplicate) {
82+
t.duplicates[iss.Number] = true
83+
}
7784
}
7885
return nil
7986
}
@@ -127,6 +134,7 @@ func (t *triage) triage(ctx context.Context, iss *issues.Issue) {
127134
strings.Join(aliases, ", "),
128135
filepath.ToSlash(ref)))
129136
}
137+
slices.Sort(strs)
130138
t.addStat(iss, statDuplicate, strings.Join(strs, listItem))
131139
labels = append(labels, labelPossibleDuplicate)
132140
}
@@ -191,8 +199,14 @@ func (t *triage) findDuplicates(ctx context.Context, iss *issues.Issue) map[stri
191199
if iss.Number == dup {
192200
continue
193201
}
202+
// If the other issue is already marked as a duplicate,
203+
// we don't need to mark this one.
204+
if t.duplicates[dup] {
205+
continue
206+
}
194207
ref := t.ic.Reference(dup)
195208
xrefs[ref] = append(xrefs[ref], a)
209+
t.duplicates[iss.Number] = true
196210
}
197211
}
198212

0 commit comments

Comments
 (0)