Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change loading of OVAL result reports #140

Merged
merged 6 commits into from
Apr 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ def get_applicable_cpe_platforms_for_profile(self):
return ", ".join(self.cpe_platforms_for_profile.keys())

def get_cpe_platforms_that_satisfy_evaluation_target(self):
return ", ".join(
[cpe_id for cpe_id, is_satisfy in self.cpe_platforms_for_profile.items() if is_satisfy]
)
return ", ".join(self.get_list_of_cpe_platforms_that_satisfy_evaluation_target())

def get_list_of_cpe_platforms_that_satisfy_evaluation_target(self):
return [
cpe_id for cpe_id, is_satisfy in self.cpe_platforms_for_profile.items() if is_satisfy
]
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class Rule: # pylint: disable=R0902
warnings: List[RuleWarning] = field(default_factory=list)
platforms: List[str] = field(default_factory=list)
oval_definition_id: str = None
oval_reference: str = None
oval_definition: OvalDefinition = None
messages: List[str] = field(default_factory=list)
remediations: List[Remediation] = field(default_factory=list)
Expand Down
118 changes: 84 additions & 34 deletions openscap_report/scap_results_parser/oval_and_cpe_tree_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,55 +9,89 @@


class OVALAndCPETreeBuilder: # pylint: disable=R0902
def __init__(self, root, group_parser, profile_platforms):
def __init__(self, root, group_parser, profile_platforms, oval_definitions_and_results_sources):
self.profile_platforms = profile_platforms
self.root = root
self.group_parser = group_parser
self.oval_definitions_and_results_sources = oval_definitions_and_results_sources
self.cpe_source = ""
self.missing_oval_results = False
self.cpe_al = True
self.oval_definitions = {}
self.oval_cpe_definitions = {}
self.reports_with_oval_definitions = None
self.platform_to_oval_cpe_id = {}
self.cpe_platforms = {}
self.dict_of_oval_cpe_definitions = {}
self.load_oval_definitions()

def load_oval_definitions(self):
try:
self.cpe_al_parser = CPEApplicabilityLanguageParser(self.root)
self.platform_to_oval_cpe_id = self.cpe_al_parser.platform_to_oval_cpe_id
self.oval_definition_parser = OVALDefinitionParser(
self.root, self.platform_to_oval_cpe_id
self.oval_definition_parser = OVALDefinitionParser(self.root)
self.reports_with_oval_definitions = self.oval_definition_parser.get_oval_definitions()
self._determine_cpe_source()
self.dict_of_oval_cpe_definitions = self._get_dict_of_oval_cpe_definitions()
self.cpe_al_parser = CPEApplicabilityLanguageParser(
self.root, self.dict_of_oval_cpe_definitions
)
self.oval_definitions = self.oval_definition_parser.get_oval_definitions()
self.oval_cpe_definitions = self.oval_definition_parser.get_oval_cpe_definitions()
self.platform_to_oval_cpe_id = self.cpe_al_parser.platform_to_oval_cpe_id
self._load_cpe_platforms()
except MissingOVALResult as error:
logging.warning((
"The given input doesn't contain OVAL results (\"%s\"),"
" OVAL details won't be shown in the report."), error)
if str(error) != "oval1":
self.missing_oval_results = True
"The given input doesn't contain OVAL results (\"%s\"), "
"OVAL details won't be shown in the report."), error)
self.missing_oval_results = True

def _determine_cpe_source(self):
source_id = set(self.reports_with_oval_definitions.keys()).difference(
self.oval_definitions_and_results_sources
)
if len(source_id) == 1:
self.cpe_source = source_id.pop()

def _get_dict_of_oval_cpe_definitions(self):
if self.cpe_source in self.reports_with_oval_definitions:
return self.reports_with_oval_definitions[self.cpe_source]
logging.warning((
"The given input does not contain a clear mapping of the OVAL definition used "
"for CPE checks. The results of the OVAL definition in the CPE checks could "
"be biased."
))
all_oval_definition = {}
for report in self.reports_with_oval_definitions.values():
for id_definition, definition in report.items():
if id_definition not in all_oval_definition:
all_oval_definition[id_definition] = definition
else:
if definition.oval_tree.evaluate_tree() != "not evaluated":
all_oval_definition[id_definition] = definition
return all_oval_definition

def _get_oval_definition_of_cpe(self, platform):
cpe_oval_id = self.platform_to_oval_cpe_id.get(platform)
return self.dict_of_oval_cpe_definitions.get(cpe_oval_id)

def _load_cpe_platforms(self):
try:
self.cpe_platforms = self.cpe_al_parser.get_cpe_platforms(self.oval_cpe_definitions)
self.cpe_platforms = self.cpe_al_parser.get_cpe_platforms()
for platform in self.profile_platforms:
if platform in self.platform_to_oval_cpe_id:
cpe_oval_id = self.platform_to_oval_cpe_id[platform]
if cpe_oval_id in self.oval_cpe_definitions:
oval_tree = self.oval_cpe_definitions[cpe_oval_id].oval_tree
self.cpe_platforms[platform] = Platform(
platform_id=platform,
logical_test=LogicalTest(
node_type="AND",
children=[LogicalTest(
node_type="frac-ref",
value=cpe_oval_id,
oval_tree=oval_tree
)],
),
title="Profile platform",
)
oval_definition = self._get_oval_definition_of_cpe(platform)
if oval_definition is None:
logging.warning(
"Platform (\"%s\") doesn't exist, Platform won't be shown in the report.",
platform
)
continue
self.cpe_platforms[platform] = Platform(
platform_id=platform,
logical_test=LogicalTest(
node_type="AND",
children=[LogicalTest(
node_type="frac-ref",
value=oval_definition.definition_id,
oval_tree=oval_definition.oval_tree
)],
),
title="Profile platform",
)
self._evaluate_all_cpe_platforms()
except ExceptionNoCPEApplicabilityLanguage:
self.cpe_al = False
Expand All @@ -71,8 +105,8 @@ def _get_oval_tree_from_oval_cpe_definition(self, platform):
cpe_platform = platform.lstrip("#")
if cpe_platform in self.platform_to_oval_cpe_id:
cpe_oval_id = self.platform_to_oval_cpe_id[cpe_platform]
if cpe_oval_id in self.oval_cpe_definitions:
return self.oval_cpe_definitions[cpe_oval_id].oval_tree
if cpe_oval_id in self.dict_of_oval_cpe_definitions:
return self.dict_of_oval_cpe_definitions[cpe_oval_id].oval_tree
if cpe_platform in self.cpe_platforms:
return None
logging.warning("There is no CPE check for the platform \"%s\".", platform)
Expand Down Expand Up @@ -100,13 +134,29 @@ def _remove_double_cpe_requirement(rule, group_platforms):
if platform in group_platforms:
group_platforms.remove(platform)

def get_oval_definition(self, rule):
report = self.reports_with_oval_definitions.get(rule.oval_reference, None)
if report is not None:
return report.get(rule.oval_definition_id)
oval_def = None
for report in self.reports_with_oval_definitions.values():
if oval_def is not None and rule.oval_definition_id in report:
logging.warning(
("The given input contains the duplicate results of "
"the OVAL definition (\"%s\")."),
rule.oval_definition_id
)
if rule.oval_definition_id in report:
oval_def = report[rule.oval_definition_id]
return oval_def

def insert_oval_and_cpe_trees_to_rules(self, rules):
if self.missing_oval_results:
return

for rule in rules.values():
if rule.oval_definition_id in self.oval_definitions:
rule.oval_definition = self.oval_definitions[rule.oval_definition_id]
rule.oval_definition = self.get_oval_definition(rule)

rule_group = self.group_parser.rule_to_group_id.get(rule.rule_id, "")
group_platforms = self.group_parser.group_to_platforms.get(rule_group, [])
self._remove_double_cpe_requirement(rule, group_platforms)
Expand Down
7 changes: 3 additions & 4 deletions openscap_report/scap_results_parser/parsers/cpe_al_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@


class CPEApplicabilityLanguageParser:
def __init__(self, root):
def __init__(self, root, oval_cpe_definitions):
self.root = root
self.platform_to_oval_cpe_id = self.get_platform_to_oval_cpe_id_dict()
self.full_text_parser = FullTextParser({})
self.oval_cpe_definitions = {}
self.oval_cpe_definitions = oval_cpe_definitions

def get_platform_to_oval_cpe_id_dict(self):
cpe_list = self.root.find(".//ds:component/cpe-dict:cpe-list", NAMESPACES)
Expand Down Expand Up @@ -69,9 +69,8 @@ def get_logical_test(self, logical_test_el):
logical_test.children.append(self.get_logical_test(child_logical_test_el))
return logical_test

def get_cpe_platforms(self, oval_cpe_definitions):
def get_cpe_platforms(self):
out = {}
self.oval_cpe_definitions = oval_cpe_definitions
for platform, platform_el in self._get_cpe_platform_elements().items():
title_el = platform_el.find(".//cpe-lang:title", NAMESPACES)
title_str = ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,18 @@


class OVALDefinitionParser:
def __init__(self, root, platform_to_oval_cpe_id):
def __init__(self, root):
self.root = root
self.oval_result_parser = OVALResultParser(self.root, platform_to_oval_cpe_id)
self.oval_trees = self.oval_result_parser.get_oval_trees()
self.oval_cpe_trees = self.oval_result_parser.get_oval_cpe_trees()
self.oval_result_parser = OVALResultParser(self.root)
self.oval_trees_by_oval_reports = self.oval_result_parser.get_oval_trees_by_oval_reports()

self.oval_reports = self.oval_result_parser.oval_reports
self.oval_definitions = self._get_xml_elements_of_oval_definitions()

def _get_xml_elements_of_oval_definitions(self):
out = {}
for oval, oval_report in self.oval_reports.items():
out[oval] = oval_report.find(
out[oval] = oval_report.oval_report_element.find(
'.//oval-definitions:oval_definitions/oval-definitions:definitions', NAMESPACES)
return out

Expand Down Expand Up @@ -64,10 +63,10 @@ def _get_oval_definitions(self, oval):
return definitions

def get_oval_definitions(self):
return self._get_oval_definitions("oval0")

def get_oval_cpe_definitions(self):
return self._get_oval_definitions("oval1")
oval_definitions_by_reports = {}
for report_id in self.oval_trees_by_oval_reports:
oval_definitions_by_reports[report_id] = self._get_oval_definitions(report_id)
return oval_definitions_by_reports

def _get_test_criteria(self, criterion):
out = {"comment": criterion.get("comment")}
Expand All @@ -90,11 +89,9 @@ def _create_dict_from_criteria(self, criteria):
criteria_dict["child_criteria"].append(self._get_test_criteria(criterion))
return criteria_dict

def _add_oval_tree_to_definition(self, definitions, oval):
def _add_oval_tree_to_definition(self, definitions, oval_report_id):
oval_tree_source = self.oval_trees_by_oval_reports.get(oval_report_id, {})
for definition_id in definitions:
oval_tree_source = self.oval_trees
if oval == "oval1":
oval_tree_source = self.oval_cpe_trees
self._set_oval_tree_to_definition(definitions, definition_id, oval_tree_source)

def _set_oval_tree_to_definition(self, definitions, definition_id, oval_tree_source):
Expand Down Expand Up @@ -126,11 +123,9 @@ def _fill_oval_tree_with_comments(self, oval_tree, criteria_id, criteria_dict, c
self._fill_oval_tree_with_comments(
oval_node, criterion.get("extend_definition"), criteria_dict)

def _add_comments_to_oval_tree(self, dict_of_criteria, oval):
def _add_comments_to_oval_tree(self, dict_of_criteria, oval_report_id):
oval_tree_source = self.oval_trees_by_oval_reports.get(oval_report_id, {})
for id_ in dict_of_criteria:
oval_tree_source = self.oval_trees
if oval == "oval1":
oval_tree_source = self.oval_cpe_trees

if id_ not in oval_tree_source:
continue
Expand Down
Loading