Skip to content

Commit df1ea13

Browse files
committed
Remove duplicate rows for CVSS
Signed-off-by: ziadhany <[email protected]>
1 parent 377826e commit df1ea13

File tree

6 files changed

+117
-5
lines changed

6 files changed

+117
-5
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: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 4.0.7 on 2022-09-22 21:25
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+
]
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from django.db import migrations
2+
3+
from vulnerabilities.severity_systems import SCORING_SYSTEMS
4+
5+
6+
def compute_score(apps, schema_editor):
7+
Vuln_severity = apps.get_model('vulnerabilities', 'VulnerabilitySeverity')
8+
for vuln_severity in Vuln_severity.objects.all():
9+
if vuln_severity.value and not vuln_severity.scoring_elements:
10+
try:
11+
vuln_severity.scoring_elements = SCORING_SYSTEMS[vuln_severity.scoring_system].as_score(vuln_severity.value)
12+
vuln_severity.save()
13+
except NotImplementedError:
14+
pass
15+
16+
17+
class Migration(migrations.Migration):
18+
dependencies = [
19+
('vulnerabilities', '0028_vulnerabilityseverity_scoring_elements'),
20+
]
21+
22+
operations = [
23+
migrations.RunPython(compute_score, migrations.RunPython.noop),
24+
]
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from django.db import migrations
2+
3+
4+
def remove_extra_rows(apps, schema_editor):
5+
Vuln_severity = apps.get_model('vulnerabilities', 'VulnerabilitySeverity')
6+
duplicates = (
7+
Vuln_severity.objects
8+
.filter(scoring_system__in=["cvssv2_vector", "cvssv3_vector", "cvssv3.1_vector"])
9+
)
10+
11+
for duplicate in duplicates:
12+
(
13+
Vuln_severity.objects
14+
.filter(reference_id=duplicate.reference_id,
15+
scoring_system__in=["cvssv2", "cvssv3", "cvssv3.1"],
16+
value=duplicate.scoring_elements)
17+
.delete()
18+
)
19+
20+
21+
def swap_scoring_elements_with_value(apps, schema_editor):
22+
Vuln_severity = apps.get_model('vulnerabilities', 'VulnerabilitySeverity')
23+
for vuln_severity in Vuln_severity.objects.all():
24+
cvss_mapper = {
25+
"cvssv2_vector": "cvssv2",
26+
"cvssv3_vector": "cvssv3",
27+
"cvssv3.1_vector": "cvssv3.1",
28+
}
29+
if vuln_severity.scoring_system in ["cvssv2_vector", "cvssv3_vector", "cvssv3.1_vector"]:
30+
vuln_severity.scoring_system = cvss_mapper[vuln_severity.scoring_system]
31+
temp = vuln_severity.scoring_elements # value
32+
vuln_severity.scoring_elements = vuln_severity.value
33+
vuln_severity.value = temp
34+
vuln_severity.save()
35+
36+
37+
class Migration(migrations.Migration):
38+
dependencies = [
39+
('vulnerabilities', '0029_vulnerabilityserverity_compute_score'),
40+
]
41+
42+
operations = [
43+
migrations.RunPython(remove_extra_rows), migrations.RunPython.noop,
44+
migrations.RunPython(swap_scoring_elements_with_value, migrations.RunPython.noop),
45+
]

vulnerabilities/models.py

Lines changed: 8 additions & 2 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(
@@ -371,6 +369,14 @@ class VulnerabilitySeverity(models.Model):
371369

372370
value = models.CharField(max_length=50, help_text="Example: 9.0, Important, High")
373371

372+
scoring_elements = models.CharField(
373+
max_length=100,
374+
null=True,
375+
help_text="Supporting a scoring elements as a string "
376+
"For example a CVSS vector Important, High, Medium ,Low."
377+
"Typically used to compute the value",
378+
)
379+
374380
class Meta:
375381
unique_together = ["reference", "scoring_system", "value"]
376382
ordering = ["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("Can't compute a score")
3856

3957

4058
CVSSV2 = ScoringSystem(

0 commit comments

Comments
 (0)