cmd/vulnreport: auto-populate symbols at creation time for NEEDS_REVIEW issues
- Updated vulnreport to auto populate symbols by default for
high-priority issues (NEEDS_REVIEW).
- Updated vulnreport_test with test cases for vulnreport create.
- Added run_test support for explicit error message validation.
- Added testing guide to illustrate how to update golden test file
structure.
Change-Id: I9e877be369a6eb3b709f896eea42aac80d035512
Reviewed-on: https://go-review.googlesource.com/c/vulndb/+/691995
Reviewed-by: Neal Patel <nealpatel@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Markus Kusano <kusano@google.com>
diff --git a/cmd/vulnreport/create.go b/cmd/vulnreport/create.go
index b963410..693d105 100644
--- a/cmd/vulnreport/create.go
+++ b/cmd/vulnreport/create.go
@@ -14,7 +14,7 @@
var (
preferCVE = flag.Bool("cve", false, "for create, prefer CVEs over GHSAs as canonical source")
useAI = flag.Bool("ai", false, "for create, use AI to write draft summary and description when creating report")
- populateSymbols = flag.Bool("symbols", false, "for create, attempt to auto-populate symbols")
+ populateSymbols = flag.Bool("symbols", true, "for create, attempt to auto-populate symbols")
user = flag.String("user", "", "for create & create-excluded, only consider issues assigned to the given user")
reviewStatus = flag.String("status", "", "for create, use this review status (REVIEWED or UNREVIEWED) instead of default based on label; for commit, only commit reports with this status")
)
diff --git a/cmd/vulnreport/creator.go b/cmd/vulnreport/creator.go
index 404a11a..0018a72 100644
--- a/cmd/vulnreport/creator.go
+++ b/cmd/vulnreport/creator.go
@@ -227,8 +227,8 @@
}
}
- if *populateSymbols {
- log.Infof("%s: attempting to auto-populate symbols (this may take a while...)", r.ID)
+ if *populateSymbols && raw.NeedsReview() {
+ log.Infof("%s: attempting to auto-populate symbols for NEEDS_REVIEW report (this may take a while...)", r.ID)
if err := symbols.Populate(r.Report, false); err != nil {
r.AddNote(report.NoteTypeCreate, "failed to auto-populate symbols")
log.Warnf("%s: could not auto-populate symbols: %s", r.ID, err)
diff --git a/cmd/vulnreport/run_test.go b/cmd/vulnreport/run_test.go
index a91a5f8..ddb1bed 100644
--- a/cmd/vulnreport/run_test.go
+++ b/cmd/vulnreport/run_test.go
@@ -36,9 +36,10 @@
)
type testCase struct {
- name string
- args []string
- wantErr bool
+ name string
+ args []string
+ wantErr bool
+ expectedErr string
}
type memWFS struct {
@@ -149,6 +150,10 @@
if err == nil {
t.Errorf("run(%s, %s) = %v, want error", cmd.name(), tc.args, err)
}
+ if tc.expectedErr != "" && !strings.Contains(logs.String(), tc.expectedErr) {
+ diff := cmp.Diff(tc.expectedErr, logs.String())
+ t.Errorf("run(%s, %s) mismatch, did not find expected substring (-want, +got):\n%s", cmd.name(), tc.args, diff)
+ }
} else if err != nil {
t.Errorf("run(%s, %s) = %v, want no error", cmd.name(), tc.args, err)
}
diff --git a/cmd/vulnreport/testdata/TestCreate/invalid_issue_id.txtar b/cmd/vulnreport/testdata/TestCreate/invalid_issue_id.txtar
new file mode 100644
index 0000000..64ec2c2
--- /dev/null
+++ b/cmd/vulnreport/testdata/TestCreate/invalid_issue_id.txtar
@@ -0,0 +1,12 @@
+Copyright 2025 The Go Authors. All rights reserved.
+Use of this source code is governed by a BSD-style
+license that can be found in the LICENSE file.
+
+Expected output of test TestCreate/invalid_issue_id
+command: "vulnreport create 999"
+
+-- out --
+-- logs --
+info: create: operating on 1 issue(s)
+ERROR: create: lookup 999 failed: issue 999 not found
+info: create: processed 1 issue(s) (success=0; skip=0; error=1)
diff --git a/cmd/vulnreport/testdata/TestCreate/new_report_high_priority.txtar b/cmd/vulnreport/testdata/TestCreate/new_report_high_priority.txtar
new file mode 100644
index 0000000..023c0a1
--- /dev/null
+++ b/cmd/vulnreport/testdata/TestCreate/new_report_high_priority.txtar
@@ -0,0 +1,39 @@
+Copyright 2025 The Go Authors. All rights reserved.
+Use of this source code is governed by a BSD-style
+license that can be found in the LICENSE file.
+
+Expected output of test TestCreate/new_report_high_priority
+command: "vulnreport create 100"
+
+-- out --
+data/reports/GO-0000-0100.yaml
+-- logs --
+info: create: operating on 1 issue(s)
+info: create 100
+info: GO-0000-0100: creating new NEEDS_REVIEW report
+info: GO-0000-0100: no suitable alias found, creating basic report
+info: GO-0000-0100: attempting to auto-populate symbols for NEEDS_REVIEW report (this may take a while...)
+WARNING: GO-0000-0100: could not auto-populate symbols: no commits found for golang.org/x/tools
+info: GO-0000-0100: checking that all packages exist
+info: GO-0000-0100: checking symbols (use -skip-symbols to skip this)
+info: GO-0000-0100: module golang.org/x/tools has no packages, skipping symbol checks
+info: GO-0000-0100: checking for missing GHSAs and CVEs (use -skip-alias to skip this)
+info: GO-0000-0100: checking that all references are reachable
+WARNING: GO-0000-0100: still has lint errors after fix
+ERROR: create: GO-0000-0100: could not fix all errors; requires manual review
+info: create: processed 1 issue(s) (success=0; skip=0; error=1)
+-- data/reports/GO-0000-0100.yaml --
+id: GO-0000-0100
+modules:
+ - module: golang.org/x/tools
+ vulnerable_at: 0.35.0
+summary: Vulnerability in golang.org/x/tools
+notes:
+ - create: failed to auto-populate symbols
+ - lint: 'modules[0] "golang.org/x/tools": versions: no latest fixed version (required for NEEDS_REVIEW report)'
+ - lint: 'references: missing advisory (required because report has no description or is UNREVIEWED)'
+ - lint: 'source: if id=go-security-team, report must be REVIEWED'
+source:
+ id: go-security-team
+ created: 2025-08-05T18:42:11.83533638Z
+review_status: NEEDS_REVIEW
diff --git a/cmd/vulnreport/testdata/TestCreate/report_already_exists.txtar b/cmd/vulnreport/testdata/TestCreate/report_already_exists.txtar
new file mode 100644
index 0000000..720b96c
--- /dev/null
+++ b/cmd/vulnreport/testdata/TestCreate/report_already_exists.txtar
@@ -0,0 +1,12 @@
+Copyright 2025 The Go Authors. All rights reserved.
+Use of this source code is governed by a BSD-style
+license that can be found in the LICENSE file.
+
+Expected output of test TestCreate/report_already_exists
+command: "vulnreport create 1"
+
+-- out --
+-- logs --
+info: create: operating on 1 issue(s)
+info: create: skipping issue #1 (already has report)
+info: create: processed 1 issue(s) (success=0; skip=1; error=0)
diff --git a/cmd/vulnreport/testdata/TestTriage/all.txtar b/cmd/vulnreport/testdata/TestTriage/all.txtar
index 273a824..03edfef 100644
--- a/cmd/vulnreport/testdata/TestTriage/all.txtar
+++ b/cmd/vulnreport/testdata/TestTriage/all.txtar
@@ -16,22 +16,29 @@
issue test-issue-tracker/12 is likely duplicate
- #12 shares alias(es) CVE-1999-0002, GHSA-xxxx-yyyy-0002, GHSA-xxxx-yyyy-0003 with test-issue-tracker/13
- #12 shares alias(es) CVE-1999-0002, GHSA-xxxx-yyyy-0002, GHSA-xxxx-yyyy-0003 with test-issue-tracker/14
+ - #12 shares alias(es) CVE-1999-0002, GHSA-xxxx-yyyy-0002, GHSA-xxxx-yyyy-0003 with test-issue-tracker/15
posted comment to issue 12: Duplicate of #13
posted comment to issue 12: Duplicate of #14
+posted comment to issue 12: Duplicate of #15
issue test-issue-tracker/13 is likely duplicate
- #13 shares alias(es) CVE-1999-0002, GHSA-xxxx-yyyy-0002, GHSA-xxxx-yyyy-0003 with test-issue-tracker/14
+ - #13 shares alias(es) CVE-1999-0002, GHSA-xxxx-yyyy-0002, GHSA-xxxx-yyyy-0003 with test-issue-tracker/15
posted comment to issue 13: Duplicate of #14
-triaged 6 issues:
+posted comment to issue 13: Duplicate of #15
+issue test-issue-tracker/14 is likely duplicate
+ - #14 shares alias(es) CVE-1999-0002, GHSA-xxxx-yyyy-0002, GHSA-xxxx-yyyy-0003 with test-issue-tracker/15
+posted comment to issue 14: Duplicate of #15
+triaged 8 issues:
- 1 high priority
- - 5 low priority
+ - 7 low priority
- 0 unknown priority
- - 3 likely duplicate
+ - 4 likely duplicate
- 1 possibly not Go
helpful commands:
$ vulnreport create 10
-- logs --
info: creating alias map for open issues
-info: triage: operating on 7 issue(s)
+info: triage: operating on 9 issue(s)
info: triage: skipping issue #1 (already has report)
info: triage 7
info: issue test-issue-tracker/7 is low priority
@@ -49,4 +56,11 @@
info: triage 14
info: issue test-issue-tracker/14 is low priority
- golang.org/x/tools has 50 importers (< 100)
-info: triage: processed 7 issue(s) (success=6; skip=1; error=0)
+info: triage 15
+info: issue test-issue-tracker/15 is low priority
+ - golang.org/x/tools has 50 importers (< 100)
+info: triage 100
+info: issue #100: skipping duplicate search (no aliases found)
+info: issue test-issue-tracker/100 is low priority
+ - golang.org/x/tools has 50 importers (< 100)
+info: triage: processed 9 issue(s) (success=8; skip=1; error=0)
diff --git a/cmd/vulnreport/testdata/issue_tracker.txtar b/cmd/vulnreport/testdata/issue_tracker.txtar
index 4c515de..a68986b 100644
--- a/cmd/vulnreport/testdata/issue_tracker.txtar
+++ b/cmd/vulnreport/testdata/issue_tracker.txtar
@@ -41,3 +41,17 @@
title: "x/vulndb: potential Go vuln in golang.org/x/tools: GHSA-xxxx-yyyy-0003"
state: open
+-- 15 --
+number: 15
+title: "x/vulndb: potential Go vuln in golang.org/x/tools: GHSA-xxxx-yyyy-0003"
+state: open
+
+-- 100 --
+{
+ "number": 100,
+ "title": "x/vulndb: potential high priority vulnerability in golang.org/x/tools",
+ "state": "open",
+ "labels": [
+ "high priority"
+ ]
+}
diff --git a/cmd/vulnreport/testdata/pkgsite/TestCreate/invalid_issue_id.json b/cmd/vulnreport/testdata/pkgsite/TestCreate/invalid_issue_id.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/cmd/vulnreport/testdata/pkgsite/TestCreate/invalid_issue_id.json
@@ -0,0 +1 @@
+{}
diff --git a/cmd/vulnreport/testdata/pkgsite/TestCreate/new_report_high_priority.json b/cmd/vulnreport/testdata/pkgsite/TestCreate/new_report_high_priority.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/cmd/vulnreport/testdata/pkgsite/TestCreate/new_report_high_priority.json
@@ -0,0 +1 @@
+{}
diff --git a/cmd/vulnreport/testdata/pkgsite/TestCreate/report_already_exists.json b/cmd/vulnreport/testdata/pkgsite/TestCreate/report_already_exists.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/cmd/vulnreport/testdata/pkgsite/TestCreate/report_already_exists.json
@@ -0,0 +1 @@
+{}
diff --git a/cmd/vulnreport/testdata/proxy/TestCreate/invalid_issue_id.json b/cmd/vulnreport/testdata/proxy/TestCreate/invalid_issue_id.json
new file mode 100644
index 0000000..9e26dfe
--- /dev/null
+++ b/cmd/vulnreport/testdata/proxy/TestCreate/invalid_issue_id.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/cmd/vulnreport/testdata/proxy/TestCreate/new_report_high_priority.json b/cmd/vulnreport/testdata/proxy/TestCreate/new_report_high_priority.json
new file mode 100644
index 0000000..24bedb3
--- /dev/null
+++ b/cmd/vulnreport/testdata/proxy/TestCreate/new_report_high_priority.json
@@ -0,0 +1,6 @@
+{
+ "golang.org/x/tools/@latest": {
+ "body": "{\"Version\":\"v0.35.0\",\"Time\":\"2025-07-11T16:19:56Z\",\"Origin\":{\"VCS\":\"git\",\"URL\":\"https://go.googlesource.com/tools\",\"Hash\":\"50ec2f15fda46d8960c1d871856265127b4dcce5\",\"Ref\":\"refs/tags/v0.35.0\"}}",
+ "status_code": 200
+ }
+}
\ No newline at end of file
diff --git a/cmd/vulnreport/testdata/proxy/TestCreate/report_already_exists.json b/cmd/vulnreport/testdata/proxy/TestCreate/report_already_exists.json
new file mode 100644
index 0000000..9e26dfe
--- /dev/null
+++ b/cmd/vulnreport/testdata/proxy/TestCreate/report_already_exists.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/cmd/vulnreport/testing-guide.md b/cmd/vulnreport/testing-guide.md
new file mode 100644
index 0000000..80358ce
--- /dev/null
+++ b/cmd/vulnreport/testing-guide.md
@@ -0,0 +1,31 @@
+# Updating Golden Tests for `vulnreport`
+
+This guide explains how to add or update golden file test cases for most `vulnreport` commands.
+
+The tests for this command use a "golden file" system. This means the output of the command (including logs and any files it creates) is compared against a pre-recorded, known-good version stored in a `.txtar` file. To generate or update these golden files, you must run the test in a special mode that allows it to contact the real Go module proxy and record the results.
+
+### The Update Command
+
+The primary command used for this process is:
+
+```shell
+go test -v -proxy -update-test -run TestCreate/<test_case_name>
+```
+
+Here is a breakdown of what each flag does:
+
+* `-v`: Enables verbose mode, showing detailed log output for each test.
+* `-proxy`: This flag temporarily allows the test to make live network calls to the public Go module proxy (`proxy.golang.org`). The test client will cache the responses as JSON files in the `testdata/proxy/` directory so that subsequent test runs can be performed offline.
+* `-update-test`: This flag puts the test into "update" mode. Instead of comparing the command's output to the existing golden file, it will create or overwrite the golden file with the new output.
+* `-run TestCreate/<test_case_name>`: This specifies which test to run. You should target a specific test case to avoid updating golden files for unrelated tests.
+
+### Workflow for Adding a New Test Case
+
+Follow these steps to add a new test for a `create` command scenario:
+
+1. **Add a Mock Issue**: Add a new issue entry to `cmd/vulnreport/testdata/issue_tracker.txtar`. Ensure the module path in the issue's title refers to a real, public Go module.
+2. **Add the Test Case**: Add a new `testCase` struct to the `TestCreate` function in `cmd/vulnreport/vulnreport_test.go`. Use a descriptive name for your test case.
+3. **Generate Test Files**: Run the `go test` command with both the `-proxy` and `-update-test` flags, targeting your new test case. This single command creates two essential files:
+ * A JSON file in `testdata/proxy/TestCreate/` containing the cached module data from the Go proxy.
+ * A `.txtar` file in `testdata/TestCreate/` containing the captured output of the command. This is your new golden file.
+4. **Verify the Test**: Run the test again without the flags (`go test -v -run TestCreate/<test_case_name>`). The test should now pass by comparing the command's live output against the files you just generated.
diff --git a/cmd/vulnreport/vulnreport_test.go b/cmd/vulnreport/vulnreport_test.go
index 376a81d..3eb9457 100644
--- a/cmd/vulnreport/vulnreport_test.go
+++ b/cmd/vulnreport/vulnreport_test.go
@@ -10,7 +10,21 @@
func TestCreate(t *testing.T) {
for _, tc := range []*testCase{
- // TODO(tatianabradley): add test cases
+ {
+ name: "invalid issue id",
+ args: []string{"999"},
+ wantErr: true,
+ },
+ {
+ name: "report already exists",
+ args: []string{"1"},
+ },
+ {
+ name: "new report high priority",
+ args: []string{"100"},
+ wantErr: true,
+ expectedErr: "ERROR: create: GO-0000-0100: could not fix all errors; requires manual review",
+ },
} {
runTest(t, &create{}, tc)
}