Skip to content

Commit

Permalink
Refine filters and sorting for the Vulnerabilities tab #98
Browse files Browse the repository at this point in the history
Signed-off-by: tdruez <tdruez@nexb.com>
  • Loading branch information
tdruez committed Nov 25, 2024
1 parent 2c526a3 commit 606fa3a
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 12 deletions.
9 changes: 9 additions & 0 deletions dejacode/static/css/dejacode_bootstrap.css
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,15 @@ table.vulnerabilities-table .column-summary {
#tab_vulnerabilities .column-summary {
width: 300px;
}
#tab_vulnerabilities .column-vulnerability_analyses__state {
min-width: 100px;
}
#tab_vulnerabilities .column-vulnerability_analyses__justification {
min-width: 130px;
}
#tab_vulnerabilities .column-vulnerability_analyses__responses {
min-width: 120px;
}

/* -- Dependency tab -- */
#tab_dependencies .column-for_package {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
{% include 'includes/object_list_table_header.html' with filter=filterset include_actions=True %}
<tbody>
{% for vulnerability in page_obj.object_list %}
{# TODO: Replace this with a value on the object %}
{# TODO: Replace this with a value on the object #}
{% with affected_packages_count=vulnerability.affected_packages.count %}
<tr>
<td rowspan="{{ affected_packages_count }}">
Expand Down
9 changes: 5 additions & 4 deletions product_portfolio/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@
from django.test import TestCase

from guardian.shortcuts import assign_perm
from vulnerabilities.tests import make_vulnerability

from component_catalog.models import Component
from component_catalog.models import ComponentAssignedPackage
from component_catalog.models import Package
from component_catalog.tests import make_package
from dje.models import Dataspace
from dje.models import History
from dje.tests import add_perms
from dje.tests import create_admin
from dje.tests import create_superuser
from component_catalog.tests import make_package
from dje.tests import create_user
from license_library.models import License
from organization.models import Owner
Expand All @@ -41,6 +41,7 @@
from product_portfolio.models import ProductStatus
from product_portfolio.models import ScanCodeProject
from product_portfolio.tests import make_product_package
from vulnerabilities.tests import make_vulnerability
from workflow.models import RequestTemplate


Expand Down Expand Up @@ -504,8 +505,8 @@ def test_product_model_get_vulnerability_qs(self):
package2 = make_package(self.dataspace)
vulnerability1 = make_vulnerability(self.dataspace, affecting=[package1, package2])
vulnerability2 = make_vulnerability(self.dataspace, affecting=[package1, package2])
pp1 = make_product_package(self.product1, package=package1)
pp2 = make_product_package(self.product1, package=package2)
make_product_package(self.product1, package=package1)
make_product_package(self.product1, package=package2)

queryset = self.product1.get_vulnerability_qs()
# Makeing sure the distinct() is properly applied
Expand Down
14 changes: 9 additions & 5 deletions product_portfolio/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@
from product_portfolio.models import ProductPackage
from product_portfolio.models import ProductRelationshipMixin
from product_portfolio.models import ScanCodeProject
from vulnerabilities.filters import VulnerabilityFilterSet
from vulnerabilities.filters import ProductVulnerabilityFilterSet
from vulnerabilities.models import AffectedByVulnerabilityMixin
from vulnerabilities.models import Vulnerability
from vulnerabilities.models import VulnerabilityAnalysis
Expand Down Expand Up @@ -1109,7 +1109,7 @@ class ProductTabVulnerabilitiesView(
query_dict_page_param = "vulnerabilities-page"
tab_id = "vulnerabilities"
table_model = Vulnerability
filterset_class = VulnerabilityFilterSet
filterset_class = ProductVulnerabilityFilterSet
table_headers = (
Header("vulnerability_id", _("Vulnerability")),
Header("exploitability", _("Exploitability"), filter="exploitability"),
Expand All @@ -1119,19 +1119,23 @@ class ProductTabVulnerabilitiesView(
Header(
"vulnerability_analyses__state",
_("Status"),
help_text=_("Exploitability analysis"),
help_text=_("Exploitability analysis status"),
filter="vulnerability_analyses__state",
),
Header(
"vulnerability_analyses__justification",
_("Justification"),
help_text=_("TODO"),
help_text=_("The rationale of why the impact analysis state was asserted."),
filter="vulnerability_analyses__justification",
),
Header(
"vulnerability_analyses__responses",
_("Responses"),
help_text=_("TODO"),
help_text=_(
"A response to the vulnerability by the manufacturer, supplier, or project "
"responsible for the affected component or service."
),
filter="responses",
),
)

Expand Down
40 changes: 38 additions & 2 deletions vulnerabilities/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from dje.widgets import DropDownRightWidget
from dje.widgets import SortDropDownWidget
from vulnerabilities.models import Vulnerability
from vulnerabilities.models import VulnerabilityAnalysisMixin

RISK_SCORE_RANGES = {
"low": (0.1, 2.9),
Expand Down Expand Up @@ -104,8 +105,6 @@ class Meta:
model = Vulnerability
fields = [
"q",
"vulnerability_analyses__state",
"vulnerability_analyses__justification",
"exploitability",
]

Expand All @@ -115,8 +114,45 @@ def __init__(self, *args, **kwargs):
"exploitability",
"weighted_severity",
"risk_score",
]
for field_name in dropdown_fields:
self.filters[field_name].extra["widget"] = DropDownRightWidget(anchor=self.anchor)


# Add few filters specific to the Product Vulnerabilities tab.
class ProductVulnerabilityFilterSet(VulnerabilityFilterSet):
sort = NullsLastOrderingFilter(
label=_("Sort"),
fields=[
"exploitability",
"weighted_severity",
"risk_score",
"affected_packages",
"vulnerability_analyses__state",
],
widget=SortDropDownWidget,
)
responses = django_filters.ChoiceFilter(
field_name="vulnerability_analyses__responses",
lookup_expr="icontains",
choices=VulnerabilityAnalysisMixin.Response.choices,
)

class Meta:
model = Vulnerability
fields = [
"q",
"vulnerability_analyses__state",
"vulnerability_analyses__justification",
"exploitability",
]

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
dropdown_fields = [
"vulnerability_analyses__state",
"vulnerability_analyses__justification",
"responses",
]
for field_name in dropdown_fields:
self.filters[field_name].extra["widget"] = DropDownRightWidget(anchor=self.anchor)

0 comments on commit 606fa3a

Please sign in to comment.