diff --git a/models/cvecontents.go b/models/cvecontents.go index fc3566f6..68822888 100644 --- a/models/cvecontents.go +++ b/models/cvecontents.go @@ -58,72 +58,6 @@ func (v CveContents) Except(exceptCtypes ...CveContentType) (values CveContents) return } -// Titles returns tilte (TUI) -func (v CveContents) Titles(lang, myFamily string) (values []CveContentStr) { - if lang == "ja" { - if cont, found := v[JVN]; found && 0 < len(cont.Title) { - values = append(values, CveContentStr{JVN, cont.Title}) - } - } - - order := CveContentTypes{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[ctype]; found && 0 < len(cont.Summary) { - summary := strings.Replace(cont.Summary, "\n", " ", -1) - index := 75 - if index < len(summary) { - summary = summary[0:index] + "..." - } - values = append(values, CveContentStr{ - Type: ctype, - Value: summary, - }) - } - } - - if len(values) == 0 { - values = []CveContentStr{{ - Type: Unknown, - Value: "-", - }} - } - return -} - -// Summaries returns summaries -func (v CveContents) Summaries(lang, myFamily string) (values []CveContentStr) { - if lang == "ja" { - if cont, found := v[JVN]; found && 0 < len(cont.Summary) { - summary := cont.Title - summary += "\n" + strings.Replace( - strings.Replace(cont.Summary, "\n", " ", -1), "\r", " ", -1) - values = append(values, CveContentStr{JVN, summary}) - } - } - - order := CveContentTypes{NVD, NewCveContentType(myFamily)} - order = append(order, AllCveContetTypes.Except(append(order, JVN)...)...) - for _, ctype := range order { - if cont, found := v[ctype]; found && 0 < len(cont.Summary) { - summary := strings.Replace(cont.Summary, "\n", " ", -1) - values = append(values, CveContentStr{ - Type: ctype, - Value: summary, - }) - } - } - - if len(values) == 0 { - values = []CveContentStr{{ - Type: Unknown, - Value: "-", - }} - } - return -} - // SourceLinks returns link of source func (v CveContents) SourceLinks(lang, myFamily, cveID string) (values []CveContentStr) { if lang == "ja" { diff --git a/models/cvecontents_test.go b/models/cvecontents_test.go index 03a186f6..4c3cadb2 100644 --- a/models/cvecontents_test.go +++ b/models/cvecontents_test.go @@ -44,202 +44,6 @@ func TestExcept(t *testing.T) { } } -func TestTitles(t *testing.T) { - type in struct { - lang string - cont CveContents - } - var tests = []struct { - in in - out []CveContentStr - }{ - // lang: ja - { - in: in{ - lang: "ja", - cont: CveContents{ - JVN: { - Type: JVN, - Title: "Title1", - }, - RedHat: { - Type: RedHat, - Summary: "Summary RedHat", - }, - NVD: { - Type: NVD, - Summary: "Summary NVD", - // Severity is NIOT included in NVD - }, - }, - }, - out: []CveContentStr{ - { - Type: JVN, - Value: "Title1", - }, - { - Type: NVD, - Value: "Summary NVD", - }, - { - Type: RedHat, - Value: "Summary RedHat", - }, - }, - }, - // lang: en - { - in: in{ - lang: "en", - cont: CveContents{ - JVN: { - Type: JVN, - Title: "Title1", - }, - RedHat: { - Type: RedHat, - Summary: "Summary RedHat", - }, - NVD: { - Type: NVD, - Summary: "Summary NVD", - // Severity is NIOT included in NVD - }, - }, - }, - out: []CveContentStr{ - { - Type: NVD, - Value: "Summary NVD", - }, - { - Type: RedHat, - Value: "Summary RedHat", - }, - }, - }, - // lang: empty - { - in: in{ - lang: "en", - cont: CveContents{}, - }, - out: []CveContentStr{ - { - Type: Unknown, - Value: "-", - }, - }, - }, - } - for _, tt := range tests { - actual := tt.in.cont.Titles(tt.in.lang, "redhat") - if !reflect.DeepEqual(tt.out, actual) { - t.Errorf("\nexpected: %v\n actual: %v\n", tt.out, actual) - } - } -} - -func TestSummaries(t *testing.T) { - type in struct { - lang string - cont CveContents - } - var tests = []struct { - in in - out []CveContentStr - }{ - // lang: ja - { - in: in{ - lang: "ja", - cont: CveContents{ - JVN: { - Type: JVN, - Title: "Title JVN", - Summary: "Summary JVN", - }, - RedHat: { - Type: RedHat, - Summary: "Summary RedHat", - }, - NVD: { - Type: NVD, - Summary: "Summary NVD", - // Severity is NIOT included in NVD - }, - }, - }, - out: []CveContentStr{ - { - Type: JVN, - Value: "Title JVN\nSummary JVN", - }, - { - Type: NVD, - Value: "Summary NVD", - }, - { - Type: RedHat, - Value: "Summary RedHat", - }, - }, - }, - // lang: en - { - in: in{ - lang: "en", - cont: CveContents{ - JVN: { - Type: JVN, - Title: "Title JVN", - Summary: "Summary JVN", - }, - RedHat: { - Type: RedHat, - Summary: "Summary RedHat", - }, - NVD: { - Type: NVD, - Summary: "Summary NVD", - // Severity is NIOT included in NVD - }, - }, - }, - out: []CveContentStr{ - { - Type: NVD, - Value: "Summary NVD", - }, - { - Type: RedHat, - Value: "Summary RedHat", - }, - }, - }, - // lang: empty - { - in: in{ - lang: "en", - cont: CveContents{}, - }, - out: []CveContentStr{ - { - Type: Unknown, - Value: "-", - }, - }, - }, - } - for _, tt := range tests { - actual := tt.in.cont.Summaries(tt.in.lang, "redhat") - if !reflect.DeepEqual(tt.out, actual) { - t.Errorf("\nexpected: %v\n actual: %v\n", tt.out, actual) - } - } -} - func TestSourceLinks(t *testing.T) { type in struct { lang string diff --git a/models/vulninfos.go b/models/vulninfos.go index 5b458cb3..01107497 100644 --- a/models/vulninfos.go +++ b/models/vulninfos.go @@ -114,6 +114,83 @@ type VulnInfo struct { CveContents CveContents } +// Titles returns tilte (TUI) +func (v VulnInfo) Titles(lang, myFamily string) (values []CveContentStr) { + if lang == "ja" { + if cont, found := v.CveContents[JVN]; found && 0 < len(cont.Title) { + values = append(values, CveContentStr{JVN, cont.Title}) + } + } + + order := CveContentTypes{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) { + summary := strings.Replace(cont.Summary, "\n", " ", -1) + values = append(values, CveContentStr{ + Type: ctype, + Value: summary, + }) + } + } + + for _, adv := range v.DistroAdvisories { + values = append(values, CveContentStr{ + Type: "Vendor", + Value: strings.Replace(adv.Description, "\n", " ", -1), + }) + } + + if len(values) == 0 { + values = []CveContentStr{{ + Type: Unknown, + Value: "-", + }} + } + return +} + +// 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) { + summary := cont.Title + summary += "\n" + strings.Replace( + strings.Replace(cont.Summary, "\n", " ", -1), "\r", " ", -1) + values = append(values, CveContentStr{JVN, summary}) + } + } + + order := CveContentTypes{NVD, NewCveContentType(myFamily)} + order = append(order, AllCveContetTypes.Except(append(order, JVN)...)...) + for _, ctype := range order { + if cont, found := v.CveContents[ctype]; found && 0 < len(cont.Summary) { + summary := strings.Replace(cont.Summary, "\n", " ", -1) + values = append(values, CveContentStr{ + Type: ctype, + Value: summary, + }) + } + } + + for _, adv := range v.DistroAdvisories { + values = append(values, CveContentStr{ + Type: "Vendor", + Value: adv.Description, + }) + } + + if len(values) == 0 { + return []CveContentStr{{ + Type: Unknown, + Value: "-", + }} + } + + return +} + // Cvss2Scores returns CVSS V2 Scores func (v VulnInfo) Cvss2Scores() (values []CveContentCvss) { order := []CveContentType{NVD, RedHat, JVN} diff --git a/models/vulninfos_test.go b/models/vulninfos_test.go index 067b5ed3..7502f4ea 100644 --- a/models/vulninfos_test.go +++ b/models/vulninfos_test.go @@ -21,6 +21,210 @@ import ( "testing" ) +func TestTitles(t *testing.T) { + type in struct { + lang string + cont VulnInfo + } + var tests = []struct { + in in + out []CveContentStr + }{ + // lang: ja + { + in: in{ + lang: "ja", + cont: VulnInfo{ + CveContents: CveContents{ + JVN: { + Type: JVN, + Title: "Title1", + }, + RedHat: { + Type: RedHat, + Summary: "Summary RedHat", + }, + NVD: { + Type: NVD, + Summary: "Summary NVD", + // Severity is NIOT included in NVD + }, + }, + }, + }, + out: []CveContentStr{ + { + Type: JVN, + Value: "Title1", + }, + { + Type: NVD, + Value: "Summary NVD", + }, + { + Type: RedHat, + Value: "Summary RedHat", + }, + }, + }, + // lang: en + { + in: in{ + lang: "en", + cont: VulnInfo{ + CveContents: CveContents{ + JVN: { + Type: JVN, + Title: "Title1", + }, + RedHat: { + Type: RedHat, + Summary: "Summary RedHat", + }, + NVD: { + Type: NVD, + Summary: "Summary NVD", + // Severity is NIOT included in NVD + }, + }, + }, + }, + out: []CveContentStr{ + { + Type: NVD, + Value: "Summary NVD", + }, + { + Type: RedHat, + Value: "Summary RedHat", + }, + }, + }, + // lang: empty + { + in: in{ + lang: "en", + cont: VulnInfo{}, + }, + out: []CveContentStr{ + { + Type: Unknown, + Value: "-", + }, + }, + }, + } + for _, tt := range tests { + actual := tt.in.cont.Titles(tt.in.lang, "redhat") + if !reflect.DeepEqual(tt.out, actual) { + t.Errorf("\nexpected: %v\n actual: %v\n", tt.out, actual) + } + } +} + +func TestSummaries(t *testing.T) { + type in struct { + lang string + cont VulnInfo + } + var tests = []struct { + in in + out []CveContentStr + }{ + // lang: ja + { + in: in{ + lang: "ja", + cont: VulnInfo{ + CveContents: CveContents{ + JVN: { + Type: JVN, + Title: "Title JVN", + Summary: "Summary JVN", + }, + RedHat: { + Type: RedHat, + Summary: "Summary RedHat", + }, + NVD: { + Type: NVD, + Summary: "Summary NVD", + // Severity is NIOT included in NVD + }, + }, + }, + }, + out: []CveContentStr{ + { + Type: JVN, + Value: "Title JVN\nSummary JVN", + }, + { + Type: NVD, + Value: "Summary NVD", + }, + { + Type: RedHat, + Value: "Summary RedHat", + }, + }, + }, + // lang: en + { + in: in{ + lang: "en", + cont: VulnInfo{ + CveContents: CveContents{ + JVN: { + Type: JVN, + Title: "Title JVN", + Summary: "Summary JVN", + }, + RedHat: { + Type: RedHat, + Summary: "Summary RedHat", + }, + NVD: { + Type: NVD, + Summary: "Summary NVD", + // Severity is NIOT included in NVD + }, + }, + }, + }, + out: []CveContentStr{ + { + Type: NVD, + Value: "Summary NVD", + }, + { + Type: RedHat, + Value: "Summary RedHat", + }, + }, + }, + // lang: empty + { + in: in{ + lang: "en", + cont: VulnInfo{}, + }, + out: []CveContentStr{ + { + Type: Unknown, + Value: "-", + }, + }, + }, + } + for _, tt := range tests { + actual := tt.in.cont.Summaries(tt.in.lang, "redhat") + if !reflect.DeepEqual(tt.out, actual) { + t.Errorf("\nexpected: %v\n actual: %v\n", tt.out, actual) + } + } +} + func TestCountGroupBySeverity(t *testing.T) { var tests = []struct { in VulnInfos @@ -578,6 +782,24 @@ func TestMaxCvssScores(t *testing.T) { }, }, }, + { + in: VulnInfo{ + DistroAdvisories: []DistroAdvisory{ + { + Severity: "HIGH", + }, + }, + }, + out: CveContentCvss{ + Type: "Vendor", + Value: Cvss{ + Type: CVSS2, + Score: 8.9, + Vector: "-", + Severity: "HIGH", + }, + }, + }, // Empty { in: VulnInfo{}, diff --git a/report/slack.go b/report/slack.go index 53af4673..7b975e9c 100644 --- a/report/slack.go +++ b/report/slack.go @@ -270,7 +270,7 @@ func attachmentText(vinfo models.VulnInfo, osFamily string) string { severity, cweIDs(vinfo, osFamily), strings.Join(vectors, "\n"), - vinfo.CveContents.Summaries(config.Conf.Lang, osFamily)[0].Value, + vinfo.Summaries(config.Conf.Lang, osFamily)[0].Value, ) } diff --git a/report/tui.go b/report/tui.go index 1405e6d1..1d04de20 100644 --- a/report/tui.go +++ b/report/tui.go @@ -638,7 +638,7 @@ func summaryLines() string { } for i, vinfo := range vinfos { - summary := vinfo.CveContents.Summaries( + summary := vinfo.Titles( config.Conf.Lang, currentScanResult.Family)[0].Value cvssScore := fmt.Sprintf("| %4.1f", vinfo.MaxCvssScore().Value.Score) @@ -790,7 +790,7 @@ func detailLines() (string, error) { } } - summary := vinfo.CveContents.Summaries(r.Lang, r.Family)[0] + summary := vinfo.Summaries(r.Lang, r.Family)[0] data := dataForTmpl{ CveID: vinfo.CveID, diff --git a/report/util.go b/report/util.go index 30a3cb91..b92d1c5f 100644 --- a/report/util.go +++ b/report/util.go @@ -110,7 +110,7 @@ func formatShortPlainText(r models.ScanResult) string { stable.MaxColWidth = maxColWidth stable.Wrap = true for _, vuln := range vulns.ToSortedSlice() { - summaries := vuln.CveContents.Summaries(config.Conf.Lang, r.Family) + summaries := vuln.Summaries(config.Conf.Lang, r.Family) links := vuln.CveContents.SourceLinks( config.Conf.Lang, r.Family, vuln.CveID) @@ -199,7 +199,7 @@ func formatFullPlainText(r models.ScanResult) string { if 0 < len(vuln.Cvss3Scores()) { table.AddRow("CVSSv3 Calc", vuln.Cvss3CalcURL()) } - table.AddRow("Summary", vuln.CveContents.Summaries( + table.AddRow("Summary", vuln.Summaries( config.Conf.Lang, r.Family)[0].Value) links := vuln.CveContents.SourceLinks(