diff --git a/client/client_test.go b/client/client_test.go index c9c1eeb7..c6f2da46 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -19,13 +19,13 @@ import ( var testVuln1 string = `[ {"ID":"ID1","Package":{"Name":"golang.org/example/one","Ecosystem":"go"}, "Summary":"", - "Severity":2,"Affects":{"Ranges":[{"Type":"SEMVER","Introduced":"","Fixed":"v2.2.0"}]}, + "Severity":"High","Affects":{"Ranges":[{"Type":"SEMVER","Introduced":"","Fixed":"v2.2.0"}]}, "ecosystem_specific":{"Symbols":["some_symbol_1"] }}]` var testVuln2 string = `[ {"ID":"ID2","Package":{"Name":"golang.org/example/two","Ecosystem":"go"}, "Summary":"", - "Severity":2,"Affects":{"Ranges":[{"Type":"SEMVER","Introduced":"","Fixed":"v2.1.0"}]}, + "Severity":"High","Affects":{"Ranges":[{"Type":"SEMVER","Introduced":"","Fixed":"v2.1.0"}]}, "ecosystem_specific":{"Symbols":["some_symbol_2"] }}]` diff --git a/osv/json.go b/osv/json.go index 1ee0867f..d128838b 100644 --- a/osv/json.go +++ b/osv/json.go @@ -122,6 +122,7 @@ type Entry struct { ID string `json:"id"` Published time.Time `json:"published"` Modified time.Time `json:"modified"` + Severity string `json:"severity,omitempty"` Withdrawn *time.Time `json:"withdrawn,omitempty"` Aliases []string `json:"aliases,omitempty"` Package Package `json:"package"` @@ -144,6 +145,7 @@ func Generate(id string, url string, r report.Report) []Entry { ID: id, Published: r.Published, Modified: lastModified, + Severity: report.CvssScoreToSeverity(r.CVEMetadata.CVSSMeta), Withdrawn: r.Withdrawn, Package: Package{ Name: importPath, diff --git a/osv/json_test.go b/osv/json_test.go index 39bfa5de..7c5ce2b9 100644 --- a/osv/json_test.go +++ b/osv/json_test.go @@ -43,6 +43,7 @@ func TestGenerate(t *testing.T) { Commit: "commit", Context: []string{"issue-a", "issue-b"}, }, + CVEMetadata: &report.CVEMeta{ID: "CVE-2020-1234"}, } want := []Entry{ diff --git a/report/report.go b/report/report.go index a400a005..ee1094bb 100644 --- a/report/report.go +++ b/report/report.go @@ -28,6 +28,12 @@ type CVEMeta struct { ID string `yaml:",omitempty"` CWE string `yaml:",omitempty"` Description string `yaml:",omitempty"` + CVSSMeta *CVSS `yaml:",omitempty"` +} +type CVSS struct { + Version string `yaml:",omitempty"` + Score float32 `yaml:",omitempty"` + Vector string `yaml:",omitempty"` } type Report struct { diff --git a/report/utils.go b/report/utils.go new file mode 100644 index 00000000..23a3abf1 --- /dev/null +++ b/report/utils.go @@ -0,0 +1,47 @@ +package report + +//CvssScoreToSeverity calculate severity by cvss version and score +//accept cvss version and score , return severity +func CvssScoreToSeverity(cvss *CVSS) string { + if cvss == nil { + return "" + } + switch cvss.Version { + case "v2": + return cvssV2SeverityByScore(cvss.Score) + case "v3": + return cvssV3SeverityByScore(cvss.Score) + default: + return "" + } +} + +func cvssV3SeverityByScore(score float32) string { + switch { + case score == 0.0: + return "None" + case score >= 0.1 && score <= 3.9: + return "Low" + case score >= 4.0 && score <= 6.9: + return "Medium" + case score >= 7.0 && score <= 8.9: + return "High" + case score >= 9.0 && score <= 10.0: + return "Critical" + default: + return "" + } +} + +func cvssV2SeverityByScore(score float32) string { + switch { + case score >= 0.0 && score <= 3.9: + return "Low" + case score >= 4.0 && score <= 6.9: + return "Medium" + case score >= 7.0 && score <= 10.0: + return "High" + default: + return "" + } +} diff --git a/report/utils_test.go b/report/utils_test.go new file mode 100644 index 00000000..efb4e1cc --- /dev/null +++ b/report/utils_test.go @@ -0,0 +1,31 @@ +package report + +import "testing" + +func TestReverseString1(t *testing.T) { + tests := []struct { + name string + version string + baseScore float32 + want string + }{ + {name: "Low v2", version: "v2", baseScore: 1.0, want: "Low"}, + {name: "Medium v2", version: "v2", baseScore: 4.0, want: "Medium"}, + {name: "High v2", version: "v2", baseScore: 7.0, want: "High"}, + {name: "Non Existing score v2", version: "v2", baseScore: 12.0, want: ""}, + {name: "None v3", version: "v3", baseScore: 0.0, want: "None"}, + {name: "low v3", version: "v3", baseScore: 1.0, want: "Low"}, + {name: "Medium v3", version: "v3", baseScore: 4.0, want: "Medium"}, + {name: "High v3", version: "v3", baseScore: 7.0, want: "High"}, + {name: "Critical v3", version: "v3", baseScore: 9.0, want: "Critical"}, + {name: "Non Existing score v3", version: "v3", baseScore: 12.0, want: ""}, + {name: "Non existing version", version: "v1", baseScore: 9.0, want: ""}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := CvssScoreToSeverity(&CVSS{Version: tt.version, Score: tt.baseScore}); got != tt.want { + t.Errorf("CvssScoreToSeverity() = %v, want %v", got, tt.want) + } + }) + } +}