diff --git a/github/github.go b/github/github.go index 1019a992..074de21e 100644 --- a/github/github.go +++ b/github/github.go @@ -101,20 +101,39 @@ func DetectGitHubSecurityAlerts(r *models.ScanResult, owner, repo, token string) cveIDs = other } + refs := []models.Reference{} + for _, r := range v.Node.SecurityAdvisory.References { + refs = append(refs, models.Reference{Link: r.URL}) + } + for _, cveID := range cveIDs { + cveContent := models.CveContent{ + Type: models.GitHub, + CveID: cveID, + Title: v.Node.SecurityAdvisory.Summary, + Summary: v.Node.SecurityAdvisory.Description, + Cvss2Severity: v.Node.SecurityVulnerability.Severity, + Cvss3Severity: v.Node.SecurityVulnerability.Severity, + SourceLink: v.Node.SecurityAdvisory.Permalink, + References: refs, + Published: v.Node.SecurityAdvisory.PublishedAt, + LastModified: v.Node.SecurityAdvisory.UpdatedAt, + } + if val, ok := r.ScannedCves[cveID]; ok { val.GitHubSecurityAlerts = val.GitHubSecurityAlerts.Add(m) + val.CveContents[models.GitHub] = cveContent r.ScannedCves[cveID] = val - nCVEs++ } else { v := models.VulnInfo{ CveID: cveID, Confidences: models.Confidences{models.GitHubMatch}, GitHubSecurityAlerts: models.GitHubSecurityAlerts{m}, + CveContents: models.NewCveContents(cveContent), } r.ScannedCves[cveID] = v - nCVEs++ } + nCVEs++ } } if !alerts.Data.Repository.VulnerabilityAlerts.PageInfo.HasNextPage { diff --git a/models/cvecontents.go b/models/cvecontents.go index a14fb775..983aa8b3 100644 --- a/models/cvecontents.go +++ b/models/cvecontents.go @@ -1,6 +1,7 @@ package models import ( + "strings" "time" "github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability" @@ -58,7 +59,7 @@ func (v CveContents) PrimarySrcURLs(lang, myFamily, cveID string) (values []CveC } } - order := CveContentTypes{Nvd, NewCveContentType(myFamily)} + order := CveContentTypes{Nvd, NewCveContentType(myFamily), GitHub} for _, ctype := range order { if cont, found := v[ctype]; found { if cont.SourceLink == "" { @@ -74,7 +75,7 @@ func (v CveContents) PrimarySrcURLs(lang, myFamily, cveID string) (values []CveC } } - if len(values) == 0 { + if len(values) == 0 && strings.HasPrefix(cveID, "CVE") { return []CveContentStr{{ Type: Nvd, Value: "https://nvd.nist.gov/vuln/detail/" + cveID, @@ -252,6 +253,8 @@ func NewCveContentType(name string) CveContentType { return Amazon case "trivy": return Trivy + case "GitHub": + return Trivy default: return Unknown } @@ -297,6 +300,9 @@ const ( // Trivy is Trivy Trivy CveContentType = "trivy" + // GitHub is GitHub Security Alerts + GitHub CveContentType = "github" + // Unknown is Unknown Unknown CveContentType = "unknown" ) @@ -317,6 +323,7 @@ var AllCveContetTypes = CveContentTypes{ DebianSecurityTracker, WpScan, Trivy, + GitHub, } // Except returns CveContentTypes except for given args diff --git a/models/vulninfos.go b/models/vulninfos.go index ab9f57df..83453b69 100644 --- a/models/vulninfos.go +++ b/models/vulninfos.go @@ -237,21 +237,25 @@ func (g WpPackages) Add(pkg WpPackage) WpPackages { // Titles returns title (TUI) func (v VulnInfo) Titles(lang, myFamily string) (values []CveContentStr) { if lang == "ja" { - if cont, found := v.CveContents[Jvn]; found && 0 < len(cont.Title) { + if cont, found := v.CveContents[Jvn]; found && cont.Title != "" { values = append(values, CveContentStr{Jvn, cont.Title}) } } // RedHat API has one line title. - if cont, found := v.CveContents[RedHatAPI]; found && 0 < len(cont.Title) { + if cont, found := v.CveContents[RedHatAPI]; found && cont.Title != "" { values = append(values, CveContentStr{RedHatAPI, cont.Title}) } + // GitHub security alerts has a title. + if cont, found := v.CveContents[GitHub]; found && cont.Title != "" { + values = append(values, CveContentStr{GitHub, cont.Title}) + } + order := CveContentTypes{Trivy, Nvd, NewCveContentType(myFamily)} order = append(order, AllCveContetTypes.Except(append(order, Jvn)...)...) for _, ctype := range order { - // Only JVN has meaningful title. so return first 100 char of summary - if cont, found := v.CveContents[ctype]; found && 0 < len(cont.Summary) { + if cont, found := v.CveContents[ctype]; found && cont.Summary != "" { summary := strings.Replace(cont.Summary, "\n", " ", -1) values = append(values, CveContentStr{ Type: ctype, @@ -279,7 +283,7 @@ func (v VulnInfo) Titles(lang, myFamily string) (values []CveContentStr) { // Summaries returns summaries func (v VulnInfo) Summaries(lang, myFamily string) (values []CveContentStr) { if lang == "ja" { - if cont, found := v.CveContents[Jvn]; found && 0 < len(cont.Summary) { + if cont, found := v.CveContents[Jvn]; found && cont.Summary != "" { summary := cont.Title summary += "\n" + strings.Replace( strings.Replace(cont.Summary, "\n", " ", -1), "\r", " ", -1) @@ -287,10 +291,10 @@ func (v VulnInfo) Summaries(lang, myFamily string) (values []CveContentStr) { } } - order := CveContentTypes{Trivy, NewCveContentType(myFamily), Nvd} + order := CveContentTypes{Trivy, NewCveContentType(myFamily), Nvd, GitHub} order = append(order, AllCveContetTypes.Except(append(order, Jvn)...)...) for _, ctype := range order { - if cont, found := v.CveContents[ctype]; found && 0 < len(cont.Summary) { + if cont, found := v.CveContents[ctype]; found && cont.Summary != "" { summary := strings.Replace(cont.Summary, "\n", " ", -1) values = append(values, CveContentStr{ Type: ctype, @@ -308,7 +312,7 @@ func (v VulnInfo) Summaries(lang, myFamily string) (values []CveContentStr) { if v, ok := v.CveContents[WpScan]; ok { values = append(values, CveContentStr{ - Type: "WPVDB", + Type: WpScan, Value: v.Title, }) } @@ -491,7 +495,8 @@ func (v VulnInfo) MaxCvss2Score() CveContentCvss { // If CVSS score isn't on NVD, RedHat and JVN, use OVAL and advisory Severity. // Convert severity to cvss score roughly, then returns max severity. // Only Ubuntu, RedHat and Oracle have severity data in OVAL. - order = []CveContentType{Ubuntu, RedHat, Oracle} + // GitHub Security Alerts also has Severity. It is mainly used to calculate score for non-CVE-ID. + order = []CveContentType{Ubuntu, RedHat, Oracle, GitHub} for _, ctype := range order { if cont, found := v.CveContents[ctype]; found && 0 < len(cont.Cvss2Severity) { score := severityToV2ScoreRoughly(cont.Cvss2Severity) diff --git a/report/tui.go b/report/tui.go index ef13c9ff..eacd8d94 100644 --- a/report/tui.go +++ b/report/tui.go @@ -150,8 +150,6 @@ func keybindings(g *gocui.Gui) (err error) { // errs = append(errs, g.SetKeybinding("msg", gocui.KeyEnter, gocui.ModNone, delMsg)) // errs = append(errs, g.SetKeybinding("detail", gocui.KeyEnter, gocui.ModNone, showMsg)) - //TODO Help Ctrl-h - errs = append(errs, g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit)) // errs = append(errs, g.SetKeybinding("side", gocui.KeyEnter, gocui.ModNone, getLine)) // errs = append(errs, g.SetKeybinding("msg", gocui.KeyEnter, gocui.ModNone, delMsg)) diff --git a/scan/redhatbase.go b/scan/redhatbase.go index af83b32a..ef896772 100644 --- a/scan/redhatbase.go +++ b/scan/redhatbase.go @@ -374,12 +374,6 @@ func (o *redhatBase) parseUpdatablePacksLines(stdout string) (models.Packages, e updatable := models.Packages{} lines := strings.Split(stdout, "\n") for _, line := range lines { - // TODO remove - // if strings.HasPrefix(line, "Obsoleting") || - // strings.HasPrefix(line, "Security:") { - // // see https://github.com/future-architect/vuls/issues/165 - // continue - // } if len(strings.TrimSpace(line)) == 0 { continue } else if strings.HasPrefix(line, "Loading") {