internal/govulncheck: add sbom message type
Adds a minimal SBOM message to govulncheck output. This message contains
information about the code that govulncheck is scanning, like the go
version used for the standard library, modules and their version, and
the root packages gathered from the user inputted package patterns.
Change-Id: I5db597ffaaa654394faea8dda82e1f18c5f5975a
Reviewed-on: https://go-review.googlesource.com/c/vuln/+/616061
Reviewed-by: Zvonimir Pavlinovic <zpavlinovic@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/internal/govulncheck/govulncheck.go b/internal/govulncheck/govulncheck.go
index 9c6c2cb..377a378 100644
--- a/internal/govulncheck/govulncheck.go
+++ b/internal/govulncheck/govulncheck.go
@@ -39,6 +39,7 @@
type Message struct {
Config *Config `json:"config,omitempty"`
Progress *Progress `json:"progress,omitempty"`
+ SBOM *SBOM `json:"SBOM,omitempty"`
// OSV is emitted for every vulnerability in the current database
// that applies to user modules regardless of their version. If a
// module is being used at a vulnerable version, the corresponding
@@ -85,6 +86,29 @@
ScanMode ScanMode `json:"scan_mode,omitempty"`
}
+// SBOM contains minimal information about the artifacts govulncheck is scanning.
+type SBOM struct {
+ // The go version used by govulncheck when scanning, which also defines
+ // the version of the standard library used for detecting vulns.
+ GoVersion string `json:"go_version,omitempty"`
+
+ // The set of modules included in the scan.
+ Modules []*Module `json:"modules,omitempty"`
+
+ // The roots of the scan, as package paths.
+ // For binaries, this will be the main package.
+ // For source code, this will be the packages matching the provided package patterns.
+ Roots []string `json:"roots,omitempty"`
+}
+
+type Module struct {
+ // The full module path.
+ Path string `json:"path,omitempty"`
+
+ // The version of the module.
+ Version string `json:"version,omitempty"`
+}
+
// Progress messages are informational only, intended to allow users to monitor
// the progress of a long running scan.
// A stream must remain fully valid and able to be interpreted with all progress
diff --git a/internal/govulncheck/handler.go b/internal/govulncheck/handler.go
index 5676ea9..5ce7d53 100644
--- a/internal/govulncheck/handler.go
+++ b/internal/govulncheck/handler.go
@@ -17,6 +17,9 @@
// Config communicates introductory message to the user.
Config(config *Config) error
+ // SBOM shows information about what govulncheck is scanning.
+ SBOM(sbom *SBOM) error
+
// Progress is called to display a progress message.
Progress(progress *Progress) error
@@ -45,6 +48,9 @@
if msg.Progress != nil {
err = to.Progress(msg.Progress)
}
+ if msg.SBOM != nil {
+ err = to.SBOM(msg.SBOM)
+ }
if msg.OSV != nil {
err = to.OSV(msg.OSV)
}
diff --git a/internal/govulncheck/jsonhandler.go b/internal/govulncheck/jsonhandler.go
index d1ea78a..b1586e0 100644
--- a/internal/govulncheck/jsonhandler.go
+++ b/internal/govulncheck/jsonhandler.go
@@ -33,6 +33,11 @@
return h.enc.Encode(Message{Progress: progress})
}
+// SBOM writes the SBOM block in JSON to the underlying writer.
+func (h *jsonHandler) SBOM(sbom *SBOM) error {
+ return h.enc.Encode(Message{SBOM: sbom})
+}
+
// OSV writes an osv entry in JSON to the underlying writer.
func (h *jsonHandler) OSV(entry *osv.Entry) error {
return h.enc.Encode(Message{OSV: entry})
diff --git a/internal/openvex/handler.go b/internal/openvex/handler.go
index 374c4d8..a2d3282 100644
--- a/internal/openvex/handler.go
+++ b/internal/openvex/handler.go
@@ -28,6 +28,7 @@
type handler struct {
w io.Writer
cfg *govulncheck.Config
+ sbom *govulncheck.SBOM
osvs map[string]*osv.Entry
// findings contains same-level findings for an
// OSV at the most precise level of granularity
@@ -54,6 +55,11 @@
return nil
}
+func (h *handler) SBOM(s *govulncheck.SBOM) error {
+ h.sbom = s
+ return nil
+}
+
func (h *handler) OSV(e *osv.Entry) error {
h.osvs[e.ID] = e
return nil
diff --git a/internal/sarif/handler.go b/internal/sarif/handler.go
index 3424857..3d6f689 100644
--- a/internal/sarif/handler.go
+++ b/internal/sarif/handler.go
@@ -37,6 +37,7 @@
findings: make(map[string][]*govulncheck.Finding),
}
}
+
func (h *handler) Config(c *govulncheck.Config) error {
h.cfg = c
return nil
@@ -46,6 +47,10 @@
return nil // not needed by sarif
}
+func (h *handler) SBOM(s *govulncheck.SBOM) error {
+ return nil // not needed by sarif
+}
+
func (h *handler) OSV(e *osv.Entry) error {
h.osvs[e.ID] = e
return nil
diff --git a/internal/scan/text.go b/internal/scan/text.go
index e82ecf3..20dce77 100644
--- a/internal/scan/text.go
+++ b/internal/scan/text.go
@@ -115,6 +115,11 @@
return h.err
}
+func (h *TextHandler) SBOM(info *govulncheck.SBOM) error {
+ // TODO: implement sbom in text mode
+ return nil
+}
+
// Progress writes progress updates during govulncheck execution.
func (h *TextHandler) Progress(progress *govulncheck.Progress) error {
if h.showVerbose {
diff --git a/internal/test/handler.go b/internal/test/handler.go
index c577e2a..0d71d46 100644
--- a/internal/test/handler.go
+++ b/internal/test/handler.go
@@ -17,6 +17,7 @@
// For use in tests.
type MockHandler struct {
ConfigMessages []*govulncheck.Config
+ SBOMMessages []*govulncheck.SBOM
ProgressMessages []*govulncheck.Progress
OSVMessages []*osv.Entry
FindingMessages []*govulncheck.Finding
@@ -31,6 +32,11 @@
return nil
}
+func (h *MockHandler) SBOM(sbom *govulncheck.SBOM) error {
+ h.SBOMMessages = append(h.SBOMMessages, sbom)
+ return nil
+}
+
func (h *MockHandler) Progress(progress *govulncheck.Progress) error {
h.ProgressMessages = append(h.ProgressMessages, progress)
return nil
@@ -91,6 +97,11 @@
return err
}
}
+ for _, sbom := range h.SBOMMessages {
+ if err := to.SBOM(sbom); err != nil {
+ return err
+ }
+ }
seen := map[string]bool{}
for _, finding := range h.FindingMessages {
if !seen[finding.OSV] {
diff --git a/internal/vulncheck/binary.go b/internal/vulncheck/binary.go
index 8084a52..73da4c9 100644
--- a/internal/vulncheck/binary.go
+++ b/internal/vulncheck/binary.go
@@ -47,6 +47,8 @@
// It does not compute call graphs so the corresponding
// info in Result will be empty.
func binary(ctx context.Context, handler govulncheck.Handler, bin *Bin, cfg *govulncheck.Config, client *client.Client) (*Result, error) {
+ // TODO: Pass SBOM to handler
+
graph := NewPackageGraph(bin.GoVersion)
mods := append(bin.Modules, graph.GetModule(internal.GoStdModulePath))
if bin.Main != nil {
diff --git a/internal/vulncheck/source.go b/internal/vulncheck/source.go
index 975ecb4..fe10746 100644
--- a/internal/vulncheck/source.go
+++ b/internal/vulncheck/source.go
@@ -57,6 +57,8 @@
}()
}
+ // TODO: pass SBOM to handler
+
if err := handler.Progress(&govulncheck.Progress{Message: fetchingVulnsMessage}); err != nil {
return nil, err
}