Skip to content

Commit 630e608

Browse files
committed
Add tests to cover scraping
Signed-off-by: Tushar Goel <tushar.goel.dav@gmail.com>
1 parent 040332c commit 630e608

4 files changed

Lines changed: 98 additions & 28 deletions

File tree

vulnerabilities/importers/alpine_linux.py

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,23 @@
3838
from vulnerabilities.references import XsaReference
3939
from vulnerabilities.references import ZbxReference
4040

41+
BASE_URL = "https://secdb.alpinelinux.org/"
42+
4143

4244
class AlpineImporter(Importer):
4345
spdx_license_expression = "CC-BY-SA-4.0"
4446
license_url = "https://secdb.alpinelinux.org/license.txt"
4547

4648
def advisory_data(self) -> Iterable[AdvisoryData]:
4749
advisories = []
48-
advisory_links = fetch_advisory_links()
50+
page_response_content = fetch_response(BASE_URL).content
51+
advisory_directory_links = fetch_advisory_directory_links(page_response_content)
52+
advisory_links = []
53+
for advisory_directory_link in advisory_directory_links:
54+
advisory_directory_page = fetch_response(advisory_directory_link).content
55+
advisory_links.extend(
56+
fetch_advisory_links(advisory_directory_page, advisory_directory_link)
57+
)
4958
for link in advisory_links:
5059
record = fetch_response(link).json()
5160
if not record["packages"]:
@@ -64,34 +73,30 @@ def fetch_response(url):
6473
raise Exception("Failed to fetch data from the URL")
6574

6675

67-
def fetch_advisory_links():
76+
def fetch_advisory_directory_links(page_response_content):
6877
"""
69-
Fetch content from `BASE_URL` and scrape data from it
70-
Take all the alpine versions starting with `v`
71-
collect all the urls for json files in the directory
72-
and return them as `advisory_links`
78+
Return `advisory_directory_links` present in `index_page`
7379
"""
74-
BASE_URL = "https://secdb.alpinelinux.org/"
75-
page_response_content = fetch_response(BASE_URL).content
7680
index_page = BeautifulSoup(page_response_content, features="lxml")
77-
7881
alpine_versions = [link.text for link in index_page.find_all("a") if link.text.startswith("v")]
7982

8083
assert alpine_versions, f"No versions found in {BASE_URL}"
8184

8285
advisory_directory_links = [f"{BASE_URL}{version}" for version in alpine_versions]
8386

84-
advisory_links = []
85-
for advisory_directory_link in advisory_directory_links:
86-
advisory_directory_page = fetch_response(advisory_directory_link).content
87-
advisory_directory_page = BeautifulSoup(advisory_directory_page, features="lxml")
88-
anchor_tags = advisory_directory_page.find_all("a")
89-
assert anchor_tags, f"No anchor tags found in {advisory_directory_link}"
90-
for anchor_tag in anchor_tags:
91-
if anchor_tag.text.endswith("json"):
92-
advisory_links.append(f"{advisory_directory_link}{anchor_tag.text}")
93-
94-
return advisory_links
87+
return advisory_directory_links
88+
89+
90+
def fetch_advisory_links(advisory_directory_page, advisory_directory_link):
91+
"""
92+
Yield json file urls present in `advisory_directory_page`
93+
"""
94+
advisory_directory_page = BeautifulSoup(advisory_directory_page, features="lxml")
95+
anchor_tags = advisory_directory_page.find_all("a")
96+
assert anchor_tags, f"No anchor tags found in {advisory_directory_link}"
97+
for anchor_tag in anchor_tags:
98+
if anchor_tag.text.endswith("json"):
99+
yield f"{advisory_directory_link}{anchor_tag.text}"
95100

96101

97102
def process_record(record: dict) -> List[AdvisoryData]:

vulnerabilities/tests/test_alpine.py

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,26 +22,27 @@
2222
# Visit https://github.com/nexB/vulnerablecode/ for support and download.
2323
import json
2424
import os
25-
from unittest import TestCase
2625

2726
from packageurl import PackageURL
2827
from univers.versions import AlpineLinuxVersion
2928

3029
from vulnerabilities.importer import AdvisoryData
3130
from vulnerabilities.importer import AffectedPackage
31+
from vulnerabilities.importers.alpine_linux import fetch_advisory_directory_links
32+
from vulnerabilities.importers.alpine_linux import fetch_advisory_links
3233
from vulnerabilities.importers.alpine_linux import process_record
3334
from vulnerabilities.references import XsaReference
3435

3536
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
36-
TEST_DATA = os.path.join(BASE_DIR, "test_data", "alpine", "v3.11")
37+
TEST_DATA = os.path.join(BASE_DIR, "test_data", "alpine")
3738

3839

39-
# INVALID VERSIONS
40-
# 1.9.5p2-r0
41-
# 6.6.2p1-r0
42-
# 6.6.4p1-r1
43-
# 4.10-1-r1
4440
def test_process_record():
41+
# INVALID VERSIONS
42+
# 1.9.5p2-r0
43+
# 6.6.2p1-r0
44+
# 6.6.4p1-r1
45+
# 4.10-1-r1
4546
expected_advisories = [
4647
AdvisoryData(
4748
aliases=[],
@@ -456,6 +457,33 @@ def test_process_record():
456457
date_published=None,
457458
),
458459
]
459-
with open(os.path.join(TEST_DATA, "main.json")) as f:
460+
with open(os.path.join(TEST_DATA, os.path.join(TEST_DATA, "v3.11", "main.json"))) as f:
460461
found_advisories = process_record(json.loads(f.read()))
461462
assert found_advisories == expected_advisories
463+
464+
465+
def test_fetch_advisory_directory_links():
466+
expected = [
467+
"https://secdb.alpinelinux.org/v3.10/",
468+
"https://secdb.alpinelinux.org/v3.11/",
469+
"https://secdb.alpinelinux.org/v3.12/",
470+
"https://secdb.alpinelinux.org/v3.13/",
471+
"https://secdb.alpinelinux.org/v3.14/",
472+
"https://secdb.alpinelinux.org/v3.15/",
473+
"https://secdb.alpinelinux.org/v3.2/",
474+
"https://secdb.alpinelinux.org/v3.3/",
475+
"https://secdb.alpinelinux.org/v3.4/",
476+
"https://secdb.alpinelinux.org/v3.5/",
477+
"https://secdb.alpinelinux.org/v3.6/",
478+
"https://secdb.alpinelinux.org/v3.7/",
479+
"https://secdb.alpinelinux.org/v3.8/",
480+
"https://secdb.alpinelinux.org/v3.9/",
481+
]
482+
with open(os.path.join(TEST_DATA, "web_pages", "directory.html")) as f:
483+
assert fetch_advisory_directory_links(f.read()) == expected
484+
485+
486+
def test_fetch_advisory_links():
487+
expected = ["v3.11community.json", "v3.11main.json"]
488+
with open(os.path.join(TEST_DATA, "web_pages", "v3.11.html")) as f:
489+
assert list(fetch_advisory_links(f.read(), "v3.11")) == expected
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
<html>
3+
<head><title>Index of /</title></head>
4+
<body>
5+
<h1>Index of /</h1><hr><pre><a href="../">../</a>
6+
<a href="edge/">edge/</a> 27-Feb-2022 12:30 -
7+
<a href="v3.10/">v3.10/</a> 29-Jul-2021 09:11 -
8+
<a href="v3.11/">v3.11/</a> 23-Nov-2021 23:18 -
9+
<a href="v3.12/">v3.12/</a> 26-Feb-2022 19:25 -
10+
<a href="v3.13/">v3.13/</a> 24-Feb-2022 20:33 -
11+
<a href="v3.14/">v3.14/</a> 24-Feb-2022 20:27 -
12+
<a href="v3.15/">v3.15/</a> 24-Feb-2022 20:18 -
13+
<a href="v3.2/">v3.2/</a> 07-Jun-2021 20:24 -
14+
<a href="v3.3/">v3.3/</a> 07-Jun-2021 20:25 -
15+
<a href="v3.4/">v3.4/</a> 07-Jun-2021 20:25 -
16+
<a href="v3.5/">v3.5/</a> 07-Jun-2021 20:26 -
17+
<a href="v3.6/">v3.6/</a> 21-May-2021 11:55 -
18+
<a href="v3.7/">v3.7/</a> 28-Apr-2021 20:53 -
19+
<a href="v3.8/">v3.8/</a> 28-Apr-2021 20:53 -
20+
<a href="v3.9/">v3.9/</a> 07-Jun-2021 20:05 -
21+
<a href="last-update">last-update</a> 28-Feb-2022 15:17 11
22+
<a href="license.txt">license.txt</a> 25-Jun-2021 19:25 20K
23+
</pre><hr></body>
24+
</html>
25+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
<html>
3+
<head><title>Index of /v3.11/</title></head>
4+
<body>
5+
<h1>Index of /v3.11/</h1><hr><pre><a href="../">../</a>
6+
<a href="community.json">community.json</a> 21-Jun-2021 20:49 28K
7+
<a href="community.yaml">community.yaml</a> 21-Jun-2021 20:49 36K
8+
<a href="main.json">main.json</a> 23-Nov-2021 23:18 48K
9+
<a href="main.yaml">main.yaml</a> 23-Nov-2021 23:18 60K
10+
</pre><hr></body>
11+
</html>
12+

0 commit comments

Comments
 (0)