1616from packageurl import PackageURL
1717from univers .version_range import RANGE_CLASS_BY_SCHEMES
1818from univers .versions import InvalidVersion
19- from univers .versions import PypiVersion
2019from univers .versions import SemverVersion
2120from univers .versions import Version
2221
3029
3130logger = logging .getLogger (__name__ )
3231
32+ PURL_TYPE_BY_OSV_SCHEME = {
33+ "npm" : "npm" ,
34+ "pypi" : "pypi" ,
35+ "maven" : "maven" ,
36+ "nuget" : "nuget" ,
37+ "packagist" : "composer" ,
38+ "rubygems" : "gem" ,
39+ "go" : "golang" ,
40+ "hex" : "hex" ,
41+ "cargo" : "cargo" ,
42+ }
3343
34- def parse_advisory_data (raw_data : dict , supported_ecosystem ) -> Optional [AdvisoryData ]:
44+
45+ def parse_advisory_data (raw_data : dict , supported_ecosystems : List ) -> Optional [AdvisoryData ]:
3546 """
3647 Return an AdvisoryData build from a ``raw_data`` mapping of OSV advisory and
3748 a ``supported_ecosystem`` string.
@@ -53,18 +64,23 @@ def parse_advisory_data(raw_data: dict, supported_ecosystem) -> Optional[Advisor
5364
5465 for affected_pkg in raw_data .get ("affected" ) or []:
5566 purl = get_affected_purl (affected_pkg = affected_pkg , raw_id = raw_id )
56- if purl .type != supported_ecosystem :
67+ if purl .type in PURL_TYPE_BY_OSV_SCHEME .keys ():
68+ purl = purl ._replace (type = PURL_TYPE_BY_OSV_SCHEME [purl .type ])
69+
70+ if purl .type not in supported_ecosystems :
5771 logger .error (f"Unsupported package type: { purl !r} in OSV: { raw_id !r} " )
5872 continue
5973
6074 affected_version_range = get_affected_version_range (
6175 affected_pkg = affected_pkg ,
6276 raw_id = raw_id ,
63- supported_ecosystem = supported_ecosystem ,
77+ supported_ecosystem = purl . type ,
6478 )
6579
6680 for fixed_range in affected_pkg .get ("ranges" ) or []:
67- fixed_version = get_fixed_versions (fixed_range = fixed_range , raw_id = raw_id )
81+ fixed_version = get_fixed_versions (
82+ fixed_range = fixed_range , raw_id = raw_id , supported_ecosystem = purl .type
83+ )
6884
6985 for version in fixed_version :
7086 affected_packages .append (
@@ -74,7 +90,6 @@ def parse_advisory_data(raw_data: dict, supported_ecosystem) -> Optional[Advisor
7490 fixed_version = version ,
7591 )
7692 )
77-
7893 return AdvisoryData (
7994 aliases = aliases ,
8095 summary = summary ,
@@ -113,14 +128,19 @@ def get_severities(raw_data) -> Iterable[VulnerabilitySeverity]:
113128 """
114129 Yield VulnerabilitySeverity extracted from a mapping of OSV ``raw_data``
115130 """
116- for severity in raw_data .get ("severity" ) or []:
117- if severity .get ("type" ) == "CVSS_V3" :
118- vector = severity ["score" ]
119- system = SCORING_SYSTEMS ["cvssv3.1" ]
120- score = system .compute (vector )
121- yield VulnerabilitySeverity (system = system , value = score , scoring_elements = vector )
122- else :
123- logger .error (f"Unsupported severity type: { severity !r} for OSV id: { raw_data ['id' ]!r} " )
131+ try :
132+ for severity in raw_data .get ("severity" ) or []:
133+ if severity .get ("type" ) == "CVSS_V3" :
134+ vector = severity ["score" ]
135+ system = SCORING_SYSTEMS ["cvssv3.1" ]
136+ score = system .compute (vector )
137+ yield VulnerabilitySeverity (system = system , value = score , scoring_elements = vector )
138+ else :
139+ logger .error (
140+ f"Unsupported severity type: { severity !r} for OSV id: { raw_data ['id' ]!r} "
141+ )
142+ except Exception as e :
143+ logger .error (f"Invalid severity { e } " )
124144
125145 ecosystem_specific = raw_data .get ("ecosystem_specific" ) or {}
126146 severity = ecosystem_specific .get ("severity" )
@@ -199,18 +219,19 @@ def get_affected_version_range(affected_pkg, raw_id, supported_ecosystem):
199219 )
200220
201221
202- def get_fixed_versions (fixed_range , raw_id ) -> List [Version ]:
222+ def get_fixed_versions (fixed_range , raw_id , supported_ecosystem ) -> List [Version ]:
203223 """
204224 Return a list of unique fixed univers Versions given a ``fixed_range``
205225 univers VersionRange and a ``raw_id``.
206226
207227 For example::
208228
209- >>> get_fixed_versions(fixed_range={}, raw_id="GHSA-j3f7-7rmc-6wqj")
229+ >>> get_fixed_versions(fixed_range={}, raw_id="GHSA-j3f7-7rmc-6wqj", supported_ecosystem="pypi", )
210230 []
211231 >>> get_fixed_versions(
212232 ... fixed_range={"type": "ECOSYSTEM", "events": [{"fixed": "1.7.0"}]},
213- ... raw_id="GHSA-j3f7-7rmc-6wqj"
233+ ... raw_id="GHSA-j3f7-7rmc-6wqj",
234+ ... supported_ecosystem="pypi",
214235 ... )
215236 [PypiVersion(string='1.7.0')]
216237 """
@@ -221,21 +242,32 @@ def get_fixed_versions(fixed_range, raw_id) -> List[Version]:
221242
222243 fixed_range_type = fixed_range ["type" ]
223244
224- for version in extract_fixed_versions (fixed_range ):
245+ version_class = None
246+ try :
247+ version_class = RANGE_CLASS_BY_SCHEMES [supported_ecosystem ].version_class
248+ except KeyError :
249+ logger .error (
250+ f"Unknown version range for ecosystem { supported_ecosystem } for OSV id: { raw_id !r} "
251+ )
225252
226- # FIXME: ECOSYSTEM does not imply PyPI!!!!
253+ for version in extract_fixed_versions ( fixed_range ):
227254 if fixed_range_type == "ECOSYSTEM" :
228255 try :
229- fixed_versions .append (PypiVersion (version ))
256+ if not version_class :
257+ raise InvalidVersion (
258+ f"Unsupported version for ecosystem: { supported_ecosystem } "
259+ )
260+ fixed_versions .append (version_class (version ))
230261 except InvalidVersion :
231- logger .error (f"Invalid PypiVersion: { version !r} for OSV id: { raw_id !r} " )
262+ logger .error (
263+ f"Invalid version class: { version_class } - { version !r} for OSV id: { raw_id !r} "
264+ )
232265
233266 elif fixed_range_type == "SEMVER" :
234267 try :
235268 fixed_versions .append (SemverVersion (version ))
236269 except InvalidVersion :
237270 logger .error (f"Invalid SemverVersion: { version !r} for OSV id: { raw_id !r} " )
238-
239271 else :
240272 logger .error (f"Unsupported fixed version type: { version !r} for OSV id: { raw_id !r} " )
241273
0 commit comments