Skip to content

Commit cfd477b

Browse files
committed
Cleanup codebase and fix minor bugs and other improvements
* Move the implementation of the methods for handling etags and different file formats into a separate `helpers.py` module to prevent code duplication * Fix bugs in the msr2019 importer.
1 parent 1959a22 commit cfd477b

22 files changed

Lines changed: 212 additions & 213 deletions

vulnerabilities/helpers.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Copyright (c) nexB Inc. and others. All rights reserved.
2+
# http://nexb.com and https://github.com/nexB/vulnerablecode/
3+
# The VulnerableCode software is licensed under the Apache License version 2.0.
4+
# Data generated with VulnerableCode require an acknowledgment.
5+
#
6+
# You may not use this software except in compliance with the License.
7+
# You may obtain a copy of the License at: http://apache.org/licenses/LICENSE-2.0
8+
# Unless required by applicable law or agreed to in writing, software distributed
9+
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
10+
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
# specific language governing permissions and limitations under the License.
12+
#
13+
# When you publish or redistribute any data created with VulnerableCode or any VulnerableCode
14+
# derivative work, you must accompany this data with the following acknowledgment:
15+
#
16+
# Generated with VulnerableCode and provided on an "AS IS" BASIS, WITHOUT WARRANTIES
17+
# OR CONDITIONS OF ANY KIND, either express or implied. No content created from
18+
# VulnerableCode should be considered or used as legal advice. Consult an Attorney
19+
# for any legal advice.
20+
# VulnerableCode is a free software from nexB Inc. and others.
21+
# Visit https://github.com/nexB/vulnerablecode/ for support and download.
22+
23+
import json
24+
import requests
25+
import yaml
26+
import pytoml as toml
27+
28+
29+
def load_yaml(path):
30+
with open(path) as f:
31+
return yaml.safe_load(f)
32+
33+
34+
def load_json(path):
35+
with open(path) as f:
36+
return json.load(f)
37+
38+
39+
def load_toml(path):
40+
with open(path) as f:
41+
return toml.load(f)
42+
43+
44+
def create_etag(data_src, url, etag_key):
45+
etag = requests.head(url).headers.get(etag_key)
46+
if not etag:
47+
return True
48+
49+
elif url in data_src.config.etags:
50+
if data_src.config.etags[url] == etag:
51+
return False
52+
53+
data_src.config.etags[url] = etag
54+
return True

vulnerabilities/import_runner.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ class ImportRunner:
9090
Efficiency:
9191
- Bulk inserts should be used whenever possible.
9292
- Checking whether a record already exists should be kept to a minimum
93-
(the data source should know this instead).
93+
(the data source should know this instead).
9494
- All update and select operations must use indexed columns.
9595
"""
9696

vulnerabilities/importer_yielder.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@
188188
'last_run': None,
189189
'data_source': 'ProjectKBMSRDataSource',
190190
'data_source_cfg': {
191-
'etag': {}
191+
'etags': {}
192192
}
193193
},
194194
{
@@ -216,7 +216,7 @@
216216
'last_run': None,
217217
'data_source': 'NginxDataSource',
218218
'data_source_cfg': {
219-
'etag': {}
219+
'etags': {}
220220
},
221221
},
222222
{

vulnerabilities/importers/alpine_linux.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
# for any legal advice.
2121
# VulnerableCode is a free software code scanning tool from nexB Inc. and others.
2222
# Visit https://github.com/nexB/vulnerablecode/ for support and download.
23+
import logging
2324
from typing import Any
2425
from typing import Iterable
2526
from typing import List

vulnerabilities/importers/apache_httpd.py

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
# VulnerableCode is a free software tool from nexB Inc. and others.
2121
# Visit https://github.com/nexB/vulnerablecode/ for support and download.
2222

23-
from dataclasses import dataclass
23+
import dataclasses
2424
from xml.etree import ElementTree
2525

2626
import requests
@@ -29,9 +29,10 @@
2929
from vulnerabilities.data_source import Advisory
3030
from vulnerabilities.data_source import DataSource
3131
from vulnerabilities.data_source import DataSourceConfiguration
32+
from vulnerabilities.helpers import create_etag
3233

3334

34-
@dataclass
35+
@dataclasses.dataclass
3536
class ApacheHTTPDDataSourceConfiguration(DataSourceConfiguration):
3637
etags: dict
3738

@@ -47,25 +48,13 @@ def updated_advisories(self):
4748
# (url, etag) pair. If a (url, etag) already exists then the code
4849
# skips processing the response further to avoid duplicate work
4950

50-
if self.create_etag(self.url):
51+
if create_etag(data_src=self, url=self.url, etag_key="ETag"):
5152
data = fetch_xml(self.url)
5253
advisories = to_advisories(data)
5354
return self.batch_advisories(advisories)
5455

5556
return []
5657

57-
def create_etag(self, url):
58-
etag = requests.head(url).headers.get("ETag")
59-
if not etag:
60-
return True
61-
62-
elif url in self.config.etags:
63-
if self.config.etags[url] == etag:
64-
return False
65-
66-
self.config.etags[url] = etag
67-
return True
68-
6958

7059
def to_advisories(data):
7160
advisories = []

vulnerabilities/importers/debian_oval.py

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535

3636
from vulnerabilities.data_source import OvalDataSource, DataSourceConfiguration
3737
from vulnerabilities.package_managers import DebianVersionAPI
38+
from vulnerabilities.helpers import create_etag
3839

3940

4041
@dataclasses.dataclass
@@ -52,35 +53,24 @@ def __init__(self, *args, **kwargs):
5253
# we could avoid setting translations, and have it
5354
# set by default in the OvalParser, but we don't yet know
5455
# whether all OVAL providers use the same format
55-
self.translations = {'less than': '<'}
56+
self.translations = {"less than": "<"}
5657
self.pkg_manager_api = DebianVersionAPI()
5758

5859
def _fetch(self):
59-
base_url = 'https://www.debian.org/security/oval/'
60-
file_name = 'oval-definitions-{}.xml'
60+
base_url = "https://www.debian.org/security/oval/"
61+
file_name = "oval-definitions-{}.xml"
6162
releases = self.config.releases
6263
for release in releases:
6364
file_url = base_url + file_name.format(release)
64-
if not self.create_etag(file_url):
65+
if not create_etag(data_src=self, url=file_url, etag_key="ETag"):
6566
continue
67+
6668
resp = requests.get(file_url).content
6769
yield (
68-
{'type': 'deb', 'namespace': 'debian',
69-
'qualifiers': {'distro': release}
70-
},
71-
ET.ElementTree(ET.fromstring(resp.decode('utf-8')))
70+
{"type": "deb", "namespace": "debian", "qualifiers": {"distro": release}},
71+
ET.ElementTree(ET.fromstring(resp.decode("utf-8"))),
7272
)
7373
return []
7474

7575
def set_api(self, packages):
7676
asyncio.run(self.pkg_manager_api.load_api(packages))
77-
78-
def create_etag(self, url):
79-
etag = requests.head(url).headers.get('ETag')
80-
if not etag:
81-
return True
82-
elif url in self.config.etags:
83-
if self.config.etags[url] == etag:
84-
return False
85-
self.config.etags[url] = etag
86-
return True

vulnerabilities/importers/kaybee.py

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,12 @@
2020
# VulnerableCode is a free software tool from nexB Inc. and others.
2121
# Visit https://github.com/nexB/vulnerablecode/ for support and download.
2222

23-
import yaml
24-
2523
from packageurl import PackageURL
2624

2725
from vulnerabilities.data_source import GitDataSource
2826
from vulnerabilities.data_source import Advisory
2927
from vulnerabilities.data_source import Reference
28+
from vulnerabilities.helpers import load_yaml
3029

3130

3231
class KaybeeDataSource(GitDataSource):
@@ -36,14 +35,11 @@ def __enter__(self):
3635
recursive=True,
3736
file_ext="yaml",
3837
)
39-
print(self._added_files.union(self._updated_files))
4038

4139
def updated_advisories(self):
4240
advisories = []
4341
for yaml_file in self._added_files.union(self._updated_files):
44-
print(yaml_file)
4542
advisories.append(yaml_file_to_advisory(yaml_file))
46-
print(advisories[-1])
4743

4844
return self.batch_advisories(advisories)
4945

@@ -76,9 +72,3 @@ def yaml_file_to_advisory(yaml_path):
7672
resolved_package_urls=resolved_packages,
7773
vuln_references=references,
7874
)
79-
80-
81-
# TODO refactor all such commonly needed helpers into one single module
82-
def load_yaml(path):
83-
with open(path) as f:
84-
return yaml.safe_load(f)

vulnerabilities/importers/nginx.py

Lines changed: 16 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
1-
# Copyright (c) nexB Inc. and others. All rights reserved.
1+
# Copyright (c) nexB Inc. and others. All rights reserved.
22
# http://nexb.com and https://github.com/nexB/vulnerablecode/
3-
# The VulnerableCode software is licensed under the Apache License version
3+
# The VulnerableCode software is licensed under the Apache License version 2.0.
44
# Data generated with VulnerableCode require an acknowledgment.
55
#
66
# You may not use this software except in compliance with the License.
7-
# You may obtain a copy of the License at: http://apache.org/licenses/LICE
8-
# Unless required by applicable law or agreed to in writing, software dist
9-
# under the License is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES
10-
# CONDITIONS OF ANY KIND, either express or implied. See the License for t
11-
# specific language governing permissions and limitations under the Licens
7+
# You may obtain a copy of the License at: http://apache.org/licenses/LICENSE-2.0
8+
# Unless required by applicable law or agreed to in writing, software distributed
9+
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
10+
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
# specific language governing permissions and limitations under the License.
1212
#
13-
# When you publish or redistribute any data created with VulnerableCode or
14-
# derivative work, you must accompany this data with the following acknowl
13+
# When you publish or redistribute any data created with VulnerableCode or any VulnerableCode
14+
# derivative work, you must accompany this data with the following acknowledgment:
1515
#
16-
# Generated with VulnerableCode and provided on an 'AS IS' BASIS, WITHOUT
17-
# OR CONDITIONS OF ANY KIND, either express or implied. No content create
18-
# VulnerableCode should be considered or used as legal advice. Consult an
16+
# Generated with VulnerableCode and provided on an "AS IS" BASIS, WITHOUT WARRANTIES
17+
# OR CONDITIONS OF ANY KIND, either express or implied. No content created from
18+
# VulnerableCode should be considered or used as legal advice. Consult an Attorney
1919
# for any legal advice.
20-
# VulnerableCode is a free software from nexB Inc. and others.
20+
# VulnerableCode is a free software tool from nexB Inc. and others.
2121
# Visit https://github.com/nexB/vulnerablecode/ for support and download.
2222

2323
import asyncio
@@ -34,11 +34,12 @@
3434
from vulnerabilities.data_source import DataSourceConfiguration
3535
from vulnerabilities.data_source import Reference
3636
from vulnerabilities.package_managers import GitHubTagsAPI
37+
from vulnerabilities.helpers import create_etag
3738

3839

3940
@dataclasses.dataclass
4041
class NginxDataSourceConfiguration(DataSourceConfiguration):
41-
etag: dict
42+
etags: dict
4243

4344

4445
class NginxDataSource(DataSource):
@@ -57,24 +58,12 @@ def set_api(self):
5758

5859
def updated_advisories(self):
5960
advisories = []
60-
if self.create_etag():
61+
if create_etag(data_src=self, url=self.url, etag_key="ETag"):
6162
self.set_api()
6263
data = requests.get(self.url).content
6364
advisories.extend(self.to_advisories(data))
6465
return self.batch_advisories(advisories)
6566

66-
def create_etag(self):
67-
etag = requests.head(self.url).headers.get("ETag")
68-
if not etag:
69-
return True
70-
71-
elif self.url in self.config.etag:
72-
if self.config.etag[self.url] == etag:
73-
return False
74-
75-
self.config.etag[self.url] = etag
76-
return True
77-
7867
def to_advisories(self, data):
7968
advisories = []
8069
soup = BeautifulSoup(data)

vulnerabilities/importers/npm.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Author: Navonil Das (@NavonilDas)
2-
# Copyright (c) 2017 nexB Inc. and others. All rights reserved.
2+
# Copyright (c) nexB Inc. and others. All rights reserved.
33
# http://nexb.com and https://github.com/nexB/vulnerablecode/
44
# The VulnerableCode software is licensed under the Apache License version 2.0.
55
# Data generated with VulnerableCode require an acknowledgment.
@@ -18,11 +18,10 @@
1818
# OR CONDITIONS OF ANY KIND, either express or implied. No content created from
1919
# VulnerableCode should be considered or used as legal advice. Consult an Attorney
2020
# for any legal advice.
21-
# VulnerableCode is a free software code scanning tool from nexB Inc. and others.
21+
# VulnerableCode is a free software from nexB Inc. and others.
2222
# Visit https://github.com/nexB/vulnerablecode/ for support and download.
2323

2424
import asyncio
25-
import json
2625
from typing import Any
2726
from typing import List
2827
from typing import Mapping
@@ -40,6 +39,7 @@
4039
from vulnerabilities.data_source import GitDataSource
4140
from vulnerabilities.data_source import Reference
4241
from vulnerabilities.package_managers import NpmVersionAPI
42+
from vulnerabilities.helpers import load_json
4343

4444
NPM_URL = "https://registry.npmjs.org{}"
4545

@@ -121,7 +121,9 @@ def _versions_to_purls(package_name, versions):
121121

122122

123123
def categorize_versions(
124-
all_versions: Set[str], aff_version_range: str, fixed_version_range: str,
124+
all_versions: Set[str],
125+
aff_version_range: str,
126+
fixed_version_range: str,
125127
) -> Tuple[Set[str], Set[str]]:
126128
"""
127129
Seperate list of affected versions and unaffected versions from all versions
@@ -146,8 +148,3 @@ def categorize_versions(
146148
aff_ver.add(ver)
147149

148150
return aff_ver, fix_ver
149-
150-
151-
def load_json(path):
152-
with open(path) as f:
153-
return json.load(f)

vulnerabilities/importers/nvd.py

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
from vulnerabilities.data_source import DataSource
3333
from vulnerabilities.data_source import DataSourceConfiguration
3434
from vulnerabilities.data_source import Reference
35+
from vulnerabilities.helpers import create_etag
3536

3637

3738
@dataclasses.dataclass
@@ -49,13 +50,13 @@ class NVDDataSource(DataSource):
4950
def updated_advisories(self):
5051
current_year = date.today().year
5152
# NVD json feeds start from 2002.
52-
for year in range(2002, current_year+1):
53+
for year in range(2002, current_year + 1):
5354
download_url = BASE_URL.format(year)
5455
# Etags are like hashes of web responses. We maintain
5556
# (url, etag) mappings in the DB. `create_etag` creates
5657
# (url, etag) pair. If a (url, etag) already exists then the code
5758
# skips processing the response further to avoid duplicate work
58-
if self.create_etag(download_url):
59+
if create_etag(data_src=self, url=download_url, etag_key="etag"):
5960
data = self.fetch(download_url)
6061
yield self.to_advisories(data)
6162

@@ -130,15 +131,3 @@ def extract_cpes(cve_item):
130131
for cpe_data in node.get("cpe_match", []):
131132
cpes.add(cpe_data["cpe23Uri"])
132133
return cpes
133-
134-
def create_etag(self, url):
135-
etag = requests.head(url).headers.get("etag")
136-
if not etag:
137-
# Kind of inaccurate to return True since etag is
138-
# not created
139-
return True
140-
elif url in self.config.etags:
141-
if self.config.etags[url] == etag:
142-
return False
143-
self.config.etags[url] = etag
144-
return True

0 commit comments

Comments
 (0)