Sort results order by CVSS score, CVE-ID
This commit is contained in:
		@@ -185,7 +185,7 @@ func severityToScoreForUbuntu(severity string) float64 {
 | 
			
		||||
 | 
			
		||||
// Convert Severity to Score for RedHat, Oracle OVAL
 | 
			
		||||
// https://access.redhat.com/security/updates/classification
 | 
			
		||||
// Since I don't know the definition, Use the definition of CVSSv3
 | 
			
		||||
// Use the definition of CVSSv3 because the exact definition of severity and score is not described.
 | 
			
		||||
func severityToScoreForRedHat(severity string) float64 {
 | 
			
		||||
	switch strings.ToUpper(severity) {
 | 
			
		||||
	case "CRITICAL":
 | 
			
		||||
@@ -231,7 +231,6 @@ func cvss3ScoreToSeverity(score float64) string {
 | 
			
		||||
 | 
			
		||||
// Cvss3Scores returns CVSS V3 Score
 | 
			
		||||
func (v CveContents) Cvss3Scores() (values []CveContentCvss3) {
 | 
			
		||||
	//TODO Severity Ubuntu, Debian...
 | 
			
		||||
	order := []CveContentType{RedHat}
 | 
			
		||||
	for _, ctype := range order {
 | 
			
		||||
		if cont, found := v[ctype]; found && 0 < cont.Cvss3Score {
 | 
			
		||||
@@ -255,7 +254,6 @@ func (v CveContents) Cvss3Scores() (values []CveContentCvss3) {
 | 
			
		||||
 | 
			
		||||
// MaxCvss3Score returns Max CVSS V3 Score
 | 
			
		||||
func (v CveContents) MaxCvss3Score() CveContentCvss3 {
 | 
			
		||||
	//TODO Severity Ubuntu, Debian...
 | 
			
		||||
	order := []CveContentType{RedHat}
 | 
			
		||||
	max := 0.0
 | 
			
		||||
	value := CveContentCvss3{
 | 
			
		||||
@@ -283,6 +281,18 @@ func (v CveContents) MaxCvss3Score() CveContentCvss3 {
 | 
			
		||||
	return value
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MaxCvssScore returns max CVSS Score
 | 
			
		||||
// If there is no CVSS Score, return Severity as a numerical value.
 | 
			
		||||
func (v CveContents) MaxCvssScore() float64 {
 | 
			
		||||
	v3Max := v.MaxCvss3Score()
 | 
			
		||||
	v2Max := v.MaxCvss2Score()
 | 
			
		||||
	max := v3Max.Value.Score
 | 
			
		||||
	if max < v2Max.Value.Score {
 | 
			
		||||
		max = v2Max.Value.Score
 | 
			
		||||
	}
 | 
			
		||||
	return max
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FormatMaxCvssScore returns Max CVSS Score
 | 
			
		||||
func (v CveContents) FormatMaxCvssScore() string {
 | 
			
		||||
	v2Max := v.MaxCvss2Score()
 | 
			
		||||
 
 | 
			
		||||
@@ -21,18 +21,6 @@ import (
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var m = CveContent{
 | 
			
		||||
	Type:        RedHat,
 | 
			
		||||
	CveID:       "CVE-2017-0001",
 | 
			
		||||
	Title:       "title",
 | 
			
		||||
	Summary:     "summary",
 | 
			
		||||
	Severity:    "High",
 | 
			
		||||
	Cvss2Score:  8.0,
 | 
			
		||||
	Cvss2Vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
 | 
			
		||||
	Cvss3Score:  9.0,
 | 
			
		||||
	Cvss3Vector: "AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestExcept(t *testing.T) {
 | 
			
		||||
	var tests = []struct {
 | 
			
		||||
		in  CveContents
 | 
			
		||||
@@ -284,6 +272,69 @@ func TestMaxCvss3Scores(t *testing.T) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestMaxCvssScores(t *testing.T) {
 | 
			
		||||
	var tests = []struct {
 | 
			
		||||
		in  CveContents
 | 
			
		||||
		out float64
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			in: CveContents{
 | 
			
		||||
				NVD: {
 | 
			
		||||
					Type:       NVD,
 | 
			
		||||
					Cvss3Score: 7.0,
 | 
			
		||||
				},
 | 
			
		||||
				RedHat: {
 | 
			
		||||
					Type:       RedHat,
 | 
			
		||||
					Cvss2Score: 8.0,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			out: 8.0,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			in: CveContents{
 | 
			
		||||
				RedHat: {
 | 
			
		||||
					Type:       RedHat,
 | 
			
		||||
					Cvss3Score: 8.0,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			out: 8.0,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			in: CveContents{
 | 
			
		||||
				Ubuntu: {
 | 
			
		||||
					Type:     Ubuntu,
 | 
			
		||||
					Severity: "HIGH",
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			out: 10.0,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			in: CveContents{
 | 
			
		||||
				Ubuntu: {
 | 
			
		||||
					Type:     Ubuntu,
 | 
			
		||||
					Severity: "MEDIUM",
 | 
			
		||||
				},
 | 
			
		||||
				NVD: {
 | 
			
		||||
					Type:       NVD,
 | 
			
		||||
					Cvss2Score: 7.0,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			out: 7.0,
 | 
			
		||||
		},
 | 
			
		||||
		// Empty
 | 
			
		||||
		{
 | 
			
		||||
			in:  CveContents{},
 | 
			
		||||
			out: 0,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for i, tt := range tests {
 | 
			
		||||
		actual := tt.in.MaxCvssScore()
 | 
			
		||||
		if !reflect.DeepEqual(tt.out, actual) {
 | 
			
		||||
			t.Errorf("\n[%d] expected: %v\n  actual: %v\n", i, tt.out, actual)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestFormatMaxCvssScore(t *testing.T) {
 | 
			
		||||
	var tests = []struct {
 | 
			
		||||
		in  CveContents
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,7 @@ package models
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -36,7 +37,7 @@ func (v VulnInfos) Find(f func(VulnInfo) bool) VulnInfos {
 | 
			
		||||
	return filtered
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FindScoredVulns return socred vulnerabilities
 | 
			
		||||
// FindScoredVulns return scored vulnerabilities
 | 
			
		||||
func (v VulnInfos) FindScoredVulns() VulnInfos {
 | 
			
		||||
	return v.Find(func(vv VulnInfo) bool {
 | 
			
		||||
		if 0 < vv.CveContents.MaxCvss2Score().Value.Score ||
 | 
			
		||||
@@ -47,6 +48,22 @@ func (v VulnInfos) FindScoredVulns() VulnInfos {
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ToSortedSlice returns slice of VulnInfos that is sorted by CVE-ID
 | 
			
		||||
func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {
 | 
			
		||||
	for k := range v {
 | 
			
		||||
		sorted = append(sorted, v[k])
 | 
			
		||||
	}
 | 
			
		||||
	sort.Slice(sorted, func(i, j int) bool {
 | 
			
		||||
		maxI := sorted[i].CveContents.MaxCvssScore()
 | 
			
		||||
		maxJ := sorted[j].CveContents.MaxCvssScore()
 | 
			
		||||
		if maxI != maxJ {
 | 
			
		||||
			return maxJ < maxI
 | 
			
		||||
		}
 | 
			
		||||
		return sorted[i].CveID < sorted[j].CveID
 | 
			
		||||
	})
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// VulnInfo holds a vulnerability information and unsecure packages
 | 
			
		||||
type VulnInfo struct {
 | 
			
		||||
	CveID            string
 | 
			
		||||
 
 | 
			
		||||
@@ -15,3 +15,174 @@ You should have received a copy of the GNU General Public License
 | 
			
		||||
along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
package models
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestToSortedSlice(t *testing.T) {
 | 
			
		||||
	var tests = []struct {
 | 
			
		||||
		in  VulnInfos
 | 
			
		||||
		out []VulnInfo
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			in: VulnInfos{
 | 
			
		||||
				"CVE-2017-0002": {
 | 
			
		||||
					CveID: "CVE-2017-0002",
 | 
			
		||||
					CveContents: CveContents{
 | 
			
		||||
						NVD: {
 | 
			
		||||
							Type:       NVD,
 | 
			
		||||
							Cvss3Score: 6.0,
 | 
			
		||||
						},
 | 
			
		||||
						RedHat: {
 | 
			
		||||
							Type:       RedHat,
 | 
			
		||||
							Cvss2Score: 7.0,
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
				"CVE-2017-0001": {
 | 
			
		||||
					CveID: "CVE-2017-0001",
 | 
			
		||||
					CveContents: CveContents{
 | 
			
		||||
						NVD: {
 | 
			
		||||
							Type:       NVD,
 | 
			
		||||
							Cvss3Score: 7.0,
 | 
			
		||||
						},
 | 
			
		||||
						RedHat: {
 | 
			
		||||
							Type:       RedHat,
 | 
			
		||||
							Cvss2Score: 8.0,
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			out: []VulnInfo{
 | 
			
		||||
				{
 | 
			
		||||
					CveID: "CVE-2017-0001",
 | 
			
		||||
					CveContents: CveContents{
 | 
			
		||||
						NVD: {
 | 
			
		||||
							Type:       NVD,
 | 
			
		||||
							Cvss3Score: 7.0,
 | 
			
		||||
						},
 | 
			
		||||
						RedHat: {
 | 
			
		||||
							Type:       RedHat,
 | 
			
		||||
							Cvss2Score: 8.0,
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					CveID: "CVE-2017-0002",
 | 
			
		||||
					CveContents: CveContents{
 | 
			
		||||
						NVD: {
 | 
			
		||||
							Type:       NVD,
 | 
			
		||||
							Cvss3Score: 6.0,
 | 
			
		||||
						},
 | 
			
		||||
						RedHat: {
 | 
			
		||||
							Type:       RedHat,
 | 
			
		||||
							Cvss2Score: 7.0,
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		// When max scores are the same, sort by CVE-ID
 | 
			
		||||
		{
 | 
			
		||||
			in: VulnInfos{
 | 
			
		||||
				"CVE-2017-0002": {
 | 
			
		||||
					CveID: "CVE-2017-0002",
 | 
			
		||||
					CveContents: CveContents{
 | 
			
		||||
						NVD: {
 | 
			
		||||
							Type:       NVD,
 | 
			
		||||
							Cvss3Score: 6.0,
 | 
			
		||||
						},
 | 
			
		||||
						RedHat: {
 | 
			
		||||
							Type:       RedHat,
 | 
			
		||||
							Cvss2Score: 7.0,
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
				"CVE-2017-0001": {
 | 
			
		||||
					CveID: "CVE-2017-0001",
 | 
			
		||||
					CveContents: CveContents{
 | 
			
		||||
						RedHat: {
 | 
			
		||||
							Type:       RedHat,
 | 
			
		||||
							Cvss2Score: 7.0,
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			out: []VulnInfo{
 | 
			
		||||
				{
 | 
			
		||||
					CveID: "CVE-2017-0001",
 | 
			
		||||
					CveContents: CveContents{
 | 
			
		||||
						RedHat: {
 | 
			
		||||
							Type:       RedHat,
 | 
			
		||||
							Cvss2Score: 7.0,
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					CveID: "CVE-2017-0002",
 | 
			
		||||
					CveContents: CveContents{
 | 
			
		||||
						NVD: {
 | 
			
		||||
							Type:       NVD,
 | 
			
		||||
							Cvss3Score: 6.0,
 | 
			
		||||
						},
 | 
			
		||||
						RedHat: {
 | 
			
		||||
							Type:       RedHat,
 | 
			
		||||
							Cvss2Score: 7.0,
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		// When there are no cvss scores, sort by severity
 | 
			
		||||
		{
 | 
			
		||||
			in: VulnInfos{
 | 
			
		||||
				"CVE-2017-0002": {
 | 
			
		||||
					CveID: "CVE-2017-0002",
 | 
			
		||||
					CveContents: CveContents{
 | 
			
		||||
						Ubuntu: {
 | 
			
		||||
							Type:     Ubuntu,
 | 
			
		||||
							Severity: "High",
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
				"CVE-2017-0001": {
 | 
			
		||||
					CveID: "CVE-2017-0001",
 | 
			
		||||
					CveContents: CveContents{
 | 
			
		||||
						Ubuntu: {
 | 
			
		||||
							Type:     Ubuntu,
 | 
			
		||||
							Severity: "Low",
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			out: []VulnInfo{
 | 
			
		||||
				{
 | 
			
		||||
					CveID: "CVE-2017-0002",
 | 
			
		||||
					CveContents: CveContents{
 | 
			
		||||
						Ubuntu: {
 | 
			
		||||
							Type:     Ubuntu,
 | 
			
		||||
							Severity: "High",
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					CveID: "CVE-2017-0001",
 | 
			
		||||
					CveContents: CveContents{
 | 
			
		||||
						Ubuntu: {
 | 
			
		||||
							Type:     Ubuntu,
 | 
			
		||||
							Severity: "Low",
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		actual := tt.in.ToSortedSlice()
 | 
			
		||||
		if !reflect.DeepEqual(tt.out, actual) {
 | 
			
		||||
			t.Errorf("\nexpected: %v\n  actual: %v\n", tt.out, actual)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user