Skip to content

Commit b263b47

Browse files
pombredannesbs2001
authored andcommitted
Make RedHat CVE import more robust
This importer failed at times toward the end of the fetch step when reaching (and trying repeatidly) to re-fetch the last page. The fix consists in fetching larger batches at once (10K instead of 1k) which measn fewer API calls and less risk to be throttled and properly handling exceptions and HTTP response codes and breaking rather than retrying. This also adds some minimal logging. Signed-off-by: Philippe Ombredanne <pombredanne@nexb.com>
1 parent 0a10bb3 commit b263b47

1 file changed

Lines changed: 37 additions & 18 deletions

File tree

vulnerabilities/importers/redhat.py

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -38,40 +38,57 @@ class RedhatDataSource(DataSource):
3838
CONFIG_CLASS = DataSourceConfiguration
3939

4040
def __enter__(self):
41-
self.redhat_response = fetch()
4241

43-
def updated_advisories(self):
44-
processed_advisories = []
45-
for advisory_data in self.redhat_response:
46-
processed_advisories.append(to_advisory(advisory_data))
42+
self.redhat_cves = fetch()
4743

44+
def updated_advisories(self):
45+
processed_advisories = list(map(to_advisory, self.redhat_cves))
4846
return self.batch_advisories(processed_advisories)
4947

5048

5149
def fetch():
52-
53-
response = []
50+
"""
51+
Return a list of CVE data mappings fetched from the RedHat API.
52+
See:
53+
https://access.redhat.com/documentation/en-us/red_hat_security_data_api/1.0/html/red_hat_security_data_api/index
54+
"""
55+
cves = []
5456
page_no = 1
55-
url = "https://access.redhat.com/hydra/rest/securitydata/cve.json?page={}"
57+
url_template = "https://access.redhat.com/hydra/rest/securitydata/cve.json?per_page=10000&page={}"
5658

59+
cve_data = None
5760
while True:
58-
resp_json = requests.get(url.format(page_no)).json()
59-
page_no += 1
60-
if not resp_json:
61+
current_url = url_template.format(page_no)
62+
try:
63+
print(f'Fetching: {current_url}')
64+
response = requests.get(current_url)
65+
if response.status_code != requests.codes.ok:
66+
# TODO: log me
67+
print(f'Failed to fetch results from {current_url}')
68+
break
69+
cve_data = response.json()
70+
except Exception as e:
71+
# TODO: log me
72+
msg = f'Failed to fetch results from {current_url}:\n{e}'
73+
print(msg)
6174
break
6275

63-
for advisory in resp_json:
64-
response.append(advisory)
76+
if not cve_data:
77+
break
78+
cves.extend(cve_data)
79+
page_no += 1
6580

66-
return response
81+
print(f'Fetched {len(cves)} CVEs from: {current_url}')
82+
return cves
6783

6884

6985
def to_advisory(advisory_data):
7086
affected_purls = []
7187
if advisory_data.get("affected_packages"):
7288
for rpm in advisory_data["affected_packages"]:
73-
if rpm_to_purl(rpm):
74-
affected_purls.append(rpm_to_purl(rpm))
89+
purl = rpm_to_purl(rpm)
90+
if purl:
91+
affected_purls.append(purl)
7592

7693
references = []
7794
bugzilla = advisory_data.get("bugzilla")
@@ -137,14 +154,16 @@ def to_advisory(advisory_data):
137154
references.append(Reference(severities=redhat_scores, url=advisory_data["resource_url"]))
138155

139156
return Advisory(
157+
cve_id=advisory_data["CVE"],
140158
summary=advisory_data["bugzilla_description"],
141-
vulnerability_id=advisory_data["CVE"],
142159
impacted_package_urls=affected_purls,
143160
vuln_references=references,
144161
)
145162

146163

147164
def rpm_to_purl(rpm_string):
165+
# FIXME: there is code in scancode to handle RPM conversion AND this should
166+
# be all be part of the pcakageurl library
148167

149168
# Red Hat uses `-:0` instead of just `-` to separate
150169
# package name and version
@@ -155,4 +174,4 @@ def rpm_to_purl(rpm_string):
155174
name, version = components
156175

157176
if version[0].isdigit():
158-
return PackageURL(name=name, type="rpm", version=version, namespace="redhat")
177+
return PackageURL(namespace="redhat", name=name, type="rpm", version=version)

0 commit comments

Comments
 (0)