Display summary of advisory when no entry in NVD, OVAL

This commit is contained in:
kota kanbe
2017-07-30 17:04:25 +09:00
parent 27724a2faf
commit 9899cba816
7 changed files with 304 additions and 267 deletions

View File

@@ -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" {

View File

@@ -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

View File

@@ -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}

View File

@@ -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{},

View File

@@ -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,
)
}

View File

@@ -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,

View File

@@ -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(