diff --git a/vulnerabilities/importer.py b/vulnerabilities/importer.py
index e1564934e..3c4fbfa2d 100644
--- a/vulnerabilities/importer.py
+++ b/vulnerabilities/importer.py
@@ -74,7 +74,6 @@ def from_dict(cls, severity: dict):
@dataclasses.dataclass(order=True)
class Reference:
-
reference_id: str = ""
url: str = ""
severities: List[VulnerabilitySeverity] = dataclasses.field(default_factory=list)
@@ -437,48 +436,55 @@ def get_data_from_xml_doc(
for definition_data in raw_data:
# These fields are definition level, i.e common for all elements
# connected/linked to an OvalDefinition
- vuln_id = definition_data["vuln_id"]
- description = definition_data["description"]
- severities = []
- severity = definition_data.get("severity")
- if severity:
- severities.append(
- VulnerabilitySeverity(system=severity_systems.GENERIC, value=severity)
- )
- references = [
- Reference(url=url, severities=severities)
- for url in definition_data["reference_urls"]
- ]
- affected_packages = []
- for test_data in definition_data["test_data"]:
- for package_name in test_data["package_list"]:
- affected_version_range = test_data["version_ranges"]
- vrc = RANGE_CLASS_BY_SCHEMES[pkg_metadata["type"]]
- if affected_version_range:
- try:
- affected_version_range = vrc.from_native(affected_version_range)
- except Exception as e:
- logger.error(
- f"Failed to parse version range {affected_version_range!r} "
- f"for package {package_name!r}:\n{e}\n"
- f"{definition_data!r}"
- )
- continue
- if package_name:
- affected_packages.append(
- AffectedPackage(
- package=self.create_purl(package_name, pkg_metadata),
- affected_version_range=affected_version_range,
+
+ # NOTE: This is where we loop through the list of CVEs/aliases.
+ vuln_id_list = definition_data["vuln_id"]
+
+ for vuln_id_item in vuln_id_list:
+ vuln_id = vuln_id_item
+ description = definition_data["description"]
+
+ severities = []
+ severity = definition_data.get("severity")
+ if severity:
+ severities.append(
+ VulnerabilitySeverity(system=severity_systems.GENERIC, value=severity)
+ )
+ references = [
+ Reference(url=url, severities=severities)
+ for url in definition_data["reference_urls"]
+ ]
+ affected_packages = []
+
+ for test_data in definition_data["test_data"]:
+ for package_name in test_data["package_list"]:
+ affected_version_range = test_data["version_ranges"]
+ vrc = RANGE_CLASS_BY_SCHEMES[pkg_metadata["type"]]
+ if affected_version_range:
+ try:
+ affected_version_range = vrc.from_native(affected_version_range)
+ except Exception as e:
+ logger.error(
+ f"Failed to parse version range {affected_version_range!r} "
+ f"for package {package_name!r}:\n{e}"
+ )
+ continue
+ if package_name:
+ affected_packages.append(
+ AffectedPackage(
+ package=self.create_purl(package_name, pkg_metadata),
+ affected_version_range=affected_version_range,
+ )
)
- )
- date_published = dateparser.parse(timestamp)
- if not date_published.tzinfo:
- date_published = date_published.replace(tzinfo=pytz.UTC)
- yield AdvisoryData(
- aliases=[vuln_id],
- summary=description,
- affected_packages=affected_packages,
- references=sorted(references),
- date_published=date_published,
- url=self.data_url,
- )
+
+ date_published = dateparser.parse(timestamp)
+ if not date_published.tzinfo:
+ date_published = date_published.replace(tzinfo=pytz.UTC)
+ yield AdvisoryData(
+ aliases=[vuln_id],
+ summary=description,
+ affected_packages=sorted(affected_packages),
+ references=sorted(references),
+ date_published=date_published,
+ url=self.data_url,
+ )
diff --git a/vulnerabilities/importers/suse_oval.py b/vulnerabilities/importers/suse_oval.py
new file mode 100644
index 000000000..5ac35e23e
--- /dev/null
+++ b/vulnerabilities/importers/suse_oval.py
@@ -0,0 +1,69 @@
+#
+# Copyright (c) nexB Inc. and others. All rights reserved.
+# VulnerableCode is a trademark of nexB Inc.
+# SPDX-License-Identifier: Apache-2.0
+# See http://www.apache.org/licenses/LICENSE-2.0 for the license text.
+# See https://github.com/nexB/vulnerablecode for support or download.
+# See https://aboutcode.org for more information about nexB OSS projects.
+#
+
+
+import gzip
+import xml.etree.ElementTree as ET
+
+import requests
+from bs4 import BeautifulSoup
+
+from vulnerabilities.importer import OvalImporter
+
+
+class SuseOvalImporter(OvalImporter):
+ spdx_license_expression = "CC-BY-4.0"
+ license_url = "https://ftp.suse.com/pub/projects/security/oval/LICENSE"
+ base_url = "https://ftp.suse.com/pub/projects/security/oval/"
+
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.translations = {"less than": "<", "equals": "=", "greater than or equal": ">="}
+
+ def _fetch(self):
+ page = requests.get(self.base_url).text
+ soup = BeautifulSoup(page, "lxml")
+
+ suse_oval_files = [
+ self.base_url + node.get("href")
+ for node in soup.find_all("a")
+ if node.get("href").endswith(".gz")
+ ]
+
+ for suse_file in filter(suse_oval_files):
+ response = requests.get(suse_file)
+
+ extracted = gzip.decompress(response.content)
+ yield (
+ {"type": "rpm", "namespace": "opensuse"},
+ ET.ElementTree(ET.fromstring(extracted.decode("utf-8"))),
+ )
+
+
+def filter(suse_oval_files):
+ """
+ Filter to exclude "name.xml" when we also have "name-affected.xml", e.g.,
+ "opensuse.leap.15.3.xml.gz" vs. "opensuse.leap.15.3-affected.xml.gz". See
+ https://ftp.suse.com/pub/projects/security/oval/README: "name-affected.xml" includes
+ "fixed security issues and the analyzed issues both affecting and NOT affecting SUSE" and
+ "name.xml" includes "fixed security issues and the analyzed issues NOT affecting SUSE."
+ """
+ affected_files = [
+ affected_file for affected_file in suse_oval_files if "-affected" in affected_file
+ ]
+
+ trimmed_affected_files = [
+ affected_file.replace("-affected", "") for affected_file in affected_files
+ ]
+
+ filtered_suse_oval_files = [
+ gz_file for gz_file in suse_oval_files if gz_file not in trimmed_affected_files
+ ]
+
+ return filtered_suse_oval_files
diff --git a/vulnerabilities/lib_oval.py b/vulnerabilities/lib_oval.py
index 6c8a6163f..0b178d47c 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,12 @@ def setVersion(self, version):
self.element.set("version", version)
return True
+ def __lt__(self, other):
+ try:
+ return int(self.element.get("version")) < int(other.element.get("version"))
+ except:
+ return NotImplemented
+
def incrementVersion(self):
version = self.getVersion()
if not version:
diff --git a/vulnerabilities/oval_parser.py b/vulnerabilities/oval_parser.py
index 94b360bff..2a958312c 100755
--- a/vulnerabilities/oval_parser.py
+++ b/vulnerabilities/oval_parser.py
@@ -25,7 +25,6 @@
class OvalParser:
def __init__(self, translations: Dict, oval_document: ET.ElementTree):
-
self.translations = translations
self.oval_document = OvalDocument(oval_document)
self.all_definitions = self.oval_document.getDefinitions()
@@ -37,17 +36,14 @@ def get_data(self) -> List[Dict]:
"""
oval_data = []
for definition in self.all_definitions:
-
matching_tests = self.get_tests_of_definition(definition)
if not matching_tests:
continue
definition_data = {"test_data": []}
# TODO:this could use some data cleaning
definition_data["description"] = definition.getMetadata().getDescription() or ""
-
definition_data["vuln_id"] = self.get_vuln_id_from_definition(definition)
definition_data["reference_urls"] = self.get_urls_from_definition(definition)
-
definition_data["severity"] = self.get_severity_from_definition(definition)
for test in matching_tests:
@@ -72,24 +68,30 @@ def get_tests_of_definition(self, definition: OvalDefinition) -> List[OvalTest]:
criteria_refs = []
for child in definition.element.iter():
-
if "test_ref" in child.attrib:
criteria_refs.append(child.get("test_ref"))
matching_tests = []
for ref in criteria_refs:
oval_test = self.oval_document.getElementByID(ref)
+ # All matches will be `rpminfo_test` elements inside the `tests` element.
+ # Test for len == 2 because this IDs a pair of nested `object` and `state` elements.
if len(oval_test.element) == 2:
_, state = self.get_object_state_of_test(oval_test)
valid_test = True
for child in state.element:
if child.get("operation") not in self.translations:
valid_test = False
- break
- if valid_test:
- matching_tests.append(self.oval_document.getElementByID(ref))
+ continue
+ elif (
+ child.get("operation") in self.translations
+ # "debian_evr_string" is used in both Debian and Ubuntu test XML files; SUSE OVAL uses "evr_string".
+ # See also https://github.com/OVALProject/Language/blob/master/docs/oval-common-schema.md
+ and child.get("datatype") in ["evr_string", "debian_evr_string"]
+ ):
+ matching_tests.append(self.oval_document.getElementByID(ref))
- return matching_tests
+ return sorted(set(matching_tests))
def get_object_state_of_test(self, test: OvalTest) -> Tuple[OvalObject, OvalState]:
"""
@@ -109,6 +111,7 @@ def get_pkgs_from_obj(self, obj: OvalObject) -> List[str]:
pkg_list = []
for var in obj.element:
+ # It appears that `var_ref` is used in Ubuntu OVAL but not Debian or SUSE.
if var.get("var_ref"):
var_elem = self.oval_document.getElementByID(var.get("var_ref"))
comment = var_elem.element.get("comment")
@@ -178,9 +181,18 @@ def get_severity_from_definition(definition: OvalDefinition) -> Set[str]:
@staticmethod
def get_vuln_id_from_definition(definition):
- # SUSE and Ubuntu OVAL files will get cves via this loop
+ # SUSE and Ubuntu OVAL files will get CVEs via this loop.
+ cve_list = []
for child in definition.element.iter():
- if child.get("ref_id"):
- return child.get("ref_id")
- # Debian OVAL files will get cves via this
- return definition.getMetadata().getTitle()
+ if child.get("ref_id") and child.get("source"):
+ if child.get("source") == "CVE":
+ if not child.get("ref_id").startswith("CVE"):
+ unwanted_prefix = child.get("ref_id").split("CVE")[0]
+ cve_list.append(child.get("ref_id").replace(unwanted_prefix, ""))
+ else:
+ cve_list.append(child.get("ref_id"))
+ # Debian OVAL files (no "ref_id") will get CVEs via this.
+ if len(cve_list) == 0:
+ cve_list.append(definition.getMetadata().getTitle())
+
+ return cve_list
diff --git a/vulnerabilities/tests/test_data/suse_oval/mock-definitions-only.xml b/vulnerabilities/tests/test_data/suse_oval/mock-definitions-only.xml
new file mode 100644
index 000000000..8d7c7756e
--- /dev/null
+++ b/vulnerabilities/tests/test_data/suse_oval/mock-definitions-only.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+ 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.
+
+
+
+
+
+ foobar-CVE-1234-5678
+
+
+
+
+ Blah blah blah.
+
+
+
+
+
+ nonesuchCVE-1111-2222
+
+
+
+
+ Blah blah blah.
+
+
+
+
+
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/suse_oval/org.opensuse.CVE-2008-5679.xml b/vulnerabilities/tests/test_data/suse_oval/org.opensuse.CVE-2008-5679.xml
new file mode 100644
index 000000000..b7c4c5e73
--- /dev/null
+++ b/vulnerabilities/tests/test_data/suse_oval/org.opensuse.CVE-2008-5679.xml
@@ -0,0 +1,81 @@
+
+
+
+ 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/suse_oval/suse-oval-CVE-2008-5679-expected.json b/vulnerabilities/tests/test_data/suse_oval/suse-oval-CVE-2008-5679-expected.json
new file mode 100644
index 000000000..93469b4a0
--- /dev/null
+++ b/vulnerabilities/tests/test_data/suse_oval/suse-oval-CVE-2008-5679-expected.json
@@ -0,0 +1,32 @@
+[
+ {
+ "aliases": [
+ "CVE-2008-5679"
+ ],
+ "summary": "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.",
+ "affected_packages": [
+ {
+ "package": {
+ "type": "rpm",
+ "namespace": "opensuse",
+ "name": "opera",
+ "version": null,
+ "qualifiers": null,
+ "subpath": null
+ },
+ "affected_version_range": "vers:rpm/<9.63-1.1",
+ "fixed_version": null
+ }
+ ],
+ "references": [
+ {
+ "reference_id": "",
+ "url": "http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-5679",
+ "severities": []
+ }
+ ],
+ "date_published": "2009-01-14T09:08:29.480000-05:00",
+ "weaknesses": [],
+ "url": ""
+ }
+]
diff --git a/vulnerabilities/tests/test_data_source.py b/vulnerabilities/tests/test_data_source.py
index e1a36c57d..369ac9c23 100644
--- a/vulnerabilities/tests/test_data_source.py
+++ b/vulnerabilities/tests/test_data_source.py
@@ -31,6 +31,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():
@@ -76,7 +77,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"}
@@ -138,3 +138,28 @@ def test_git_importer_clone(git_importer):
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()
+
+ # 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.)
+ sorted_tests = sorted(get_all_tests)
+ test_results = [(test.getId(), test.getVersion()) for test in sorted_tests]
+ expected = [
+ ("oval:org.opensuse.security:tst:2009030401", "1"),
+ ("oval:org.opensuse.security:tst:2009030403", "4"),
+ ("oval:org.opensuse.security:tst:2009030402", "9"),
+ ("oval:org.opensuse.security:tst:2009030400", "11"),
+ ]
+ assert test_results == expected
diff --git a/vulnerabilities/tests/test_suse_oval.py b/vulnerabilities/tests/test_suse_oval.py
new file mode 100644
index 000000000..eba1ca0f2
--- /dev/null
+++ b/vulnerabilities/tests/test_suse_oval.py
@@ -0,0 +1,157 @@
+#
+# Copyright (c) nexB Inc. and others. All rights reserved.
+# VulnerableCode is a trademark of nexB Inc.
+# SPDX-License-Identifier: Apache-2.0
+# See http://www.apache.org/licenses/LICENSE-2.0 for the license text.
+# See https://github.com/nexB/vulnerablecode for support or download.
+# See https://aboutcode.org for more information about nexB OSS projects.
+#
+
+
+import gzip
+import io
+import os
+import xml.etree.ElementTree as ET
+
+from vulnerabilities.importers.suse_oval import SuseOvalImporter
+from vulnerabilities.importers.suse_oval import filter
+from vulnerabilities.oval_parser import OvalParser
+from vulnerabilities.tests import util_tests
+
+BASE_DIR = os.path.dirname(os.path.abspath(__file__))
+TEST_DATA = os.path.join(BASE_DIR, "test_data/suse_oval")
+
+
+def test_suse_oval_importer_CVE_2008_5679():
+ importer = SuseOvalImporter()
+ advisories = importer.get_data_from_xml_doc(
+ ET.parse(os.path.join(TEST_DATA, "org.opensuse.CVE-2008-5679.xml")),
+ {"type": "rpm", "namespace": "opensuse"},
+ )
+ expected_file = os.path.join(TEST_DATA, f"suse-oval-CVE-2008-5679-expected.json")
+ util_tests.check_results_against_json(
+ [advisory.to_dict() for advisory in advisories], expected_file
+ )
+
+
+def test_suse_oval_parse_CVE_2008_5679():
+ xml_doc = ET.parse(os.path.join(TEST_DATA, "org.opensuse.CVE-2008-5679.xml"))
+ translations = {"less than": "<", "equals": "=", "greater than or equal": ">="}
+ parsed_oval = OvalParser(translations, xml_doc)
+
+ # Get total number of definitions
+ assert len(parsed_oval.all_definitions) == 1
+
+ # Get definition `id`: the `` element.
+ definition_1 = parsed_oval.all_definitions[0]
+ assert parsed_oval.all_definitions[0].getId() == "oval:org.opensuse.security:def:2009030400"
+
+ # Get definition `test_ref`: the `` element.
+ definition_1_test_ids = {
+ "oval:org.opensuse.security:tst:2009030400",
+ }
+ assert definition_1_test_ids == {
+ i.getId() for i in parsed_oval.get_tests_of_definition(definition_1)
+ }
+
+ # Get vuln_id from definition
+ vuln_id_1 = ["CVE-2008-5679"]
+ assert vuln_id_1 == parsed_oval.get_vuln_id_from_definition(definition_1)
+
+ # Get total number of tests
+ assert len(parsed_oval.oval_document.getTests()) == 4
+
+ # Get test object and test state
+ test_1 = parsed_oval.oval_document.getTests()[0]
+ obj_t1, state_t1 = parsed_oval.get_object_state_of_test(test_1)
+ assert obj_t1.getId() == "oval:org.opensuse.security:obj:2009030400"
+ assert state_t1.getId() == "oval:org.opensuse.security:ste:2009030400"
+
+ # Get total number of packages: `rpminfo_object` elements
+ assert len(parsed_oval.oval_document.getObjects()) == 2
+
+ # Get packages
+ obj_t1 = parsed_oval.oval_document.getObjects()[0]
+ obj_t2 = parsed_oval.oval_document.getObjects()[1]
+
+ pkg_set1 = set(parsed_oval.get_pkgs_from_obj(obj_t1))
+ pkg_set2 = set(parsed_oval.get_pkgs_from_obj(obj_t2))
+
+ assert pkg_set1 == {"opera"}
+ assert pkg_set2 == {"openSUSE-release"}
+
+ # Get total number of versions: `rpminfo_state` elements
+ assert len(parsed_oval.oval_document.getStates()) == 4
+
+ # Get versions
+ state_1 = parsed_oval.oval_document.getStates()[0]
+
+ exp_range_1 = "<9.63-1.1"
+
+ assert parsed_oval.get_version_range_from_state(state_1) == exp_range_1
+
+ # Get reference URLs: `ref_url` attribute from `reference` elements
+ definition_0 = parsed_oval.all_definitions[0]
+ def0_urls = {
+ "http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-5679",
+ }
+
+ assert def0_urls == parsed_oval.get_urls_from_definition(definition_0)
+
+
+def test_filter_suse_gz_files():
+ initial_suse_gz_files = [
+ "https://ftp.suse.com/pub/projects/security/oval/suse.openstack.cloud.7-affected.xml.gz",
+ "https://ftp.suse.com/pub/projects/security/oval/suse.openstack.cloud.7-patch.xml.gz",
+ "https://ftp.suse.com/pub/projects/security/oval/suse.openstack.cloud.7.xml.gz",
+ "https://ftp.suse.com/pub/projects/security/oval/suse.openstack.cloud.8-affected.xml.gz",
+ "https://ftp.suse.com/pub/projects/security/oval/suse.openstack.cloud.8-patch.xml.gz",
+ "https://ftp.suse.com/pub/projects/security/oval/suse.openstack.cloud.8.xml.gz",
+ "https://ftp.suse.com/pub/projects/security/oval/suse.openstack.cloud.9-affected.xml.gz",
+ "https://ftp.suse.com/pub/projects/security/oval/suse.openstack.cloud.9-patch.xml.gz",
+ "https://ftp.suse.com/pub/projects/security/oval/suse.openstack.cloud.9.xml.gz",
+ "https://ftp.suse.com/pub/projects/security/oval/suse.storage.6-affected.xml.gz",
+ "https://ftp.suse.com/pub/projects/security/oval/suse.storage.6-patch.xml.gz",
+ "https://ftp.suse.com/pub/projects/security/oval/suse.storage.6.xml.gz",
+ "https://ftp.suse.com/pub/projects/security/oval/suse.storage.7-affected.xml.gz",
+ "https://ftp.suse.com/pub/projects/security/oval/suse.storage.7-patch.xml.gz",
+ "https://ftp.suse.com/pub/projects/security/oval/suse.storage.7.xml.gz",
+ ]
+
+ filtered_initial_suse_gz_files = [
+ "https://ftp.suse.com/pub/projects/security/oval/suse.openstack.cloud.7-affected.xml.gz",
+ "https://ftp.suse.com/pub/projects/security/oval/suse.openstack.cloud.7-patch.xml.gz",
+ "https://ftp.suse.com/pub/projects/security/oval/suse.openstack.cloud.8-affected.xml.gz",
+ "https://ftp.suse.com/pub/projects/security/oval/suse.openstack.cloud.8-patch.xml.gz",
+ "https://ftp.suse.com/pub/projects/security/oval/suse.openstack.cloud.9-affected.xml.gz",
+ "https://ftp.suse.com/pub/projects/security/oval/suse.openstack.cloud.9-patch.xml.gz",
+ "https://ftp.suse.com/pub/projects/security/oval/suse.storage.6-affected.xml.gz",
+ "https://ftp.suse.com/pub/projects/security/oval/suse.storage.6-patch.xml.gz",
+ "https://ftp.suse.com/pub/projects/security/oval/suse.storage.7-affected.xml.gz",
+ "https://ftp.suse.com/pub/projects/security/oval/suse.storage.7-patch.xml.gz",
+ ]
+
+ assert filter(initial_suse_gz_files) == filtered_initial_suse_gz_files
+
+
+def test_cve_prefix_filter():
+ xml_doc = ET.parse(os.path.join(TEST_DATA, "mock-definitions-only.xml"))
+ translations = {"less than": "<", "equals": "=", "greater than or equal": ">="}
+ parsed_oval = OvalParser(translations, xml_doc)
+
+ assert len(parsed_oval.all_definitions) == 3
+
+ definition_1 = parsed_oval.all_definitions[0]
+
+ vuln_id_1 = ["CVE-2008-5679"]
+ assert vuln_id_1 == parsed_oval.get_vuln_id_from_definition(definition_1)
+
+ definition_2 = parsed_oval.all_definitions[1]
+
+ vuln_id_2 = ["CVE-1234-5678"]
+ assert vuln_id_2 == parsed_oval.get_vuln_id_from_definition(definition_2)
+
+ definition_3 = parsed_oval.all_definitions[2]
+
+ vuln_id_3 = ["CVE-1111-2222"]
+ assert vuln_id_3 == parsed_oval.get_vuln_id_from_definition(definition_3)