From c89c5a0b36d60a58a77eac4948c99424420f3c0f Mon Sep 17 00:00:00 2001 From: "John M. Horan" Date: Thu, 13 Oct 2022 18:32:35 -0700 Subject: [PATCH] Begin work on patch-based tests #597 Reference: https://github.com/nexB/vulnerablecode/issues/597 Reference: https://github.com/nexB/vulnerablecode/pull/935 Signed-off-by: John M. Horan --- vulnerabilities/importers/archlinux.py | 71 +-------- vulnerabilities/tests/test_archlinux.py | 139 ++---------------- .../archlinux/archlinux-multi-expected.json | 0 .../test_data/archlinux/archlinux-multi.json | 54 +++++++ .../parse-advisory-archlinux-expected.json | 36 +++++ 5 files changed, 108 insertions(+), 192 deletions(-) create mode 100644 vulnerabilities/tests/test_data/archlinux/archlinux-multi-expected.json create mode 100644 vulnerabilities/tests/test_data/archlinux/archlinux-multi.json create mode 100644 vulnerabilities/tests/test_data/archlinux/parse-advisory-archlinux-expected.json diff --git a/vulnerabilities/importers/archlinux.py b/vulnerabilities/importers/archlinux.py index 3654595be..b5b36feb9 100644 --- a/vulnerabilities/importers/archlinux.py +++ b/vulnerabilities/importers/archlinux.py @@ -40,34 +40,21 @@ def advisory_data(self) -> Iterable[AdvisoryData]: def parse_advisory(self, record) -> List[AdvisoryData]: advisories = [] - # aliases = record["issues"] aliases = record.get("issues") or [] - # for alias in record["issues"]: for alias in aliases: affected_packages = [] for name in record["packages"]: summary = record.get("type") or "" if summary == "unknown": summary = "" - - # affected_packages = AffectedPackage( - # PackageURL( - # name=name, - # type="alpm", - # namespace="archlinux", - # ), - # affected_version_range=ArchLinuxVersionRange.from_versions( - # [record.get("affected") or ""] - # ), - # fixed_version=ArchLinuxVersion(record.get("fixed") or ""), - # ) affected = record.get("affected") or "" affected_version_range = ( ArchLinuxVersionRange.from_versions([affected]) if affected else None ) fixed = record.get("fixed") or "" fixed_version = ArchLinuxVersion(fixed) if fixed else None - affected_packages = AffectedPackage( + affected_packages = [] + affected_package = AffectedPackage( package=PackageURL( name=name, type="alpm", @@ -76,6 +63,7 @@ def parse_advisory(self, record) -> List[AdvisoryData]: affected_version_range=affected_version_range, fixed_version=fixed_version, ) + affected_packages.append(affected_package) references = [] references.append( @@ -107,57 +95,4 @@ def parse_advisory(self, record) -> List[AdvisoryData]: ) ) - # The print statements below will print the structure of each test advisory when either of these tests is run: - # pytest -vvs -k test_parse_advisory_single vulnerabilities/tests/test_archlinux.py - # pytest -vvs -k test_parse_advisory_multi vulnerabilities/tests/test_archlinux.py - - print("\n\r=================================\n\r") - - for advisory in advisories: - print(f"1. aliases: {advisory.aliases}\r\n") - for alias in advisory.aliases: - - print("\talias: {}\r\n".format(alias)) - - print(f"2. summary: {advisory.summary}\r\n") - - print(f"3. affected_packages: {advisory.affected_packages}\r\n") - - print("\tpackage: {}\r\n".format(advisory.affected_packages.package)) - - print("\t\ttype: {}\r".format(advisory.affected_packages.package.type)) - - print("\t\tnamespace: {}\r".format(advisory.affected_packages.package.namespace)) - - print("\t\tname: {}\r".format(advisory.affected_packages.package.name)) - - print("\t\tversion: {}\r".format(advisory.affected_packages.package.version)) - - print("\t\tqualifiers: {}\r".format(advisory.affected_packages.package.qualifiers)) - - print("\t\tsubpath: {}\r\n".format(advisory.affected_packages.package.subpath)) - - print( - "\taffected_version_range: {}\r\n".format( - advisory.affected_packages.affected_version_range - ) - ) - - print("\tfixed_version: {}\r\n".format(advisory.affected_packages.fixed_version)) - - print(f"4. references: {advisory.references}\r") - for ref in advisory.references: - - print("\r\nref: {}\r\n".format(ref)) - - print("\treference_id: {}\r\n".format(ref.reference_id)) - - print("\turl: {}\r\n".format(ref.url)) - - print("\tseverities: {}\r\n".format(ref.severities)) - - print(f"5. date_published: {advisory.date_published}\r") - - print("\n\r=================================\n\r") - return advisories diff --git a/vulnerabilities/tests/test_archlinux.py b/vulnerabilities/tests/test_archlinux.py index aaa4a5e6f..5133a3281 100644 --- a/vulnerabilities/tests/test_archlinux.py +++ b/vulnerabilities/tests/test_archlinux.py @@ -17,90 +17,10 @@ from vulnerabilities import models from vulnerabilities.import_runner import ImportRunner from vulnerabilities.importers import archlinux +from vulnerabilities.tests import util_tests BASE_DIR = os.path.dirname(os.path.abspath(__file__)) -TEST_DATA = os.path.join(BASE_DIR, "test_data/") - - -class ArchlinuxImportTest(TestCase): - @classmethod - def setUpClass(cls) -> None: - fixture_path = os.path.join(TEST_DATA, "archlinux.json") - with open(fixture_path) as f: - cls.mock_response = json.load(f) - - cls.importer = models.Importer.objects.create( - name="archlinux_unittests", - license="", - last_run=None, - data_source="ArchlinuxImporter", - data_source_cfg={ - "archlinux_tracker_url": "https://security.example.com/json", - }, - ) - - @classmethod - def tearDownClass(cls) -> None: - pass - - def test_import(self): - runner = ImportRunner(self.importer, 5) - - with patch( - "vulnerabilities.importers.ArchlinuxImporter._fetch", return_value=self.mock_response - ): - runner.run() - assert models.Vulnerability.objects.count() == 6 - assert models.VulnerabilityReference.objects.count() == 10 - assert models.PackageRelatedVulnerability.objects.all().count() == 12 - assert ( - models.PackageRelatedVulnerability.objects.filter(patched_package__isnull=False).count() - == 8 - ) - assert models.Package.objects.count() == 10 - - self.assert_for_package( - "squid", - "4.10-2", - cve_ids={"CVE-2020-11945", "CVE-2019-12521", "CVE-2019-12519"}, - ) - self.assert_for_package("openconnect", "1:8.05-1", cve_ids={"CVE-2020-12823"}) - self.assert_for_package( - "wireshark-common", - "2.6.0-1", - cve_ids={"CVE-2018-11362", "CVE-2018-11361"}, - ) - self.assert_for_package( - "wireshark-gtk", - "2.6.0-1", - cve_ids={"CVE-2018-11362", "CVE-2018-11361"}, - ) - self.assert_for_package( - "wireshark-cli", - "2.6.0-1", - cve_ids={"CVE-2018-11362", "CVE-2018-11361"}, - ) - self.assert_for_package( - "wireshark-qt", - "2.6.0-1", - cve_ids={"CVE-2018-11362", "CVE-2018-11361"}, - ) - self.assert_for_package("wireshark-common", "2.6.1-1") - self.assert_for_package("wireshark-gtk", "2.6.1-1") - self.assert_for_package("wireshark-cli", "2.6.1-1") - self.assert_for_package("wireshark-qt", "2.6.1-1") - - def assert_for_package(self, name, version, cve_ids=None): - qs = models.Package.objects.filter( - name=name, - version=version, - type="pacman", - namespace="archlinux", - ) - assert qs - - if cve_ids: - assert cve_ids == {v.vulnerability_id for v in qs[0].vulnerabilities.all()} +TEST_DATA = os.path.join(BASE_DIR, "test_data/archlinux") def test_parse_advisory_single(): @@ -117,48 +37,19 @@ def test_parse_advisory_single(): "advisories": [], } - assert archlinux.ArchlinuxImporter().parse_advisory(record) + advisory_data = archlinux.ArchlinuxImporter().parse_advisory(record) + result = [data.to_dict() for data in advisory_data] + expected_file = os.path.join(TEST_DATA, f"parse-advisory-archlinux-expected.json") + util_tests.check_results_against_json(result, expected_file) -def test_parse_advisory_multi(): - record_list = [ - { - "name": "AVG-2781", - "packages": ["python-pyjwt"], - "status": "Unknown", - "severity": "Unknown", - "type": "unknown", - "affected": "2.3.0-1", - "fixed": "2.4.0-1", - "ticket": None, - "issues": ["CVE-2022-29217"], - "advisories": [], - }, - { - "name": "AVG-2780", - "packages": ["wpewebkit"], - "status": "Unknown", - "severity": "Unknown", - "type": "unknown", - "affected": "2.36.3-1", - "fixed": "2.36.4-1", - "ticket": None, - "issues": ["CVE-2022-26710", "CVE-2022-22677", "CVE-2022-22662"], - "advisories": [], - }, - { - "name": "AVG-4", - "packages": ["bzip2"], - "status": "Fixed", - "severity": "Low", - "type": "denial of service", - "affected": "1.0.6-5", - "fixed": "1.0.6-6", - "ticket": None, - "issues": ["CVE-2016-3189"], - "advisories": ["ASA-201702-19"], - }, - ] +@patch("vulnerabilities.importers.archlinux.ArchlinuxImporter.fetch") +def test_archlinux_importer(mock_response): + with open(os.path.join(TEST_DATA, "archlinux-multi.json")) as f: + mock_response.return_value = json.load(f) - for record in record_list: - assert archlinux.ArchlinuxImporter().parse_advisory(record) + expected_file = os.path.join(TEST_DATA, f"archlinux-multi-expected.json") + result = [data.to_dict() for data in list(archlinux.ArchlinuxImporter().advisory_data())] + # result = [data.to_dict() for data in archlinux.ArchlinuxImporter().advisory_data()] + # result = archlinux.ArchlinuxImporter().advisory_data() + util_tests.check_results_against_json(result, expected_file) diff --git a/vulnerabilities/tests/test_data/archlinux/archlinux-multi-expected.json b/vulnerabilities/tests/test_data/archlinux/archlinux-multi-expected.json new file mode 100644 index 000000000..e69de29bb diff --git a/vulnerabilities/tests/test_data/archlinux/archlinux-multi.json b/vulnerabilities/tests/test_data/archlinux/archlinux-multi.json new file mode 100644 index 000000000..14bfb17cf --- /dev/null +++ b/vulnerabilities/tests/test_data/archlinux/archlinux-multi.json @@ -0,0 +1,54 @@ +[ + { + "name": "AVG-2781", + "packages": [ + "python-pyjwt" + ], + "status": "Unknown", + "severity": "Unknown", + "type": "unknown", + "affected": "2.3.0-1", + "fixed": "2.4.0-1", + "ticket": null, + "issues": [ + "CVE-2022-29217" + ], + "advisories": [] + }, + { + "name": "AVG-2780", + "packages": [ + "wpewebkit" + ], + "status": "Unknown", + "severity": "Unknown", + "type": "unknown", + "affected": "2.36.3-1", + "fixed": "2.36.4-1", + "ticket": null, + "issues": [ + "CVE-2022-26710", + "CVE-2022-22677", + "CVE-2022-22662" + ], + "advisories": [] + }, + { + "name": "AVG-4", + "packages": [ + "bzip2" + ], + "status": "Fixed", + "severity": "Low", + "type": "denial of service", + "affected": "1.0.6-5", + "fixed": "1.0.6-6", + "ticket": null, + "issues": [ + "CVE-2016-3189" + ], + "advisories": [ + "ASA-201702-19" + ] + } +] \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/archlinux/parse-advisory-archlinux-expected.json b/vulnerabilities/tests/test_data/archlinux/parse-advisory-archlinux-expected.json new file mode 100644 index 000000000..2a94b6719 --- /dev/null +++ b/vulnerabilities/tests/test_data/archlinux/parse-advisory-archlinux-expected.json @@ -0,0 +1,36 @@ +[ + { + "aliases": [ + "CVE-2022-29217", + "AVG-2781" + ], + "summary": "", + "affected_packages": [ + { + "package": { + "type": "alpm", + "namespace": "archlinux", + "name": "python-pyjwt", + "version": null, + "qualifiers": null, + "subpath": null + }, + "affected_version_range": "vers:alpm/2.3.0-1", + "fixed_version": "2.4.0-1" + } + ], + "references": [ + { + "reference_id": "AVG-2781", + "url": "https://security.archlinux.org/AVG-2781", + "severities": [ + { + "system": "archlinux", + "value": "Unknown" + } + ] + } + ], + "date_published": null + } +] \ No newline at end of file