Skip to content

Commit 257b51f

Browse files
authored
fix(api): support conan purl query (#2961)
fixes #2960 Although OSV.dev currently doesn't have any `ConanCenter` records, it's listed in the OSV schema. So adding support for ConanCenter PURL query. The other ecosystems listed in the comments cannot be converted into PURL strings because they are not defined in the PURL spec. Queries for these ecosystems will return a 400 error with an "unknown PURL ecosystem" message
1 parent 9e88d39 commit 257b51f

File tree

4 files changed

+33
-10
lines changed

4 files changed

+33
-10
lines changed

gcp/api/integration_tests.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,7 @@ def test_query_unknown_purl_invalid_semver(self):
424424

425425
self.assert_results_equal({
426426
'code': 3,
427-
'message': 'Invalid PURL.'
427+
'message': 'Unknown PURL ecosystem.'
428428
}, response.json())
429429

430430
def test_query_semver_no_vulns(self):
@@ -644,7 +644,7 @@ def test_query_with_redundant_ecosystem(self):
644644
self.assert_results_equal(
645645
{
646646
'code': 3,
647-
'message': 'ecosystem specified in a purl query'
647+
'message': 'ecosystem specified in a PURL query'
648648
}, response.json())
649649

650650
def test_query_with_redundant_version(self):
@@ -661,7 +661,7 @@ def test_query_with_redundant_version(self):
661661
self.assert_results_equal(
662662
{
663663
'code': 3,
664-
'message': 'version specified in params and purl query'
664+
'message': 'version specified in params and PURL query'
665665
}, response.json())
666666

667667
def test_query_with_redundant_package_name(self):
@@ -677,7 +677,7 @@ def test_query_with_redundant_package_name(self):
677677
self.assert_results_equal(
678678
{
679679
'code': 3,
680-
'message': 'name specified in a purl query'
680+
'message': 'name specified in a PURL query'
681681
}, response.json())
682682

683683
def test_query_batch(self):

gcp/api/server.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,8 @@ def query_info(query) -> tuple[str, str | None, str | None]:
382382
if query.package.purl:
383383
try:
384384
purl = purl_helpers.parse_purl(query.package.purl) # can raise ValueError
385+
if purl is None:
386+
raise ValueError('purl ecosystem is unknown')
385387
if query.package.ecosystem or query.package.name:
386388
raise ValueError('purl and name/ecosystem cannot both be specified')
387389
if purl.version and query.version:
@@ -732,22 +734,26 @@ def do_query(query: osv_service_v1_pb2.Query,
732734
'Invalid PURL.',
733735
)
734736

737+
if purl is None:
738+
context.service_context.abort(grpc.StatusCode.INVALID_ARGUMENT,
739+
'Unknown PURL ecosystem.')
740+
735741
if package_name: # Purls already include the package name
736742
context.service_context.abort(
737743
grpc.StatusCode.INVALID_ARGUMENT,
738-
'name specified in a purl query',
744+
'name specified in a PURL query',
739745
)
740746
if ecosystem:
741747
# Purls already include the ecosystem inside
742748
context.service_context.abort(
743749
grpc.StatusCode.INVALID_ARGUMENT,
744-
'ecosystem specified in a purl query',
750+
'ecosystem specified in a PURL query',
745751
)
746752
if purl.version and version:
747753
# version included both in purl and query
748754
context.service_context.abort(
749755
grpc.StatusCode.INVALID_ARGUMENT,
750-
'version specified in params and purl query',
756+
'version specified in params and PURL query',
751757
)
752758

753759
ecosystem = purl.ecosystem

osv/purl_helpers.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,23 +27,28 @@
2727
'AlmaLinux': EcosystemPURL('rpm', 'almalinux'),
2828
'Alpine': EcosystemPURL('apk', 'alpine'),
2929
# Android
30+
# Bioconductor
3031
'Bitnami': EcosystemPURL('bitnami', None),
3132
'Chainguard': EcosystemPURL('apk', 'chainguard'),
33+
'ConanCenter': EcosystemPURL('conan', None),
3234
'CRAN': EcosystemPURL('cran', None),
3335
'crates.io': EcosystemPURL('cargo', None),
3436
'Debian': EcosystemPURL('deb', 'debian'),
37+
# GHC
3538
# GIT
3639
'GitHub Actions': EcosystemPURL('github', None),
3740
'Go': EcosystemPURL('golang', None),
3841
'Hackage': EcosystemPURL('hackage', None),
3942
'Hex': EcosystemPURL('hex', None),
4043
# Linux
44+
'Mageia': EcosystemPURL('rpm', 'mageia'),
4145
'Maven': EcosystemPURL('maven', None),
4246
'npm': EcosystemPURL('npm', None),
4347
'NuGet': EcosystemPURL('nuget', None),
4448
'openSUSE': EcosystemPURL('rpm', 'opensuse'),
4549
'OSS-Fuzz': EcosystemPURL('generic', None),
4650
'Packagist': EcosystemPURL('composer', None),
51+
# Photon OS
4752
'Pub': EcosystemPURL('pub', None),
4853
'PyPI': EcosystemPURL('pypi', None),
4954
'Red Hat': EcosystemPURL('rpm', 'redhat'),
@@ -123,7 +128,7 @@ def parse_purl(purl_str: str) -> ParsedPURL | None:
123128
# information (like vendors) and the namespace might be optional.
124129
ecosystem = PURL_ECOSYSTEM_MAP.get(EcosystemPURL(purl.type, None))
125130
if not ecosystem:
126-
raise ValueError('Invalid ecosystem.')
131+
return None
127132

128133
# For ecosystems with optional namespaces, the namespace might need to be
129134
# included as part of the package name.

osv/purl_helpers_test.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,15 @@ def tests_package_to_purl(self):
3535
self.assertEqual('pkg:cran/commonmark',
3636
purl_helpers.package_to_purl('CRAN', 'commonmark'))
3737

38+
self.assertEqual('pkg:conan/openssl',
39+
purl_helpers.package_to_purl('ConanCenter', 'openssl'))
40+
3841
self.assertEqual('pkg:pypi/django',
3942
purl_helpers.package_to_purl('PyPI', 'django'))
4043

44+
self.assertEqual('pkg:rpm/mageia/python-aiohttp',
45+
purl_helpers.package_to_purl('Mageia', 'python-aiohttp'))
46+
4147
self.assertEqual(
4248
'pkg:maven/org.apache.struts/struts2-core',
4349
purl_helpers.package_to_purl('Maven', 'org.apache.struts:struts2-core'))
@@ -146,6 +152,9 @@ def test_parse_purl(self):
146152
self.assertEqual(('CRAN', 'commonmark', None),
147153
purl_helpers.parse_purl('pkg:cran/commonmark'))
148154

155+
self.assertEqual(('ConanCenter', 'openssl', '3.0.3'),
156+
purl_helpers.parse_purl('pkg:conan/[email protected]'))
157+
149158
self.assertEqual(('Debian', 'mpg123', '1.26.4-1+deb11u1'),
150159
purl_helpers.parse_purl(
151160
'pkg:deb/debian/[email protected]+deb11u1?arch=source'))
@@ -163,6 +172,10 @@ def test_parse_purl(self):
163172
self.assertEqual(('Hex', 'acme/foo', '2.3.'),
164173
purl_helpers.parse_purl('pkg:hex/acme/[email protected].'))
165174

175+
self.assertEqual(('Mageia', 'python-aiohttp', None),
176+
purl_helpers.parse_purl(
177+
'pkg:rpm/mageia/python-aiohttp?distro=mageia-9'))
178+
166179
self.assertEqual(('Maven', 'org.apache.struts:struts2-core', '1.0.0'),
167180
purl_helpers.parse_purl(
168181
'pkg:maven/org.apache.struts/[email protected]'))
@@ -221,8 +234,7 @@ def test_parse_purl(self):
221234
('Wolfi', 'test-package', '1.2.3'),
222235
purl_helpers.parse_purl('pkg:apk/wolfi/[email protected]'))
223236

224-
with self.assertRaises(ValueError):
225-
purl_helpers.parse_purl('pkg:bad/ubuntu/pygments')
237+
self.assertIsNone(purl_helpers.parse_purl('pkg:bad/ubuntu/pygments'))
226238

227239
with self.assertRaises(ValueError):
228240
purl_helpers.parse_purl('purl:apk/wolfi/[email protected]')

0 commit comments

Comments
 (0)