26
26
from typing import List
27
27
from typing import Mapping
28
28
from typing import Optional
29
- from typing import Tuple
30
29
31
30
from dateutil import parser as dateparser
32
31
from django .db .models .query import QuerySet
33
32
from packageurl import PackageURL
34
- from univers .version_range import VersionRange
35
33
from univers .version_range import build_range_from_github_advisory_constraint
36
34
37
35
from vulnerabilities import severity_systems
45
43
from vulnerabilities .improver import Improver
46
44
from vulnerabilities .improver import Inference
47
45
from vulnerabilities .models import Advisory
48
- from vulnerabilities .package_managers import ComposerVersionAPI
46
+ from vulnerabilities .package_managers import VERSION_API_CLASSES_BY_PACKAGE_TYPE
49
47
from vulnerabilities .package_managers import GoproxyVersionAPI
50
- from vulnerabilities .package_managers import MavenVersionAPI
51
- from vulnerabilities .package_managers import NugetVersionAPI
52
- from vulnerabilities .package_managers import PypiVersionAPI
53
- from vulnerabilities .package_managers import RubyVersionAPI
54
48
from vulnerabilities .package_managers import VersionAPI
49
+ from vulnerabilities .package_managers import get_api_package_name
55
50
from vulnerabilities .utils import AffectedPackage as LegacyAffectedPackage
56
51
from vulnerabilities .utils import get_affected_packages_by_patched_package
57
52
from vulnerabilities .utils import get_item
58
53
from vulnerabilities .utils import nearest_patched_package
54
+ from vulnerabilities .utils import resolve_version_range
59
55
60
56
logger = logging .getLogger (__name__ )
61
57
129
125
"COMPOSER" : "composer" ,
130
126
"PIP" : "pypi" ,
131
127
"RUBYGEMS" : "gem" ,
132
- "GO" : "golang" ,
128
+ # "GO": "golang",
133
129
}
134
130
135
131
GITHUB_ECOSYSTEM_BY_PACKAGE_TYPE = {
171
167
}
172
168
"""
173
169
174
- VERSION_API_CLASSES = [
175
- MavenVersionAPI ,
176
- NugetVersionAPI ,
177
- ComposerVersionAPI ,
178
- PypiVersionAPI ,
179
- RubyVersionAPI ,
180
- GoproxyVersionAPI ,
181
- ]
182
-
183
- VERSION_API_CLASSES_BY_PACKAGE_TYPE = {cls .package_type : cls for cls in VERSION_API_CLASSES }
184
-
185
170
186
171
class GitHubAPIImporter (Importer ):
187
172
spdx_license_expression = "CC-BY-4.0"
@@ -205,38 +190,6 @@ def advisory_data(self) -> Iterable[AdvisoryData]:
205
190
break
206
191
207
192
208
- def get_reference_id (url : str ):
209
- """
210
- Return the reference id from a URL
211
- For example:
212
- >>> get_reference_id("https://github.com/advisories/GHSA-c9hw-wf7x-jp9j")
213
- 'GHSA-c9hw-wf7x-jp9j'
214
- """
215
- url_parts = url .split ("/" )
216
- last_url_part = url_parts [- 1 ]
217
- return last_url_part
218
-
219
-
220
- def extract_references (reference_data : List [dict ]) -> Iterable [Reference ]:
221
- """
222
- Yield `reference` by iterating over `reference_data`
223
- >>> list(extract_references([{'url': "https://github.com/advisories/GHSA-c9hw-wf7x-jp9j"}]))
224
- [Reference(url="https://github.com/advisories/GHSA-c9hw-wf7x-jp9j"), reference_id = "GHSA-c9hw-wf7x-jp9j" ]
225
- >>> list(extract_references([{'url': "https://github.com/advisories/c9hw-wf7x-jp9j"}]))
226
- [Reference(url="https://github.com/advisories/c9hw-wf7x-jp9j")]
227
- """
228
- for ref in reference_data :
229
- url = ref ["url" ]
230
- if not isinstance (url , str ):
231
- logger .error (f"extract_references: url is not of type `str`: { url } " )
232
- continue
233
- if "GHSA-" in url .upper ():
234
- reference = Reference (url = url , reference_id = get_reference_id (url ))
235
- else :
236
- reference = Reference (url = url )
237
- yield reference
238
-
239
-
240
193
def get_purl (pkg_type : str , github_name : str ) -> Optional [PackageURL ]:
241
194
"""
242
195
Return a PackageURL by splitting the `github_name` using the `pkg_type` convention.
@@ -255,8 +208,7 @@ def get_purl(pkg_type: str, github_name: str) -> Optional[PackageURL]:
255
208
256
209
if pkg_type == "composer" :
257
210
if "/" not in github_name :
258
- logger .error (f"get_purl: Invalid composer package name { github_name } " )
259
- return
211
+ return PackageURL (type = pkg_type , name = github_name )
260
212
vendor , _ , name = github_name .partition ("/" )
261
213
return PackageURL (type = pkg_type , namespace = vendor , name = name )
262
214
@@ -272,26 +224,6 @@ class InvalidVersionRange(Exception):
272
224
"""
273
225
274
226
275
- def get_api_package_name (purl : PackageURL ) -> str :
276
- """
277
- Return the package name expected by the GitHub API given a PackageURL
278
- >>> get_api_package_name(PackageURL(type="maven", namespace="org.apache.commons", name="commons-lang3"))
279
- "org.apache.commons:commons-lang3"
280
- >>> get_api_package_name(PackageURL(type="composer", namespace="foo", name="bar"))
281
- "foo/bar"
282
- """
283
- if purl .type == "maven" :
284
- return f"{ purl .namespace } :{ purl .name } "
285
-
286
- if purl .type == "composer" :
287
- return f"{ purl .namespace } /{ purl .name } "
288
-
289
- if purl .type in ("nuget" , "pypi" , "gem" , "golang" ):
290
- return purl .name
291
-
292
- logger .error (f"get_api_package_name: Unknown PURL { purl !r} " )
293
-
294
-
295
227
def process_response (resp : dict , package_type : str ) -> Iterable [AdvisoryData ]:
296
228
"""
297
229
Yield `AdvisoryData` by taking `resp` and `ecosystem` as input
@@ -349,7 +281,8 @@ def process_response(resp: dict, package_type: str) -> Iterable[AdvisoryData]:
349
281
350
282
references = get_item (advisory , "references" ) or []
351
283
if references :
352
- references : List [Reference ] = list (extract_references (references ))
284
+ urls = (ref ["url" ] for ref in references )
285
+ references = [Reference .from_url (u ) for u in urls ]
353
286
354
287
summary = get_item (advisory , "summary" )
355
288
identifiers = get_item (advisory , "identifiers" ) or []
@@ -451,6 +384,7 @@ def get_inferences(self, advisory_data: AdvisoryData) -> Iterable[Inference]:
451
384
aff_vers , unaff_vers = resolve_version_range (
452
385
affected_version_range = affected_version_range ,
453
386
package_versions = valid_versions ,
387
+ ignorable_versions = WEIRD_IGNORABLE_VERSIONS ,
454
388
)
455
389
affected_purls = [
456
390
PackageURL (type = pkg_type , namespace = pkg_namespace , name = pkg_name , version = version )
@@ -476,37 +410,3 @@ def get_inferences(self, advisory_data: AdvisoryData) -> Iterable[Inference]:
476
410
affected_purls = affected_packages ,
477
411
fixed_purl = fixed_package ,
478
412
)
479
-
480
-
481
- def resolve_version_range (
482
- affected_version_range : VersionRange ,
483
- package_versions : List [str ],
484
- ignorable_versions = WEIRD_IGNORABLE_VERSIONS ,
485
- ) -> Tuple [List [str ], List [str ]]:
486
- """
487
- Given an affected version range and a list of `package_versions`, resolve
488
- which versions are in this range and return a tuple of two lists of
489
- `affected_versions` and `unaffected_versions`.
490
- """
491
- if not affected_version_range :
492
- logger .error (f"affected version range is { affected_version_range !r} " )
493
- return [], []
494
- affected_versions = []
495
- unaffected_versions = []
496
- for package_version in package_versions or []:
497
- if package_version in ignorable_versions :
498
- continue
499
- # Remove whitespace
500
- package_version = package_version .replace (" " , "" )
501
- # Remove leading 'v'
502
- package_version = package_version .lstrip ("vV" )
503
- try :
504
- version = affected_version_range .version_class (package_version )
505
- except Exception :
506
- logger .error (f"Could not parse version { package_version !r} " )
507
- continue
508
- if version in affected_version_range :
509
- affected_versions .append (package_version )
510
- else :
511
- unaffected_versions .append (package_version )
512
- return affected_versions , unaffected_versions
0 commit comments