Skip to content

Commit 7cb175d

Browse files
committed
cmd/vulnreport: add command unexclude
Command `vulnreport unexclude` converts an excluded report to a regular report. Will be used as part of an experiment to add back reports that were previously excluded from vulndb. Change-Id: I420a8262144fe6b0f459cb1a8438062931a15700 Reviewed-on: https://go-review.googlesource.com/c/vulndb/+/559815 Reviewed-by: Damien Neil <[email protected]> Reviewed-by: Zvonimir Pavlinovic <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent 3d58640 commit 7cb175d

File tree

3 files changed

+120
-25
lines changed

3 files changed

+120
-25
lines changed

cmd/vulnreport/create.go

+36-25
Original file line numberDiff line numberDiff line change
@@ -218,22 +218,10 @@ func createReport(ctx context.Context, cfg *createCfg, iss *issues.Issue) (r *re
218218
return nil, err
219219
}
220220

221-
aliases := allAliases(ctx, parsed.aliases, cfg.ghsaClient)
222-
if alias, ok := pickBestAlias(aliases, *preferCVE); ok {
223-
log.Infof("creating report %s based on %s (picked from [%s])", parsed.id, alias, strings.Join(aliases, ", "))
224-
r, err = reportFromAlias(ctx, parsed.id, parsed.modulePath, alias, cfg)
225-
if err != nil {
226-
return nil, err
227-
}
228-
} else {
229-
log.Infof("no alias found, creating basic report for %s", parsed.id)
230-
r = &report.Report{
231-
ID: parsed.id,
232-
Modules: []*report.Module{
233-
{
234-
Module: parsed.modulePath,
235-
},
236-
}}
221+
r, err = reportFromAliases(ctx, parsed.id, parsed.modulePath, parsed.aliases,
222+
cfg.proxyClient, cfg.ghsaClient, cfg.aiClient)
223+
if err != nil {
224+
return nil, err
237225
}
238226

239227
if parsed.excluded != "" {
@@ -250,14 +238,38 @@ func createReport(ctx context.Context, cfg *createCfg, iss *issues.Issue) (r *re
250238
}
251239
}
252240

241+
addTODOs(r)
242+
return r, nil
243+
}
244+
245+
func reportFromAliases(ctx context.Context, id, modulePath string, aliases []string,
246+
pc *proxy.Client, gc *ghsa.Client, ac *genai.GeminiClient) (r *report.Report, err error) {
247+
aliases = allAliases(ctx, aliases, gc)
248+
if alias, ok := pickBestAlias(aliases, *preferCVE); ok {
249+
log.Infof("creating report %s based on %s (picked from [%s])", id, alias, strings.Join(aliases, ", "))
250+
r, err = reportFromAlias(ctx, id, modulePath, alias, pc, gc)
251+
if err != nil {
252+
return nil, err
253+
}
254+
} else {
255+
log.Infof("no alias found, creating basic report for %s", id)
256+
r = &report.Report{
257+
ID: id,
258+
Modules: []*report.Module{
259+
{
260+
Module: modulePath,
261+
},
262+
}}
263+
}
264+
253265
// Ensure all source aliases are added to the report.
254266
r.AddAliases(aliases)
255267

256268
// Find any additional aliases referenced by the source aliases.
257-
addMissingAliases(ctx, r, cfg.ghsaClient)
269+
addMissingAliases(ctx, r, gc)
258270

259-
if cfg.aiClient != nil {
260-
suggestions, err := suggest(ctx, cfg.aiClient, r, 1)
271+
if ac != nil {
272+
suggestions, err := suggest(ctx, ac, r, 1)
261273
if err != nil {
262274
log.Warnf("failed to get AI-generated suggestions for %s: %v\n", r.ID, err)
263275
} else if len(suggestions) == 0 {
@@ -268,7 +280,6 @@ func createReport(ctx context.Context, cfg *createCfg, iss *issues.Issue) (r *re
268280
}
269281
}
270282

271-
addTODOs(r)
272283
return r, nil
273284
}
274285

@@ -353,22 +364,22 @@ Adds excluded reports:
353364
// reportFromBestAlias returns a new report created from the "best" alias in the list.
354365
// For now, it prefers the first GHSA in the list, followed by the first CVE in the list
355366
// (if no GHSA is present). If no GHSAs or CVEs are present, it returns a new empty Report.
356-
func reportFromAlias(ctx context.Context, id, modulePath, alias string, cfg *createCfg) (*report.Report, error) {
367+
func reportFromAlias(ctx context.Context, id, modulePath, alias string, pc *proxy.Client, gc *ghsa.Client) (*report.Report, error) {
357368
switch {
358369
case ghsa.IsGHSA(alias) && *graphQL:
359-
ghsa, err := cfg.ghsaClient.FetchGHSA(ctx, alias)
370+
ghsa, err := gc.FetchGHSA(ctx, alias)
360371
if err != nil {
361372
return nil, err
362373
}
363-
r := report.GHSAToReport(ghsa, modulePath, cfg.proxyClient)
374+
r := report.GHSAToReport(ghsa, modulePath, pc)
364375
r.ID = id
365376
return r, nil
366377
case ghsa.IsGHSA(alias):
367378
ghsa, err := genericosv.Fetch(alias)
368379
if err != nil {
369380
return nil, err
370381
}
371-
return ghsa.ToReport(id, cfg.proxyClient), nil
382+
return ghsa.ToReport(id, pc), nil
372383
case cveschema5.IsCVE(alias):
373384
cve, err := cveclient.Fetch(alias)
374385
if err != nil {
@@ -377,7 +388,7 @@ func reportFromAlias(ctx context.Context, id, modulePath, alias string, cfg *cre
377388
log.Infof("no published record found for %s, creating basic report", alias)
378389
return basicReport(id, modulePath), nil
379390
}
380-
return report.CVE5ToReport(cve, id, modulePath, cfg.proxyClient), nil
391+
return report.CVE5ToReport(cve, id, modulePath, pc), nil
381392
}
382393

383394
log.Infof("alias %s is not a CVE or GHSA, creating basic report", alias)

cmd/vulnreport/main.go

+12
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"runtime/pprof"
1717

1818
vlog "golang.org/x/vulndb/cmd/vulnreport/log"
19+
"golang.org/x/vulndb/internal/genai"
1920
"golang.org/x/vulndb/internal/ghsa"
2021
"golang.org/x/vulndb/internal/gitrepo"
2122
"golang.org/x/vulndb/internal/proxy"
@@ -135,6 +136,17 @@ func main() {
135136
log.Fatal(err)
136137
}
137138
cmdFunc = func(ctx context.Context, name string) error { return setDates(ctx, name, commitDates) }
139+
case "unexclude":
140+
var ac *genai.GeminiClient
141+
var err error
142+
if *useAI {
143+
ac, err = genai.NewGeminiClient(ctx)
144+
if err != nil {
145+
log.Fatal(err)
146+
}
147+
defer ac.Close()
148+
}
149+
cmdFunc = func(ctx context.Context, name string) error { return unexclude(ctx, name, ghsaClient, pc, ac) }
138150
case "xref":
139151
repo, err := gitrepo.Open(ctx, ".")
140152
if err != nil {

cmd/vulnreport/unexclude.go

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Copyright 2024 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package main
6+
7+
import (
8+
"context"
9+
"os"
10+
11+
"golang.org/x/vulndb/cmd/vulnreport/log"
12+
"golang.org/x/vulndb/internal/derrors"
13+
"golang.org/x/vulndb/internal/genai"
14+
"golang.org/x/vulndb/internal/ghsa"
15+
"golang.org/x/vulndb/internal/proxy"
16+
"golang.org/x/vulndb/internal/report"
17+
)
18+
19+
// unexclude converts an excluded report into a regular report.
20+
func unexclude(ctx context.Context, filename string, gc *ghsa.Client, pc *proxy.Client, ac *genai.GeminiClient) (err error) {
21+
defer derrors.Wrap(&err, "unexclude(%s)", filename)
22+
23+
log.Infof("unexclude %s", filename)
24+
25+
r, err := report.Read(filename)
26+
if err != nil {
27+
return err
28+
}
29+
30+
if !r.IsExcluded() {
31+
log.Infof("report %s is not excluded, can't unexclude", r.ID)
32+
return nil
33+
}
34+
35+
// Usually, we only unexclude reports that are effectively private or not importable.
36+
if r.Excluded != "EFFECTIVELY_PRIVATE" && r.Excluded != "NOT_IMPORTABLE" {
37+
if *force {
38+
log.Warnf("report %s is excluded for reason %q, but -f was specified, continuing", r.ID, r.Excluded)
39+
} else {
40+
log.Infof("report %s is excluded for reason %q - we don't unexclude these report types (use -f to force)", r.ID, r.Excluded)
41+
return nil
42+
}
43+
}
44+
45+
log.Infof("creating regular report based on excluded report %s", filename)
46+
aliases := r.Aliases()
47+
id := r.ID
48+
var modulePath string
49+
if len(r.Modules) > 0 {
50+
modulePath = r.Modules[0].Module
51+
}
52+
newR, err := reportFromAliases(ctx, id, modulePath, aliases, pc, gc, ac)
53+
if err != nil {
54+
return err
55+
}
56+
57+
// Remove description because this is a "basic" report.
58+
newR.Description = ""
59+
60+
if err := os.Remove(filename); err != nil {
61+
log.Errf("could not remove excluded report: %v", err)
62+
}
63+
log.Infof("removed excluded report %s", filename)
64+
65+
newFilename, err := writeReport(newR)
66+
if err != nil {
67+
return err
68+
}
69+
log.Out(newFilename)
70+
71+
return nil
72+
}

0 commit comments

Comments
 (0)