Skip to content

Commit cd3d418

Browse files
committed
Test postgresql importer
Signed-off-by: Tushar Goel <[email protected]>
1 parent 7ecae58 commit cd3d418

File tree

2 files changed

+160
-1
lines changed

2 files changed

+160
-1
lines changed

vulnerabilities/pipelines/v2_importers/postgresql_importer.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,12 @@ def collect_links(self):
6969
def to_advisories(self, data):
7070
advisories = []
7171
soup = BeautifulSoup(data, features="lxml")
72-
table = soup.select("table")[0]
72+
tables = soup.select("table")
73+
74+
if not tables:
75+
return advisories
76+
77+
table = tables[0]
7378

7479
for row in table.select("tbody tr"):
7580
ref_col, affected_col, fixed_col, severity_score_col, desc_col = row.select("td")
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
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+
from unittest.mock import MagicMock
11+
from unittest.mock import patch
12+
13+
import pytest
14+
from univers.versions import SemverVersion
15+
16+
from vulnerabilities.importer import AdvisoryData
17+
from vulnerabilities.pipelines.v2_importers.postgresql_importer import PostgreSQLImporterPipeline
18+
19+
HTML_PAGE_WITH_LINKS = """
20+
<html>
21+
<body>
22+
<h3>Security Advisory</h3>
23+
<p><a href="/support/security/advisory1.html">Advisory 1</a></p>
24+
<h3>Another Advisory</h3>
25+
<p><a href="/support/security/advisory2.html">Advisory 2</a></p>
26+
</body>
27+
</html>
28+
"""
29+
30+
HTML_ADVISORY = """
31+
<html>
32+
<body>
33+
<table>
34+
<tbody>
35+
<tr>
36+
<td>
37+
<span class="nobr"><a href="/support/security/CVE-2022-1234/">CVE-2022-1234</a></span><br>
38+
<a href="/about/news/postgresql-175-169-1513-1418-and-1321-released-3072/">Announcement</a><br>
39+
</td>
40+
<td>10.0, 10.1</td>
41+
<td>10.2</td>
42+
<td><a href="/vector?vector=CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H">9.8</a></td>
43+
<td>Description of the issue</td>
44+
</tr>
45+
</tbody>
46+
</table>
47+
</body>
48+
</html>
49+
"""
50+
51+
52+
@pytest.fixture
53+
def importer():
54+
return PostgreSQLImporterPipeline()
55+
56+
57+
@patch("vulnerabilities.pipelines.v2_importers.postgresql_importer.requests.get")
58+
def test_collect_links(mock_get, importer):
59+
mock_get.return_value.content = HTML_PAGE_WITH_LINKS.encode("utf-8")
60+
61+
importer.collect_links()
62+
63+
assert len(importer.links) == 3 # base + 2 new
64+
assert any("advisory1.html" in link for link in importer.links)
65+
assert any("advisory2.html" in link for link in importer.links)
66+
67+
68+
@patch("vulnerabilities.pipelines.v2_importers.postgresql_importer.requests.get")
69+
def test_advisories_count(mock_get, importer):
70+
mock_get.return_value.content = HTML_PAGE_WITH_LINKS.encode("utf-8")
71+
72+
count = importer.advisories_count()
73+
assert count >= 3
74+
75+
76+
@patch("vulnerabilities.pipelines.v2_importers.postgresql_importer.requests.get")
77+
def test_collect_advisories(mock_get, importer):
78+
importer.links = {
79+
"https://www.postgresql.org/support/security/advisory1.html",
80+
"https://www.postgresql.org/support/security/advisory2.html",
81+
}
82+
83+
mock_get.return_value.content = HTML_ADVISORY.encode("utf-8")
84+
85+
advisories = list(importer.collect_advisories())
86+
87+
assert len(advisories) == 2
88+
advisory = advisories[0]
89+
assert isinstance(advisory, AdvisoryData)
90+
assert advisory.advisory_id == "CVE-2022-1234"
91+
assert "Description of the issue" in advisory.summary
92+
assert len(advisory.references_v2) > 0
93+
assert advisory.affected_packages[0].package.name == "postgresql"
94+
assert str(advisory.affected_packages[0].fixed_version) == "10.2"
95+
assert advisory.affected_packages[0].affected_version_range.contains(SemverVersion("10.0.0"))
96+
assert advisory.affected_packages[0].affected_version_range.contains(SemverVersion("10.1.0"))
97+
98+
99+
@patch("vulnerabilities.pipelines.v2_importers.postgresql_importer.requests.get")
100+
def test_collect_advisories_with_no_fixed_version(mock_get, importer):
101+
no_fix_html = """
102+
<html>
103+
<body>
104+
<table>
105+
<tbody>
106+
<tr>
107+
<td>
108+
<span class="nobr"><a href="/support/security/CVE-2023-5678/">CVE-2023-5678</a></span><br>
109+
<a href="/about/news/postgresql-175-169-1513-1418-and-1321-released-3072/">Announcement</a><br>
110+
</td>
111+
<td>9.5, 9.6</td>
112+
<td></td>
113+
<td></td>
114+
<td>Unpatched issue</td>
115+
</tr>
116+
</tbody>
117+
</table>
118+
</body>
119+
</html>
120+
"""
121+
122+
def side_effect(url, *args, **kwargs):
123+
if "advisory" not in url:
124+
return MagicMock(content=HTML_PAGE_WITH_LINKS.encode("utf-8"))
125+
return MagicMock(content=no_fix_html.encode("utf-8"))
126+
127+
mock_get.side_effect = side_effect
128+
129+
advisories = list(importer.collect_advisories())
130+
131+
assert len(advisories) == 2
132+
advisory = advisories[0]
133+
assert advisory.advisory_id == "CVE-2023-5678"
134+
assert advisory.affected_packages[0].fixed_version is None
135+
assert advisory.affected_packages[0].affected_version_range.contains(SemverVersion("9.5"))
136+
137+
138+
@patch("vulnerabilities.pipelines.v2_importers.postgresql_importer.requests.get")
139+
def test_cvss_parsing(mock_get, importer):
140+
mock_get.side_effect = lambda url, *args, **kwargs: MagicMock(
141+
content=HTML_ADVISORY.encode("utf-8")
142+
)
143+
144+
importer.links = {"https://www.postgresql.org/support/security/advisory1.html"}
145+
146+
advisories = list(importer.collect_advisories())
147+
148+
assert len(advisories) == 1
149+
reference = advisories[0].references_v2[0]
150+
151+
severity = reference.severities[0]
152+
assert severity.system.identifier == "cvssv3"
153+
assert severity.value == "9.8"
154+
assert "AV:N/AC:L/PR:N/UI:N" in severity.scoring_elements

0 commit comments

Comments
 (0)