Skip to content

Commit

Permalink
Add package context in vulnerability details view
Browse files Browse the repository at this point in the history
Signed-off-by: Tushar Goel <tushar.goel.dav@gmail.com>
  • Loading branch information
TG1999 committed Jul 20, 2023
1 parent ff95e09 commit 6c5bb53
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 27 deletions.
41 changes: 18 additions & 23 deletions vulnerabilities/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,28 +341,32 @@ class Meta:
ordering = ["vulnerability", "reference"]


def purl_to_dict(purl: PackageURL):
def purl_to_dict(purl: PackageURL, without_version=False):
"""
Return a dict of purl components suitable for use in a queryset.
We need to have specific empty values for using in querysets because of our peculiar model structure.
For example::
>>> purl_to_dict(PackageURL.from_string("pkg:generic/postgres"))
{'type': 'generic', 'namespace': '', 'name': 'postgres', 'version': '', 'qualifiers': {}, 'subpath': ''}
{'type': 'generic', 'namespace': '', 'name': 'postgres', 'qualifiers': {}, 'subpath': '', 'version': ''}
>>> purl_to_dict(PackageURL.from_string("pkg:generic/postgres/postgres@1.2?foo=bar#baz"))
{'type': 'generic', 'namespace': 'postgres', 'name': 'postgres', 'version': '1.2', 'qualifiers': {'foo': 'bar'}, 'subpath': 'baz'}
{'type': 'generic', 'namespace': 'postgres', 'name': 'postgres', 'qualifiers': {'foo': 'bar'}, 'subpath': 'baz', 'version': '1.2'}
>>> purl_to_dict(purl = PackageURL.from_string("pkg:generic/postgres/postgres@1.2?foo=bar#baz"), without_version=True)
{'type': 'generic', 'namespace': 'postgres', 'name': 'postgres', 'qualifiers': {'foo': 'bar'}, 'subpath': 'baz'}
"""
if isinstance(purl, str):
purl = PackageURL.from_string(purl)

return dict(
lookup = dict(
type=purl.type,
namespace=purl.namespace or "",
name=purl.name,
version=purl.version or "",
qualifiers=purl.qualifiers or {},
subpath=purl.subpath or "",
)
if not without_version:
lookup["version"] = purl.version or ""
return lookup


class PackageQuerySet(BaseQuerySet, PackageURLQuerySet):
Expand Down Expand Up @@ -416,17 +420,6 @@ def with_vulnerability_counts(self):
),
)

def fixing_packages(self, package, with_qualifiers_and_subpath=True):
"""
Return a queryset of packages that are fixing the vulnerability of
``package``.
"""

return self.match_purl(
purl=package.purl,
with_qualifiers_and_subpath=with_qualifiers_and_subpath,
).fixing()

def search(self, query=None):
"""
Return a Package queryset searching for the ``query``.
Expand Down Expand Up @@ -481,6 +474,15 @@ def for_cve(self, cve):
"""
return self.filter(vulnerabilities__vulnerabilityreference__reference_id__exact=cve)

def matching_packages(self, purl):
if not purl:
return self
if not isinstance(purl, PackageURL):
purl = str(purl)
purl = PackageURL.from_string(purl)
lookups = purl_to_dict(purl=purl, without_version=True)
return self.filter(**lookups)


def get_purl_query_lookups(purl):
"""
Expand Down Expand Up @@ -584,13 +586,6 @@ def fixing(self):
# legacy aliases
resolved_to = fixing

@property
def fixed_packages(self):
"""
Return a queryset of packages that are fixed.
"""
return Package.objects.fixing_packages(package=self).distinct()

@property
def is_vulnerable(self) -> bool:
"""
Expand Down
4 changes: 2 additions & 2 deletions vulnerabilities/templates/package_details.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
{% for vulnerability in affected_by_vulnerabilities %}
<tr>
<td>
<a href="{{ vulnerability.get_absolute_url }}" target="_self">{{ vulnerability.vulnerability_id }}</a>
<a href="{{ vulnerability.get_absolute_url }}?package={{package.purl}}" target="_self">{{ vulnerability.vulnerability_id }}</a>
</td>
<td>
{{ vulnerability.summary }}
Expand Down Expand Up @@ -105,7 +105,7 @@
{% for vulnerability in fixing_vulnerabilities %}
<tr>
<td>
<a href="{{ vulnerability.get_absolute_url }}" target="_self">{{ vulnerability.vulnerability_id }}</a>
<a href="{{ vulnerability.get_absolute_url }}?package={{package.purl}}" target="_self">{{ vulnerability.vulnerability_id }}</a>
</td>
<td>
{{ vulnerability.summary }}
Expand Down
13 changes: 11 additions & 2 deletions vulnerabilities/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from django.views import generic
from django.views.generic.detail import DetailView
from django.views.generic.list import ListView
from packageurl import PackageURL

from vulnerabilities import models
from vulnerabilities.forms import ApiUserCreationForm
Expand Down Expand Up @@ -116,15 +117,23 @@ def get_queryset(self):

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
request_query = self.request.GET
package = request_query.get("package")
purl = None
if package:
try:
purl = PackageURL.from_string(package)
except:
purl = None
context.update(
{
"vulnerability": self.object,
"vulnerability_search_form": VulnerabilitySearchForm(self.request.GET),
"severities": list(self.object.severities),
"references": self.object.references.all(),
"aliases": self.object.aliases.all(),
"affected_packages": self.object.affected_packages.all(),
"fixed_by_packages": self.object.fixed_by_packages.all(),
"affected_packages": self.object.affected_packages.matching_packages(purl),
"fixed_by_packages": self.object.fixed_by_packages.matching_packages(purl),
"weaknesses": self.object.weaknesses.all(),
}
)
Expand Down

0 comments on commit 6c5bb53

Please sign in to comment.