Skip to content

Commit 90a379e

Browse files
committed
wip
Signed-off-by: Keshav Priyadarshi <[email protected]>
1 parent 05b26dd commit 90a379e

File tree

3 files changed

+123
-10
lines changed

3 files changed

+123
-10
lines changed

vulnerabilities/pipelines/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ class VulnerableCodeBaseImporterPipelineV2(VulnerableCodePipeline):
261261
spdx_license_expression = None
262262
repo_url = None
263263
ignorable_versions = []
264+
importer_name = None
264265

265266
@classmethod
266267
def steps(cls):
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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 logging
12+
import shutil
13+
import tempfile
14+
from io import DEFAULT_BUFFER_SIZE
15+
from pathlib import Path
16+
from typing import Iterable
17+
from urllib.parse import urljoin
18+
19+
import dateparser
20+
import requests
21+
from dateutil.parser import parse
22+
from extractcode import ExtractError
23+
from fetchcode.vcs import fetch_via_vcs
24+
from packageurl import PackageURL
25+
from univers.version_constraint import VersionConstraint
26+
from univers.version_range import OpensslVersionRange
27+
from univers.version_range import RpmVersionRange
28+
from univers.versions import OpensslVersion
29+
30+
from vulnerabilities.importer import AdvisoryData
31+
from vulnerabilities.importer import AffectedPackageV2
32+
from vulnerabilities.importer import ReferenceV2
33+
from vulnerabilities.importer import VulnerabilitySeverity
34+
from vulnerabilities.pipelines import VulnerableCodeBaseImporterPipelineV2
35+
from vulnerabilities.pipes import extractcode_utils
36+
from vulnerabilities.severity_systems import REDHAT_AGGREGATE
37+
from vulnerabilities.utils import build_description
38+
from vulnerabilities.utils import get_item
39+
from vulnerabilities.utils import load_json
40+
from vulntotal import vulntotal_utils
41+
42+
43+
class OpenSSLImporterPipeline(VulnerableCodeBaseImporterPipelineV2):
44+
"""Import OpenSSL Advisories"""
45+
46+
pipeline_id = "openssl_importer_v2"
47+
spdx_license_expression = "Apache-2.0"
48+
importer_name = "OpenSSL Importer V2"
49+
50+
license_url = "https://github.com/openssl/openssl/blob/master/LICENSE.txt"
51+
repo_url = "git+https://github.com/openssl/release-metadata/"
52+
53+
@classmethod
54+
def steps(cls):
55+
return (
56+
cls.clone,
57+
cls.collect_and_store_advisories,
58+
cls.clean_downloads,
59+
)
60+
61+
def clone(self):
62+
self.log(f"Cloning `{self.repo_url}`")
63+
self.vcs_response = fetch_via_vcs(self.repo_url)
64+
65+
def advisories_count(self):
66+
vuln_directory = Path(self.vcs_response.dest_dir) / "secjson"
67+
return sum(1 for _ in vuln_directory.glob("CVE-*.json"))
68+
69+
def collect_advisories(self) -> Iterable[AdvisoryData]:
70+
vuln_directory = Path(self.vcs_response.dest_dir) / "secjson"
71+
72+
for advisory in vuln_directory.glob("CVE-*.json"):
73+
yield self.to_advisory_data(advisory)
74+
75+
def to_advisory_data(self, file: Path) -> Iterable[AdvisoryData]:
76+
data = load_json(file)
77+
advisory_text = file.read_text()
78+
advisory = get_item(data, "containers", "cna")
79+
description = get_item(advisory, "descriptions", 0, "value")
80+
title = get_item(advisory, "title")
81+
date_published = parse(get_item(advisory, "datePublic"))
82+
83+
affected_packages = []
84+
85+
for affected in get_item(advisory, "affected", 0, "versions") or []:
86+
impact_end = affected.get("lessThan")
87+
impact_start = affected.get("version")
88+
89+
affected_version_range = OpensslVersionRange(
90+
constraints=(
91+
VersionConstraint(comparator=">=", version=OpensslVersion(string=impact_start)),
92+
VersionConstraint(comparator="<", version=OpensslVersion(string=impact_end)),
93+
)
94+
)
95+
fixed_version_range = OpensslVersionRange.from_versions([impact_end])
96+
affected_packages.append(
97+
AffectedPackageV2(
98+
package=PackageURL(type="openssl", name="openssl"),
99+
affected_version_range=affected_version_range,
100+
fixed_version_range=fixed_version_range,
101+
)
102+
)

vulnerabilities/utils.py

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -206,28 +206,38 @@ def __get__(self, owner_self, owner_cls):
206206
return self.fget(owner_cls)
207207

208208

209-
def get_item(dictionary: dict, *attributes):
209+
def get_item(entity: Union[dict, list], *attributes):
210210
"""
211-
Return `item` by going through all the `attributes` present in the `dictionary`
211+
Return `item` by going through all the `attributes` present in the `dictionary/list`
212212
213-
Do a DFS for the `item` in the `dictionary` by traversing the `attributes`
213+
Do a DFS for the `item` in the `dictionary/list` by traversing the `attributes`
214214
and return None if can not traverse through the `attributes`
215215
For example:
216+
>>> assert get_item({'a': {'b': {'c': 'd'}}}, 'a', 'b', 'c') == 'd'
217+
>>> assert get_item({'a': [{'b': {'c': 'd'}}]}, 'a', 0, 'b') == {'c': 'd'}
218+
>>> assert get_item(['b', ['c', ['d']]], 1, 1, 0) == 'd'
216219
>>> get_item({'a': {'b': {'c': 'd'}}}, 'a', 'b', 'c')
217220
'd'
218221
>>> assert(get_item({'a': {'b': {'c': 'd'}}}, 'a', 'b', 'e')) == None
219222
"""
220223
for attribute in attributes:
221-
if not dictionary:
224+
if not entity:
222225
return
223-
if not isinstance(dictionary, dict):
224-
logger.error("dictionary must be of type `dict`")
226+
if not isinstance(entity, (dict, list)):
227+
logger.error(f"Entity must be of type `dict` or `list` not {type(entity)}")
225228
return
226-
if attribute not in dictionary:
227-
logger.error(f"Missing attribute {attribute} in {dictionary}")
229+
if isinstance(entity, dict) and attribute not in entity:
230+
logger.error(f"Missing attribute {attribute} in {entity}")
228231
return
229-
dictionary = dictionary[attribute]
230-
return dictionary
232+
if isinstance(entity, list) and not isinstance(attribute, int):
233+
logger.error(f"List indices must be integers not {type(attribute)}")
234+
return
235+
if isinstance(entity, list) and len(entity) <= attribute:
236+
logger.error(f"Index {attribute} out of range for {entity}")
237+
return
238+
239+
entity = entity[attribute]
240+
return entity
231241

232242

233243
class GitHubTokenError(Exception):

0 commit comments

Comments
 (0)