From 15fddb6ab584ad279c79bf86dcfbd72242bd96e3 Mon Sep 17 00:00:00 2001 From: "John M. Horan" Date: Sun, 24 Dec 2023 12:06:05 -0800 Subject: [PATCH] Modify OvalElement class __lt__ method and create test #1079 Reference: https://github.com/nexB/vulnerablecode/issues/1079 Signed-off-by: John M. Horan --- vulnerabilities/lib_oval.py | 18 ++-- vulnerabilities/oval_parser.py | 2 - ...ensuse.CVE-2008-5679-modified-versions.xml | 90 +++++++++++++++++++ vulnerabilities/tests/test_data_source.py | 35 +++++++- 4 files changed, 134 insertions(+), 11 deletions(-) create mode 100644 vulnerabilities/tests/test_data/suse_oval/org.opensuse.CVE-2008-5679-modified-versions.xml diff --git a/vulnerabilities/lib_oval.py b/vulnerabilities/lib_oval.py index 6c8a6163f..9715e08c0 100644 --- a/vulnerabilities/lib_oval.py +++ b/vulnerabilities/lib_oval.py @@ -62,8 +62,8 @@ Available exceptions: - None at this time - - + + :Usage: 1. Create an OvalDocument: @@ -80,21 +80,21 @@ 3. Read an XML file with a single OVAL Definition (error checking omitted for brevity): - >>> tree = ElementTree() + >>> tree = ElementTree() >>> tree.parse('test-definition.xml') - >>> root = tree.getroot() + >>> root = tree.getroot() >>> definition = lib_oval.OvalDefinition(root) - + 4. Change information in the definition from #3 and write the changes >>> meta = definition.getMetadata() >>> repo = meta.getOvalRepositoryInformation() >>> repo.setMinimumSchemaVersion("5.9") >>> tree.write("outfilename.xml", UTF-8", True) - - + + TODO: - Add exceptions that give more detail about why a value of None is sometimes returned @@ -253,7 +253,6 @@ def writeToFile(self, filename): return False def to_string(self): - if not self.tree: return None @@ -767,6 +766,9 @@ def setVersion(self, version): self.element.set("version", version) return True + def __lt__(self, other): + return int(self.element.get("version")) < int(other.element.get("version")) + def incrementVersion(self): version = self.getVersion() if not version: diff --git a/vulnerabilities/oval_parser.py b/vulnerabilities/oval_parser.py index 6cdddb7f7..2a958312c 100755 --- a/vulnerabilities/oval_parser.py +++ b/vulnerabilities/oval_parser.py @@ -91,8 +91,6 @@ def get_tests_of_definition(self, definition: OvalDefinition) -> List[OvalTest]: ): matching_tests.append(self.oval_document.getElementByID(ref)) - # return list(set(matching_tests)) - # FIXME: 2023-12-13 Wednesday 10:00:57. This change currently throws an error: FAILED vulnerabilities/tests/test_data_source.py::test__collect_pkgs - TypeError: '<' not supported between instances of 'OvalTest' and 'OvalTest'. Waiting for response to my 2023-12-12 GH comments. return sorted(set(matching_tests)) def get_object_state_of_test(self, test: OvalTest) -> Tuple[OvalObject, OvalState]: diff --git a/vulnerabilities/tests/test_data/suse_oval/org.opensuse.CVE-2008-5679-modified-versions.xml b/vulnerabilities/tests/test_data/suse_oval/org.opensuse.CVE-2008-5679-modified-versions.xml new file mode 100644 index 000000000..9ad88ee30 --- /dev/null +++ b/vulnerabilities/tests/test_data/suse_oval/org.opensuse.CVE-2008-5679-modified-versions.xml @@ -0,0 +1,90 @@ + + + + Marcus OVAL Generator + 5.5 + 2009-01-14T09:08:29.480-05:00 + + + + + + CVE-2008-5679 + + + + + The HTML parsing engine in Opera before 9.63 allows remote attackers to execute arbitrary code via crafted web pages that trigger an invalid pointer calculation and heap corruption. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + opera + + + openSUSE-release + + + + + 0:9.63-1.1 + + + ^10.3$ + + + ^11.0$ + + + ^11.1$ + + + diff --git a/vulnerabilities/tests/test_data_source.py b/vulnerabilities/tests/test_data_source.py index a603ff50c..f21345ee5 100644 --- a/vulnerabilities/tests/test_data_source.py +++ b/vulnerabilities/tests/test_data_source.py @@ -30,6 +30,7 @@ BASE_DIR = os.path.dirname(os.path.abspath(__file__)) TEST_DATA = os.path.join(BASE_DIR, "test_data/") +TEST_DATA_01 = os.path.join(BASE_DIR, "test_data/suse_oval") def load_oval_data(): @@ -74,7 +75,6 @@ def test_create_purl(): def test__collect_pkgs(): - xmls = load_oval_data() expected_suse_pkgs = {"cacti-spine", "apache2-mod_perl", "cacti", "apache2-mod_perl-devel"} @@ -134,3 +134,36 @@ def test_git_importer_clone(): list(git_importer().advisory_data()) mock_fetch.assert_called_once() mock_delete.assert_called_once() + + +# Here we use a modified copy of org.opensuse.CVE-2008-5679.xml -- the test versions are modified to illustrate sort order. +def test_ovaltest_sorting(): + xml_doc = ET.parse( + os.path.join(TEST_DATA_01, "org.opensuse.CVE-2008-5679-modified-versions.xml") + ) + translations = {"less than": "<", "equals": "=", "greater than or equal": ">="} + parsed_oval = OvalParser(translations, xml_doc) + + # Get the list of all tests and check the total number of tests. + get_all_tests = parsed_oval.oval_document.getTests() + assert len(get_all_tests) == 4 + + # Check the order of the four tests in the sorted `get_all_tests` list. (Testing suggests that the + # original list of tests, `get_all_tests`, is unsorted and is ordered in the same order as the test + # elements appear in the .xml file.) + for test in sorted(get_all_tests): + if test.getId() == "oval:org.opensuse.security:tst:2009030400": + assert test.getVersion() == "11" + assert test == sorted(get_all_tests)[3] + + if test.getId() == "oval:org.opensuse.security:tst:2009030401": + assert test.getVersion() == "1" + assert test == sorted(get_all_tests)[0] + + if test.getId() == "oval:org.opensuse.security:tst:2009030402": + assert test.getVersion() == "9" + assert test == sorted(get_all_tests)[2] + + if test.getId() == "oval:org.opensuse.security:tst:2009030403": + assert test.getVersion() == "4" + assert test == sorted(get_all_tests)[1]