Skip to content

Commit

Permalink
Add sorting and filtering by score #95
Browse files Browse the repository at this point in the history
Signed-off-by: tdruez <tdruez@nexb.com>
  • Loading branch information
tdruez committed Aug 23, 2024
1 parent c9f1144 commit 7161375
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 12 deletions.
30 changes: 29 additions & 1 deletion component_catalog/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,19 @@ def show_last_modified_date(self):
return not self.sort_value or self.has_sort_by("last_modified_date")


vulnerability_score_ranges = {
"low": (0.1, 3),
"medium": (4.0, 6.9),
"high": (7.0, 8.9),
"critical": (9.0, 10.0),
}

SCORE_CHOICES = [
(key, f"{key.capitalize()} ({value[0]} - {value[1]})")
for key, value in vulnerability_score_ranges.items()
]


class VulnerabilityFilterSet(DataspacedFilterSet):
q = SearchFilter(
label=_("Search"),
Expand All @@ -284,15 +297,23 @@ class VulnerabilityFilterSet(DataspacedFilterSet):
sort = DefaultOrderingFilter(
label=_("Sort"),
fields=[
"highest_score",
"lowest_score",
"priority",
"vulnerability_id",
"affected_packages_count",
"fixed_packages_length",
"priority",
"created_date",
"last_modified_date",
],
widget=SortDropDownWidget,
)
highest_score = django_filters.ChoiceFilter(
choices=SCORE_CHOICES,
method='filter_by_score_range',
label='Score Range',
help_text='Select a score range to filter.'
)

class Meta:
model = Vulnerability
Expand All @@ -304,3 +325,10 @@ class Meta:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.filters["priority"].extra["widget"] = DropDownRightWidget()
self.filters["highest_score"].extra["widget"] = DropDownRightWidget()

def filter_by_score_range(self, queryset, name, value):
if value in vulnerability_score_ranges:
low, high = vulnerability_score_ranges[value]
return queryset.filter(highest_score__gte=low, highest_score__lte=high)
return queryset
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 5.0.6 on 2024-08-23 11:55

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('component_catalog', '0008_vulnerability_priority'),
]

operations = [
migrations.AddField(
model_name='vulnerability',
name='highest_score',
field=models.FloatField(blank=True, help_text='The highest score of the range.', null=True),
),
migrations.AddField(
model_name='vulnerability',
name='lowest_score',
field=models.FloatField(blank=True, help_text='The lowest score of the range.', null=True),
),
]
41 changes: 41 additions & 0 deletions component_catalog/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2609,6 +2609,16 @@ class Vulnerability(HistoryDateFieldsMixin, DataspacedModel):
output_field=models.IntegerField(),
db_persist=True,
)
highest_score = models.FloatField(
null=True,
blank=True,
help_text=_("The highest score of the range."),
)
lowest_score = models.FloatField(
null=True,
blank=True,
help_text=_("The lowest score of the range."),
)

# The second set of fields are in the context of handling vulnerabilities in DejaCode
class Priority(models.IntegerChoices):
Expand Down Expand Up @@ -2659,15 +2669,46 @@ def add_affected_components(self, components):
"""Assign the ``components`` as affected to this vulnerability."""
self.affected_components.add(*components)

@staticmethod
def range_to_values(self, range_str):
try:
min_str, max_str = score.split('-')
return float(min_str.strip()), float(max_str.strip())
except Exception:
return None, None

@classmethod
def create_from_data(cls, dataspace, data, validate=False, affecting=None):
# severity_range_score = data.get("severity_range_score")
# if severity_range_score:
# min_score, max_score = self.range_to_values(severity_range_score)
# data["lowest_score"] = min_score
# data["highest_score"] = max_score

severities = [
score
for reference in data.get("references")
for score in reference.get("scores", [])
]
scores = cls.get_severity_scores(severities)
data["lowest_score"] = min(scores)
data["highest_score"] = max(scores)

instance = super().create_from_data(user=dataspace, data=data, validate=False)

if affecting:
instance.add_affected(affecting)

return instance

@property
def severity_score_range(self):
if not (self.lowest_score and self.highest_score):
return ""
if self.lowest_score == self.highest_score:
return str(self.highest_score)
return f"{self.lowest_score} - {self.highest_score}"

def get_severities(self):
return [score for reference in self.references for score in reference.get("scores", [])]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,20 @@
{% include 'component_catalog/includes/vulnerability_aliases.html' with aliases=vulnerability.aliases only %}
</td>
<td>
<strong>{{ vulnerability.get_highest_score }}</strong>
<div>Range: {{ vulnerability.get_severity_range }}</div>
</td>
<td>
{% if vulnerability.priority %}
{{ vulnerability.priority }}
{% if vulnerability.lowest_score %}
{{ vulnerability.lowest_score }} -
{% endif %}
{% if vulnerability.highest_score %}
<strong>
{{ vulnerability.highest_score }}
</strong>
{% endif %}
</td>
<!-- <td>-->
<!-- {% if vulnerability.priority %}-->
<!-- {{ vulnerability.priority }}-->
<!-- {% endif %}-->
<!-- </td>-->
<td>
{% if vulnerability.summary %}
{% if vulnerability.summary|length > 120 %}
Expand Down
10 changes: 5 additions & 5 deletions component_catalog/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2491,8 +2491,8 @@ class VulnerabilityListView(
table_headers = (
Header("vulnerability_id", _("Vulnerability")),
Header("aliases", _("Aliases")),
Header("score", _("Severity score"), help_text="TODO"),
Header("priority", _("Priority"), filter="priority"),
Header("highest_score", _("Severity score"), help_text="TODO", filter="highest_score"),
# Header("priority", _("Priority"), filter="priority"),
Header("summary", _("Summary")),
Header("affected_packages_count", "Affected packages", help_text="TODO"),
Header("fixed_packages_length", "Fixed by packages", help_text="TODO"),
Expand All @@ -2517,9 +2517,9 @@ def get_queryset(self):
affected_packages_count=Count("affected_packages"),
)
.order_by(
"priority",
# "highest_score",
# "lowest_score",
# "priority",
"-highest_score",
"-lowest_score",
)
)

Expand Down

0 comments on commit 7161375

Please sign in to comment.