|
7 | 7 | # See https://aboutcode.org for more information about nexB OSS projects. |
8 | 8 | # |
9 | 9 |
|
| 10 | +import logging |
| 11 | +from pathlib import Path |
10 | 12 | from typing import Iterable |
| 13 | + |
11 | 14 | from packageurl import PackageURL |
| 15 | +from univers import version_range |
12 | 16 |
|
13 | 17 | from vulnerabilities.importer import AdvisoryData |
| 18 | +from vulnerabilities.importer import AffectedPackage |
14 | 19 | from vulnerabilities.importer import GitImporter |
15 | 20 | from vulnerabilities.importer import Reference |
16 | | -from pathlib import Path |
17 | 21 | from vulnerabilities.utils import load_yaml |
18 | | -from vulnerabilities.utils import nearest_patched_package |
| 22 | + |
| 23 | +logger = logging.getLogger(__name__) |
19 | 24 |
|
20 | 25 |
|
21 | 26 | class KaybeeImporter(GitImporter): |
22 | 27 | spdx_license_expression = "MIT" |
23 | 28 | license_url = "https://gitlab.com/gitlab-org/advisories-community/-/blob/main/LICENSE" |
24 | 29 |
|
25 | 30 | def __init__(self): |
26 | | - super().__init__(repo_url="git+https://github.com/SAP/project-kb/tree/vulnerability-data") |
27 | | - |
| 31 | + super().__init__(repo_url="git+https://github.com/SAP/project-kb.git@vulnerability-data") |
| 32 | + |
28 | 33 | def advisory_data(self, _keep_clone=True) -> Iterable[AdvisoryData]: |
29 | 34 | try: |
30 | 35 | self.clone() |
31 | 36 | base_path = Path(self.vcs_response.dest_dir) |
32 | 37 | statements = base_path.glob("statements/**/*.yaml") |
33 | 38 | for statement_file in statements: |
34 | | - yaml_file_to_advisory(statement_file) |
35 | | - |
| 39 | + yield yaml_file_to_advisory(statement_file) |
| 40 | + |
36 | 41 | finally: |
37 | 42 | if self.vcs_response and not _keep_clone: |
38 | 43 | self.vcs_response.delete() |
39 | 44 |
|
40 | 45 |
|
41 | | - |
42 | 46 | def yaml_file_to_advisory(yaml_path): |
43 | 47 | references = [] |
44 | 48 |
|
45 | 49 | data = load_yaml(yaml_path) |
46 | | - vuln_id = data["vulnerability_id"] |
| 50 | + aliases = [] |
| 51 | + vuln_id = data.get("vulnerability_id") |
| 52 | + if vuln_id: |
| 53 | + aliases.append(vuln_id) |
47 | 54 | summary = "" |
48 | | - if data.get("text"): |
49 | | - summary = "\n".join([note["text"] for note in data["notes"]]) |
| 55 | + notes = data.get("notes") |
| 56 | + if notes: |
| 57 | + note_texts = [] |
| 58 | + for note in notes: |
| 59 | + note_text = note.get("text") |
| 60 | + if note_text: |
| 61 | + note_texts.append(note_text) |
| 62 | + summary = "\n".join(note_texts) |
| 63 | + |
| 64 | + affected_packages = [] |
50 | 65 |
|
51 | 66 | for entry in data.get("artifacts", []): |
52 | | - package = PackageURL.from_string(entry["id"]) |
53 | | - if entry["affected"]: |
54 | | - impacted_packages.append(package) |
| 67 | + purl = entry.get("id") |
| 68 | + if not purl: |
| 69 | + continue |
| 70 | + package = PackageURL.from_string(purl) |
| 71 | + version = package.version |
| 72 | + affected_version_range = None |
| 73 | + fixed_version = None |
| 74 | + vrc = version_range.RANGE_CLASS_BY_SCHEMES.get(package.type) |
| 75 | + if not vrc: |
| 76 | + logger.warning(f"Unknown package type {package.type} for {purl} in {vuln_id}") |
| 77 | + continue |
| 78 | + if entry.get("affected"): |
| 79 | + affected_version_range = vrc.from_versions([version]) |
55 | 80 | else: |
56 | | - resolved_packages.append(package) |
| 81 | + fixed_version = vrc.version_class(version) |
| 82 | + versionless_purl = PackageURL( |
| 83 | + type=package.type, |
| 84 | + namespace=package.namespace, |
| 85 | + name=package.name, |
| 86 | + qualifiers=package.qualifiers, |
| 87 | + subpath=package.subpath, |
| 88 | + ) |
| 89 | + affected_packages.append( |
| 90 | + AffectedPackage( |
| 91 | + package=versionless_purl, |
| 92 | + affected_version_range=affected_version_range, |
| 93 | + fixed_version=fixed_version, |
| 94 | + ) |
| 95 | + ) |
57 | 96 |
|
58 | | - for fix in data.get("fixes", []): |
59 | | - for commit in fix["commits"]: |
| 97 | + for fix in data.get("fixes") or []: |
| 98 | + for commit in fix.get("commits") or []: |
60 | 99 | references.append(Reference(url=f"{commit['repository']}/{commit['id']}")) |
61 | 100 |
|
62 | 101 | return AdvisoryData( |
63 | | - vulnerability_id=vuln_id, |
| 102 | + aliases=aliases, |
64 | 103 | summary=summary, |
65 | | - affected_packages=nearest_patched_package(impacted_packages, resolved_packages), |
| 104 | + affected_packages=affected_packages, |
66 | 105 | references=references, |
67 | 106 | ) |
0 commit comments