Skip to content

Commit

Permalink
feat(CVSS2, CVSS3): add methods to fetch isolated temporal and enviro…
Browse files Browse the repository at this point in the history
…nmental vectors (#64)

* feat(CVSS2, CVSS3): add methods to fetch isolated temporal and environmental vectors
* test(CVSS2, CVSS3): add tests for temporal and environmental vector methods
  • Loading branch information
fqlenos authored Oct 30, 2024
1 parent e5c64e0 commit 42a77b6
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 0 deletions.
22 changes: 22 additions & 0 deletions cvss/cvss2.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,28 @@ def rh_vector(self):
"""
return str(self.scores()[0]) + "/" + self.clean_vector()

def temporal_vector(self):
"""
Returns the temporal vector from the full CVSS vector.
Returns:
(str): Temporal CVSS vector.
"""
return "/".join(
[metric + ":" + self.metrics.get(metric, "ND") for metric in TEMPORAL_METRICS]
)

def environmental_vector(self):
"""
Returns the environmental vector from the full CVSS vector.
Returns:
(str): Environmental CVSS vector.
"""
return "/".join(
[metric + ":" + self.metrics.get(metric, "ND") for metric in ENVIRONMENTAL_METRICS]
)

def as_json(self, sort=False, minimal=False):
"""
Returns a dictionary formatted with attribute names and values defined by the official
Expand Down
22 changes: 22 additions & 0 deletions cvss/cvss3.py
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,28 @@ def rh_vector(self):
"""
return str(self.scores()[0]) + "/" + self.clean_vector()

def temporal_vector(self):
"""
Returns the temporal vector from the full CVSS vector.
Returns:
(str): Temporal CVSS vector.
"""
return "/".join(
[metric + ":" + self.metrics.get(metric, "X") for metric in TEMPORAL_METRICS]
)

def environmental_vector(self):
"""
Returns the environmental vector from the full CVSS vector.
Returns:
(str): Environmental CVSS vector.
"""
return "/".join(
[metric + ":" + self.metrics.get(metric, "X") for metric in ENVIRONMENTAL_METRICS]
)

def as_json(self, sort=False, minimal=False):
"""
Returns a dictionary formatted with attribute names and values defined by the official
Expand Down
56 changes: 56 additions & 0 deletions tests/test_cvss2.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,62 @@ def test_rh_vector(self):
v = "ABC/AV:L/AC:H/Au:M/C:C/I:P/A:P"
self.assertRaises(CVSS2RHMalformedError, CVSS2.from_rh_vector, v)

def test_temporal_vector(self):
"""
Test for retrieving only the Temporal CVSS Vector.
"""
v = "AV:A/AC:H/Au:S/C:C/I:C/A:P/E:U/RL:U/RC:UR/CDP:ND/TD:ND/CR:L/IR:M/AR:ND"
self.assertEqual(
"E:U/RL:U/RC:UR",
CVSS2(v).temporal_vector(),
)

v = "AV:A/AC:H/Au:S/C:C/I:C/A:P/CDP:ND/TD:ND/CR:L/IR:M/AR:ND"
self.assertEqual(
"E:ND/RL:ND/RC:ND",
CVSS2(v).temporal_vector(),
)

v = "AV:A/AC:H/Au:S/C:C/I:C/A:P/RL:U/RC:UR/CDP:ND/TD:ND/CR:L/IR:M/AR:ND"
self.assertEqual(
"E:ND/RL:U/RC:UR",
CVSS2(v).temporal_vector(),
)

v = "AV:A/AC:H/Au:S/C:C/I:C/A:P/E:U/RC:UR/CDP:ND/TD:ND/CR:L/IR:M/AR:ND"
self.assertEqual(
"E:U/RL:ND/RC:UR",
CVSS2(v).temporal_vector(),
)

v = "AV:A/AC:H/Au:S/C:C/I:C/A:P/E:U/RL:U/CDP:ND/TD:ND/CR:L/IR:M/AR:ND"
self.assertEqual(
"E:U/RL:U/RC:ND",
CVSS2(v).temporal_vector(),
)

def test_environmental_vector(self):
"""
Test for retrieving only the Environmental CVSS Vector.
"""
v = "AV:A/AC:H/Au:S/C:C/I:C/A:P/E:U/RL:U/CDP:N/TD:N/CR:L/IR:M/AR:L"
self.assertEqual(
"CDP:N/TD:N/CR:L/IR:M/AR:L",
CVSS2(v).environmental_vector(),
)

v = "AV:A/AC:H/Au:S/C:C/I:C/A:P/E:U/RL:U"
self.assertEqual(
"CDP:ND/TD:ND/CR:ND/IR:ND/AR:ND",
CVSS2(v).environmental_vector(),
)

v = "AV:A/AC:H/Au:S/C:C/I:C/A:P/E:U/RL:U/TD:N/CR:L/IR:M/AR:L"
self.assertEqual(
"CDP:ND/TD:N/CR:L/IR:M/AR:L",
CVSS2(v).environmental_vector(),
)

def test_parse_from_text_cvss2(self):
"""
Tests for parsing CVSS from text.
Expand Down
77 changes: 77 additions & 0 deletions tests/test_cvss3.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,83 @@ def test_rh_vector(self):
v = "ABC/CVSS:3.0/AV:A/AC:H/PR:N/UI:R/S:C/C:L/I:H/A:L"
self.assertRaises(CVSS3RHMalformedError, CVSS3.from_rh_vector, v)

def test_temporal_vector(self):
"""
Test for retrieving only the Temporal CVSS Vector.
"""
v = (
"CVSS:3.0/S:C/C:H/I:H/A:N/AV:P/AC:H/PR:H/UI:R/"
"E:H/RL:O/RC:R/CR:H/IR:X/AR:X/MAC:H/MPR:X/MUI:X/MC:L/MA:X"
)
self.assertEqual(
"E:H/RL:O/RC:R",
CVSS3(v).temporal_vector(),
)

v = (
"CVSS:3.0/S:C/C:H/I:H/A:N/AV:P/AC:H/PR:H/UI:R/"
"CR:H/IR:X/AR:X/MAC:H/MPR:X/MUI:X/MC:L/MA:X"
)
self.assertEqual(
"E:X/RL:X/RC:X",
CVSS3(v).temporal_vector(),
)

v = (
"CVSS:3.0/S:C/C:H/I:H/A:N/AV:P/AC:H/PR:H/UI:R/"
"RL:O/RC:R/CR:H/IR:X/AR:X/MAC:H/MPR:X/MUI:X/MC:L/MA:X"
)
self.assertEqual(
"E:X/RL:O/RC:R",
CVSS3(v).temporal_vector(),
)

v = (
"CVSS:3.0/S:C/C:H/I:H/A:N/AV:P/AC:H/PR:H/UI:R/"
"E:H/RC:R/CR:H/IR:X/AR:X/MAC:H/MPR:X/MUI:X/MC:L/MA:X"
)
self.assertEqual(
"E:H/RL:X/RC:R",
CVSS3(v).temporal_vector(),
)

v = (
"CVSS:3.0/S:C/C:H/I:H/A:N/AV:P/AC:H/PR:H/UI:R/"
"E:H/RL:O/CR:H/IR:X/AR:X/MAC:H/MPR:X/MUI:X/MC:L/MA:X"
)
self.assertEqual(
"E:H/RL:O/RC:X",
CVSS3(v).temporal_vector(),
)

def test_environmental_vector(self):
"""
Test for retrieving only the Environmental CVSS Vector.
"""
v = (
"CVSS:3.0/S:C/C:H/I:H/A:N/AV:P/AC:H/PR:H/UI:R/"
"E:H/RL:O/RC:R/CR:H/IR:X/AR:X/MAC:H/MPR:X/MUI:X/MC:L/MA:X"
)
self.assertEqual(
"CR:H/IR:X/AR:X/MAV:P/MAC:H/MPR:H/MUI:R/MS:C/MC:L/MI:H/MA:N",
CVSS3(v).environmental_vector(),
)

v = "CVSS:3.0/S:C/C:H/I:H/A:N/AV:P/AC:H/PR:H/UI:R/E:H/RL:O/RC:R"
self.assertEqual(
"CR:X/IR:X/AR:X/MAV:P/MAC:H/MPR:H/MUI:R/MS:C/MC:H/MI:H/MA:N",
CVSS3(v).environmental_vector(),
)

v = (
"CVSS:3.0/S:C/C:H/I:H/A:N/AV:P/AC:H/PR:H/UI:R/"
"E:H/RL:O/RC:R/MAV:N/MAC:L/MPR:N/MUI:R/MS:C/MC:L/MI:N/MA:H/CR:M/IR:L/AR:M"
)
self.assertEqual(
"CR:M/IR:L/AR:M/MAV:N/MAC:L/MPR:N/MUI:R/MS:C/MC:L/MI:N/MA:H",
CVSS3(v).environmental_vector(),
)

def test_parse_from_text_cvss3(self):
i = "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H"
e = [CVSS3(i)]
Expand Down

0 comments on commit 42a77b6

Please sign in to comment.