Skip to content

Commit 17a2d08

Browse files
authored
Merge pull request #1065 from TG1999/fix_serach_regression
Support incomplete versions for a valid purl in search
2 parents f3058d1 + 386b587 commit 17a2d08

File tree

4 files changed

+95
-4
lines changed

4 files changed

+95
-4
lines changed

CHANGELOG.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ Version v31.1.1
66
---------------
77

88
- We re-enabled support for the Apache HTTPD security advisories importer.
9+
- We now support incomplete versions for a valid purl in search. For example,
10+
you can now search for ``pkg:nginx/nginx@1`` and get all versions of nginx
11+
starting with ``1``.
912

1013

1114
Version v31.1.0

vulnerabilities/models.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
from vulnerabilities.improver import MAX_CONFIDENCE
3737
from vulnerabilities.severity_systems import SCORING_SYSTEMS
3838
from vulnerabilities.utils import build_vcid
39+
from vulnerabilities.utils import remove_qualifiers_and_subpath
3940

4041
logger = logging.getLogger(__name__)
4142

@@ -417,7 +418,8 @@ def search(self, query=None):
417418
try:
418419
# if it's a valid purl, use it as is
419420
purl = PackageURL.from_string(query)
420-
return self.for_purl(purl, with_qualifiers_and_subpath=False)
421+
purl = str(remove_qualifiers_and_subpath(purl))
422+
return qs.filter(package_url__istartswith=purl)
421423
except ValueError:
422424
return qs.filter(package_url__icontains=query)
423425

@@ -427,10 +429,9 @@ def for_purl(self, purl, with_qualifiers_and_subpath=True):
427429
"""
428430
if not isinstance(purl, PackageURL):
429431
purl = PackageURL.from_string(purl)
430-
purl = purl_to_dict(purl)
431432
if not with_qualifiers_and_subpath:
432-
del purl["qualifiers"]
433-
del purl["subpath"]
433+
remove_qualifiers_and_subpath(purl)
434+
purl = purl_to_dict(purl)
434435
return self.filter(**purl)
435436

436437
def with_cpes(self):

vulnerabilities/tests/test_view.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def setUp(self):
3434
"pkg:nginx/[email protected]",
3535
"pkg:nginx/[email protected]",
3636
"pkg:nginx/[email protected]",
37+
"pkg:pypi/foo@1",
3738
]
3839
self.packages = packages
3940
for package in packages:
@@ -63,6 +64,77 @@ def test_package_view_with_purl_fragment(self):
6364
self.assertEqual(len(pkgs), 1)
6465
self.assertEqual(pkgs[0].purl, "pkg:nginx/[email protected]")
6566

67+
def test_package_view_with_purl_fragment(self):
68+
qs = PackageSearch().get_queryset(query="nginx/nginx")
69+
pkgs = list(qs)
70+
pkgs = [p.purl for p in pkgs]
71+
assert pkgs == [
72+
"pkg:nginx/[email protected]",
73+
"pkg:nginx/[email protected]",
74+
"pkg:nginx/[email protected]",
75+
"pkg:nginx/[email protected]",
76+
"pkg:nginx/[email protected]",
77+
"pkg:nginx/[email protected]",
78+
"pkg:nginx/[email protected]",
79+
"pkg:nginx/[email protected]",
80+
"pkg:nginx/[email protected]",
81+
"pkg:nginx/[email protected]",
82+
"pkg:nginx/[email protected]",
83+
"pkg:nginx/[email protected]",
84+
"pkg:nginx/[email protected]",
85+
]
86+
87+
def test_package_view_with_valid_purl_without_version(self):
88+
qs = PackageSearch().get_queryset(query="pkg:nginx/nginx")
89+
pkgs = list(qs)
90+
pkgs = [p.purl for p in pkgs]
91+
assert pkgs == [
92+
"pkg:nginx/[email protected]",
93+
"pkg:nginx/[email protected]",
94+
"pkg:nginx/[email protected]",
95+
"pkg:nginx/[email protected]",
96+
"pkg:nginx/[email protected]",
97+
"pkg:nginx/[email protected]",
98+
"pkg:nginx/[email protected]",
99+
"pkg:nginx/[email protected]",
100+
"pkg:nginx/[email protected]",
101+
"pkg:nginx/[email protected]",
102+
"pkg:nginx/[email protected]",
103+
"pkg:nginx/[email protected]",
104+
"pkg:nginx/[email protected]",
105+
]
106+
107+
def test_package_view_with_valid_purl_and_incomplete_version(self):
108+
qs = PackageSearch().get_queryset(query="pkg:nginx/nginx@1")
109+
pkgs = list(qs)
110+
pkgs = [p.purl for p in pkgs]
111+
assert pkgs == [
112+
"pkg:nginx/[email protected]",
113+
"pkg:nginx/[email protected]",
114+
"pkg:nginx/[email protected]",
115+
"pkg:nginx/[email protected]",
116+
"pkg:nginx/[email protected]",
117+
"pkg:nginx/[email protected]",
118+
"pkg:nginx/[email protected]",
119+
"pkg:nginx/[email protected]",
120+
"pkg:nginx/[email protected]",
121+
"pkg:nginx/[email protected]",
122+
"pkg:nginx/[email protected]",
123+
"pkg:nginx/[email protected]",
124+
]
125+
126+
def test_package_view_with_purl_type(self):
127+
qs = PackageSearch().get_queryset(query="pkg:pypi")
128+
pkgs = list(qs)
129+
pkgs = [p.purl for p in pkgs]
130+
assert pkgs == ["pkg:pypi/foo@1"]
131+
132+
def test_package_view_with_type_as_input(self):
133+
qs = PackageSearch().get_queryset(query="pypi")
134+
pkgs = list(qs)
135+
pkgs = [p.purl for p in pkgs]
136+
assert pkgs == ["pkg:pypi/foo@1"]
137+
66138

67139
class VulnerabilitySearchTestCase(TestCase):
68140
def setUp(self):

vulnerabilities/utils.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,3 +420,18 @@ def fetch_response(url):
420420
if response.status_code == 200:
421421
return response
422422
raise Exception(f"Failed to fetch data from {url!r} with status code: {response.status_code!r}")
423+
424+
425+
# This should be a method on PackageURL
426+
def remove_qualifiers_and_subpath(purl):
427+
"""
428+
Return a package URL without qualifiers and subpath
429+
"""
430+
if not isinstance(purl, PackageURL):
431+
purl = PackageURL.from_string(purl)
432+
return PackageURL(
433+
type=purl.type,
434+
namespace=purl.namespace,
435+
name=purl.name,
436+
version=purl.version,
437+
)

0 commit comments

Comments
 (0)