Skip to content

Commit 171c831

Browse files
committed
add support for calculating CVSS
Signed-off-by: ziadhany <[email protected]>
1 parent 377826e commit 171c831

File tree

4 files changed

+66
-6
lines changed

4 files changed

+66
-6
lines changed

setup.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ install_requires =
7878
defusedxml>=0.7.1
7979
Markdown>=3.3.0
8080
dateparser>=1.1.1
81+
cvss>=2.4
8182

8283
# networking
8384
GitPython>=3.1.17
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Generated by Django 4.0.7 on 2022-09-12 14:50
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('vulnerabilities', '0027_alter_vulnerabilityreference_url'),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name='vulnerabilityseverity',
15+
name='scoring_elements',
16+
field=models.CharField(help_text='Supporting a scoring elements as a string For example a CVSS vector Important, High, Medium ,Low.Typically used to compute the value', max_length=100, null=True),
17+
),
18+
migrations.AlterField(
19+
model_name='vulnerabilityseverity',
20+
name='value',
21+
field=models.CharField(help_text='Score Value expressed as a number such as 9.0 that can be sorted or compared', max_length=50),
22+
),
23+
]

vulnerabilities/models.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,6 @@ def get_absolute_url(self):
278278

279279

280280
class PackageRelatedVulnerability(models.Model):
281-
282281
# TODO: Fix related_name
283282
package = models.ForeignKey(
284283
Package,
@@ -351,7 +350,6 @@ def update_or_create(self):
351350

352351

353352
class VulnerabilitySeverity(models.Model):
354-
355353
reference = models.ForeignKey(VulnerabilityReference, on_delete=models.CASCADE)
356354

357355
scoring_system_choices = tuple(
@@ -369,7 +367,27 @@ class VulnerabilitySeverity(models.Model):
369367
),
370368
)
371369

372-
value = models.CharField(max_length=50, help_text="Example: 9.0, Important, High")
370+
value = models.CharField(
371+
max_length=50,
372+
help_text="Score Value expressed as a number such as 9.0 that can be sorted or compared",
373+
)
374+
375+
scoring_elements = models.CharField(
376+
max_length=100,
377+
null=True,
378+
help_text="Supporting a scoring elements as a string "
379+
"For example a CVSS vector Important, High, Medium ,Low."
380+
"Typically used to compute the value",
381+
)
382+
383+
def save(self, *args, **kwargs):
384+
super().save(*args, **kwargs)
385+
if not self.value and self.scoring_elements:
386+
try:
387+
self.value = SCORING_SYSTEMS[self.scoring_system].as_score(self.value)
388+
super().save(update_fields=["value"])
389+
except NotImplementedError:
390+
pass
373391

374392
class Meta:
375393
unique_together = ["reference", "scoring_system", "value"]

vulnerabilities/severity_systems.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
#
99

1010
import dataclasses
11+
from decimal import Decimal
12+
13+
from cvss import CVSS2
14+
from cvss import CVSS3
1115

1216
"""
1317
Vulnerability scoring systems define scales, values and approach to score a
@@ -17,7 +21,6 @@
1721

1822
@dataclasses.dataclass(order=True)
1923
class ScoringSystem:
20-
2124
# a short identifier for the scoring system.
2225
identifier: str
2326
# a name which represents the scoring system such as `RedHat bug severity`.
@@ -28,13 +31,28 @@ class ScoringSystem:
2831
# notes about that scoring system
2932
notes: str = ""
3033

31-
def as_score(self, value):
34+
def as_score(self, value) -> Decimal:
3235
"""
3336
Return a normalized numeric score for this scoring system given a raw
3437
value. For instance this can be used to convert a CVSS vector to a base
3538
score.
39+
40+
>>> SCORING_SYSTEMS["cvssv2_vector"].as_score("AV:L/AC:L/Au:M/C:N/I:P/A:C/E:U/RL:W/RC:ND/CDP:L/TD:H/CR:ND/IR:ND/AR:M")
41+
Decimal('5.0')
42+
>>> SCORING_SYSTEMS["cvssv3_vector"].as_score('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')
43+
Decimal('6.5')
44+
>>> SCORING_SYSTEMS["cvssv3.1_vector"].as_score("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:H")
45+
Decimal('8.6')
3646
"""
37-
raise NotImplementedError
47+
48+
if self.identifier == "cvssv2_vector":
49+
c = CVSS2(value)
50+
return c.base_score
51+
elif self.identifier in ["cvssv3_vector", "cvssv3.1_vector"]:
52+
c = CVSS3(value)
53+
return c.base_score
54+
else:
55+
raise NotImplementedError
3856

3957

4058
CVSSV2 = ScoringSystem(

0 commit comments

Comments
 (0)