Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add package context in vulnerability details view #1241

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 18 additions & 23 deletions vulnerabilities/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,28 +356,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/[email protected]?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/[email protected]?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 @@ -431,17 +435,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 @@ -496,6 +489,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 @@ -599,13 +601,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
Loading