Skip to content

Commit fbaac69

Browse files
committed
Add a test for cvss_printer
Fix the cvss vector test Resolve merge conflicts Add exception for s.scoring_system when is not in SCORING_SYSTEMS Add a get serverity values test Resolve merge conflict Change the style of cvss_printer display Add a new filter to print cvss vectors Change the table heading to Vertical Add support for CVSS vectors display Signed-off-by: ziadhany <[email protected]>
1 parent bbd8c7c commit fbaac69

File tree

6 files changed

+216
-2
lines changed

6 files changed

+216
-2
lines changed

vulnerabilities/severity_systems.py

+11
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ def compute(self, scoring_elements: str) -> str:
3737
"""
3838
return NotImplementedError
3939

40+
def get(self, scoring_elements: str):
41+
return NotImplementedError
42+
4043

4144
@dataclasses.dataclass(order=True)
4245
class Cvssv2ScoringSystem(ScoringSystem):
@@ -49,6 +52,10 @@ def compute(self, scoring_elements: str) -> str:
4952
"""
5053
return str(CVSS2(vector=scoring_elements).base_score)
5154

55+
def get(self, scoring_elements: str) -> dict:
56+
scoring_elements = scoring_elements.strip()
57+
return CVSS2(vector=scoring_elements).as_json()
58+
5259

5360
CVSSV2 = Cvssv2ScoringSystem(
5461
identifier="cvssv2",
@@ -71,6 +78,10 @@ def compute(self, scoring_elements: str) -> str:
7178
"""
7279
return str(CVSS3(vector=scoring_elements).base_score)
7380

81+
def get(self, scoring_elements: str) -> dict:
82+
scoring_elements = scoring_elements.strip()
83+
return CVSS3(vector=scoring_elements).as_json()
84+
7485

7586
CVSSV3 = Cvssv3ScoringSystem(
7687
identifier="cvssv3",

vulnerabilities/templates/vulnerability_details.html

+65-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
{% load humanize %}
33
{% load widget_tweaks %}
44
{% load static %}
5+
{% load show_cvss %}
56

67
{% block title %}
78
VulnerableCode Vulnerability Details - {{ vulnerability.vulnerability_id }}
@@ -52,6 +53,13 @@
5253
</span>
5354
</a>
5455
</li>
56+
<li data-tab="severities-vectors">
57+
<a>
58+
<span>
59+
Severities vectors ({{ severity_vectors|length }})
60+
</span>
61+
</a>
62+
</li>
5563
<li data-tab="history">
5664
<a>
5765
<span>
@@ -309,7 +317,63 @@
309317
</tbody>
310318
</table>
311319
</div>
312-
320+
<div class="tab-div content" data-content="severities-vectors">
321+
{% for severity_vector in severity_vectors %}
322+
{% if severity_vector.version == '2.0' %}
323+
Vector: {{ severity_vector.vectorString }}
324+
<table class="table is-bordered is-striped is-narrow is-hoverable is-fullwidth gray-header-border">
325+
<tr>
326+
<th>Exploitability (E)</th>
327+
<th>Access Vector (AV)</th>
328+
<th>Access Complexity (AC)</th>
329+
<th>Authentication (Au)</th>
330+
<th>Confidentiality Impact (C)</th>
331+
<th>Integrity Impact (I)</th>
332+
<th>Availability Impact (A)</th>
333+
</tr>
334+
<tr>
335+
<td>{{ severity_vector.exploitability|cvss_printer:"high,functional,unproven,proof_of_concept,not_defined" }}</td>
336+
<td>{{ severity_vector.accessVector|cvss_printer:"local,adjacent_network,network" }}</td>
337+
<td>{{ severity_vector.accessComplexity|cvss_printer:"high,medium,low" }}</td>
338+
<td>{{ severity_vector.authentication|cvss_printer:"multiple,single,none" }}</td>
339+
<td>{{ severity_vector.confidentialityImpact|cvss_printer:"none,partial,complete" }}</td>
340+
<td>{{ severity_vector.integrityImpact|cvss_printer:"none,partial,complete" }}</td>
341+
<td>{{ severity_vector.availabilityImpact|cvss_printer:"none,partial,complete" }}</td>
342+
</tr>
343+
</table>
344+
{% elif severity_vector.version == '3.1' or severity_vector.version == '3.0'%}
345+
Vector: {{ severity_vector.vectorString }}
346+
<table class="table is-bordered is-striped is-narrow is-hoverable is-fullwidth gray-header-border">
347+
<tr>
348+
<th>Attack Vector (AV)</th>
349+
<th>Attack Complexity (AC)</th>
350+
<th>Privileges Required (PR)</th>
351+
<th>User Interaction (UI)</th>
352+
<th>Scope (S)</th>
353+
<th>Confidentiality Impact (C)</th>
354+
<th>Integrity Impact (I)</th>
355+
<th>Availability Impact (A)</th>
356+
</tr>
357+
<tr>
358+
<td>{{ severity_vector.attackVector|cvss_printer:"network,adjacent_network,local,physical"}}</td>
359+
<td>{{ severity_vector.attackComplexity|cvss_printer:"low,high" }}</td>
360+
<td>{{ severity_vector.privilegesRequired|cvss_printer:"none,low,high" }}</td>
361+
<td>{{ severity_vector.userInteraction|cvss_printer:"none,required"}}</td>
362+
<td>{{ severity_vector.scope|cvss_printer:"unchanged,changed" }}</td>
363+
<td>{{ severity_vector.confidentialityImpact|cvss_printer:"high,low,none" }}</td>
364+
<td>{{ severity_vector.integrityImpact|cvss_printer:"high,low,none" }}</td>
365+
<td>{{ severity_vector.availabilityImpact|cvss_printer:"high,low,none" }}</td>
366+
</tr>
367+
</table>
368+
{% endif %}
369+
{% empty %}
370+
<tr>
371+
<td>
372+
There are no known CVSS vectors.
373+
</td>
374+
</tr>
375+
{% endfor %}
376+
</div>
313377
<div class="tab-div content" data-content="history">
314378
<table class="table is-bordered is-striped is-narrow is-hoverable is-fullwidth">
315379
<thead>
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#
2+
# Copyright (c) nexB Inc. and others. All rights reserved.
3+
# VulnerableCode is a trademark of nexB Inc.
4+
# SPDX-License-Identifier: Apache-2.0
5+
# See http://www.apache.org/licenses/LICENSE-2.0 for the license text.
6+
# See https://github.com/nexB/vulnerablecode for support or download.
7+
# See https://aboutcode.org for more information about nexB OSS projects.
8+
#
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from django import template
2+
from django.utils.safestring import mark_safe
3+
4+
register = template.Library()
5+
6+
7+
@register.filter(is_safe=True)
8+
def cvss_printer(selected_vector, vector_values):
9+
"""highlight the selected vector value and return a list of paragraphs"""
10+
p_list = []
11+
selected_vector = selected_vector.lower()
12+
for vector_value in vector_values.split(","):
13+
if selected_vector == vector_value:
14+
p_list.append(f"<p class='has-text-black-bis mb-2'>{selected_vector}</p>")
15+
else:
16+
p_list.append(f"<p class='has-text-grey mb-2'>{vector_value}</p>")
17+
return mark_safe("".join(p_list))
+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import pytest
2+
from cvss.exceptions import CVSS2MalformedError
3+
from cvss.exceptions import CVSS3MalformedError
4+
5+
from vulnerabilities.severity_systems import CVSSV2
6+
from vulnerabilities.severity_systems import CVSSV3
7+
from vulnerabilities.templatetags.show_cvss import cvss_printer
8+
9+
10+
def test_get_cvss2_vector_values():
11+
assert (
12+
CVSSV2.get("AV:N/AC:L/Au:N/C:P/I:N/A:N ")
13+
== CVSSV2.get("AV:N/AC:L/Au:N/C:P/I:N/A:N")
14+
== {
15+
"accessComplexity": "LOW",
16+
"accessVector": "NETWORK",
17+
"authentication": "NONE",
18+
"availabilityImpact": "NONE",
19+
"availabilityRequirement": "NOT_DEFINED",
20+
"baseScore": 5.0,
21+
"collateralDamagePotential": "NOT_DEFINED",
22+
"confidentialityImpact": "PARTIAL",
23+
"confidentialityRequirement": "NOT_DEFINED",
24+
"environmentalScore": 0.0,
25+
"exploitability": "NOT_DEFINED",
26+
"integrityImpact": "NONE",
27+
"integrityRequirement": "NOT_DEFINED",
28+
"remediationLevel": "NOT_DEFINED",
29+
"reportConfidence": "NOT_DEFINED",
30+
"targetDistribution": "NOT_DEFINED",
31+
"temporalScore": 0.0,
32+
"vectorString": "AV:N/AC:L/Au:N/C:P/I:N/A:N",
33+
"version": "2.0",
34+
}
35+
)
36+
37+
with pytest.raises(CVSS2MalformedError):
38+
CVSSV2.get("")
39+
40+
with pytest.raises(CVSS2MalformedError):
41+
CVSSV2.get("AV:N/AffgL/Au:N/C:P/I:N/A:N ")
42+
43+
44+
def test_get_cvss3_vector_values():
45+
assert (
46+
CVSSV3.get("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H ")
47+
== CVSSV3.get("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H")
48+
== {
49+
"attackComplexity": "LOW",
50+
"attackVector": "NETWORK",
51+
"availabilityImpact": "HIGH",
52+
"availabilityRequirement": "NOT_DEFINED",
53+
"baseScore": 9.1,
54+
"baseSeverity": "CRITICAL",
55+
"confidentialityImpact": "HIGH",
56+
"confidentialityRequirement": "NOT_DEFINED",
57+
"environmentalScore": 9.1,
58+
"environmentalSeverity": "CRITICAL",
59+
"exploitCodeMaturity": "NOT_DEFINED",
60+
"integrityImpact": "HIGH",
61+
"integrityRequirement": "NOT_DEFINED",
62+
"modifiedAttackComplexity": "LOW",
63+
"modifiedAttackVector": "NETWORK",
64+
"modifiedAvailabilityImpact": "HIGH",
65+
"modifiedConfidentialityImpact": "HIGH",
66+
"modifiedIntegrityImpact": "HIGH",
67+
"modifiedPrivilegesRequired": "HIGH",
68+
"modifiedScope": "CHANGED",
69+
"modifiedUserInteraction": "NONE",
70+
"privilegesRequired": "HIGH",
71+
"remediationLevel": "NOT_DEFINED",
72+
"reportConfidence": "NOT_DEFINED",
73+
"scope": "CHANGED",
74+
"temporalScore": 9.1,
75+
"temporalSeverity": "CRITICAL",
76+
"userInteraction": "NONE",
77+
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H",
78+
"version": "3.1",
79+
}
80+
)
81+
82+
with pytest.raises(CVSS3MalformedError):
83+
CVSSV3.get("CVSS:3.7/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H ")
84+
85+
with pytest.raises(CVSS3MalformedError):
86+
CVSSV3.get("")
87+
88+
89+
def test_blank_cvss_printer():
90+
result = cvss_printer("", "")
91+
assert result == "<p class='has-text-black-bis mb-2'></p>"
92+
93+
94+
def test_cvss_printer():
95+
result = cvss_printer("HIGH", "high,medium,low")
96+
assert result == (
97+
"<p class='has-text-black-bis mb-2'>high</p>"
98+
"<p class='has-text-grey mb-2'>medium</p>"
99+
"<p class='has-text-grey mb-2'>low</p>"
100+
)

vulnerabilities/views.py

+15-1
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
# See https://github.com/nexB/vulnerablecode for support or download.
77
# See https://aboutcode.org for more information about nexB OSS projects.
88
#
9-
9+
import logging
1010
from datetime import datetime
1111

12+
from cvss.exceptions import CVSS2MalformedError
13+
from cvss.exceptions import CVSS3MalformedError
1214
from django.contrib import messages
1315
from django.core.exceptions import ValidationError
1416
from django.core.mail import send_mail
@@ -26,6 +28,7 @@
2628
from vulnerabilities.forms import PackageSearchForm
2729
from vulnerabilities.forms import VulnerabilitySearchForm
2830
from vulnerabilities.models import VulnerabilityStatusType
31+
from vulnerabilities.severity_systems import SCORING_SYSTEMS
2932
from vulnerabilities.utils import get_severity_range
3033
from vulnerablecode.settings import env
3134

@@ -132,6 +135,16 @@ def get_context_data(self, **kwargs):
132135
weakness_object for weakness_object in weaknesses if weakness_object.weakness
133136
]
134137
status = self.object.get_status_label
138+
139+
severity_vectors = []
140+
for s in self.object.severities:
141+
if s.scoring_elements and s.scoring_system in SCORING_SYSTEMS:
142+
try:
143+
vector_values = SCORING_SYSTEMS[s.scoring_system].get(s.scoring_elements)
144+
severity_vectors.append(vector_values)
145+
except (CVSS2MalformedError, CVSS3MalformedError, NotImplementedError):
146+
logging.error(f"CVSSMalformedError for {s.scoring_elements}")
147+
135148
context.update(
136149
{
137150
"vulnerability": self.object,
@@ -140,6 +153,7 @@ def get_context_data(self, **kwargs):
140153
"severity_score_range": get_severity_range(
141154
{s.value for s in self.object.severities}
142155
),
156+
"severity_vectors": severity_vectors,
143157
"references": self.object.references.all(),
144158
"aliases": self.object.aliases.all(),
145159
"affected_packages": self.object.affected_packages.all(),

0 commit comments

Comments
 (0)