Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions vulnerabilities/importers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@
from vulnerabilities.pipelines.v2_importers import ruby_importer as ruby_importer_v2
from vulnerabilities.pipelines.v2_importers import suse_score_importer as suse_score_importer_v2
from vulnerabilities.pipelines.v2_importers import ubuntu_osv_importer as ubuntu_osv_importer_v2
from vulnerabilities.pipelines.v2_importers import (
vmware_photon_importer_v2 as vmware_photon_importer_v2,
)
from vulnerabilities.pipelines.v2_importers import vulnrichment_importer as vulnrichment_importer_v2
from vulnerabilities.pipelines.v2_importers import xen_importer as xen_importer_v2
from vulnerabilities.utils import create_registry
Expand Down Expand Up @@ -111,6 +114,7 @@
epss_importer_v2.EPSSImporterPipeline,
gentoo_importer_v2.GentooImporterPipeline,
nginx_importer_v2.NginxImporterPipeline,
vmware_photon_importer_v2.VmwarePhotonImporterPipeline,
debian_importer_v2.DebianImporterPipeline,
mattermost_importer_v2.MattermostImporterPipeline,
apache_tomcat_v2.ApacheTomcatImporterPipeline,
Expand Down
146 changes: 146 additions & 0 deletions vulnerabilities/pipelines/v2_importers/vmware_photon_importer_v2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
#
# Copyright (c) nexB Inc. and others. All rights reserved.
# VulnerableCode is a trademark of nexB Inc.
# SPDX-License-Identifier: Apache-2.0
# See http://www.apache.org/licenses/LICENSE-2.0 for the license text.
# See https://github.com/aboutcode-org/vulnerablecode for support or download.
# See https://aboutcode.org for more information about nexB OSS projects.
#

import json
import re
from typing import Iterable

from packageurl import PackageURL
from univers.version_range import RANGE_CLASS_BY_SCHEMES

from vulnerabilities.importer import AdvisoryDataV2
from vulnerabilities.importer import AffectedPackageV2
from vulnerabilities.importer import VulnerabilitySeverity
from vulnerabilities.pipelines import VulnerableCodeBaseImporterPipelineV2
from vulnerabilities.severity_systems import CVSSV3
from vulnerabilities.utils import fetch_response

PHOTON_URLS = [
"https://packages.vmware.com/photon/photon_cve_metadata/cve_data_photon1.0.json",
"https://packages.vmware.com/photon/photon_cve_metadata/cve_data_photon2.0.json",
"https://packages.vmware.com/photon/photon_cve_metadata/cve_data_photon3.0.json",
"https://packages.vmware.com/photon/photon_cve_metadata/cve_data_photon4.0.json",
"https://packages.vmware.com/photon/photon_cve_metadata/cve_data_photon5.0.json",
]


class VmwarePhotonImporterPipeline(VulnerableCodeBaseImporterPipelineV2):
"""Collect advisories from Vmware Photon Advisory.

Example of advisory
{
"cve_id": "CVE-2020-11979",
"pkg": "apache-ant",
"cve_score": 7.5,
"aff_ver": "all versions before 1.10.8-2.ph1 are vulnerable",
"res_ver": "1.10.8-2.ph1"
}
"""

pipeline_id = "vmware_photon_importer_v2"
spdx_license_expression = "CC BY-SA 4.0"
license_url = "https://creativecommons.org/licenses/by-sa/4.0"
repo_url = "https://packages.vmware.com/photon/photon_cve_metadata"

precedence = 100

@classmethod
def steps(cls):
return (
cls.fetch,
cls.group_records_by_cve,
cls.collect_and_store_advisories,
)

def fetch(self):
self.records = []
for url in PHOTON_URLS:
self.log(f"Fetching `{url}`")
response = fetch_response(url)
if response:
self.records.extend(response.json())
self.log(f"Fetched {len(self.records):,d} total records from {len(PHOTON_URLS)} sources")

def group_records_by_cve(self):
"""
A particular CVE may have more than one record. This method groups records by CVE ID and filters "Not Affected" records.
"""
self.cve_to_records = {}
skipped_non_affected = 0

for record in self.records:
cve_id = record.get("cve_id")

# Skip records that are marked as "Not Affected"
if record.get("status") == "Not Affected":
skipped_non_affected += 1
continue

self.cve_to_records.setdefault(cve_id, []).append(record)

self.log(
f"Grouped {len(self.records):,d} records into {len(self.cve_to_records):,d} unique CVEs "
f"(skipped {skipped_non_affected:,d} non-affected)"
)

def advisories_count(self) -> int:
return len(self.cve_to_records)

def collect_advisories(self) -> Iterable[AdvisoryDataV2]:
rpm_range_cls = RANGE_CLASS_BY_SCHEMES["rpm"]

for cve_id, records in self.cve_to_records.items():
affected_packages = []

for record in records:
pkg_name = record.get("pkg")
aff_ver = record.get("aff_ver")
res_ver = record.get("res_ver")

# Example PURL Format: pkg:rpm/vmware/apache-ant?distro=photon
purl = PackageURL(
type="rpm",
namespace="vmware",
name=pkg_name,
qualifiers={"distro": "photon"},
)

ver_match = re.match(r"all versions before (.+) are vulnerable", aff_ver)
if ver_match:
affected_version_range = rpm_range_cls.from_string(
f"vers:{rpm_range_cls.scheme}/<{ver_match.group(1)}"
)

fixed_version_range = rpm_range_cls.from_versions([res_ver])

affected_packages.append(
AffectedPackageV2(
package=purl,
affected_version_range=affected_version_range,
fixed_version_range=fixed_version_range,
)
)

severities = []
cve_score = records[0].get("cve_score")
severities.append(
VulnerabilitySeverity(
system=CVSSV3,
value=str(cve_score),
scoring_elements="",
)
)

yield AdvisoryDataV2(
advisory_id=cve_id,
affected_packages=affected_packages,
severities=severities,
url=f"https://nvd.nist.gov/vuln/detail/{cve_id}",
original_advisory_text=json.dumps(records, indent=2, ensure_ascii=False),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#
# Copyright (c) nexB Inc. and others. All rights reserved.
# VulnerableCode is a trademark of nexB Inc.
# SPDX-License-Identifier: Apache-2.0
# See http://www.apache.org/licenses/LICENSE-2.0 for the license text.
# See https://github.com/aboutcode-org/vulnerablecode for support or download.
# See https://aboutcode.org for more information about nexB OSS projects.
#

import json
from pathlib import Path
from unittest import TestCase
from unittest.mock import Mock
from unittest.mock import patch

from vulnerabilities.pipelines.v2_importers.vmware_photon_importer_v2 import (
VmwarePhotonImporterPipeline,
)
from vulnerabilities.tests import util_tests

TEST_DATA = Path(__file__).parent.parent.parent / "test_data" / "vmware_photon"


class TestVmwarePhotonImporterPipeline(TestCase):
@patch("vulnerabilities.pipelines.v2_importers.vmware_photon_importer_v2.fetch_response")
def test_collect_advisories(self, mock_fetch):
sample_path = TEST_DATA / "data.json"
sample_data = json.loads(sample_path.read_text(encoding="utf-8"))

def side_effect(url):
if "photon4.0" in url:
return Mock(json=lambda: sample_data)
return None

mock_fetch.side_effect = side_effect

pipeline = VmwarePhotonImporterPipeline()
pipeline.fetch()
pipeline.group_records_by_cve()

advisories = [data.to_dict() for data in list(pipeline.collect_advisories())]
assert len(advisories) == 2

expected_file = TEST_DATA / "expected.json"
util_tests.check_results_against_json(advisories, expected_file)
106 changes: 106 additions & 0 deletions vulnerabilities/tests/test_data/vmware_photon/data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
[
{
"cve_id": "CVE-2024-43853",
"pkg": "linux",
"cve_score": 5.5,
"aff_ver": "all versions before 5.10.224-4.ph4 are vulnerable",
"res_ver": "5.10.224-4.ph4",
"status": "Fixed"
},
{
"cve_id": "CVE-2024-43853",
"pkg": "linux-devel",
"cve_score": 5.5,
"aff_ver": "all versions before 5.10.224-4.ph4 are vulnerable",
"res_ver": "5.10.224-4.ph4",
"status": "Fixed"
},
{
"cve_id": "CVE-2024-43853",
"pkg": "linux-drivers-gpu",
"cve_score": 5.5,
"aff_ver": "all versions before 5.10.224-4.ph4 are vulnerable",
"res_ver": "5.10.224-4.ph4",
"status": "Fixed"
},
{
"cve_id": "CVE-2024-43853",
"pkg": "linux-drivers-sound",
"cve_score": 5.5,
"aff_ver": "all versions before 5.10.224-4.ph4 are vulnerable",
"res_ver": "5.10.224-4.ph4",
"status": "Fixed"
},
{
"cve_id": "CVE-2024-43853",
"pkg": "linux-docs",
"cve_score": 5.5,
"aff_ver": "all versions before 5.10.224-4.ph4 are vulnerable",
"res_ver": "5.10.224-4.ph4",
"status": "Fixed"
},
{
"cve_id": "CVE-2024-43853",
"pkg": "linux-drivers-intel-sgx",
"cve_score": 5.5,
"aff_ver": "all versions before 5.10.224-4.ph4 are vulnerable",
"res_ver": "5.10.224-4.ph4",
"status": "Fixed"
},
{
"cve_id": "CVE-2024-43853",
"pkg": "linux-oprofile",
"cve_score": 5.5,
"aff_ver": "all versions before 5.10.224-4.ph4 are vulnerable",
"res_ver": "5.10.224-4.ph4",
"status": "Fixed"
},
{
"cve_id": "CVE-2024-43853",
"pkg": "linux-tools",
"cve_score": 5.5,
"aff_ver": "all versions before 5.10.224-4.ph4 are vulnerable",
"res_ver": "5.10.224-4.ph4",
"status": "Fixed"
},
{
"cve_id": "CVE-2024-43853",
"pkg": "linux-python3-perf",
"cve_score": 5.5,
"aff_ver": "all versions before 5.10.224-4.ph4 are vulnerable",
"res_ver": "5.10.224-4.ph4",
"status": "Fixed"
},
{
"cve_id": "CVE-2024-43853",
"pkg": "bpftool",
"cve_score": 5.5,
"aff_ver": "all versions before 5.10.224-4.ph4 are vulnerable",
"res_ver": "5.10.224-4.ph4",
"status": "Fixed"
},
{
"cve_id": "CVE-2024-43853",
"pkg": "linux-aws",
"cve_score": 5.5,
"aff_ver": "all versions before 5.10.224-3.ph4 are vulnerable",
"res_ver": "5.10.224-3.ph4",
"status": "Fixed"
},
{
"cve_id": "CVE-2021-45417",
"pkg": "aide",
"cve_score": 7.8,
"aff_ver": "all versions before 0.16.2-3.ph4 are vulnerable",
"res_ver": "0.16.2-3.ph4",
"status": "Fixed"
},
{
"cve_id": "CVE-2018-1085",
"pkg": "ansible",
"cve_score": 9.8,
"aff_ver": "NA",
"res_ver": "NA",
"status": "Not Affected"
}
]
Loading