|
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 |
| 12 | +from typing import Iterable |
| 13 | + |
10 | 14 | from packageurl import PackageURL |
| 15 | +from univers import version_range |
11 | 16 |
|
12 | 17 | from vulnerabilities.importer import AdvisoryData |
| 18 | +from vulnerabilities.importer import AffectedPackage |
13 | 19 | from vulnerabilities.importer import GitImporter |
14 | 20 | from vulnerabilities.importer import Reference |
15 | 21 | from vulnerabilities.utils import load_yaml |
16 | | -from vulnerabilities.utils import nearest_patched_package |
| 22 | + |
| 23 | +logger = logging.getLogger(__name__) |
17 | 24 |
|
18 | 25 |
|
19 | 26 | class KaybeeImporter(GitImporter): |
20 | | - def __enter__(self): |
21 | | - super(KaybeeImporter, self).__enter__() |
22 | | - self._added_files, self._updated_files = self.file_changes( |
23 | | - recursive=True, |
24 | | - file_ext="yaml", |
25 | | - ) |
| 27 | + spdx_license_expression = "MIT" |
| 28 | + license_url = "https://gitlab.com/gitlab-org/advisories-community/-/blob/main/LICENSE" |
| 29 | + |
| 30 | + def __init__(self): |
| 31 | + super().__init__(repo_url="git+https://github.com/SAP/project-kb.git@vulnerability-data") |
26 | 32 |
|
27 | | - def updated_advisories(self): |
28 | | - advisories = [] |
29 | | - for yaml_file in self._added_files.union(self._updated_files): |
30 | | - advisories.append(yaml_file_to_advisory(yaml_file)) |
| 33 | + def advisory_data(self, _keep_clone=True) -> Iterable[AdvisoryData]: |
| 34 | + try: |
| 35 | + self.clone() |
| 36 | + base_path = Path(self.vcs_response.dest_dir) |
| 37 | + statements = base_path.glob("statements/**/*.yaml") |
| 38 | + for statement_file in statements: |
| 39 | + yield yaml_file_to_advisory(statement_file) |
31 | 40 |
|
32 | | - return self.batch_advisories(advisories) |
| 41 | + finally: |
| 42 | + if self.vcs_response and not _keep_clone: |
| 43 | + self.vcs_response.delete() |
33 | 44 |
|
34 | 45 |
|
35 | 46 | def yaml_file_to_advisory(yaml_path): |
36 | | - impacted_packages = [] |
37 | | - resolved_packages = [] |
38 | 47 | references = [] |
39 | 48 |
|
40 | 49 | data = load_yaml(yaml_path) |
41 | | - vuln_id = data["vulnerability_id"] |
| 50 | + aliases = [] |
| 51 | + vuln_id = data.get("vulnerability_id") |
| 52 | + if vuln_id: |
| 53 | + aliases.append(vuln_id) |
42 | 54 | summary = "" |
43 | | - if data.get("text"): |
44 | | - 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 = [] |
45 | 65 |
|
46 | 66 | for entry in data.get("artifacts", []): |
47 | | - package = PackageURL.from_string(entry["id"]) |
48 | | - if entry["affected"]: |
49 | | - 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]) |
50 | 80 | else: |
51 | | - 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 | + ) |
52 | 96 |
|
53 | | - for fix in data.get("fixes", []): |
54 | | - for commit in fix["commits"]: |
| 97 | + for fix in data.get("fixes") or []: |
| 98 | + for commit in fix.get("commits") or []: |
55 | 99 | references.append(Reference(url=f"{commit['repository']}/{commit['id']}")) |
56 | 100 |
|
57 | 101 | return AdvisoryData( |
58 | | - vulnerability_id=vuln_id, |
| 102 | + aliases=aliases, |
59 | 103 | summary=summary, |
60 | | - affected_packages=nearest_patched_package(impacted_packages, resolved_packages), |
| 104 | + affected_packages=affected_packages, |
61 | 105 | references=references, |
62 | 106 | ) |
0 commit comments