Skip to content

Commit 9821d91

Browse files
committed
Add VMware Photon Importer
Signed-off-by: Sampurna Pyne <sampurnapyne1710@gmail.com>
1 parent 2dbbd38 commit 9821d91

5 files changed

Lines changed: 509 additions & 0 deletions

File tree

vulnerabilities/importers/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@
8080
from vulnerabilities.pipelines.v2_importers import ruby_importer as ruby_importer_v2
8181
from vulnerabilities.pipelines.v2_importers import suse_score_importer as suse_score_importer_v2
8282
from vulnerabilities.pipelines.v2_importers import ubuntu_osv_importer as ubuntu_osv_importer_v2
83+
from vulnerabilities.pipelines.v2_importers import (
84+
vmware_photon_importer_v2 as vmware_photon_importer_v2,
85+
)
8386
from vulnerabilities.pipelines.v2_importers import vulnrichment_importer as vulnrichment_importer_v2
8487
from vulnerabilities.pipelines.v2_importers import xen_importer as xen_importer_v2
8588
from vulnerabilities.utils import create_registry
@@ -111,6 +114,7 @@
111114
epss_importer_v2.EPSSImporterPipeline,
112115
gentoo_importer_v2.GentooImporterPipeline,
113116
nginx_importer_v2.NginxImporterPipeline,
117+
vmware_photon_importer_v2.VmwarePhotonImporterPipeline,
114118
debian_importer_v2.DebianImporterPipeline,
115119
mattermost_importer_v2.MattermostImporterPipeline,
116120
apache_tomcat_v2.ApacheTomcatImporterPipeline,
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
#
2+
# Copyright (c) nexB Inc. and others. All rights reserved.
3+
# VulnerableCode is a trademark of nexB Inc.
4+
# SPDX-License-Identifier: Apache-2.0
5+
# See http://www.apache.org/licenses/LICENSE-2.0 for the license text.
6+
# See https://github.com/aboutcode-org/vulnerablecode for support or download.
7+
# See https://aboutcode.org for more information about nexB OSS projects.
8+
#
9+
10+
import json
11+
import re
12+
from typing import Iterable
13+
14+
from packageurl import PackageURL
15+
from univers.version_range import RANGE_CLASS_BY_SCHEMES
16+
17+
from vulnerabilities.importer import AdvisoryDataV2
18+
from vulnerabilities.importer import AffectedPackageV2
19+
from vulnerabilities.importer import VulnerabilitySeverity
20+
from vulnerabilities.pipelines import VulnerableCodeBaseImporterPipelineV2
21+
from vulnerabilities.severity_systems import CVSSV3
22+
from vulnerabilities.utils import fetch_response
23+
24+
PHOTON_URLS = [
25+
"https://packages.vmware.com/photon/photon_cve_metadata/cve_data_photon1.0.json",
26+
"https://packages.vmware.com/photon/photon_cve_metadata/cve_data_photon2.0.json",
27+
"https://packages.vmware.com/photon/photon_cve_metadata/cve_data_photon3.0.json",
28+
"https://packages.vmware.com/photon/photon_cve_metadata/cve_data_photon4.0.json",
29+
"https://packages.vmware.com/photon/photon_cve_metadata/cve_data_photon5.0.json",
30+
]
31+
32+
33+
class VmwarePhotonImporterPipeline(VulnerableCodeBaseImporterPipelineV2):
34+
"""Collect advisories from Vmware Photon Advisory.
35+
36+
Example of advisory
37+
{
38+
"cve_id": "CVE-2020-11979",
39+
"pkg": "apache-ant",
40+
"cve_score": 7.5,
41+
"aff_ver": "all versions before 1.10.8-2.ph1 are vulnerable",
42+
"res_ver": "1.10.8-2.ph1"
43+
}
44+
"""
45+
46+
pipeline_id = "vmware_photon_importer_v2"
47+
spdx_license_expression = "CC BY-SA 4.0"
48+
license_url = "https://creativecommons.org/licenses/by-sa/4.0"
49+
repo_url = "https://packages.vmware.com/photon/photon_cve_metadata"
50+
51+
precedence = 100
52+
53+
@classmethod
54+
def steps(cls):
55+
return (
56+
cls.fetch,
57+
cls.group_records_by_cve,
58+
cls.collect_and_store_advisories,
59+
)
60+
61+
def fetch(self):
62+
self.records = []
63+
for url in PHOTON_URLS:
64+
self.log(f"Fetching `{url}`")
65+
response = fetch_response(url)
66+
if response:
67+
self.records.extend(response.json())
68+
self.log(f"Fetched {len(self.records):,d} total records from {len(PHOTON_URLS)} sources")
69+
70+
def group_records_by_cve(self):
71+
"""
72+
A particular CVE may have more than one record. This method groups records by CVE ID and filters "Not Affected" records.
73+
"""
74+
self.cve_to_records = {}
75+
skipped_non_affected = 0
76+
77+
for record in self.records:
78+
cve_id = record.get("cve_id")
79+
80+
# Skip records that are marked as "Not Affected"
81+
if record.get("status") == "Not Affected":
82+
skipped_non_affected += 1
83+
continue
84+
85+
self.cve_to_records.setdefault(cve_id, []).append(record)
86+
87+
self.log(
88+
f"Grouped {len(self.records):,d} records into {len(self.cve_to_records):,d} unique CVEs "
89+
f"(skipped {skipped_non_affected:,d} non-affected)"
90+
)
91+
92+
def advisories_count(self) -> int:
93+
return len(self.cve_to_records)
94+
95+
def collect_advisories(self) -> Iterable[AdvisoryDataV2]:
96+
rpm_range_cls = RANGE_CLASS_BY_SCHEMES["rpm"]
97+
98+
for cve_id, records in self.cve_to_records.items():
99+
affected_packages = []
100+
101+
for record in records:
102+
pkg_name = record.get("pkg")
103+
aff_ver = record.get("aff_ver")
104+
res_ver = record.get("res_ver")
105+
106+
# Example PURL Format: pkg:rpm/vmware/apache-ant?distro=photon
107+
purl = PackageURL(
108+
type="rpm",
109+
namespace="vmware",
110+
name=pkg_name,
111+
qualifiers={"distro": "photon"},
112+
)
113+
114+
ver_match = re.match(r"all versions before (.+) are vulnerable", aff_ver)
115+
if ver_match:
116+
affected_version_range = rpm_range_cls.from_string(
117+
f"vers:{rpm_range_cls.scheme}/<{ver_match.group(1)}"
118+
)
119+
120+
fixed_version_range = rpm_range_cls.from_versions([res_ver])
121+
122+
affected_packages.append(
123+
AffectedPackageV2(
124+
package=purl,
125+
affected_version_range=affected_version_range,
126+
fixed_version_range=fixed_version_range,
127+
)
128+
)
129+
130+
severities = []
131+
cve_score = records[0].get("cve_score")
132+
severities.append(
133+
VulnerabilitySeverity(
134+
system=CVSSV3,
135+
value=str(cve_score),
136+
scoring_elements="",
137+
)
138+
)
139+
140+
yield AdvisoryDataV2(
141+
advisory_id=cve_id,
142+
affected_packages=affected_packages,
143+
severities=severities,
144+
url=f"https://nvd.nist.gov/vuln/detail/{cve_id}",
145+
original_advisory_text=json.dumps(records, indent=2, ensure_ascii=False),
146+
)
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#
2+
# Copyright (c) nexB Inc. and others. All rights reserved.
3+
# VulnerableCode is a trademark of nexB Inc.
4+
# SPDX-License-Identifier: Apache-2.0
5+
# See http://www.apache.org/licenses/LICENSE-2.0 for the license text.
6+
# See https://github.com/aboutcode-org/vulnerablecode for support or download.
7+
# See https://aboutcode.org for more information about nexB OSS projects.
8+
#
9+
10+
import json
11+
from pathlib import Path
12+
from unittest import TestCase
13+
from unittest.mock import Mock
14+
from unittest.mock import patch
15+
16+
from vulnerabilities.pipelines.v2_importers.vmware_photon_importer_v2 import (
17+
VmwarePhotonImporterPipeline,
18+
)
19+
from vulnerabilities.tests import util_tests
20+
21+
TEST_DATA = Path(__file__).parent.parent.parent / "test_data" / "vmware_photon"
22+
23+
24+
class TestVmwarePhotonImporterPipeline(TestCase):
25+
@patch("vulnerabilities.pipelines.v2_importers.vmware_photon_importer_v2.fetch_response")
26+
def test_collect_advisories(self, mock_fetch):
27+
sample_path = TEST_DATA / "data.json"
28+
sample_data = json.loads(sample_path.read_text(encoding="utf-8"))
29+
30+
def side_effect(url):
31+
if "photon4.0" in url:
32+
return Mock(json=lambda: sample_data)
33+
return None
34+
35+
mock_fetch.side_effect = side_effect
36+
37+
pipeline = VmwarePhotonImporterPipeline()
38+
pipeline.fetch()
39+
pipeline.group_records_by_cve()
40+
41+
advisories = [data.to_dict() for data in list(pipeline.collect_advisories())]
42+
assert len(advisories) == 2
43+
44+
expected_file = TEST_DATA / "expected.json"
45+
util_tests.check_results_against_json(advisories, expected_file)
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
[
2+
{
3+
"cve_id": "CVE-2024-43853",
4+
"pkg": "linux",
5+
"cve_score": 5.5,
6+
"aff_ver": "all versions before 5.10.224-4.ph4 are vulnerable",
7+
"res_ver": "5.10.224-4.ph4",
8+
"status": "Fixed"
9+
},
10+
{
11+
"cve_id": "CVE-2024-43853",
12+
"pkg": "linux-devel",
13+
"cve_score": 5.5,
14+
"aff_ver": "all versions before 5.10.224-4.ph4 are vulnerable",
15+
"res_ver": "5.10.224-4.ph4",
16+
"status": "Fixed"
17+
},
18+
{
19+
"cve_id": "CVE-2024-43853",
20+
"pkg": "linux-drivers-gpu",
21+
"cve_score": 5.5,
22+
"aff_ver": "all versions before 5.10.224-4.ph4 are vulnerable",
23+
"res_ver": "5.10.224-4.ph4",
24+
"status": "Fixed"
25+
},
26+
{
27+
"cve_id": "CVE-2024-43853",
28+
"pkg": "linux-drivers-sound",
29+
"cve_score": 5.5,
30+
"aff_ver": "all versions before 5.10.224-4.ph4 are vulnerable",
31+
"res_ver": "5.10.224-4.ph4",
32+
"status": "Fixed"
33+
},
34+
{
35+
"cve_id": "CVE-2024-43853",
36+
"pkg": "linux-docs",
37+
"cve_score": 5.5,
38+
"aff_ver": "all versions before 5.10.224-4.ph4 are vulnerable",
39+
"res_ver": "5.10.224-4.ph4",
40+
"status": "Fixed"
41+
},
42+
{
43+
"cve_id": "CVE-2024-43853",
44+
"pkg": "linux-drivers-intel-sgx",
45+
"cve_score": 5.5,
46+
"aff_ver": "all versions before 5.10.224-4.ph4 are vulnerable",
47+
"res_ver": "5.10.224-4.ph4",
48+
"status": "Fixed"
49+
},
50+
{
51+
"cve_id": "CVE-2024-43853",
52+
"pkg": "linux-oprofile",
53+
"cve_score": 5.5,
54+
"aff_ver": "all versions before 5.10.224-4.ph4 are vulnerable",
55+
"res_ver": "5.10.224-4.ph4",
56+
"status": "Fixed"
57+
},
58+
{
59+
"cve_id": "CVE-2024-43853",
60+
"pkg": "linux-tools",
61+
"cve_score": 5.5,
62+
"aff_ver": "all versions before 5.10.224-4.ph4 are vulnerable",
63+
"res_ver": "5.10.224-4.ph4",
64+
"status": "Fixed"
65+
},
66+
{
67+
"cve_id": "CVE-2024-43853",
68+
"pkg": "linux-python3-perf",
69+
"cve_score": 5.5,
70+
"aff_ver": "all versions before 5.10.224-4.ph4 are vulnerable",
71+
"res_ver": "5.10.224-4.ph4",
72+
"status": "Fixed"
73+
},
74+
{
75+
"cve_id": "CVE-2024-43853",
76+
"pkg": "bpftool",
77+
"cve_score": 5.5,
78+
"aff_ver": "all versions before 5.10.224-4.ph4 are vulnerable",
79+
"res_ver": "5.10.224-4.ph4",
80+
"status": "Fixed"
81+
},
82+
{
83+
"cve_id": "CVE-2024-43853",
84+
"pkg": "linux-aws",
85+
"cve_score": 5.5,
86+
"aff_ver": "all versions before 5.10.224-3.ph4 are vulnerable",
87+
"res_ver": "5.10.224-3.ph4",
88+
"status": "Fixed"
89+
},
90+
{
91+
"cve_id": "CVE-2021-45417",
92+
"pkg": "aide",
93+
"cve_score": 7.8,
94+
"aff_ver": "all versions before 0.16.2-3.ph4 are vulnerable",
95+
"res_ver": "0.16.2-3.ph4",
96+
"status": "Fixed"
97+
},
98+
{
99+
"cve_id": "CVE-2018-1085",
100+
"pkg": "ansible",
101+
"cve_score": 9.8,
102+
"aff_ver": "NA",
103+
"res_ver": "NA",
104+
"status": "Not Affected"
105+
}
106+
]

0 commit comments

Comments
 (0)