2121# Visit https://github.com/nexB/vulnerablecode/ for support and download.
2222import json
2323import logging
24+ from builtins import set
2425from datetime import datetime
2526from datetime import timezone
2627from io import BytesIO
4546
4647
4748class PyPIImporter (Importer ):
48- spdx_license_expression = "Apache-2 .0"
49+ spdx_license_expression = "CC-BY-4 .0"
4950
5051 def advisory_data (self ) -> Iterable [AdvisoryData ]:
5152 """
@@ -55,32 +56,32 @@ def advisory_data(self) -> Iterable[AdvisoryData]:
5556 4. yield the json file to parse_advisory_data
5657 """
5758 url = "https://osv-vulnerabilities.storage.googleapis.com/PyPI/all.zip"
58- response = requests .get (url ).content
5959 try :
60+ response = requests .get (url ).content
6061 with ZipFile (BytesIO (response )) as zip_file :
6162 for file_name in zip_file .namelist ():
6263 with zip_file .open (file_name ) as f :
6364 vul_info = json .loads (f .read ())
6465 yield parse_advisory_data (vul_info )
6566 except requests .exceptions .RequestException :
66- logger .error (f "Failed to fetch osv-vulnerabilities PyPI: HTTP " )
67+ logger .error ("Failed to fetch osv-vulnerabilities PyPI" )
6768
6869
6970def parse_advisory_data (raw_data : dict ) -> AdvisoryData :
70- if "summary" in raw_data :
71- summary = raw_data ["summary" ]
72- else :
73- summary = ""
71+ summary = raw_data .get ("summary" ) or ""
7472
75- aliases = raw_data ["aliases" ] if "aliases" in raw_data else raw_data ["id" ]
73+ vulnerability_id = raw_data .get ("id" )
74+ vulnerability_aliases = raw_data .get ("aliases" ) or []
75+ vulnerability_aliases .append (vulnerability_id )
76+ aliases = list (dict .fromkeys (vulnerability_aliases ))
7677
7778 if "published" in raw_data :
7879 date_published = datetime .strptime (
7980 raw_data ["published" ][0 :19 ], "%Y-%m-%dT%H:%M:%S"
8081 ).replace (tzinfo = timezone .utc )
8182 else :
8283 date_published = None
83- logger .error ("date_published not found " + raw_data ["id" ])
84+ logger .warning ("date_published not found " + raw_data ["id" ])
8485
8586 severity = []
8687 if "severity" in raw_data :
@@ -92,7 +93,7 @@ def parse_advisory_data(raw_data: dict) -> AdvisoryData:
9293 value = sever_list ["score" ],
9394 )
9495 )
95- elif "ecosystem_specific" in raw_data and "severity" in raw_data ["ecosystem_specific" ]:
96+ if "ecosystem_specific" in raw_data and "severity" in raw_data ["ecosystem_specific" ]:
9697 severity .append (
9798 VulnerabilitySeverity (
9899 system = SCORING_SYSTEMS ["generic_textual" ],
@@ -113,59 +114,59 @@ def parse_advisory_data(raw_data: dict) -> AdvisoryData:
113114 if "affected" in raw_data :
114115 for affected_pkg in raw_data ["affected" ]:
115116 package = affected_pkg ["package" ]
117+
118+ purl = ""
116119 if "ecosystem" in package and "name" in package :
117120 purl = PackageURL (type = package ["ecosystem" ], name = package ["name" ])
121+ if "purl" in package :
122+ try :
123+ purl = PackageURL .from_string (package ["purl" ])
124+ except ValueError :
125+ logger .error (
126+ f"PackageURL ValueError - { raw_data ['id' ] !r} - purl: { package ['purl' ] !r} "
127+ )
118128 else :
119- purl = ""
120129 logger .error (f"purl affected_pkg not found - { raw_data ['id' ] !r} " )
121130
122131 affected_version_range = None
123- if "versions" in affected_pkg :
132+ if "versions" in affected_pkg and len ( affected_pkg [ "versions" ]) < 200 :
124133 affected_version_range = (
125- # HINT: Values larger than 1/3 of a buffer page cannot be indexed.
126- PypiVersionRange (affected_pkg ["versions" ][ slice ( 200 )] )
134+ # HINT: Values larger than 1/3 of a buffer page cannot be indexed.
135+ PypiVersionRange (affected_pkg ["versions" ])
127136 )
128137
129- if "ranges" in affected_pkg :
130- for fix_range in affected_pkg ["ranges" ]:
131- fixed_version = set ()
132- if "type" in fix_range :
133- if fix_range ["type" ] == "ECOSYSTEM" :
134- filter_fixed = list (
135- filter (lambda x : x .keys () == {"fixed" }, fix_range ["events" ])
136- )
137- list_fixed = [i ["fixed" ] for i in filter_fixed ]
138- for i in list_fixed :
139- try :
140- fixed_version .add (PypiVersion (i ))
141- except InvalidVersion :
142- logger .error (
143- f"fixed_version InvalidVersion - PypiVersion - { raw_data ['id' ] !r} "
144- )
145-
146- if fix_range ["type" ] == "SEMVER" :
147- filter_fixed = list (
148- filter (lambda x : x .keys () == {"fixed" }, fix_range ["events" ])
149- )
150- list_fixed = [i ["fixed" ] for i in filter_fixed ]
151-
152- for i in list_fixed :
153- try :
154- fixed_version .add (SemverVersion (i ))
155- except InvalidVersion :
156- logger .error (
157- f"fixed_version InvalidVersion - SemverVersion - { raw_data ['id' ] !r} "
158- )
138+ for fixed_range in affected_pkg .get ("ranges" , []):
139+ fixed_version = set ()
140+ if "type" in fixed_range :
141+ list_fixed = fixed_filter (fixed_range )
142+ for i in list_fixed :
143+ if fixed_range ["type" ] == "ECOSYSTEM" :
144+ try :
145+ fixed_version .add (PypiVersion (i ))
146+ except InvalidVersion :
147+ logger .error (
148+ f"Invalid Version - PypiVersion - { raw_data ['id' ] !r} - { i !r} "
149+ )
150+ if fixed_range ["type" ] == "SEMVER" :
151+ try :
152+ fixed_version .add (SemverVersion (i ))
153+ except InvalidVersion :
154+ logger .error (
155+ f"Invalid Version - SemverVersion - { raw_data ['id' ] !r} - { i !r} "
156+ )
159157
160158 # TODO add GitHubVersion univers fix_version
161- for version in fixed_version :
162- affected_package .append (
163- AffectedPackage (
164- package = purl ,
165- affected_version_range = affected_version_range ,
166- fixed_version = version ,
167- )
159+ else :
160+ logger .error (f"Invalid type - { raw_data ['id' ] !r} " )
161+
162+ for version in fixed_version :
163+ affected_package .append (
164+ AffectedPackage (
165+ package = purl ,
166+ affected_version_range = affected_version_range ,
167+ fixed_version = version ,
168168 )
169+ )
169170 else :
170171 logger .error (f"affected_package not found - { raw_data ['id' ] !r} " )
171172
@@ -176,3 +177,9 @@ def parse_advisory_data(raw_data: dict) -> AdvisoryData:
176177 references = references ,
177178 date_published = date_published ,
178179 )
180+
181+
182+ def fixed_filter (fixed_range ) -> []:
183+ filter_fixed = list (filter (lambda x : x .keys () == {"fixed" }, fixed_range ["events" ]))
184+ list_fixed = [i ["fixed" ] for i in filter_fixed ]
185+ return list_fixed
0 commit comments