diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 98148bf8e..a4714a520 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,14 @@ Release notes ============= +Version v31.1.1 +---------------- + +- We now support incomplete versions for a valid purl in search. For example, + you can now search for ``pkg:nginx/nginx@1`` and get all versions of nginx + starting with ``1``. + + Version v31.1.0 ---------------- diff --git a/vulnerabilities/models.py b/vulnerabilities/models.py index 8310aece0..8e7a4f858 100644 --- a/vulnerabilities/models.py +++ b/vulnerabilities/models.py @@ -417,7 +417,9 @@ def search(self, query=None): 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) + if purl.qualifiers or purl.subpath: + return self.for_purl(purl, with_qualifiers_and_subpath=False) + return qs.filter(package_url__istartswith=query) except ValueError: return qs.filter(package_url__icontains=query) diff --git a/vulnerabilities/tests/test_view.py b/vulnerabilities/tests/test_view.py index 44030408c..c3f15cdf8 100644 --- a/vulnerabilities/tests/test_view.py +++ b/vulnerabilities/tests/test_view.py @@ -34,6 +34,7 @@ def setUp(self): "pkg:nginx/nginx@1.14.1", "pkg:nginx/nginx@1.0.7", "pkg:nginx/nginx@1.0.15", + "pkg:pypi/foo@1", ] self.packages = packages for package in packages: @@ -63,6 +64,65 @@ def test_package_view_with_purl_fragment(self): self.assertEqual(len(pkgs), 1) self.assertEqual(pkgs[0].purl, "pkg:nginx/nginx@1.0.15") + def test_package_view_with_purl_fragment(self): + qs = PackageSearch().get_queryset(query="nginx/nginx") + pkgs = list(qs) + pkgs = [p.purl for p in pkgs] + assert pkgs == [ + "pkg:nginx/nginx@0.6.18", + "pkg:nginx/nginx@1.20.0", + "pkg:nginx/nginx@1.21.0", + "pkg:nginx/nginx@1.20.1", + "pkg:nginx/nginx@1.9.5", + "pkg:nginx/nginx@1.17.2", + "pkg:nginx/nginx@1.17.3", + "pkg:nginx/nginx@1.16.1", + "pkg:nginx/nginx@1.15.5", + "pkg:nginx/nginx@1.15.6", + "pkg:nginx/nginx@1.14.1", + "pkg:nginx/nginx@1.0.7", + "pkg:nginx/nginx@1.0.15", + ] + + def test_package_view_with_valid_purl_without_version(self): + qs = PackageSearch().get_queryset(query="pkg:nginx/nginx") + pkgs = list(qs) + pkgs = [p.purl for p in pkgs] + assert pkgs == [ + "pkg:nginx/nginx@0.6.18", + "pkg:nginx/nginx@1.20.0", + "pkg:nginx/nginx@1.21.0", + "pkg:nginx/nginx@1.20.1", + "pkg:nginx/nginx@1.9.5", + "pkg:nginx/nginx@1.17.2", + "pkg:nginx/nginx@1.17.3", + "pkg:nginx/nginx@1.16.1", + "pkg:nginx/nginx@1.15.5", + "pkg:nginx/nginx@1.15.6", + "pkg:nginx/nginx@1.14.1", + "pkg:nginx/nginx@1.0.7", + "pkg:nginx/nginx@1.0.15", + ] + + def test_package_view_with_valid_purl_and_incomplete_version(self): + qs = PackageSearch().get_queryset(query="pkg:nginx/nginx@1") + pkgs = list(qs) + pkgs = [p.purl for p in pkgs] + assert pkgs == [ + "pkg:nginx/nginx@1.20.0", + "pkg:nginx/nginx@1.21.0", + "pkg:nginx/nginx@1.20.1", + "pkg:nginx/nginx@1.9.5", + "pkg:nginx/nginx@1.17.2", + "pkg:nginx/nginx@1.17.3", + "pkg:nginx/nginx@1.16.1", + "pkg:nginx/nginx@1.15.5", + "pkg:nginx/nginx@1.15.6", + "pkg:nginx/nginx@1.14.1", + "pkg:nginx/nginx@1.0.7", + "pkg:nginx/nginx@1.0.15", + ] + class VulnerabilitySearchTestCase(TestCase): def setUp(self):