Skip to content

Commit ba20954

Browse files
committed
Adress review comments
Signed-off-by: Tushar Goel <tushar.goel.dav@gmail.com>
1 parent ea1fbf4 commit ba20954

File tree

4 files changed

+105
-54
lines changed

4 files changed

+105
-54
lines changed

vulnerabilities/importer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ def to_dict(self):
110110
@classmethod
111111
def from_dict(cls, ref: dict):
112112
return cls(
113-
reference_id=ref["reference_id"],
113+
reference_type=ref.get("reference_type") or "",
114114
reference_type=ref["reference_type"],
115115
url=ref["url"],
116116
severities=[

vulnerabilities/models.py

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
# See https://aboutcode.org for more information about nexB OSS projects.
88
#
99

10+
import csv
1011
import hashlib
1112
import json
1213
import logging
14+
import xml.etree.ElementTree as ET
1315
from contextlib import suppress
1416
from functools import cached_property
1517
from itertools import groupby
@@ -20,6 +22,8 @@
2022
from cvss.exceptions import CVSS3MalformedError
2123
from cvss.exceptions import CVSS4MalformedError
2224
from cwe2.database import Database
25+
from cwe2.mappings import xml_database_path
26+
from cwe2.weakness import Weakness as DBWeakness
2327
from django.contrib.auth import get_user_model
2428
from django.contrib.auth.models import UserManager
2529
from django.core import exceptions
@@ -46,7 +50,6 @@
4650
from univers.version_range import AlpineLinuxVersionRange
4751
from univers.versions import Version
4852

49-
from aboutcode import hashid
5053
from vulnerabilities import utils
5154
from vulnerabilities.severity_systems import EPSS
5255
from vulnerabilities.severity_systems import SCORING_SYSTEMS
@@ -467,14 +470,48 @@ def get_severity_vectors_and_values(self):
467470
return severity_vectors, severity_values
468471

469472

473+
def get_cwes(self):
474+
"""Yield CWE Weakness objects"""
475+
for cwe_category in self.cwe_files:
476+
cwe_category.seek(0)
477+
reader = csv.DictReader(cwe_category)
478+
for row in reader:
479+
yield DBWeakness(*list(row.values())[0:-1])
480+
tree = ET.parse(xml_database_path)
481+
root = tree.getroot()
482+
for tag_num in [1, 2]: # Categories , Views
483+
tag = root[tag_num]
484+
for child in tag:
485+
yield DBWeakness(
486+
*[
487+
child.attrib["ID"],
488+
child.attrib.get("Name"),
489+
None,
490+
child.attrib.get("Status"),
491+
child[0].text,
492+
]
493+
)
494+
495+
496+
Database.get_cwes = get_cwes
497+
498+
470499
class Weakness(models.Model):
471500
"""
472501
A Common Weakness Enumeration model
473502
"""
474503

475504
cwe_id = models.IntegerField(help_text="CWE id")
476505
vulnerabilities = models.ManyToManyField(Vulnerability, related_name="weaknesses")
477-
db = Database()
506+
507+
cwe_by_id = {}
508+
509+
def get_cwe(self, cwe_id):
510+
if not self.cwe_by_id:
511+
db = Database()
512+
for weakness in db.get_cwes():
513+
self.cwe_by_id[str(weakness.cwe_id)] = weakness
514+
return self.cwe_by_id[cwe_id]
478515

479516
@property
480517
def cwe(self):
@@ -486,7 +523,7 @@ def weakness(self):
486523
Return a queryset of Weakness for this vulnerability.
487524
"""
488525
try:
489-
weakness = self.db.get(self.cwe_id)
526+
weakness = self.get_cwe(str(self.cwe_id))
490527
return weakness
491528
except Exception as e:
492529
logger.warning(f"Could not find CWE {self.cwe_id}: {e}")

vulnerabilities/templates/vulnerability_details.html

Lines changed: 22 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -503,60 +503,48 @@
503503
</div>
504504

505505

506-
{% for severity in severities %}
507-
{% if severity.scoring_system == 'epss' %}
508-
<div class="tab-div content" data-content="epss">
509-
<div class="has-text-weight-bold tab-nested-div ml-1 mb-1 mt-1">
510-
Exploit Prediction Scoring System
511-
</div>
512-
<table class="table vcio-table width-100-pct mt-2">
506+
<div class="tab-div content" data-content="epss">
507+
{% if epss_data %}
508+
<div class="has-text-weight-bold tab-nested-div ml-1 mb-1 mt-1">
509+
Exploit Prediction Scoring System (EPSS)
510+
</div>
511+
<table class="table vcio-table width-100-pct mt-2">
513512
<tbody>
514513
<tr>
515514
<td class="two-col-left">
516515
<span class="has-tooltip-multiline has-tooltip-black has-tooltip-arrow has-tooltip-text-left"
517-
data-tooltip="the percentile of the current score, the proportion of all scored vulnerabilities with the same or a lower EPSS score">
518-
Percentile
516+
data-tooltip="The percentile of the current score, the proportion of all scored vulnerabilities with the same or a lower EPSS score">
517+
Percentile
519518
</span>
520519
</td>
521-
<td class="two-col-right">{{ severity.scoring_elements }}</td>
520+
<td class="two-col-right">{{ epss_data.percentile }}</td>
522521
</tr>
523-
524522
<tr>
525523
<td class="two-col-left">
526524
<span class="has-tooltip-multiline has-tooltip-black has-tooltip-arrow has-tooltip-text-left"
527-
data-tooltip="the EPSS score representing the probability [0-1] of exploitation in the wild in the next 30 days (following score publication)">
528-
EPSS score
525+
data-tooltip="The EPSS score represents the probability [0-1] of exploitation in the wild in the next 30 days.">
526+
EPSS Score
529527
</span>
530528
</td>
531-
<td class="two-col-right">{{ severity.value }}</td>
529+
<td class="two-col-right">{{ epss_data.score }}</td>
532530
</tr>
533-
534-
{% if severity.published_at %}
531+
{% if epss_data.published_at %}
535532
<tr>
536533
<td class="two-col-left">
537-
<span
538-
class="has-tooltip-multiline has-tooltip-black has-tooltip-arrow has-tooltip-text-left"
539-
data-tooltip="When was the time we fetched epss">
540-
Published at
534+
<span class="has-tooltip-multiline has-tooltip-black has-tooltip-arrow has-tooltip-text-left"
535+
data-tooltip="Date when the EPSS score was published.">
536+
Published At
541537
</span>
542538
</td>
543-
<td class="two-col-right">{{ severity.published_at }}</td>
539+
<td class="two-col-right">{{ epss_data.published_at }}</td>
544540
</tr>
545-
{% endif %}
546-
541+
{% endif %}
547542
</tbody>
548-
</table>
543+
</table>
544+
{% else %}
545+
<p>No EPSS data available for this vulnerability.</p>
546+
{% endif %}
549547
</div>
550-
{% endif %}
551-
{% empty %}
552-
<div class="tab-div content" data-content="epss">
553-
<tr>
554-
<td>
555-
There are no EPSS available.
556-
</td>
557-
</tr>
558-
</div>
559-
{% endfor %}
560548

561549
<div class="tab-div content" data-content="history">
562550
<table class="table is-bordered is-striped is-narrow is-hoverable is-fullwidth">

vulnerabilities/views.py

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -156,26 +156,36 @@ class VulnerabilityDetails(DetailView):
156156
slug_field = "vulnerability_id"
157157

158158
def get_queryset(self):
159-
"""
160-
Prefetch and optimize related data to minimize database hits.
161-
"""
162159
return (
163160
super()
164161
.get_queryset()
165162
.select_related()
166163
.prefetch_related(
167-
"references",
168-
"aliases",
169-
"weaknesses",
170-
"severities",
171-
"exploits",
172164
Prefetch(
173-
"affecting_packages",
174-
queryset=models.Package.objects.only("type", "namespace", "name", "version"),
165+
"references",
166+
queryset=models.VulnerabilityReference.objects.only(
167+
"reference_id", "reference_type", "url"
168+
),
175169
),
176170
Prefetch(
177-
"fixed_by_packages",
178-
queryset=models.Package.objects.only("type", "namespace", "name", "version"),
171+
"aliases",
172+
queryset=models.Alias.objects.only("alias"),
173+
),
174+
Prefetch(
175+
"weaknesses",
176+
queryset=models.Weakness.objects.only("cwe_id"),
177+
),
178+
Prefetch(
179+
"severities",
180+
queryset=models.VulnerabilitySeverity.objects.only(
181+
"scoring_system", "value", "url", "scoring_elements", "published_at"
182+
),
183+
),
184+
Prefetch(
185+
"exploits",
186+
queryset=models.Exploit.objects.only(
187+
"data_source", "description", "required_action", "due_date", "notes"
188+
),
179189
),
180190
)
181191
)
@@ -195,20 +205,35 @@ def get_context_data(self, **kwargs):
195205
]
196206

197207
valid_severities = self.object.severities.exclude(scoring_system=EPSS.identifier).filter(
198-
scoring_elements__isnull=False,
199-
scoring_system__in=SCORING_SYSTEMS.keys()
208+
scoring_elements__isnull=False, scoring_system__in=SCORING_SYSTEMS.keys()
200209
)
201210

202211
severity_vectors = []
203212

204213
for severity in valid_severities:
205214
try:
206-
vector_values = SCORING_SYSTEMS[severity.scoring_system].get(severity.scoring_elements)
215+
vector_values = SCORING_SYSTEMS[severity.scoring_system].get(
216+
severity.scoring_elements
217+
)
207218
if vector_values:
208219
severity_vectors.append({"vector": vector_values, "origin": severity.url})
209-
except (CVSS2MalformedError, CVSS3MalformedError, CVSS4MalformedError, NotImplementedError):
220+
except (
221+
CVSS2MalformedError,
222+
CVSS3MalformedError,
223+
CVSS4MalformedError,
224+
NotImplementedError,
225+
):
210226
logging.error(f"CVSSMalformedError for {severity.scoring_elements}")
211227

228+
epss_severity = vulnerability.severities.filter(scoring_system="epss").first()
229+
epss_data = None
230+
if epss_severity:
231+
epss_data = {
232+
"percentile": epss_severity.scoring_elements,
233+
"score": epss_severity.value,
234+
"published_at": epss_severity.published_at,
235+
}
236+
212237
context.update(
213238
{
214239
"vulnerability": vulnerability,
@@ -220,6 +245,7 @@ def get_context_data(self, **kwargs):
220245
"weaknesses": weaknesses_present_in_db,
221246
"status": vulnerability.get_status_label,
222247
"history": vulnerability.history,
248+
"epss_data": epss_data,
223249
}
224250
)
225251
return context

0 commit comments

Comments
 (0)