Skip to content

Commit

Permalink
Add a test for cvss_printer (aboutcode-org#1312)
Browse files Browse the repository at this point in the history
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 <ziadhany2016@gmail.com>
  • Loading branch information
ziadhany authored and TG1999 committed Jul 19, 2024
1 parent 7cf86d9 commit 8ca20db
Show file tree
Hide file tree
Showing 6 changed files with 216 additions and 2 deletions.
11 changes: 11 additions & 0 deletions vulnerabilities/severity_systems.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ def compute(self, scoring_elements: str) -> str:
"""
return NotImplementedError

def get(self, scoring_elements: str):
return NotImplementedError


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

def get(self, scoring_elements: str) -> dict:
scoring_elements = scoring_elements.strip()
return CVSS2(vector=scoring_elements).as_json()


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

def get(self, scoring_elements: str) -> dict:
scoring_elements = scoring_elements.strip()
return CVSS3(vector=scoring_elements).as_json()


CVSSV3 = Cvssv3ScoringSystem(
identifier="cvssv3",
Expand Down
66 changes: 65 additions & 1 deletion vulnerabilities/templates/vulnerability_details.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{% load humanize %}
{% load widget_tweaks %}
{% load static %}
{% load show_cvss %}

{% block title %}
VulnerableCode Vulnerability Details - {{ vulnerability.vulnerability_id }}
Expand Down Expand Up @@ -52,6 +53,13 @@
</span>
</a>
</li>
<li data-tab="severities-vectors">
<a>
<span>
Severities vectors ({{ severity_vectors|length }})
</span>
</a>
</li>
<li data-tab="history">
<a>
<span>
Expand Down Expand Up @@ -309,7 +317,63 @@
</tbody>
</table>
</div>

<div class="tab-div content" data-content="severities-vectors">
{% for severity_vector in severity_vectors %}
{% if severity_vector.version == '2.0' %}
Vector: {{ severity_vector.vectorString }}
<table class="table is-bordered is-striped is-narrow is-hoverable is-fullwidth gray-header-border">
<tr>
<th>Exploitability (E)</th>
<th>Access Vector (AV)</th>
<th>Access Complexity (AC)</th>
<th>Authentication (Au)</th>
<th>Confidentiality Impact (C)</th>
<th>Integrity Impact (I)</th>
<th>Availability Impact (A)</th>
</tr>
<tr>
<td>{{ severity_vector.exploitability|cvss_printer:"high,functional,unproven,proof_of_concept,not_defined" }}</td>
<td>{{ severity_vector.accessVector|cvss_printer:"local,adjacent_network,network" }}</td>
<td>{{ severity_vector.accessComplexity|cvss_printer:"high,medium,low" }}</td>
<td>{{ severity_vector.authentication|cvss_printer:"multiple,single,none" }}</td>
<td>{{ severity_vector.confidentialityImpact|cvss_printer:"none,partial,complete" }}</td>
<td>{{ severity_vector.integrityImpact|cvss_printer:"none,partial,complete" }}</td>
<td>{{ severity_vector.availabilityImpact|cvss_printer:"none,partial,complete" }}</td>
</tr>
</table>
{% elif severity_vector.version == '3.1' or severity_vector.version == '3.0'%}
Vector: {{ severity_vector.vectorString }}
<table class="table is-bordered is-striped is-narrow is-hoverable is-fullwidth gray-header-border">
<tr>
<th>Attack Vector (AV)</th>
<th>Attack Complexity (AC)</th>
<th>Privileges Required (PR)</th>
<th>User Interaction (UI)</th>
<th>Scope (S)</th>
<th>Confidentiality Impact (C)</th>
<th>Integrity Impact (I)</th>
<th>Availability Impact (A)</th>
</tr>
<tr>
<td>{{ severity_vector.attackVector|cvss_printer:"network,adjacent_network,local,physical"}}</td>
<td>{{ severity_vector.attackComplexity|cvss_printer:"low,high" }}</td>
<td>{{ severity_vector.privilegesRequired|cvss_printer:"none,low,high" }}</td>
<td>{{ severity_vector.userInteraction|cvss_printer:"none,required"}}</td>
<td>{{ severity_vector.scope|cvss_printer:"unchanged,changed" }}</td>
<td>{{ severity_vector.confidentialityImpact|cvss_printer:"high,low,none" }}</td>
<td>{{ severity_vector.integrityImpact|cvss_printer:"high,low,none" }}</td>
<td>{{ severity_vector.availabilityImpact|cvss_printer:"high,low,none" }}</td>
</tr>
</table>
{% endif %}
{% empty %}
<tr>
<td>
There are no known CVSS vectors.
</td>
</tr>
{% endfor %}
</div>
<div class="tab-div content" data-content="history">
<table class="table is-bordered is-striped is-narrow is-hoverable is-fullwidth">
<thead>
Expand Down
8 changes: 8 additions & 0 deletions vulnerabilities/templatetags/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#
# Copyright (c) nexB Inc. and others. All rights reserved.
# VulnerableCode is a trademark of nexB Inc.
# SPDX-License-Identifier: Apache-2.0
# See http://www.apache.org/licenses/LICENSE-2.0 for the license text.
# See https://github.com/nexB/vulnerablecode for support or download.
# See https://aboutcode.org for more information about nexB OSS projects.
#
17 changes: 17 additions & 0 deletions vulnerabilities/templatetags/show_cvss.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from django import template
from django.utils.safestring import mark_safe

register = template.Library()


@register.filter(is_safe=True)
def cvss_printer(selected_vector, vector_values):
"""highlight the selected vector value and return a list of paragraphs"""
p_list = []
selected_vector = selected_vector.lower()
for vector_value in vector_values.split(","):
if selected_vector == vector_value:
p_list.append(f"<p class='has-text-black-bis mb-2'>{selected_vector}</p>")
else:
p_list.append(f"<p class='has-text-grey mb-2'>{vector_value}</p>")
return mark_safe("".join(p_list))
100 changes: 100 additions & 0 deletions vulnerabilities/tests/test_get_serverity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import pytest
from cvss.exceptions import CVSS2MalformedError
from cvss.exceptions import CVSS3MalformedError

from vulnerabilities.severity_systems import CVSSV2
from vulnerabilities.severity_systems import CVSSV3
from vulnerabilities.templatetags.show_cvss import cvss_printer


def test_get_cvss2_vector_values():
assert (
CVSSV2.get("AV:N/AC:L/Au:N/C:P/I:N/A:N ")
== CVSSV2.get("AV:N/AC:L/Au:N/C:P/I:N/A:N")
== {
"accessComplexity": "LOW",
"accessVector": "NETWORK",
"authentication": "NONE",
"availabilityImpact": "NONE",
"availabilityRequirement": "NOT_DEFINED",
"baseScore": 5.0,
"collateralDamagePotential": "NOT_DEFINED",
"confidentialityImpact": "PARTIAL",
"confidentialityRequirement": "NOT_DEFINED",
"environmentalScore": 0.0,
"exploitability": "NOT_DEFINED",
"integrityImpact": "NONE",
"integrityRequirement": "NOT_DEFINED",
"remediationLevel": "NOT_DEFINED",
"reportConfidence": "NOT_DEFINED",
"targetDistribution": "NOT_DEFINED",
"temporalScore": 0.0,
"vectorString": "AV:N/AC:L/Au:N/C:P/I:N/A:N",
"version": "2.0",
}
)

with pytest.raises(CVSS2MalformedError):
CVSSV2.get("")

with pytest.raises(CVSS2MalformedError):
CVSSV2.get("AV:N/AffgL/Au:N/C:P/I:N/A:N ")


def test_get_cvss3_vector_values():
assert (
CVSSV3.get("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H ")
== CVSSV3.get("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H")
== {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "HIGH",
"availabilityRequirement": "NOT_DEFINED",
"baseScore": 9.1,
"baseSeverity": "CRITICAL",
"confidentialityImpact": "HIGH",
"confidentialityRequirement": "NOT_DEFINED",
"environmentalScore": 9.1,
"environmentalSeverity": "CRITICAL",
"exploitCodeMaturity": "NOT_DEFINED",
"integrityImpact": "HIGH",
"integrityRequirement": "NOT_DEFINED",
"modifiedAttackComplexity": "LOW",
"modifiedAttackVector": "NETWORK",
"modifiedAvailabilityImpact": "HIGH",
"modifiedConfidentialityImpact": "HIGH",
"modifiedIntegrityImpact": "HIGH",
"modifiedPrivilegesRequired": "HIGH",
"modifiedScope": "CHANGED",
"modifiedUserInteraction": "NONE",
"privilegesRequired": "HIGH",
"remediationLevel": "NOT_DEFINED",
"reportConfidence": "NOT_DEFINED",
"scope": "CHANGED",
"temporalScore": 9.1,
"temporalSeverity": "CRITICAL",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H",
"version": "3.1",
}
)

with pytest.raises(CVSS3MalformedError):
CVSSV3.get("CVSS:3.7/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H ")

with pytest.raises(CVSS3MalformedError):
CVSSV3.get("")


def test_blank_cvss_printer():
result = cvss_printer("", "")
assert result == "<p class='has-text-black-bis mb-2'></p>"


def test_cvss_printer():
result = cvss_printer("HIGH", "high,medium,low")
assert result == (
"<p class='has-text-black-bis mb-2'>high</p>"
"<p class='has-text-grey mb-2'>medium</p>"
"<p class='has-text-grey mb-2'>low</p>"
)
16 changes: 15 additions & 1 deletion vulnerabilities/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
# See https://github.com/nexB/vulnerablecode for support or download.
# See https://aboutcode.org for more information about nexB OSS projects.
#

import logging
from datetime import datetime

from cvss.exceptions import CVSS2MalformedError
from cvss.exceptions import CVSS3MalformedError
from django.contrib import messages
from django.core.exceptions import ValidationError
from django.core.mail import send_mail
Expand All @@ -26,6 +28,7 @@
from vulnerabilities.forms import PackageSearchForm
from vulnerabilities.forms import VulnerabilitySearchForm
from vulnerabilities.models import VulnerabilityStatusType
from vulnerabilities.severity_systems import SCORING_SYSTEMS
from vulnerabilities.utils import get_severity_range
from vulnerablecode.settings import env

Expand Down Expand Up @@ -132,6 +135,16 @@ def get_context_data(self, **kwargs):
weakness_object for weakness_object in weaknesses if weakness_object.weakness
]
status = self.object.get_status_label

severity_vectors = []
for s in self.object.severities:
if s.scoring_elements and s.scoring_system in SCORING_SYSTEMS:
try:
vector_values = SCORING_SYSTEMS[s.scoring_system].get(s.scoring_elements)
severity_vectors.append(vector_values)
except (CVSS2MalformedError, CVSS3MalformedError, NotImplementedError):
logging.error(f"CVSSMalformedError for {s.scoring_elements}")

context.update(
{
"vulnerability": self.object,
Expand All @@ -140,6 +153,7 @@ def get_context_data(self, **kwargs):
"severity_score_range": get_severity_range(
{s.value for s in self.object.severities}
),
"severity_vectors": severity_vectors,
"references": self.object.references.all(),
"aliases": self.object.aliases.all(),
"affected_packages": self.object.affected_packages.all(),
Expand Down

0 comments on commit 8ca20db

Please sign in to comment.