aboutsummaryrefslogtreecommitdiff
path: root/report.go
diff options
context:
space:
mode:
Diffstat (limited to 'report.go')
-rw-r--r--report.go82
1 files changed, 82 insertions, 0 deletions
diff --git a/report.go b/report.go
new file mode 100644
index 0000000..e52c9d4
--- /dev/null
+++ b/report.go
@@ -0,0 +1,82 @@
+package app
+
+import (
+ "fmt"
+ "os"
+ "sort"
+ "strings"
+)
+
+// BrewVulnsReport is the JSON structure emitted on stdout.
+type BrewVulnsReport struct {
+ Exploited []string `json:"exploited"`
+ NotExploited []string `json:"not_exploited"`
+ NonCVE []string `json:"non_cve"`
+ VulnerablePackages []string `json:"vulnerable_packages"`
+}
+
+// BuildBrewVulnsReport checks each brew-reported CVE against fprox and
+// classifies it as exploited or not, alongside the vulnerable packages.
+func BuildBrewVulnsReport() (BrewVulnsReport, error) {
+ r, err := runBrewVulns()
+ if err != nil {
+ return BrewVulnsReport{}, err
+ }
+
+ // Maintain a CVE -> homebrew package mapping while accumulating the
+ // vulnerable packages and non-CVE identifiers so the report references all.
+ cvePkg := make(map[string]string)
+ pkgSeen := make(map[string]struct{})
+ nonCveSeen := make(map[string]struct{})
+ for _, finding := range r.Findings {
+ for _, v := range finding.Vulnerabilities {
+ if v.ID == "" {
+ continue
+ }
+ if strings.HasPrefix(v.ID, "CVE-") {
+ if _, ok := cvePkg[v.ID]; !ok {
+ cvePkg[v.ID] = finding.Formula
+ }
+ pkgSeen[finding.Formula] = struct{}{}
+ } else {
+ nonCveSeen[v.ID] = struct{}{}
+ }
+ }
+ }
+
+ var exploited, notExploited []string
+ for cve := range cvePkg {
+ has, err := CveHasExploits(cve)
+ if err != nil {
+ // Skip CVEs we could not resolve so they are never mislabeled.
+ fmt.Fprintf(os.Stderr, "warning: skipping %s: %v\n", cve, err)
+ continue
+ }
+ if has {
+ exploited = append(exploited, cve)
+ } else {
+ notExploited = append(notExploited, cve)
+ }
+ }
+ sort.Strings(exploited)
+ sort.Strings(notExploited)
+
+ pkgs := make([]string, 0, len(pkgSeen))
+ for pkg := range pkgSeen {
+ pkgs = append(pkgs, pkg)
+ }
+ sort.Strings(pkgs)
+
+ nonCves := make([]string, 0, len(nonCveSeen))
+ for id := range nonCveSeen {
+ nonCves = append(nonCves, id)
+ }
+ sort.Strings(nonCves)
+
+ return BrewVulnsReport{
+ Exploited: exploited,
+ NotExploited: notExploited,
+ NonCVE: nonCves,
+ VulnerablePackages: pkgs,
+ }, nil
+}