Skip to content

Commit

Permalink
Merge pull request #1033 from TG1999/fix/1032
Browse files Browse the repository at this point in the history
Handle purl fragments in package search #1032
  • Loading branch information
TG1999 authored Dec 28, 2022
2 parents 465a171 + 5791236 commit 5dabfc9
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 47 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ Version v31.1.0

- We re-enabled support for the NPM vulnerabilities advisories importer.
- We re-enabled support for the Retiredotnet vulnerabilities advisories importer.
- We are now handling purl fragments in package search. For example:
you can now serch using queries in the UI like this : `[email protected]`,
`cherrypy` or `pkg:pypi`.


Version v31.0.0
Expand Down
55 changes: 8 additions & 47 deletions vulnerabilities/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,61 +412,22 @@ def search(self, query=None):
query = query and query.strip()
if not query:
return self.none()

qs = self
if not query.startswith("pkg:"):
# treat this as a plain search
qs = qs.filter(Q(name__icontains=query) | Q(namespace__icontains=query))
else:
# this looks like a purl: check if it quacks like a purl
purl_type = namespace = name = version = None

_, _scheme, remainder = query.partition("pkg:")
remainder = remainder.strip()
if not remainder:
return qs.none()

try:
# First, treat the query as a syntactically-correct purl
purl = PackageURL.from_string(query)
purl_type, namespace, name, version, _quals, _subp = purl.to_dict().values()
except ValueError:
# Otherwise, attempt a more lenient parsing of a possibly partial purl
if "/" in remainder:
purl_type, _scheme, ns_name = remainder.partition("/")
ns_name = ns_name.strip()
if ns_name:
if "/" in ns_name:
namespace, _, name = ns_name.partition("/")
else:
name = ns_name
name = name.strip()
if name:
if "@" in name:
name, _, version = name.partition("@")
version = version.strip()
name = name.strip()
else:
purl_type = remainder

if purl_type:
qs = qs.filter(type__iexact=purl_type)
if namespace:
qs = qs.filter(namespace__iexact=namespace)
if name:
qs = qs.filter(name__iexact=name)
if version:
qs = qs.filter(version__iexact=version)

return qs

try:
# if it's a valid purl, use it as is
purl = PackageURL.from_string(query)
return self.for_purl(purl, with_qualifiers_and_subpath=False)
except ValueError:
return qs.filter(package_url__icontains=query)

def for_purl(self, purl, with_qualifiers_and_subpath=True):
"""
Return a queryset matching the ``purl`` Package URL.
"""
if not isinstance(purl, PackageURL):
purl = PackageURL.from_string(purl)
purl = purl.to_dict()
purl = purl_to_dict(purl)
if not with_qualifiers_and_subpath:
del purl["qualifiers"]
del purl["subpath"]
Expand Down
6 changes: 6 additions & 0 deletions vulnerabilities/tests/test_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ def test_package_view(self):
self.assertEqual(len(pkgs), 1)
self.assertEqual(pkgs[0].purl, "pkg:nginx/[email protected]")

def test_package_view_with_purl_fragment(self):
qs = PackageSearch().get_queryset(query="[email protected]")
pkgs = list(qs)
self.assertEqual(len(pkgs), 1)
self.assertEqual(pkgs[0].purl, "pkg:nginx/[email protected]")


class VulnerabilitySearchTestCase(TestCase):
def setUp(self):
Expand Down

0 comments on commit 5dabfc9

Please sign in to comment.