Skip to content

Commit 694ceeb

Browse files
authored
Merge branch 'main' into patch-1
2 parents 1b3ff55 + f254b0d commit 694ceeb

9 files changed

Lines changed: 123 additions & 14 deletions

File tree

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ jobs:
3838
pip install -r requirements.txt
3939
4040
- name: Run tests
41-
run: python -m pytest
41+
run: python -m pytest -v -m "not webtest"
4242
env:
4343
# The hostname, username used to communicate with the PostgreSQL service container
4444
POSTGRES_HOST: localhost
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
on:
2+
workflow_dispatch: # allow manual execution
3+
push:
4+
schedule:
5+
# run on every 9 o'clock
6+
- cron: '0 9 * * *'
7+
8+
jobs:
9+
unit_tests:
10+
runs-on: ubuntu-latest
11+
12+
services:
13+
# Label used to access the service container
14+
postgres:
15+
image: postgres
16+
env:
17+
POSTGRES_PASSWORD: vulnerablecode
18+
POSTGRES_DB: vulnerablecode
19+
# Set health checks to wait until postgres has started
20+
options: >-
21+
--health-cmd pg_isready
22+
--health-interval 10s
23+
--health-timeout 5s
24+
--health-retries 5
25+
ports:
26+
# Maps tcp port 5432 on service container to the host
27+
- 5432:5432
28+
steps:
29+
- name: Check out repository code
30+
uses: actions/checkout@v2
31+
32+
- name: Set up Python 3.8
33+
uses: actions/setup-python@v2
34+
with:
35+
python-version: 3.8
36+
37+
- name: Install dependencies
38+
run: |
39+
sudo apt install python3-dev postgresql libpq-dev build-essential libxml2-dev libxslt1-dev
40+
python -m pip install --upgrade pip
41+
pip install -r requirements.txt
42+
43+
- name: Run tests
44+
run: pytest -v -m webtest
45+
env:
46+
# The hostname, username used to communicate with the PostgreSQL service container
47+
POSTGRES_HOST: localhost
48+
VC_DB_USER: postgres
49+
POSTGRES_PORT: 5432
50+
DJANGO_DEV: 1
51+
GH_TOKEN: 1

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ before_script:
1818

1919
script:
2020
- ./manage.py collectstatic
21-
- python -m pytest
21+
- python -m pytest -v -m "not webtest"
2222

2323
notifications:
2424
email: false

README.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ compose. For this you need to have the following installed.
106106
Use ``sudo docker-compose up`` to start VulnerableCode. Then access
107107
VulnerableCode at http://localhost:8000/ or at http://127.0.0.1:8000/
108108

109+
**Important**: Don't forget to run ``sudo docker-compose up -d --no-deps --build web`` to sync your instance after every ``git pull``.
110+
111+
109112
Use ``sudo docker-compose exec web bash`` to access the VulnerableCode
110113
container. From here you can access ``manage.py`` and run management commands
111114
to import data as specified below.

vulnerabilities/helpers.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
import requests
2727
import toml
28+
import urllib3
2829
import yaml
2930

3031
# TODO add logging here
@@ -78,4 +79,22 @@ def create_etag(data_src, url, etag_key):
7879
return True
7980

8081

81-
is_cve = re.compile(r"CVE-\d+-\d+", re.IGNORECASE).match
82+
is_cve = re.compile(r"CVE-\d{4}-\d{4,7}", re.IGNORECASE).match
83+
84+
85+
def requests_with_5xx_retry(max_retries=5, backoff_factor=0.5):
86+
"""
87+
Returns a requests sessions which retries on 5xx errors with
88+
a backoff_factor
89+
"""
90+
retries = urllib3.util.Retry(
91+
total=max_retries,
92+
backoff_factor=backoff_factor,
93+
raise_on_status=True,
94+
status_forcelist=range(500, 600, 1),
95+
)
96+
adapter = requests.adapters.HTTPAdapter(max_retries=retries)
97+
session = requests.Session()
98+
session.mount("https://", adapter)
99+
session.mount("http://", adapter)
100+
return session

vulnerabilities/importers/redhat.py

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

23-
from packageurl import PackageURL
2423
import requests
24+
from packageurl import PackageURL
2525

2626
from vulnerabilities.data_source import Advisory
2727
from vulnerabilities.data_source import DataSource
2828
from vulnerabilities.data_source import DataSourceConfiguration
2929
from vulnerabilities.data_source import Reference
3030
from vulnerabilities.data_source import VulnerabilitySeverity
31+
from vulnerabilities.helpers import requests_with_5xx_retry
3132
from vulnerabilities.severity_systems import scoring_systems
3233

3334

@@ -43,6 +44,9 @@ def updated_advisories(self):
4344
return self.batch_advisories(processed_advisories)
4445

4546

47+
requests_session = requests_with_5xx_retry(max_retries=5, backoff_factor=1)
48+
49+
4650
def fetch():
4751
"""
4852
Return a list of CVE data mappings fetched from the RedHat API.
@@ -58,7 +62,7 @@ def fetch():
5862
current_url = url_template.format(page_no)
5963
try:
6064
print(f"Fetching: {current_url}")
61-
response = requests.get(current_url)
65+
response = requests_session.get(current_url)
6266
if response.status_code != requests.codes.ok:
6367
# TODO: log me
6468
print(f"Failed to fetch results from {current_url}")
@@ -90,7 +94,9 @@ def to_advisory(advisory_data):
9094
bugzilla = advisory_data.get("bugzilla")
9195
if bugzilla:
9296
url = "https://bugzilla.redhat.com/show_bug.cgi?id={}".format(bugzilla)
93-
bugzilla_data = requests.get(f"https://bugzilla.redhat.com/rest/bug/{bugzilla}").json()
97+
bugzilla_data = requests_session.get(
98+
f"https://bugzilla.redhat.com/rest/bug/{bugzilla}"
99+
).json()
94100
if (
95101
bugzilla_data.get("bugs")
96102
and len(bugzilla_data["bugs"])
@@ -115,18 +121,24 @@ def to_advisory(advisory_data):
115121
# See https://access.redhat.com/articles/2130961 for more details.
116122

117123
if "RHSA" in rh_adv.upper():
118-
rhsa_data = requests.get(
124+
rhsa_data = requests_session.get(
119125
f"https://access.redhat.com/hydra/rest/securitydata/cvrf/{rh_adv}.json"
120126
).json() # nopep8
121-
value = rhsa_data["cvrfdoc"]["aggregate_severity"]
122-
rhsa_aggregate_severity = VulnerabilitySeverity(
123-
system=scoring_systems["rhas"],
124-
value=value,
125-
)
127+
128+
rhsa_aggregate_severities = []
129+
if rhsa_data.get("cvrfdoc"):
130+
# not all RHSA errata have a corresponding CVRF document
131+
value = rhsa_data["cvrfdoc"]["aggregate_severity"]
132+
rhsa_aggregate_severities.append(
133+
VulnerabilitySeverity(
134+
system=scoring_systems["rhas"],
135+
value=value,
136+
)
137+
)
126138

127139
references.append(
128140
Reference(
129-
severities=[rhsa_aggregate_severity],
141+
severities=rhsa_aggregate_severities,
130142
url="https://access.redhat.com/errata/{}".format(rh_adv),
131143
reference_id=rh_adv,
132144
)

vulnerabilities/severity_systems.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,10 @@ def as_score(self, value):
8181
url="https://www.first.org/cvss/specification-document#Qualitative-Severity-Rating-Scale",
8282
notes="A textual interpretation of severity. Has values like HIGH, MODERATE etc",
8383
),
84+
"generic_textual": ScoringSystem(
85+
identifier="generic_textual",
86+
name="Generic textual severity rating",
87+
url="",
88+
notes="Severity for unknown scoring systems. Contains generic textual values like High, Low etc",
89+
),
8490
}

vulnerabilities/tests/test_redhat_importer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ def test_to_advisory(self):
139139
}
140140
for adv in data:
141141
with unittest.mock.patch(
142-
"vulnerabilities.importers.redhat.requests.get", return_value=mock_resp
142+
"vulnerabilities.importers.redhat.requests_session.get", return_value=mock_resp
143143
):
144144
adv = redhat.to_advisory(adv)
145145
found_advisories.append(adv)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import pytest
2+
from vulnerabilities import importers
3+
from vulnerabilities.importer_yielder import IMPORTER_REGISTRY
4+
5+
6+
@pytest.mark.webtest
7+
@pytest.mark.parametrize(
8+
("data_source", "config"),
9+
((data["data_source"], data["data_source_cfg"]) for data in IMPORTER_REGISTRY),
10+
)
11+
def test_updated_advisories(data_source, config):
12+
13+
if not data_source == "GitHubAPIDataSource":
14+
data_src = getattr(importers, data_source)
15+
data_src = data_src(batch_size=1, config=config)
16+
with data_src:
17+
for i in data_src.updated_advisories():
18+
pass

0 commit comments

Comments
 (0)