diff --git a/build-scripts/combine_ovals.py b/build-scripts/combine_ovals.py index be0bee0b6f2..077a804a5ad 100755 --- a/build-scripts/combine_ovals.py +++ b/build-scripts/combine_ovals.py @@ -2,105 +2,108 @@ import argparse import sys +import logging +import os import ssg.build_ovals -import ssg.constants -import ssg.utils -import ssg.xml import ssg.environment +from ssg.oval_object_model import ( + ExceptionDuplicateObjectReferenceInTest, + ExceptionDuplicateOVALEntity, + ExceptionEmptyNote, + ExceptionMissingObjectReferenceInTest, +) + +MASSAGE_FORMAT = "%(levelname)s: %(message)s" +EXPECTED_ERRORS = ( + ExceptionDuplicateObjectReferenceInTest, + ExceptionDuplicateOVALEntity, + ExceptionEmptyNote, + ExceptionMissingObjectReferenceInTest, + ValueError, +) def parse_args(): p = argparse.ArgumentParser() p.add_argument( - "--build-config-yaml", required=True, dest="build_config_yaml", + "--build-config-yaml", + required=True, + dest="build_config_yaml", help="YAML file with information about the build configuration. " - "e.g.: ~/scap-security-guide/build/build_config.yml" + "e.g.: ~/scap-security-guide/build/build_config.yml", ) p.add_argument( - "--product-yaml", required=True, dest="product_yaml", + "--product-yaml", + required=True, + dest="product_yaml", help="YAML file with information about the product we are building. " - "e.g.: ~/scap-security-guide/rhel7/product.yml" + "e.g.: ~/scap-security-guide/rhel7/product.yml", ) p.add_argument( - "--build-ovals-dir", required=True, dest="build_ovals_dir", - help="Directory to store intermediate built OVAL files." + "--build-ovals-dir", + required=True, + dest="build_ovals_dir", + help="Directory to store intermediate built OVAL files.", ) p.add_argument("--output", type=argparse.FileType("wb"), required=True) p.add_argument( - "--include-benchmark", action="store_true", + "--include-benchmark", + action="store_true", help="Include OVAL checks from rule directories in the benchmark " "directory tree which is specified by product.yml " - "in the `benchmark_root` key.") + "in the `benchmark_root` key.", + ) p.add_argument( - "ovaldirs", metavar="OVAL_DIR", nargs="+", + "ovaldirs", + metavar="OVAL_DIR", + nargs="+", help="Shared directory(ies) from which we will collect OVAL " "definitions to combine. Order matters, latter directories override " "former. If --include-benchmark is provided, these will be " "overwritten by OVALs in the rule directory (which in turn preference " - "oval/{{{ product }}}.xml over oval/shared.xml for a given rule.") + "oval/{{{ product }}}.xml over oval/shared.xml for a given rule.", + ) + p.add_argument( + "--log", + action="store", + default="WARNING", + choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"], + help="write debug information to the log up to the LOG_LEVEL.", + ) return p.parse_args() +def setup_logging(log_level_str): + numeric_level = getattr(logging, log_level_str.upper(), None) + if not isinstance(numeric_level, int): + raise ValueError("Invalid log level: {}".format(log_level_str)) + logging.basicConfig(format=MASSAGE_FORMAT, level=numeric_level) + + def main(): args = parse_args() + setup_logging(args.log) - oval_ns = ssg.constants.oval_namespace - footer = ssg.constants.oval_footer env_yaml = ssg.environment.open_environment( - args.build_config_yaml, args.product_yaml) - - header = ssg.xml.oval_generated_header( - "combine_ovals.py", - ssg.utils.required_key(env_yaml, "target_oval_version_str"), - ssg.utils.required_key(env_yaml, "ssg_version")) + args.build_config_yaml, args.product_yaml + ) oval_builder = ssg.build_ovals.OVALBuilder( - env_yaml, - args.product_yaml, - args.ovaldirs, - args.build_ovals_dir) - body = oval_builder.build_shorthand(args.include_benchmark) - - # parse new file(string) as an ssg.xml.ElementTree, so we can reorder elements - # appropriately - corrected_tree = ssg.xml.ElementTree.fromstring( - ("%s%s%s" % (header, body, footer)).encode("utf-8")) - tree = ssg.build_ovals.finalize_affected_platforms(corrected_tree, env_yaml) - definitions = ssg.xml.ElementTree.Element("{%s}definitions" % oval_ns) - tests = ssg.xml.ElementTree.Element("{%s}tests" % oval_ns) - objects = ssg.xml.ElementTree.Element("{%s}objects" % oval_ns) - states = ssg.xml.ElementTree.Element("{%s}states" % oval_ns) - variables = ssg.xml.ElementTree.Element("{%s}variables" % oval_ns) - - for childnode in tree.findall("./{%s}def-group/*" % oval_ns): - if childnode.tag is ssg.xml.ElementTree.Comment: - continue - elif childnode.tag.endswith("definition"): - ssg.build_ovals.append(definitions, childnode) - elif childnode.tag.endswith("_test"): - ssg.build_ovals.append(tests, childnode) - elif childnode.tag.endswith("_object"): - ssg.build_ovals.append(objects, childnode) - elif childnode.tag.endswith("_state"): - ssg.build_ovals.append(states, childnode) - elif childnode.tag.endswith("_variable"): - ssg.build_ovals.append(variables, childnode) - else: - sys.stderr.write("Warning: Unknown element '%s'\n" - % (childnode.tag)) - - root = ssg.xml.ElementTree.fromstring(("%s%s" % (header, footer)).encode("utf-8")) - root.append(definitions) - root.append(tests) - root.append(objects) - if list(states): - root.append(states) - if list(variables): - root.append(variables) - - ssg.xml.ElementTree.ElementTree(root).write(args.output) + env_yaml, args.product_yaml, args.ovaldirs, args.build_ovals_dir + ) + oval_builder.product_name = "Script {}".format(os.path.basename(__file__)) + + try: + oval_document = oval_builder.get_oval_document_from_shorthands( + args.include_benchmark + ) + oval_document.finalize_affected_platforms(env_yaml) + + oval_document.save_as_xml(args.output) + except EXPECTED_ERRORS as error: + logging.critical(error) sys.exit(0) diff --git a/ssg/build_ovals.py b/ssg/build_ovals.py index df7bfb372a4..ba556bbd4b0 100644 --- a/ssg/build_ovals.py +++ b/ssg/build_ovals.py @@ -1,454 +1,168 @@ -from __future__ import absolute_import -from __future__ import print_function - import os -import os.path -import sys -from copy import deepcopy -import collections +import logging +from . import utils, products +from .rules import get_rule_dir_ovals, find_rule_dirs_in_paths +from .oval_object_model import OVALDocument from .build_yaml import Rule, DocumentationNotComplete -from .constants import oval_namespace as oval_ns -from .constants import oval_footer -from .constants import oval_header -from .constants import MULTI_PLATFORM_LIST -from .id_translate import IDTranslator from .jinja import process_file_with_macros from .rule_yaml import parse_prodtype -from .rules import get_rule_dir_ovals, find_rule_dirs_in_paths -from . import utils, products -from .utils import mkdir_p -from .xml import ElementTree, oval_generated_header -from .oval_object_model import get_product_name - - -def _create_subtree(shorthand_tree, category): - parent_tag = "{%s}%ss" % (oval_ns, category) - parent = ElementTree.Element(parent_tag) - for node in shorthand_tree.findall(".//{%s}def-group/*" % oval_ns): - if node.tag is ElementTree.Comment: - continue - elif node.tag.endswith(category): - append(parent, node) - return parent +from .id_translate import IDTranslator +from .xml import ElementTree def expand_shorthand(shorthand_path, oval_path, env_yaml): + oval_document = OVALDocument() + oval_document.ssg_version = env_yaml.get("ssg_version", "Unknown ssg_version") + oval_document.product_name = "test" + oval_document.schema_version = env_yaml.get("target_oval_version_str", "5.11") + shorthand_file_content = process_file_with_macros(shorthand_path, env_yaml) - wrapped_shorthand = (oval_header + shorthand_file_content + oval_footer) - shorthand_tree = ElementTree.fromstring(wrapped_shorthand.encode("utf-8")) - header = oval_generated_header("test", "5.11", "1.0") - skeleton = header + oval_footer - root = ElementTree.fromstring(skeleton.encode("utf-8")) - for category in ["definition", "test", "object", "state", "variable"]: - subtree = _create_subtree(shorthand_tree, category) - if list(subtree): - root.append(subtree) + oval_document.load_shorthand(shorthand_file_content) + + root = oval_document.get_xml_element() + id_translator = IDTranslator("test") root_translated = id_translator.translate(root) ElementTree.ElementTree(root_translated).write(oval_path) -def _check_is_applicable_for_product(oval_check_def, product): - """Based on the specifier of the OVAL check determine if this - OVAL check is applicable for this product. Return 'True' if so, 'False' - otherwise""" - - product, product_version = utils.parse_name(product) - - # Define general platforms - multi_platforms = ['multi_platform_all', - 'multi_platform_' + product] - - # First test if OVAL check isn't for 'multi_platform_all' or - # 'multi_platform_' + product - for multi_prod in multi_platforms: - if multi_prod in oval_check_def and product in MULTI_PLATFORM_LIST: - return True - - # Current SSG checks aren't unified which element of '' - # and '' to use as OVAL AffectedType metadata element, - # e.g. Chromium content uses both of them across the various checks - # Thus for now check both of them when checking concrete platform / product - affected_type_elements = ['', ''] - - for afftype in affected_type_elements: - # Get official name for product (prefixed with content of afftype) - product_name = afftype + get_product_name(product, product_version) - - # Test if this OVAL check is for the concrete product version - if product_name in oval_check_def: - return True - - # OVAL check isn't neither a multi platform one, nor isn't applicable - # for this product => return False to indicate that - - return False - - -def finalize_affected_platforms(xml_tree, env_yaml): - """Depending on your use-case of OVAL you may not need the - element. Such use-cases including using OVAL as a check engine for XCCDF - benchmarks. Since the XCCDF Benchmarks use cpe:platform with CPE IDs, - the affected element in OVAL definitions is redundant and just bloats the - files. This function removes all *irrelevant* affected platform elements - from given OVAL tree. It then adds one platform of the product we are - building. - """ - - for affected in xml_tree.findall(".//{%s}affected" % (oval_ns)): - for platform in affected.findall("./{%s}platform" % (oval_ns)): - affected.remove(platform) - for product in affected.findall("./{%s}product" % (oval_ns)): - affected.remove(product) - - final = ElementTree.SubElement( - affected, "{%s}%s" % (oval_ns, utils.required_key(env_yaml, "type"))) - final.text = utils.required_key(env_yaml, "full_name") - - return xml_tree - - -def oval_entities_are_identical(firstelem, secondelem): - """Check if OVAL entities represented by XML elements are identical - Return: True if identical, False otherwise - Based on: http://stackoverflow.com/a/24349916""" - - # Per https://github.com/ComplianceAsCode/content/pull/1343#issuecomment-234541909 - # and https://github.com/ComplianceAsCode/content/pull/1343#issuecomment-234545296 - # ignore the differences in 'comment', 'version', 'state_operator', and - # 'deprecated' attributes. Also ignore different nsmap, since all these - # don't affect the semantics of the OVAL entities - - # Operate on copies of the elements (since we will modify - # some attributes). Deepcopy will also reset the namespace map - # on copied elements for us - firstcopy = deepcopy(firstelem) - secondcopy = deepcopy(secondelem) - - # Ignore 'comment', 'version', 'state_operator', and 'deprecated' - # attributes since they don't change the semantics of an element - for copy in [firstcopy, secondcopy]: - for key in copy.keys(): - if key in ["comment", "version", "state_operator", - "deprecated"]: - del copy.attrib[key] - - # Compare the equality of the copies - if firstcopy.tag != secondcopy.tag: - return False - if firstcopy.text != secondcopy.text: - return False - if firstcopy.tail != secondcopy.tail: - return False - if firstcopy.attrib != secondcopy.attrib: - return False - if len(firstcopy) != len(secondcopy): - return False - - return all(oval_entities_are_identical( - fchild, schild) for fchild, schild in zip(firstcopy, secondcopy)) - - -def oval_entity_is_extvar(elem): - """Check if OVAL entity represented by XML element is OVAL - element - Return: True if , False otherwise""" - - return elem.tag == '{%s}external_variable' % oval_ns - - -element_child_cache = collections.defaultdict(dict) - - -def append(element, newchild): - """Append new child ONLY if it's not a duplicate""" - - global element_child_cache - - newid = newchild.get("id") - existing = element_child_cache[element].get(newid, None) - - if existing is not None: - # ID is identical and OVAL entities are identical - if oval_entities_are_identical(existing, newchild): - # Moreover the entity is OVAL - if oval_entity_is_extvar(newchild): - # If OVAL entity is identical to some already included - # in the benchmark and represents an OVAL - # it's safe to ignore this ID (since external variables are - # in multiple checks for clarity reasons) - pass - # Some other OVAL entity - else: - # If OVAL entity is identical, but not external_variable, the - # implementation should be rewritten each entity to be present - # just once - sys.stderr.write("ERROR: OVAL ID '%s' is used multiple times " - "and should represent the same elements.\n" - % (newid)) - sys.stderr.write("Rewrite the OVAL checks. Place the identical " - "IDs into their own definition and extend " - "this definition by it.\n") - sys.exit(1) - # ID is identical, but OVAL entities are semantically difference => - # report and error and exit with failure - # Fixes: https://github.com/ComplianceAsCode/content/issues/1275 - else: - if not oval_entity_is_extvar(existing) and \ - not oval_entity_is_extvar(newchild): - # This is an error scenario - since by skipping second - # implementation and using the first one for both references, - # we might evaluate wrong requirement for the second entity - # => report an error and exit with failure in that case - # See - # https://github.com/ComplianceAsCode/content/issues/1275 - # for a reproducer and what could happen in this case - sys.stderr.write("ERROR: it's not possible to use the " + - "same ID: %s " % newid + "for two " + - "semantically different OVAL entities:\n") - sys.stderr.write("First entity %s\n" % ElementTree.tostring(existing)) - sys.stderr.write("Second entity %s\n" % ElementTree.tostring(newchild)) - sys.stderr.write("Use different ID for the second entity!!!\n") - sys.exit(1) - else: - element.append(newchild) - element_child_cache[element][newid] = newchild - - -def check_oval_version(oval_version): - """Not necessary, but should help with typos""" - - supported_versions = ["5.11"] - if oval_version not in supported_versions: - supported_versions_str = ", ".join(supported_versions) - sys.stderr.write( - "Suspicious oval version \"%s\", one of {%s} is " - "expected.\n" % (oval_version, supported_versions_str)) - sys.exit(1) - - -def _check_is_loaded(loaded_dict, filename, version): - if filename in loaded_dict: - if loaded_dict[filename] >= version: - return True - - # Should rather fail, than override something unwanted - sys.stderr.write( - "You cannot override generic OVAL file in version '%s' " - "by more specific one in older version '%s'" % - (version, loaded_dict[filename]) - ) - sys.exit(1) - - return False - - -def _create_oval_tree_from_string(xml_content): - try: - argument = oval_header + xml_content + oval_footer - oval_file_tree = ElementTree.fromstring(argument) - except ElementTree.ParseError as error: - line, column = error.position - lines = argument.splitlines() - before = '\n'.join(lines[:line]) - column_pointer = ' ' * (column - 1) + '^' - sys.stderr.write( - "%s\n%s\nError when parsing OVAL file.\n" % - (before, column_pointer)) - sys.exit(1) - return oval_file_tree - - -def _check_oval_version_from_oval(oval_file_tree, oval_version): - for defgroup in oval_file_tree.findall("./{%s}def-group" % oval_ns): - file_oval_version = defgroup.get("oval_version") - - if file_oval_version is None: - # oval_version does not exist in - # which means the OVAL is supported for any version. - # By default, that version is 5.11 - file_oval_version = "5.11" - - if tuple(oval_version.split(".")) >= tuple(file_oval_version.split(".")): - return True - - -def _check_rule_id(oval_file_tree, rule_id): - for definition in oval_file_tree.findall( - "./{%s}def-group/{%s}definition" % (oval_ns, oval_ns)): - definition_id = definition.get("id") - return definition_id == rule_id - return False - - -def _list_full_paths(directory): - full_paths = [os.path.join(directory, x) for x in os.listdir(directory)] - return sorted(full_paths) +class OVALBuildException(Exception): + pass class OVALBuilder: def __init__( - self, env_yaml, product_yaml_path, shared_directories, - build_ovals_dir): + self, + env_yaml, + product_yaml_path, + shared_directories, + build_ovals_dir, + ): self.env_yaml = env_yaml self.product_yaml = products.Product(product_yaml_path) + self.product = utils.required_key(env_yaml, "product") + self.shared_directories = shared_directories self.build_ovals_dir = build_ovals_dir - self.already_loaded = dict() - self.oval_version = utils.required_key( - env_yaml, "target_oval_version_str") - self.product = utils.required_key(env_yaml, "product") - def build_shorthand(self, include_benchmark): + self.oval_document = OVALDocument() + self.oval_document.ssg_version = env_yaml.get( + "ssg_version", "Unknown ssg_version" + ) + self.oval_document.schema_version = utils.required_key( + env_yaml, "target_oval_version_str" + ) + + self.already_processed = [] + + @property + def product_name(self): + return self.oval_document.product_name + + @product_name.setter + def product_name(self, __value): + self.oval_document.product_name = __value + + def get_oval_document_from_shorthands(self, include_benchmark): if self.build_ovals_dir: - mkdir_p(self.build_ovals_dir) - all_checks = [] + utils.mkdir_p(self.build_ovals_dir) if include_benchmark: - all_checks += self._get_checks_from_benchmark() - all_checks += self._get_checks_from_shared_directories() - document_body = "".join(all_checks) - return document_body + self._load_checks_from_benchmark() + self._load_checks_from_shared_directories() + return self.oval_document - def _get_checks_from_benchmark(self): + def _get_dirs_rules_from_benchmark(self): product_dir = self.product_yaml["product_dir"] relative_guide_dir = utils.required_key(self.env_yaml, "benchmark_root") - guide_dir = os.path.abspath( - os.path.join(product_dir, relative_guide_dir)) + guide_dir = os.path.abspath(os.path.join(product_dir, relative_guide_dir)) additional_content_directories = self.env_yaml.get( - "additional_content_directories", []) + "additional_content_directories", [] + ) dirs_to_scan = [guide_dir] for rd in additional_content_directories: abspath = os.path.abspath(os.path.join(product_dir, rd)) dirs_to_scan.append(abspath) - rule_dirs = list(find_rule_dirs_in_paths(dirs_to_scan)) - oval_checks = self._process_directories(rule_dirs, True) - return oval_checks + return list(find_rule_dirs_in_paths(dirs_to_scan)) + + def _load_checks_from_benchmark(self): + rule_dirs = self._get_dirs_rules_from_benchmark() + self._process_directories(rule_dirs, True) - def _get_checks_from_shared_directories(self): + def _load_checks_from_shared_directories(self): # earlier directory has higher priority reversed_dirs = self.shared_directories[::-1] - oval_checks = self._process_directories(reversed_dirs, False) - return oval_checks + self._process_directories(reversed_dirs, False) def _process_directories(self, directories, from_benchmark): - oval_checks = [] for directory in directories: if not os.path.exists(directory): continue - oval_checks += self._process_directory(directory, from_benchmark) - return oval_checks - - def _get_list_of_oval_files(self, directory, from_benchmark): - if from_benchmark: - oval_files = get_rule_dir_ovals(directory, self.product) - else: - oval_files = _list_full_paths(directory) - return oval_files + self._process_directory(directory, from_benchmark) def _process_directory(self, directory, from_benchmark): try: context = self._get_context(directory, from_benchmark) except DocumentationNotComplete: - return [] - oval_files = self._get_list_of_oval_files(directory, from_benchmark) - oval_checks = self._get_directory_oval_checks( - context, oval_files, from_benchmark) - return oval_checks - - def _get_directory_oval_checks(self, context, oval_files, from_benchmark): - oval_checks = [] - for file_path in oval_files: - xml_content = self._process_oval_file( - file_path, from_benchmark, context) - if xml_content is None: - continue - oval_checks.append(xml_content) - return oval_checks + return + for file_path in self._get_list_of_oval_files(directory, from_benchmark): + self._process_oval_file(file_path, from_benchmark, context) - def _read_oval_file(self, file_path, context, from_benchmark): - if from_benchmark or "checks_from_templates" not in file_path: - xml_content = process_file_with_macros(file_path, context) - else: - with open(file_path, "r") as f: - xml_content = f.read() - return xml_content + def _get_context(self, directory, from_benchmark): + if from_benchmark: + rule_path = os.path.join(directory, "rule.yml") + rule = Rule.from_yaml(rule_path, self.env_yaml) + + local_env_yaml = dict(**self.env_yaml) + local_env_yaml["rule_id"] = rule.id_ + local_env_yaml["rule_title"] = rule.title + prodtypes = parse_prodtype(rule.prodtype) + local_env_yaml["products"] = prodtypes # default is all + + return local_env_yaml + return self.env_yaml + + def _get_list_of_oval_files(self, directory, from_benchmark): + if from_benchmark: + return get_rule_dir_ovals(directory, self.product) + return sorted([os.path.join(directory, x) for x in os.listdir(directory)]) def _create_key(self, file_path, from_benchmark): if from_benchmark: - rule_id = os.path.basename( - (os.path.dirname(os.path.dirname(file_path)))) + rule_id = self._get_rule_id(file_path) oval_key = "%s.xml" % rule_id else: oval_key = os.path.basename(file_path) return oval_key + def _get_rule_id(self, file_path): + return os.path.basename(os.path.dirname(os.path.dirname(file_path))) + def _process_oval_file(self, file_path, from_benchmark, context): - if not file_path.endswith(".xml"): - return None oval_key = self._create_key(file_path, from_benchmark) - if _check_is_loaded(self.already_loaded, oval_key, self.oval_version): - return None + if oval_key in self.already_processed: + return + xml_content = self._read_oval_file(file_path, context, from_benchmark) - if not self._manage_oval_file_xml_content( - file_path, xml_content, from_benchmark): - return None - self.already_loaded[oval_key] = self.oval_version - return xml_content - - def _check_affected(self, tree): - definitions = tree.findall(".//{%s}definition" % (oval_ns)) - for definition in definitions: - def_id = definition.get("id") - affected = definition.findall( - "./{%s}metadata/{%s}affected" % (oval_ns, oval_ns)) - if not affected: - raise ValueError( - "Definition '%s' doesn't contain OVAL 'affected' element" - % (def_id)) - - def _manage_oval_file_xml_content( - self, file_path, xml_content, from_benchmark): - oval_file_tree = _create_oval_tree_from_string(xml_content) - self._check_affected(oval_file_tree) - if not _check_is_applicable_for_product(xml_content, self.product): - return False - if not _check_oval_version_from_oval(oval_file_tree, self.oval_version): - return False - if from_benchmark: - self._benchmark_specific_actions( - file_path, xml_content, oval_file_tree) - return True - - def _benchmark_specific_actions( - self, file_path, xml_content, oval_file_tree): - rule_id = os.path.basename( - (os.path.dirname(os.path.dirname(file_path)))) - self._store_intermediate_file(rule_id, xml_content) - if not _check_rule_id(oval_file_tree, rule_id): - msg = "ERROR: OVAL definition in '%s' doesn't match rule ID '%s'." % ( - file_path, rule_id) - print(msg, file=sys.stderr) - sys.exit(1) - def _get_context(self, directory, from_benchmark): + rule_id = None if from_benchmark: - rule_path = os.path.join(directory, "rule.yml") - rule = Rule.from_yaml(rule_path, self.env_yaml) - context = self._create_local_env_yaml_for_rule(rule) - else: - context = self.env_yaml - return context - - def _create_local_env_yaml_for_rule(self, rule): - local_env_yaml = dict() - local_env_yaml.update(self.env_yaml) - local_env_yaml['rule_id'] = rule.id_ - local_env_yaml['rule_title'] = rule.title - prodtypes = parse_prodtype(rule.prodtype) - local_env_yaml['products'] = prodtypes # default is all - return local_env_yaml + rule_id = self._get_rule_id(file_path) + self._store_intermediate_file(rule_id, xml_content) + + if self.oval_document.load_shorthand(xml_content, self.product, rule_id): + self.already_processed.append(oval_key) + + def _read_oval_file(self, file_path, context, from_benchmark): + if not file_path.endswith(".xml"): + logging.critical("File name '{}' doesn't end with '.xml'.".format(file_path)) + + if from_benchmark or "checks_from_templates" not in file_path: + return process_file_with_macros(file_path, context) + + with open(file_path, "r") as f: + return f.read() def _store_intermediate_file(self, rule_id, xml_content): if not self.build_ovals_dir: diff --git a/ssg/oval_object_model/general.py b/ssg/oval_object_model/general.py index 7c747f85119..c01d241d65c 100644 --- a/ssg/oval_object_model/general.py +++ b/ssg/oval_object_model/general.py @@ -62,6 +62,9 @@ def namespace(self, __value): __value = __value + "}" self.__namespace = __value + def __ne__(self, __value): + return self.__dict__ != __value.__dict__ + def __eq__(self, __value): return self.__dict__ == __value.__dict__ diff --git a/tests/unit/ssg-module/test_build_ovals.py b/tests/unit/ssg-module/test_build_ovals.py index e0a329ab61e..1c7d3503013 100644 --- a/tests/unit/ssg-module/test_build_ovals.py +++ b/tests/unit/ssg-module/test_build_ovals.py @@ -1,7 +1,5 @@ import os -import pytest import tempfile -import xml.etree.ElementTree as ET import ssg.build_ovals @@ -12,10 +10,8 @@ SHARED_OVALS = os.path.join(DATADIR, "shared_ovals") BUILD_OVALS_DIR = tempfile.mkdtemp() -shared_oval_1_def_tag = '' -benchmark_oval_1_def_tag = '' +shared_oval_1_def_id = "tmux_conf_readable_by_others" +benchmark_oval_1_def_id = "selinux_state" def test_build_ovals(): @@ -23,11 +19,11 @@ def test_build_ovals(): "product": "rhel9", "target_oval_version_str": "5.11", } - obuilder = ssg.build_ovals.OVALBuilder( + oval_builder = ssg.build_ovals.OVALBuilder( env_yaml, PRODUCT_YAML, [SHARED_OVALS], BUILD_OVALS_DIR) - shorthand = obuilder.build_shorthand(include_benchmark=False) - assert shared_oval_1_def_tag in shorthand - assert benchmark_oval_1_def_tag not in shorthand + oval_document = oval_builder.get_oval_document_from_shorthands(include_benchmark=False) + assert shared_oval_1_def_id in oval_document.definitions + assert benchmark_oval_1_def_id not in oval_document.definitions def test_build_ovals_include_benchmark(): @@ -36,8 +32,8 @@ def test_build_ovals_include_benchmark(): "product": "rhel9", "target_oval_version_str": "5.11", } - obuilder = ssg.build_ovals.OVALBuilder( + oval_builder = ssg.build_ovals.OVALBuilder( env_yaml, PRODUCT_YAML, [SHARED_OVALS], BUILD_OVALS_DIR) - shorthand = obuilder.build_shorthand(include_benchmark=True) - assert shared_oval_1_def_tag in shorthand - assert benchmark_oval_1_def_tag in shorthand + oval_document = oval_builder.get_oval_document_from_shorthands(include_benchmark=True) + assert shared_oval_1_def_id in oval_document.definitions + assert benchmark_oval_1_def_id in oval_document.definitions