Fix -to-email

This commit is contained in:
Kota Kanbe
2017-05-26 12:50:12 +09:00
committed by kota kanbe
parent 306182e2ae
commit bc5a95ebb3
7 changed files with 134 additions and 56 deletions

View File

@@ -231,14 +231,12 @@ func cvss3ScoreToSeverity(score float64) string {
// Cvss3Scores returns CVSS V3 Score
func (v CveContents) Cvss3Scores() (values []CveContentCvss3) {
// TODO implement NVD
order := []CveContentType{RedHat}
for _, ctype := range order {
if cont, found := v[ctype]; found && 0 < cont.Cvss3Score {
// https://nvd.nist.gov/vuln-metrics/cvss
sev := cont.Severity
if ctype == NVD {
sev = cvss3ScoreToSeverity(cont.Cvss2Score)
}
values = append(values, CveContentCvss3{
Type: ctype,
Value: Cvss3{
@@ -254,6 +252,7 @@ func (v CveContents) Cvss3Scores() (values []CveContentCvss3) {
// MaxCvss3Score returns Max CVSS V3 Score
func (v CveContents) MaxCvss3Score() CveContentCvss3 {
// TODO implement NVD
order := []CveContentType{RedHat}
max := 0.0
value := CveContentCvss3{
@@ -264,9 +263,6 @@ func (v CveContents) MaxCvss3Score() CveContentCvss3 {
if cont, found := v[ctype]; found && max < cont.Cvss3Score {
// https://nvd.nist.gov/vuln-metrics/cvss
sev := cont.Severity
if ctype == NVD {
sev = cvss3ScoreToSeverity(cont.Cvss2Score)
}
value = CveContentCvss3{
Type: ctype,
Value: Cvss3{

View File

@@ -23,7 +23,6 @@ import (
"strings"
"time"
"github.com/future-architect/vuls/config"
cvedict "github.com/kotakanbe/go-cve-dictionary/models"
)
@@ -215,34 +214,6 @@ func (r ScanResult) FormatServerName() string {
r.Container.Name, r.ServerName)
}
// CveSummary summarize the number of CVEs group by CVSSv2 Severity
func (r ScanResult) CveSummary() string {
var high, medium, low, unknown int
for _, vInfo := range r.ScannedCves {
score := vInfo.CveContents.MaxCvss2Score().Value.Score
if score < 0.1 {
score = vInfo.CveContents.MaxCvss3Score().Value.Score
}
switch {
case 7.0 <= score:
high++
case 4.0 <= score:
medium++
case 0 < score:
low++
default:
unknown++
}
}
if config.Conf.IgnoreUnscoredCves {
return fmt.Sprintf("Total: %d (High:%d Medium:%d Low:%d)",
high+medium+low, high, medium, low)
}
return fmt.Sprintf("Total: %d (High:%d Medium:%d Low:%d ?:%d)",
high+medium+low+unknown, high, medium, low, unknown)
}
// FormatTextReportHeadedr returns header of text report
func (r ScanResult) FormatTextReportHeadedr() string {
serverInfo := r.ServerInfo()
@@ -253,7 +224,7 @@ func (r ScanResult) FormatTextReportHeadedr() string {
return fmt.Sprintf("%s\n%s\n%s\t%s\n",
r.ServerInfo(),
buf.String(),
r.CveSummary(),
r.ScannedCves.FormatCveSummary(),
r.Packages.FormatUpdatablePacksSummary(),
)
}

View File

@@ -22,6 +22,8 @@ import (
"sort"
"strings"
"time"
"github.com/future-architect/vuls/config"
)
// VulnInfos is VulnInfo list, getter/setter, sortable methods.
@@ -65,7 +67,42 @@ func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {
return
}
// VulnInfo holds a vulnerability information and unsecure packages
// CountGroupBySeverity summarize the number of CVEs group by CVSSv2 Severity
func (v VulnInfos) CountGroupBySeverity() map[string]int {
m := map[string]int{}
for _, vInfo := range v {
score := vInfo.CveContents.MaxCvss2Score().Value.Score
if score < 0.1 {
score = vInfo.CveContents.MaxCvss3Score().Value.Score
}
switch {
case 7.0 <= score:
m["High"]++
case 4.0 <= score:
m["Medium"]++
case 0 < score:
m["Low"]++
default:
m["Unknown"]++
}
}
return m
}
// FormatCveSummary summarize the number of CVEs group by CVSSv2 Severity
func (v VulnInfos) FormatCveSummary() string {
m := v.CountGroupBySeverity()
if config.Conf.IgnoreUnscoredCves {
return fmt.Sprintf("Total: %d (High:%d Medium:%d Low:%d)",
m["High"]+m["Medium"]+m["Low"], m["High"], m["Medium"], m["Low"])
}
return fmt.Sprintf("Total: %d (High:%d Medium:%d Low:%d ?:%d)",
m["High"]+m["Medium"]+m["Low"]+m["Unknown"],
m["High"], m["Medium"], m["Low"], m["Unknown"])
}
// VulnInfo has a vulnerability information and unsecure packages
type VulnInfo struct {
CveID string
Confidence Confidence

View File

@@ -21,6 +21,67 @@ import (
"testing"
)
func TestCountGroupBySeverity(t *testing.T) {
var tests = []struct {
in VulnInfos
out map[string]int
}{
{
in: VulnInfos{
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
CveContents: CveContents{
NVD: {
Type: NVD,
Cvss2Score: 6.0,
},
RedHat: {
Type: RedHat,
Cvss2Score: 7.0,
},
},
},
"CVE-2017-0003": {
CveID: "CVE-2017-0003",
CveContents: CveContents{
NVD: {
Type: NVD,
Cvss2Score: 2.0,
},
},
},
"CVE-2017-0004": {
CveID: "CVE-2017-0004",
CveContents: CveContents{
NVD: {
Type: NVD,
Cvss2Score: 5.0,
},
},
},
"CVE-2017-0005": {
CveID: "CVE-2017-0005",
},
},
out: map[string]int{
"High": 1,
"Medium": 1,
"Low": 1,
"Unknown": 1,
},
},
}
for _, tt := range tests {
actual := tt.in.CountGroupBySeverity()
for k := range tt.out {
if tt.out[k] != actual[k] {
t.Errorf("\nexpected %s: %d\n actual %d\n",
k, tt.out[k], actual[k])
}
}
}
}
func TestToSortedSlice(t *testing.T) {
var tests = []struct {
in VulnInfos
@@ -33,11 +94,11 @@ func TestToSortedSlice(t *testing.T) {
CveContents: CveContents{
NVD: {
Type: NVD,
Cvss3Score: 6.0,
Cvss2Score: 6.0,
},
RedHat: {
Type: RedHat,
Cvss2Score: 7.0,
Cvss3Score: 7.0,
},
},
},
@@ -46,11 +107,11 @@ func TestToSortedSlice(t *testing.T) {
CveContents: CveContents{
NVD: {
Type: NVD,
Cvss3Score: 7.0,
Cvss2Score: 7.0,
},
RedHat: {
Type: RedHat,
Cvss2Score: 8.0,
Cvss3Score: 8.0,
},
},
},
@@ -61,11 +122,11 @@ func TestToSortedSlice(t *testing.T) {
CveContents: CveContents{
NVD: {
Type: NVD,
Cvss3Score: 7.0,
Cvss2Score: 7.0,
},
RedHat: {
Type: RedHat,
Cvss2Score: 8.0,
Cvss3Score: 8.0,
},
},
},
@@ -74,11 +135,11 @@ func TestToSortedSlice(t *testing.T) {
CveContents: CveContents{
NVD: {
Type: NVD,
Cvss3Score: 6.0,
Cvss2Score: 6.0,
},
RedHat: {
Type: RedHat,
Cvss2Score: 7.0,
Cvss3Score: 7.0,
},
},
},
@@ -92,11 +153,11 @@ func TestToSortedSlice(t *testing.T) {
CveContents: CveContents{
NVD: {
Type: NVD,
Cvss3Score: 6.0,
Cvss2Score: 6.0,
},
RedHat: {
Type: RedHat,
Cvss2Score: 7.0,
Cvss3Score: 7.0,
},
},
},
@@ -125,11 +186,11 @@ func TestToSortedSlice(t *testing.T) {
CveContents: CveContents{
NVD: {
Type: NVD,
Cvss3Score: 6.0,
Cvss2Score: 6.0,
},
RedHat: {
Type: RedHat,
Cvss2Score: 7.0,
Cvss3Score: 7.0,
},
},
},

View File

@@ -35,12 +35,18 @@ type EMailWriter struct{}
func (w EMailWriter) Write(rs ...models.ScanResult) (err error) {
conf := config.Conf
var message string
var totalResult models.ScanResult
sender := NewEMailSender()
m := map[string]int{}
for _, r := range rs {
if conf.FormatOneEMail {
message += formatFullPlainText(r) + "\r\n\r\n"
mm := r.ScannedCves.CountGroupBySeverity()
keys := []string{"High", "Medium", "Low", "Unknown"}
for _, k := range keys {
m[k] += mm[k]
}
} else {
var subject string
if len(r.Errors) != 0 {
@@ -50,7 +56,7 @@ func (w EMailWriter) Write(rs ...models.ScanResult) (err error) {
subject = fmt.Sprintf("%s%s %s",
conf.EMail.SubjectPrefix,
r.ServerInfo(),
r.CveSummary())
r.ScannedCves.FormatCveSummary())
}
message = formatFullPlainText(r)
if err := sender.Send(subject, message); err != nil {
@@ -59,6 +65,15 @@ func (w EMailWriter) Write(rs ...models.ScanResult) (err error) {
}
}
summary := ""
if config.Conf.IgnoreUnscoredCves {
summary = fmt.Sprintf("Total: %d (High:%d Medium:%d Low:%d)",
m["High"]+m["Medium"]+m["Low"], m["High"], m["Medium"], m["Low"])
}
summary = fmt.Sprintf("Total: %d (High:%d Medium:%d Low:%d ?:%d)",
m["High"]+m["Medium"]+m["Low"]+m["Unknown"],
m["High"], m["Medium"], m["Low"], m["Unknown"])
if conf.FormatOneEMail {
message = fmt.Sprintf(
`
@@ -71,9 +86,7 @@ One Line Summary
formatOneLineSummary(rs...), message)
subject := fmt.Sprintf("%s %s",
conf.EMail.SubjectPrefix,
totalResult.CveSummary(),
)
conf.EMail.SubjectPrefix, summary)
return sender.Send(subject, message)
}
return nil

View File

@@ -159,7 +159,7 @@ func msgText(r models.ScanResult) string {
return fmt.Sprintf("%s\n%s\n>%s",
notifyUsers,
serverInfo,
r.CveSummary())
r.ScannedCves.FormatCveSummary())
}
func toSlackAttachments(scanResult models.ScanResult) (attaches []*attachment) {

View File

@@ -72,7 +72,7 @@ func formatOneLineSummary(rs ...models.ScanResult) string {
if len(r.Errors) == 0 {
cols = []interface{}{
r.FormatServerName(),
r.CveSummary(),
r.ScannedCves.FormatCveSummary(),
r.Packages.FormatUpdatablePacksSummary(),
}
} else {