diff --git a/component_catalog/models.py b/component_catalog/models.py index 30f3cf1a..a4fa55ac 100644 --- a/component_catalog/models.py +++ b/component_catalog/models.py @@ -2604,10 +2604,7 @@ class Vulnerability(HistoryDateFieldsMixin, DataspacedModel): help_text=_("A list of packages that are not affected by this vulnerability."), ) fixed_packages_length = models.GeneratedField( - expression=models.Func( - models.F('fixed_packages'), - function='jsonb_array_length' - ), + expression=models.Func(models.F("fixed_packages"), function="jsonb_array_length"), output_field=models.IntegerField(), db_persist=True, ) @@ -2656,3 +2653,46 @@ def create_from_data(cls, dataspace, data, validate=False, affecting=None): instance.add_affected(affecting) return instance + + def get_severities(self): + return [score for reference in self.references for score in reference.get("scores", [])] + + # Duplicated from + # https://github.com/aboutcode-org/vulnerablecode/blob/main/vulnerabilities/utils.py + # Until made available in the API https://github.com/aboutcode-org/vulnerablecode/issues/1565 + def get_severity_range(self): + severities = self.get_severities() + if len(severities) < 1: + return + + scores = self.get_severity_scores(severities) + if scores: + return f"{min(scores)} - {max(scores)}" + + @staticmethod + def get_severity_scores(severities): + score_map = { + "low": [0.1, 3], + "moderate": [4.0, 6.9], + "medium": [4.0, 6.9], + "high": [7.0, 8.9], + "important": [7.0, 8.9], + "critical": [9.0, 10.0], + } + + consolidated_scores = [] + for severity in severities: + score = severity.get("value") + try: + consolidated_scores.append(float(score)) + except ValueError: + if score_range := score_map.get(score.lower(), None): + consolidated_scores.extend(score_range) + + return consolidated_scores + + def get_highest_score(self): + severities = self.get_severities() + scores = self.get_severity_scores(severities) + if scores: + return max(scores) diff --git a/component_catalog/templates/component_catalog/includes/vulnerability_list_table.html b/component_catalog/templates/component_catalog/includes/vulnerability_list_table.html index 0d6bf5d2..2a6e5392 100644 --- a/component_catalog/templates/component_catalog/includes/vulnerability_list_table.html +++ b/component_catalog/templates/component_catalog/includes/vulnerability_list_table.html @@ -3,15 +3,14 @@ {% load urlize_target_blank from dje_tags %} {% load naturaltime_short from dje_tags %} - +
{% include 'includes/object_list_table_header.html' %} {% for vulnerability in object_list %} + + diff --git a/component_catalog/views.py b/component_catalog/views.py index fd2285a6..422ed3a7 100644 --- a/component_catalog/views.py +++ b/component_catalog/views.py @@ -2491,9 +2491,10 @@ class VulnerabilityListView( table_headers = ( Header("vulnerability_id", _("Vulnerability")), Header("aliases", _("Aliases")), - # Header("score"), - Header("affected_packages_count", "Affected packages", help_text=" "), - Header("fixed_packages_length", "Fixed by packages", help_text=" "), + Header("score", _("Severity score"), help_text="TODO"), + Header("summary", _("Summary")), + Header("affected_packages_count", "Affected packages", help_text="TODO"), + Header("fixed_packages_length", "Fixed by packages", help_text="TODO"), # Header("affected_product_count", "Affected products"), ) @@ -2501,15 +2502,16 @@ def get_queryset(self): return ( super() .get_queryset() - .only( - "uuid", - "vulnerability_id", - "aliases", - "fixed_packages_length", - "created_date", - "last_modified_date", - "dataspace", - ) + # .only( + # "uuid", + # "vulnerability_id", + # "aliases", + # "summary", + # "fixed_packages_length", + # "created_date", + # "last_modified_date", + # "dataspace", + # ) .annotate( affected_packages_count=Count("affected_packages"), ) @@ -2517,3 +2519,9 @@ def get_queryset(self): "-last_modified_date", ) ) + + def get_context_data(self, **kwargs): + context_data = super().get_context_data(**kwargs) + vulnerablecode = VulnerableCode(self.dataspace) + context_data["vulnerablecode_url"] = vulnerablecode.service_url + return context_data diff --git a/dejacode/static/css/dejacode_bootstrap.css b/dejacode/static/css/dejacode_bootstrap.css index 26bf7b52..1fdd2907 100644 --- a/dejacode/static/css/dejacode_bootstrap.css +++ b/dejacode/static/css/dejacode_bootstrap.css @@ -358,6 +358,15 @@ table.packages-table .column-primary_language { margin-right: 0.3rem; } +/* -- Vulnerability List -- */ +table.vulnerabilities-table .column-vulnerability_id { + width: 220px; +} +table.vulnerabilities-table .column-summary { + width: 300px; + max-width: 300px; +} + /* -- Package Details -- */ textarea.licenseexpressionwidget { height: 62px;
- {# TODO #} - + {{ vulnerability.vulnerability_id }} @@ -20,6 +19,22 @@ {% include 'component_catalog/includes/vulnerability_aliases.html' with aliases=vulnerability.aliases only %} + {{ vulnerability.get_highest_score }} +
Range: {{ vulnerability.get_severity_range }}
+
+ {% if vulnerability.summary %} + {% if vulnerability.summary|length > 120 %} +
+ {{ vulnerability.summary|slice:":120" }}... + {{ vulnerability.summary|slice:"120:" }} +
+ {% else %} + {{ vulnerability.summary }} + {% endif %} + {% endif %} +
{{ vulnerability.affected_packages_count }}