package cvss import ( "reflect" "testing" ) func TestNewV2Vector(t *testing.T) { passTests := []struct { val string exp []string } { { val: "AV:L/AC:L/Au:N/C:N/I:N/A:P", exp: []string { "AV:L", "AC:L", "Au:N", "C:N", "I:N", "A:P" }, }, } for _, test := range(passTests) { t.Run(test.val, func(t *testing.T) { // parse vector vec, err := newV2Vector(test.val) if err != nil { t.Error(err) return } // check version if vec.Version() != V20 { t.Errorf("got %s, exp %s", vec.Version(), V20) return } // check metric length if len(vec.Metrics()) != len(test.exp) { t.Errorf("got %d, exp %d", len(vec.Metrics()), len(test.exp)) return } // check metrics for i, m := range(vec.Metrics()) { got := m.String() if got != test.exp[i] { t.Errorf("got %s, exp %s", got, test.exp[i]) } } }) } failTests := []struct { val string exp string } { { val: "AV:L/junk/Au:N/C:N/I:N/A:P", exp: "invalid CVSS 2.0 metric: junk", }, } for _, test := range(failTests) { t.Run(test.val, func(t *testing.T) { got, err := newV2Vector(test.val) if err != nil && err.Error() != test.exp { t.Errorf("got \"%s\", exp \"%s\"", err.Error(), test.exp) } else if err == nil { t.Errorf("got \"%s\", exp badMetric", got) } }) } } func TestV2VectorScores(t *testing.T) { // test vectors from section 3.3 passTests := []struct { name string // test name val string // test cvss v2 vector exps []float64 // expected base, temporal, and env scores } {{ name: "CVE-2002-0392/base", // 3.3.1 val: "AV:N/AC:L/Au:N/C:N/I:N/A:C", exps: []float64 { 7.8, 0.0, 0.0 }, }, { name: "CVE-2002-0392/temporal", // 3.3.1 val: "AV:N/AC:L/Au:N/C:N/I:N/A:C/E:F/RL:OF/RC:C", exps: []float64 { 7.8, 6.4, 0.0 }, }, { name: "CVE-2002-0392/all", // 3.3.1 val: "AV:N/AC:L/Au:N/C:N/I:N/A:C/E:F/RL:OF/RC:C/CDP:H/TD:H/CR:M/IR:M/AR:H", exps: []float64 { 7.8, 6.4, 9.2 }, }, { name: "CVE-2003-0818/base", // 3.3.2 val: "AV:N/AC:L/Au:N/C:C/I:C/A:C", exps: []float64 { 10.0, 0.0, 0.0 }, }, { name: "CVE-2003-0818/temporal", // 3.3.2 val: "AV:N/AC:L/Au:N/C:C/I:C/A:C/E:F/RL:OF/RC:C", exps: []float64 { 10.0, 8.3, 0.0 }, }, { name: "CVE-2003-0818/all", // 3.3.2 val: "AV:N/AC:L/Au:N/C:C/I:C/A:C/E:F/RL:OF/RC:C/CDP:H/TD:H/CR:M/IR:M/AR:L", exps: []float64 { 10.0, 8.3, 9.0 }, }, { name: "CVE-2003-0062/base", // 3.3.3 val: "AV:L/AC:H/Au:N/C:C/I:C/A:C", exps: []float64 { 6.2, 0.0, 0.0 }, }, { name: "CVE-2003-0062/temporal", // 3.3.3 val: "AV:L/AC:H/Au:N/C:C/I:C/A:C/E:POC/RL:OF/RC:C", exps: []float64 { 6.2, 4.9, 0.0 }, }, { name: "CVE-2003-0062/all", // 3.3.3 val: "AV:L/AC:H/Au:N/C:C/I:C/A:C/E:POC/RL:OF/RC:C/CDP:H/TD:H/CR:M/IR:M/AR:M", exps: []float64 { 6.2, 4.9, 7.5 }, }, { name: "A:N", // from nvd v2 calc val: "AV:A/AC:M/Au:M/C:P/I:P/A:N", exps: []float64 { 3.4, 0.0, 0.0 }, }, { name: "Au:S", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P", exps: []float64 { 4.9, 0.0, 0.0 }, }, { name: "E:ND", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:ND", exps: []float64 { 4.9, 0.0, 0.0 }, }, { name: "E:U", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:U/RL:ND/RC:ND", exps: []float64 { 4.9, 4.2, 0.0 }, }, { name: "E:H", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:ND/RC:ND", exps: []float64 { 4.9, 4.9, 0.0 }, }, { name: "RL:TF", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:TF/RC:ND", exps: []float64 { 4.9, 4.4, 0.0 }, }, { name: "RL:W", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:W/RC:ND", exps: []float64 { 4.9, 4.7, 0.0 }, }, { name: "RL:U", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:U/RC:ND", exps: []float64 { 4.9, 4.9, 0.0 }, }, { name: "RC:UC", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:U/RC:UC", exps: []float64 { 4.9, 4.4, 0.0 }, }, { name: "RC:UR", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:U/RC:UR", exps: []float64 { 4.9, 4.7, 0.0 }, }, { name: "CDP:ND", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:W/RC:ND/CDP:ND/TD:H/CR:L/IR:L/AR:L", exps: []float64 { 4.9, 4.7, 2.8 }, }, { name: "CDP:N", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:W/RC:ND/CDP:N/TD:H/CR:L/IR:L/AR:L", exps: []float64 { 4.9, 4.7, 2.8 }, }, { name: "CDP:L", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:W/RC:ND/CDP:L/TD:H/CR:L/IR:L/AR:L", exps: []float64 { 4.9, 4.7, 3.5 }, }, { name: "CDP:LM", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:W/RC:ND/CDP:LM/TD:H/CR:L/IR:L/AR:L", exps: []float64 { 4.9, 4.7, 5.0 }, }, { name: "CDP:MH", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:W/RC:ND/CDP:MH/TD:H/CR:L/IR:L/AR:L", exps: []float64 { 4.9, 4.7, 5.7 }, }, { name: "CDP:H", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:W/RC:ND/CDP:H/TD:H/CR:L/IR:L/AR:L", exps: []float64 { 4.9, 4.7, 6.4 }, }, { name: "TD:ND", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:W/RC:ND/CDP:H/TD:ND/CR:L/IR:L/AR:L", exps: []float64 { 4.9, 4.7, 6.4 }, }, { name: "TD:N", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:W/RC:ND/CDP:H/TD:N/CR:L/IR:L/AR:L", exps: []float64 { 4.9, 4.7, 0.0 }, }, { name: "TD:L", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:W/RC:ND/CDP:H/TD:L/CR:L/IR:L/AR:L", exps: []float64 { 4.9, 4.7, 1.6 }, }, { name: "TD:M", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:W/RC:ND/CDP:H/TD:M/CR:L/IR:L/AR:L", exps: []float64 { 4.9, 4.7, 4.8 }, }, { name: "TD:H", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:W/RC:ND/CDP:H/TD:H/CR:L/IR:L/AR:L", exps: []float64 { 4.9, 4.7, 6.4 }, }, { name: "CR:ND", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:W/RC:ND/CDP:H/TD:H/CR:ND/IR:L/AR:L", exps: []float64 { 4.9, 4.7, 6.8 }, }, { name: "CR:L", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:W/RC:ND/CDP:H/TD:H/CR:L/IR:L/AR:L", exps: []float64 { 4.9, 4.7, 6.4 }, }, { name: "CR:M", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:W/RC:ND/CDP:H/TD:H/CR:M/IR:L/AR:L", exps: []float64 { 4.9, 4.7, 6.8 }, }, { name: "CR:H", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:W/RC:ND/CDP:H/TD:H/CR:H/IR:L/AR:L", exps: []float64 { 4.9, 4.7, 7.1 }, }, { name: "IR:ND", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:W/RC:ND/CDP:H/TD:H/CR:L/IR:ND/AR:L", exps: []float64 { 4.9, 4.7, 6.8 }, }, { name: "IR:L", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:W/RC:ND/CDP:H/TD:H/CR:L/IR:L/AR:L", exps: []float64 { 4.9, 4.7, 6.4 }, }, { name: "IR:M", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:W/RC:ND/CDP:H/TD:H/CR:L/IR:M/AR:L", exps: []float64 { 4.9, 4.7, 6.8 }, }, { name: "IR:H", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:W/RC:ND/CDP:H/TD:H/CR:L/IR:H/AR:L", exps: []float64 { 4.9, 4.7, 7.1 }, }, { name: "AR:ND", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:W/RC:ND/CDP:H/TD:H/CR:L/IR:L/AR:ND", exps: []float64 { 4.9, 4.7, 6.8 }, }, { name: "AR:L", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:W/RC:ND/CDP:H/TD:H/CR:L/IR:L/AR:L", exps: []float64 { 4.9, 4.7, 6.4 }, }, { name: "AR:M", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:W/RC:ND/CDP:H/TD:H/CR:L/IR:L/AR:M", exps: []float64 { 4.9, 4.7, 6.8 }, }, { name: "AR:H", // from nvd v2 calc val: "AV:A/AC:M/Au:S/C:P/I:P/A:P/E:H/RL:W/RC:ND/CDP:H/TD:H/CR:L/IR:L/AR:H", exps: []float64 { 4.9, 4.7, 7.1 }, }} // TODO: add additional test vectors using v2 calc for _, test := range(passTests) { t.Run(test.name, func(t *testing.T) { // build expected result exp, err := NewScores(test.exps[0], test.exps[1], test.exps[2]) if err != nil { t.Error(err) return } // create vector, check for error vec, err := newV2Vector(test.val) if err != nil { t.Error(err) return } // get scores got, err := vec.Scores() if err != nil { t.Error(err) return } // compare to expected scores if !reflect.DeepEqual(got, exp) { t.Errorf("got %v, exp %v", got, exp) return } }) } }