aboutsummaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorPaul Duncan <pabs@pablotron.org>2022-02-01 23:53:56 -0500
committerPaul Duncan <pabs@pablotron.org>2022-02-01 23:53:56 -0500
commitce92ab3114dc8f5d9654dbfeecefb44049ea1a0c (patch)
tree3bc889b16aff9f8af9eed2572bebc8e70cb2b0d0 /internal
parent639ebc03c5dd60e104f255d0b0f2fb45ec319799 (diff)
downloadcvez-ce92ab3114dc8f5d9654dbfeecefb44049ea1a0c.tar.bz2
cvez-ce92ab3114dc8f5d9654dbfeecefb44049ea1a0c.zip
internal/cvss: add isVectorString tests
Diffstat (limited to 'internal')
-rw-r--r--internal/cvss/cvss.go26
-rw-r--r--internal/cvss/v2vector.go49
-rw-r--r--internal/cvss/v2vector_test.go100
-rw-r--r--internal/cvss/v30vector.go58
-rw-r--r--internal/cvss/v30vector_test.go98
-rw-r--r--internal/cvss/v31vector.go53
-rw-r--r--internal/cvss/v31vector_test.go588
-rw-r--r--internal/cvss/vector.go36
-rw-r--r--internal/cvss/vector_test.go (renamed from internal/cvss/cvss_test.go)0
9 files changed, 857 insertions, 151 deletions
diff --git a/internal/cvss/cvss.go b/internal/cvss/cvss.go
index 9839e84..2bae0d7 100644
--- a/internal/cvss/cvss.go
+++ b/internal/cvss/cvss.go
@@ -21,29 +21,3 @@ type Metric interface {
// Return string representation of metric.
String() string
}
-
-// CVSS metric vector.
-type Vector interface {
- // Get CVSS version.
- Version() Version
-
- // Get CVSS vector string.
- String() string
-
- // Return metrics in this vector.
- Metrics() []Metric
-}
-
-// Create new CVSS vector from vector string.
-func NewVector(s string) (Vector, error) {
- if isV31VectorString(s) {
- // create CVSS v3.1 vector.
- return newV31Vector(s)
- } else if isV30VectorString(s) {
- // create CVSS v3.0 vector.
- return newV30Vector(s)
- } else {
- // create CVSS V2 vector
- return newV2Vector(s)
- }
-}
diff --git a/internal/cvss/v2vector.go b/internal/cvss/v2vector.go
index 909bca6..b1fca1f 100644
--- a/internal/cvss/v2vector.go
+++ b/internal/cvss/v2vector.go
@@ -1,6 +1,8 @@
package cvss
import (
+ // "encoding/json"
+ "regexp"
"strings"
)
@@ -40,7 +42,7 @@ func (v v2Vector) Metrics() []Metric {
}
// Create CVSS 2.0 vector from string.
-func newV2Vector(s string) (Vector, error) {
+func newV2Vector(s string) (v2Vector, error) {
strs := strings.Split(s, "/")
r := make([]v2Metric, len(strs))
@@ -59,3 +61,48 @@ func newV2Vector(s string) (Vector, error) {
// build and return vector
return v2Vector(r), nil
}
+
+// // Unmarshal CVSS 2.0 vector from JSON string.
+// func (me *v2Vector) UnmarshalJSON(b []byte) error {
+// // decode string, check for error
+// var s string
+// if err := json.Unmarshal(b, &s); err != nil {
+// return err
+// }
+//
+// // parse vector, check for error
+// r, err := newV2Vector(s)
+// if err != nil {
+// // return error
+// return err
+// }
+//
+// // save result, return success
+// *me = r
+// return nil
+// }
+
+var v2MetricRe = "(?:" + strings.Join([]string {
+ "(?:AV:[NAL])",
+ "(?:AC:[LMH])",
+ "(?:Au:[MSN])",
+ "(?:C:[NPC])",
+ "(?:I:[NPC])",
+ "(?:A:[NPC])",
+ "(?:E:(?:ND|U|POC|F|H))",
+ "(?:RL:(?:OF|TF|W|U|ND))",
+ "(?:RC:(?:UC|UR|C|ND))",
+ "(?:CDP:(?:N|L|LM|MH|H|ND))",
+ "(?:TD:(?:N|L|M|H|ND))",
+ "(?:CR:(?:L|M|H|ND))",
+ "(?:IR:(?:L|M|H|ND))",
+}, "|") + ")"
+
+var v2VecRe = regexp.MustCompile(
+ "\\A" + v2MetricRe + "(?:/" + v2MetricRe + ")*\\z",
+)
+
+// Is the given string a CVSS v2 vector string?
+func isV2VectorString(s string) bool {
+ return len(s) > 0 && v2VecRe.MatchString(s)
+}
diff --git a/internal/cvss/v2vector_test.go b/internal/cvss/v2vector_test.go
index a943957..f297ba6 100644
--- a/internal/cvss/v2vector_test.go
+++ b/internal/cvss/v2vector_test.go
@@ -4,48 +4,66 @@ import (
"testing"
)
-// Test cvss v2
-func TestCvssV2Parser(t *testing.T) {
- // test v2 vector
- test := "AV:L/AC:L/Au:N/C:N/I:N/A:P"
- expMetrics := []string { "AV:L", "AC:L", "Au:N", "C:N", "I:N", "A:P" }
-
- t.Run("TestV2Parser", func(t *testing.T) {
- // parse vector
- vec, err := NewVector(test)
- if err != nil {
- t.Error(err)
- return
- }
-
- // check version
- if vec.Version() != V20 {
- t.Errorf("got %s, exp %s", vec.Version(), V20)
- return
- }
-
- for i, m := range(vec.Metrics()) {
- got := m.String()
- if got != expMetrics[i] {
- t.Errorf("got %s, exp %s", got, expMetrics[i])
+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
}
- }
- })
-}
-// Test cvss v2
-func TestInvalidV2Vector(t *testing.T) {
- // test invalid vector
- test := "AV:L/junk/Au:N/C:N/I:N/A:P"
- exp := "invalid CVSS 2.0 metric: junk"
-
- // parse vector
- got, err := NewVector(test)
- if err != nil && err.Error() != exp {
- t.Errorf("got \"%s\", exp \"%s\"", err.Error(), err)
- return
- } else if err == nil {
- t.Errorf("got \"%s\", exp badMetric", got)
- 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)
+ }
+ })
}
}
diff --git a/internal/cvss/v30vector.go b/internal/cvss/v30vector.go
index 0d835a0..5ef1ae8 100644
--- a/internal/cvss/v30vector.go
+++ b/internal/cvss/v30vector.go
@@ -1,6 +1,8 @@
package cvss
import (
+ // "encoding/json"
+ "regexp"
"strings"
)
@@ -43,9 +45,9 @@ func (v v30Vector) Metrics() []Metric {
}
// Create CVSS 3.0 vector from string.
-func newV30Vector(s string) (Vector, error) {
+func newV30Vector(s string) (v30Vector, error) {
// strip version prefix, split into metric strings
- strs := strings.Split(s[len(v31Prefix):], "/")
+ strs := strings.Split(s[len(v30Prefix):], "/")
r := make([]v3Metric, len(strs))
// build results
@@ -63,7 +65,55 @@ func newV30Vector(s string) (Vector, error) {
return v30Vector(r), nil
}
-// Is the given string a CVSSv3.0 vector string?
+// // Unmarshal CVSS 3.0 vector from JSON string.
+// func (me *v30Vector) UnmarshalJSON(b []byte) error {
+// // decode string, check for error
+// var s string
+// if err := json.Unmarshal(b, &s); err != nil {
+// return err
+// }
+//
+// // parse vector, check for error
+// r, err := newV30Vector(s)
+// if err != nil {
+// return err
+// }
+//
+// // save result, return success
+// *me = r
+// return nil
+// }
+
+var v30VecRe = regexp.MustCompile(
+ "\\ACVSS:3\\.0(?:/(?:" + strings.Join([]string {
+ "(?:AV:[NALP])",
+ "(?:AC:[LH])",
+ "(?:PR:[NLH])",
+ "(?:UI:[NR])",
+ "(?:S:[UC])",
+ "(?:C:[HLN])",
+ "(?:I:[HLN])",
+ "(?:A:[HLN])",
+ "(?:E:[XHFPU])",
+ "(?:RL:[XUWTO])",
+ "(?:RC:[XCRU])",
+ "(?:CR:[XHML])",
+ "(?:IR:[XHML])",
+ "(?:AR:[XHML])",
+ "(?:MAV:[XNALP])",
+ "(?:MAC:[XLH])",
+ "(?:MPR:[XNLH])",
+ "(?:MUI:[XNR])",
+ "(?:MS:[XUC])",
+ "(?:MC:[XNLH])",
+ "(?:MI:[XNLH])",
+ "(?:MA:[XNLH])",
+ }, "|") + "))+\\z",
+)
+
+// Is the given string a CVSSv3.1 vector string?
func isV30VectorString(s string) bool {
- return (len(s) > len(v30Prefix)) && (s[:len(v30Prefix)] == v30Prefix);
+ return (len(s) > len(v30Prefix)) &&
+ (s[:len(v30Prefix)] == v30Prefix) &&
+ v30VecRe.MatchString(s)
}
diff --git a/internal/cvss/v30vector_test.go b/internal/cvss/v30vector_test.go
index fae3436..1d44d35 100644
--- a/internal/cvss/v30vector_test.go
+++ b/internal/cvss/v30vector_test.go
@@ -4,46 +4,66 @@ import (
"testing"
)
-func TestV30Vector(t *testing.T) {
- // test v3 vector
- test := "CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:N"
- expMetrics := []string { "AV:L", "AC:H", "PR:L", "UI:N", "S:U", "C:H", "I:N", "A:N" }
-
- t.Run("TestV30Vector", func(t *testing.T) {
- // parse vector
- vec, err := NewVector(test)
- if err != nil {
- t.Error(err)
- return
- }
-
- // check version
- if vec.Version() != V30 {
- t.Errorf("got %s, exp %s", vec.Version(), V30)
- return
- }
-
- for i, m := range(vec.Metrics()) {
- got := m.String()
- if got != expMetrics[i] {
- t.Errorf("got %s, exp %s", got, expMetrics[i])
+func TestNewV30Vector(t *testing.T) {
+ passTests := []struct {
+ val string
+ exp []string
+ } {
+ {
+ val: "CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:N",
+ exp: []string { "AV:L", "AC:H", "PR:L", "UI:N", "S:U", "C:H", "I:N", "A:N" },
+ },
+ }
+
+ for _, test := range(passTests) {
+ t.Run(test.val, func(t *testing.T) {
+ // parse vector
+ vec, err := newV30Vector(test.val)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ // check version
+ if vec.Version() != V30 {
+ t.Errorf("got %s, exp %s", vec.Version(), V30)
+ return
+ }
+
+ // check metric length
+ if len(vec.Metrics()) != len(test.exp) {
+ t.Errorf("got %d, exp %d", len(vec.Metrics()), len(test.exp))
+ return
}
- }
- })
-}
-func TestInvalidV30Vector(t *testing.T) {
- // test invalid vector
- test := "CVSS:3.0/AV:L/junk/PR:L/UI:N/S:U/C:H/I:N/A:N"
- exp := "invalid CVSS 3.0 metric: junk"
-
- // parse vector
- got, err := NewVector(test)
- if err != nil && err.Error() != exp {
- t.Errorf("got \"%s\", exp \"%s\"", err.Error(), err)
- return
- } else if err == nil {
- t.Errorf("got \"%s\", exp badMetric", got)
- 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: "CVSS:3.0/AV:L/junk/PR:L/UI:N/S:U/C:H/I:N/A:N",
+ exp: "invalid CVSS 3.0 metric: junk",
+ },
+ }
+
+ for _, test := range(failTests) {
+ t.Run(test.val, func(t *testing.T) {
+ got, err := newV30Vector(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)
+ }
+ })
}
}
diff --git a/internal/cvss/v31vector.go b/internal/cvss/v31vector.go
index 6e2acb6..f286ea0 100644
--- a/internal/cvss/v31vector.go
+++ b/internal/cvss/v31vector.go
@@ -1,6 +1,7 @@
package cvss
import (
+ "regexp"
"strings"
)
@@ -43,7 +44,7 @@ func (v v31Vector) Metrics() []Metric {
}
// create CVSS 3.1 vector from string.
-func newV31Vector(s string) (Vector, error) {
+func newV31Vector(s string) (v31Vector, error) {
// strip version prefix, split into metric strings
strs := strings.Split(s[len(v31Prefix):], "/")
r := make([]v3Metric, len(strs))
@@ -64,7 +65,55 @@ func newV31Vector(s string) (Vector, error) {
return v31Vector(r), nil
}
+// // Unmarshal CVSS 3.1 vector from JSON string.
+// func (me *v31Vector) UnmarshalJSON(b []byte) error {
+// // decode string, check for error
+// var s string
+// if err := json.Unmarshal(b, &s); err != nil {
+// return err
+// }
+//
+// // parse vector, check for error
+// r, err := newV31Vector(s)
+// if err != nil {
+// return err
+// }
+//
+// // save result, return success
+// *me = r
+// return nil
+// }
+
+var v31VecRe = regexp.MustCompile(
+ "\\ACVSS:3\\.1(?:/(?:" + strings.Join([]string {
+ "(?:AV:[NALP])",
+ "(?:AC:[LH])",
+ "(?:PR:[NLH])",
+ "(?:UI:[NR])",
+ "(?:S:[UC])",
+ "(?:C:[HLN])",
+ "(?:I:[HLN])",
+ "(?:A:[HLN])",
+ "(?:E:[XHFPU])",
+ "(?:RL:[XUWTO])",
+ "(?:RC:[XCRU])",
+ "(?:CR:[XHML])",
+ "(?:IR:[XHML])",
+ "(?:AR:[XHML])",
+ "(?:MAV:[XNALP])",
+ "(?:MAC:[XLH])",
+ "(?:MPR:[XNLH])",
+ "(?:MUI:[XNR])",
+ "(?:MS:[XUC])",
+ "(?:MC:[XNLH])",
+ "(?:MI:[XNLH])",
+ "(?:MA:[XNLH])",
+ }, "|") + "))+\\z",
+)
+
// Is the given string a CVSSv3.1 vector string?
func isV31VectorString(s string) bool {
- return (len(s) > len(v31Prefix)) && (s[:len(v31Prefix)] == v31Prefix);
+ return (len(s) > len(v31Prefix)) &&
+ (s[:len(v31Prefix)] == v31Prefix) &&
+ v31VecRe.MatchString(s)
}
diff --git a/internal/cvss/v31vector_test.go b/internal/cvss/v31vector_test.go
index ba82edb..d05edca 100644
--- a/internal/cvss/v31vector_test.go
+++ b/internal/cvss/v31vector_test.go
@@ -4,46 +4,558 @@ import (
"testing"
)
-func TestV31Vector(t *testing.T) {
- // test v3 vector
- test := "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:N"
- expMetrics := []string { "AV:L", "AC:H", "PR:L", "UI:N", "S:U", "C:H", "I:N", "A:N" }
-
- t.Run("TestV31Vector", func(t *testing.T) {
- // parse vector
- vec, err := NewVector(test)
- if err != nil {
- t.Error(err)
- return
- }
-
- // check version
- if vec.Version() != V31 {
- t.Errorf("got %s, exp %s", vec.Version(), V31)
- return
- }
-
- for i, m := range(vec.Metrics()) {
- got := m.String()
- if got != expMetrics[i] {
- t.Errorf("got %s, exp %s", got, expMetrics[i])
+func TestNewV31Vector(t *testing.T) {
+ passTests := []struct {
+ val string
+ exp []string
+ } {
+ {
+ val: "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:N",
+ exp: []string { "AV:L", "AC:H", "PR:L", "UI:N", "S:U", "C:H", "I:N", "A:N" },
+ },
+ }
+
+ for _, test := range(passTests) {
+ t.Run(test.val, func(t *testing.T) {
+ // parse vector
+ vec, err := newV31Vector(test.val)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ // check version
+ if vec.Version() != V31 {
+ t.Errorf("got %s, exp %s", vec.Version(), V31)
+ 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: "CVSS:3.1/AV:L/junk/PR:L/UI:N/S:U/C:H/I:N/A:N",
+ exp: "invalid CVSS 3.1 metric: junk",
+ },
+ }
+
+ for _, test := range(failTests) {
+ t.Run(test.val, func(t *testing.T) {
+ got, err := newV31Vector(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 TestInvalidV31Vector(t *testing.T) {
- // test invalid vector
- test := "CVSS:3.1/AV:L/junk/PR:L/UI:N/S:U/C:H/I:N/A:N"
- exp := "invalid CVSS 3.1 metric: junk"
-
- // parse vector
- got, err := NewVector(test)
- if err != nil && err.Error() != exp {
- t.Errorf("got \"%s\", exp \"%s\"", err.Error(), err)
- return
- } else if err == nil {
- t.Errorf("got \"%s\", exp badMetric", got)
- return
+func TestIsV31VectorString(t *testing.T) {
+ // test non v31 strings
+ passTests := []string {
+ "CVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N",
+ "CVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:H",
+ "CVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N",
+ "CVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H",
+ "CVSS:3.1/AV:A/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H",
+ "CVSS:3.1/AV:A/AC:L/PR:H/UI:N/S:C/C:L/I:L/A:N",
+ "CVSS:3.1/AV:A/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:A/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:H",
+ "CVSS:3.1/AV:A/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:A/AC:L/PR:H/UI:N/S:U/C:L/I:N/A:N",
+ "CVSS:3.1/AV:A/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:H",
+ "CVSS:3.1/AV:A/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:N",
+ "CVSS:3.1/AV:A/AC:L/PR:H/UI:R/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:A/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H",
+ "CVSS:3.1/AV:A/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N",
+ "CVSS:3.1/AV:A/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:N",
+ "CVSS:3.1/AV:A/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:A/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:H",
+ "CVSS:3.1/AV:A/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:A/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N",
+ "CVSS:3.1/AV:A/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N",
+ "CVSS:3.1/AV:A/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L",
+ "CVSS:3.1/AV:A/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N",
+ "CVSS:3.1/AV:A/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:N",
+ "CVSS:3.1/AV:A/AC:L/PR:L/UI:R/S:U/C:N/I:N/A:H",
+ "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H",
+ "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:L",
+ "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:N",
+ "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:L",
+ "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:H",
+ "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:L",
+ "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L",
+ "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N",
+ "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:L",
+ "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H",
+ "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:H",
+ "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:N",
+ "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L",
+ "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N",
+ "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N",
+ "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N",
+ "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N",
+ "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
+ "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L",
+ "CVSS:3.1/AV:A/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:A/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:A/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:H",
+ "CVSS:3.1/AV:A/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N",
+ "CVSS:3.1/AV:A/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N",
+ "CVSS:3.1/AV:A/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H",
+ "CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:C/C:H/I:H/A:H",
+ "CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:C/C:H/I:N/A:N",
+ "CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U/C:N/I:H/A:N",
+ "CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U/C:N/I:L/A:H",
+ "CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U/C:N/I:N/A:H",
+ "CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U/C:N/I:N/A:L",
+ "CVSS:3.1/AV:L/AC:H/PR:H/UI:R/S:C/C:L/I:L/A:N",
+ "CVSS:3.1/AV:L/AC:H/PR:H/UI:R/S:C/C:N/I:H/A:N",
+ "CVSS:3.1/AV:L/AC:H/PR:H/UI:R/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:L/AC:H/PR:H/UI:R/S:U/C:N/I:L/A:N",
+ "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H",
+ "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:C/C:H/I:N/A:N",
+ "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:C/C:N/I:N/A:H",
+ "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N",
+ "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:H",
+ "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:H",
+ "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:N",
+ "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:H/A:H",
+ "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:H/A:N",
+ "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:N",
+ "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:H",
+ "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:L",
+ "CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:C/C:L/I:H/A:N",
+ "CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:L/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H",
+ "CVSS:3.1/AV:L/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:L/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:L/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H",
+ "CVSS:3.1/AV:L/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:L/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N",
+ "CVSS:3.1/AV:L/AC:H/PR:N/UI:R/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:L/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N",
+ "CVSS:3.1/AV:L/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:H",
+ "CVSS:3.1/AV:L/AC:H/PR:N/UI:R/S:U/C:N/I:N/A:L",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:C/C:H/I:N/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:C/C:L/I:H/A:L",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:C/C:L/I:L/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:C/C:L/I:L/A:L",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:C/C:L/I:L/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:C/C:L/I:N/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:C/C:L/I:N/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:C/C:N/I:H/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:C/C:N/I:N/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:C/C:N/I:N/A:L",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:L/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:L",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:L/I:N/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:H/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:H/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:L/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:L",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:L",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:R/S:C/C:N/I:H/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:R/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:R/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:H/UI:R/S:U/C:N/I:N/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:L",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:L/I:N/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:N/I:L/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:N/I:N/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:L",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:L",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:L",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:C/C:L/I:N/A:L",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:C/C:N/I:H/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:L/I:L/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:N/I:L/A:L",
+ "CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:N/I:N/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:N/I:H/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:L/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:L/A:L",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:L/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:L",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H",
+ "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:L",
+ "CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:C/C:H/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:C/C:L/I:L/A:L",
+ "CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:N/A:H",
+ "CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:L/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:N/I:L/A:H",
+ "CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:N/I:N/A:H",
+ "CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:C/C:L/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:C/C:L/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:U/C:H/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:U/C:L/I:L/A:L",
+ "CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:U/C:N/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:N/I:N/A:H",
+ "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:H",
+ "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:L",
+ "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:H",
+ "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:L",
+ "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:H",
+ "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:L",
+ "CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:C/C:N/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:L/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:N/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:N/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:H",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:H",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:N/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:N/A:H",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:L/A:H",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:N/A:H",
+ "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:N/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:N/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:N/I:N/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:N/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:L/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:L/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:N/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:N/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:H/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:L/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:L/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:N/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:N/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:N/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:N/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:N/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:N/I:N/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:L/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:N/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:N/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:H/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:N/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:N/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:N/I:N/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:L/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:L",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H",
+ "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:L",
+ "CVSS:3.1/AV:P/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:P/AC:H/PR:L/UI:R/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:P/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:P/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:P/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N",
+ "CVSS:3.1/AV:P/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:P/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:N",
+ "CVSS:3.1/AV:P/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:P/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:N",
+ "CVSS:3.1/AV:P/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:H",
+ "CVSS:3.1/AV:P/AC:L/PR:H/UI:R/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:P/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H",
+ "CVSS:3.1/AV:P/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H",
+ "CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:C/C:L/I:H/A:N",
+ "CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:H",
+ "CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
+ "CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N",
+ "CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H",
+ "CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
+ "CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N",
+ "CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N",
+ "CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H",
+ "CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:L",
+ "CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N",
+ "CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N",
+ "CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
+ "CVSS:3.1/AV:P/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H",
+ }
+
+ for _, test := range(passTests) {
+ t.Run(test, func(t *testing.T) {
+ if !isV31VectorString(test) {
+ t.Error("got false, exp true")
+ }
+ })
+ }
+
+ // test non v31 strings
+ failTests := []string {
+ "AV:N/AC:M/Au:S/C:N/I:P/A:C",
+ "AV:N/AC:M/Au:S/C:N/I:P/A:N",
+ "AV:N/AC:M/Au:S/C:N/I:P/A:P",
+ "AV:N/AC:M/Au:S/C:P/I:N/A:N",
+ "AV:N/AC:M/Au:S/C:P/I:N/A:P",
+ "AV:N/AC:M/Au:S/C:P/I:P/A:C",
+ "AV:N/AC:M/Au:S/C:P/I:P/A:N",
+ "AV:N/AC:M/Au:S/C:P/I:P/A:P",
+
+ "CVSS:3.0/AV:A/AC:H/PR:H/UI:R/S:U/C:H/I:H/A:H",
+ "CVSS:3.0/AV:A/AC:H/PR:H/UI:R/S:U/C:N/I:N/A:L",
+ "CVSS:3.0/AV:A/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H",
+ "CVSS:3.0/AV:A/AC:H/PR:L/UI:N/S:U/C:N/I:H/A:H",
+ "CVSS:3.0/AV:A/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H",
+ }
+
+ for _, test := range(failTests) {
+ t.Run(test, func(t *testing.T) {
+ if isV31VectorString(test) {
+ t.Error("got true, exp false")
+ }
+ })
}
}
diff --git a/internal/cvss/vector.go b/internal/cvss/vector.go
new file mode 100644
index 0000000..3e465c5
--- /dev/null
+++ b/internal/cvss/vector.go
@@ -0,0 +1,36 @@
+package cvss
+
+import (
+ "fmt"
+)
+
+// CVSS metric vector.
+type Vector interface {
+ // Get CVSS version.
+ Version() Version
+
+ // Get CVSS vector string.
+ String() string
+
+ // Return metrics in this vector.
+ Metrics() []Metric
+
+ // Unmarshal vector from JSON.
+ // UnmarshalJSON(b []byte) error
+}
+
+// Create new CVSS vector from vector string.
+func NewVector(s string) (Vector, error) {
+ if isV31VectorString(s) {
+ // create CVSS v3.1 vector.
+ return newV31Vector(s)
+ } else if isV30VectorString(s) {
+ // create CVSS v3.0 vector.
+ return newV30Vector(s)
+ } else if isV2VectorString(s) {
+ // create CVSS v2 vector.
+ return newV2Vector(s)
+ } else {
+ return nil, fmt.Errorf("invalid CVSS vector: %s", s)
+ }
+}
diff --git a/internal/cvss/cvss_test.go b/internal/cvss/vector_test.go
index 4faa30c..4faa30c 100644
--- a/internal/cvss/cvss_test.go
+++ b/internal/cvss/vector_test.go