|
9 | 9 | # |
10 | 10 |
|
11 | 11 | import os |
12 | | -import shutil |
13 | | -import tempfile |
14 | | -import zipfile |
15 | | -from unittest.mock import patch |
16 | 12 |
|
17 | | -from django.test import TestCase |
18 | | - |
19 | | -from vulnerabilities import models |
20 | | -from vulnerabilities.import_runner import ImportRunner |
21 | | -from vulnerabilities.importers.npm import categorize_versions |
22 | | -from vulnerabilities.package_managers import NpmVersionAPI |
23 | | -from vulnerabilities.package_managers import Version |
| 13 | +from vulnerabilities.importers.npm import NpmImporter |
| 14 | +from vulnerabilities.tests import util_tests |
24 | 15 |
|
25 | 16 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) |
26 | 17 | TEST_DATA = os.path.join(BASE_DIR, "test_data/") |
27 | 18 |
|
28 | 19 |
|
29 | | -MOCK_VERSION_API = NpmVersionAPI( |
30 | | - cache={ |
31 | | - "jquery": {Version("3.4.0"), Version("3.8.0")}, |
32 | | - "kerberos": {Version("0.5.8"), Version("1.2.0")}, |
33 | | - "@hapi/subtext": { |
34 | | - Version("3.7.0"), |
35 | | - Version("4.1.1"), |
36 | | - Version("6.1.3"), |
37 | | - Version("7.0.0"), |
38 | | - Version("7.0.5"), |
39 | | - }, |
40 | | - } |
41 | | -) |
42 | | - |
43 | | - |
44 | | -@patch("vulnerabilities.importers.NpmImporter._update_from_remote") |
45 | | -class NpmImportTest(TestCase): |
46 | | - |
47 | | - tempdir = None |
48 | | - |
49 | | - @classmethod |
50 | | - def setUpClass(cls) -> None: |
51 | | - cls.tempdir = tempfile.mkdtemp() |
52 | | - zip_path = os.path.join(TEST_DATA, "npm.zip") |
53 | | - |
54 | | - with zipfile.ZipFile(zip_path, "r") as zip_ref: |
55 | | - zip_ref.extractall(cls.tempdir) |
56 | | - |
57 | | - cls.importer = models.Importer.objects.create( |
58 | | - name="npm_unittests", |
59 | | - license="", |
60 | | - last_run=None, |
61 | | - data_source="NpmImporter", |
62 | | - data_source_cfg={ |
63 | | - "repository_url": "https://example.git", |
64 | | - "working_directory": os.path.join(cls.tempdir, "npm/npm_test"), |
65 | | - "create_working_directory": False, |
66 | | - "remove_working_directory": False, |
67 | | - }, |
68 | | - ) |
69 | | - |
70 | | - @classmethod |
71 | | - def tearDownClass(cls) -> None: |
72 | | - # Make sure no requests for unexpected package names have been made during the tests. |
73 | | - shutil.rmtree(cls.tempdir) |
74 | | - assert len(MOCK_VERSION_API.cache) == 3, MOCK_VERSION_API.cache |
75 | | - |
76 | | - def test_import(self, _): |
77 | | - runner = ImportRunner(self.importer, 5) |
78 | | - |
79 | | - with patch("vulnerabilities.importers.NpmImporter.versions", new=MOCK_VERSION_API): |
80 | | - with patch("vulnerabilities.importers.NpmImporter.set_api"): |
81 | | - runner.run() |
82 | | - |
83 | | - assert models.Vulnerability.objects.count() == 3 |
84 | | - assert models.VulnerabilityReference.objects.count() == 3 |
85 | | - assert models.PackageRelatedVulnerability.objects.all().count() == 4 |
86 | | - |
87 | | - assert models.Package.objects.count() == 8 |
88 | | - |
89 | | - self.assert_for_package( |
90 | | - "jquery", {"3.4.0"}, {"3.8.0"}, "1518", vulnerability_id="CVE-2020-11022" |
91 | | - ) # nopep8 |
92 | | - self.assert_for_package("kerberos", {"0.5.8"}, {"1.2.0"}, "1514") |
93 | | - self.assert_for_package("subtext", {"4.1.1", "7.0.0"}, {"6.1.3", "7.0.5"}, "1476") |
94 | | - |
95 | | - def assert_for_package( |
96 | | - self, |
97 | | - package_name, |
98 | | - impacted_versions, |
99 | | - resolved_versions, |
100 | | - vuln_id, |
101 | | - vulnerability_id=None, |
102 | | - ): |
103 | | - vuln = None |
104 | | - |
105 | | - for version in impacted_versions: |
106 | | - pkg = models.Package.objects.get(name=package_name, version=version) |
107 | | - |
108 | | - assert pkg.vulnerabilities.count() == 1 |
109 | | - vuln = pkg.vulnerabilities.first() |
110 | | - if vulnerability_id: |
111 | | - assert vuln.vulnerability_id == vulnerability_id |
112 | | - |
113 | | - ref_url = f"https://registry.npmjs.org/-/npm/v1/advisories/{vuln_id}" |
114 | | - assert models.VulnerabilityReference.objects.get(url=ref_url, vulnerability=vuln) |
115 | | - |
116 | | - for version in resolved_versions: |
117 | | - pkg = models.Package.objects.get(name=package_name, version=version) |
118 | | - assert models.PackageRelatedVulnerability.objects.filter( |
119 | | - patched_package=pkg, vulnerability=vuln |
120 | | - ) |
121 | | - |
122 | | - |
123 | | -def test_categorize_versions_simple_ranges(): |
124 | | - all_versions = {"3.4.0", "3.8.0"} |
125 | | - impacted_ranges = "<3.5.0" |
126 | | - resolved_ranges = ">=3.5.0" |
127 | | - |
128 | | - impacted_versions, resolved_versions = categorize_versions( |
129 | | - all_versions, impacted_ranges, resolved_ranges |
130 | | - ) |
131 | | - |
132 | | - assert impacted_versions == {"3.4.0"} |
133 | | - assert resolved_versions == {"3.8.0"} |
134 | | - |
135 | | - |
136 | | -def test_categorize_versions_complex_ranges(): |
137 | | - all_versions = {"3.7.0", "4.1.1", "6.1.3", "7.0.0", "7.0.5"} |
138 | | - impacted_ranges = ">=4.1.0 <6.1.3 || >= 7.0.0 <7.0.3" |
139 | | - resolved_ranges = ">=6.1.3 <7.0.0 || >=7.0.3" |
140 | | - |
141 | | - impacted_versions, resolved_versions = categorize_versions( |
142 | | - all_versions, impacted_ranges, resolved_ranges |
143 | | - ) |
144 | | - |
145 | | - assert impacted_versions == {"4.1.1", "7.0.0"} |
146 | | - assert resolved_versions == {"3.7.0", "6.1.3", "7.0.5"} |
| 20 | +def test_npm_importer(): |
| 21 | + file = os.path.join(TEST_DATA, "npm_sample.json") |
| 22 | + result = [adv.to_dict() for adv in NpmImporter().to_advisory_data(file=file)] |
| 23 | + expected_file = os.path.join(TEST_DATA, f"parse-advisory-npm-expected.json") |
| 24 | + util_tests.check_results_against_json(result, expected_file) |
0 commit comments