openscap_report.scap_results_parser.scap_results_parser   A
last analyzed

Complexity

Total Complexity 20

Size/Duplication

Total Lines 119
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 88
dl 0
loc 119
ccs 75
cts 75
cp 1
rs 10
c 0
b 0
f 0
wmc 20

10 Methods

Rating   Name   Duplication   Size   Complexity  
A SCAPResultsParser._validate_xccdf_or_arf() 0 14 4
A SCAPResultsParser._log_info_about_input_report_type() 0 6 3
A SCAPResultsParser._debug_show_rules() 0 5 2
A SCAPResultsParser.__init__() 0 4 1
A SCAPResultsParser.validate() 0 5 1
A SCAPResultsParser._get_oval_definition_references() 0 7 3
A SCAPResultsParser._get_benchmark_element() 0 5 2
A SCAPResultsParser._get_ref_values() 0 4 2
A SCAPResultsParser._get_map_oval_var_to_value() 0 6 1
A SCAPResultsParser.parse_report() 0 31 1
1
# Copyright 2022, Red Hat, Inc.
2
# SPDX-License-Identifier: LGPL-2.1-or-later
3
4 1
import logging
5 1
from pathlib import Path
6
7 1
from lxml import etree
8
9 1
from .exceptions import NotSupportedReportingFormat
10 1
from .namespaces import NAMESPACES
11 1
from .oval_and_cpe_tree_builder import OVALAndCPETreeBuilder
12 1
from .parsers import GroupParser, ReportParser, RuleParser
13
14 1
SCHEMAS_DIR = Path(__file__).parent / "schemas"
15 1
ARF_SCHEMAS_PATH = 'arf/1.1/asset-reporting-format_1.1.0.xsd'
16 1
XCCDF_1_2_SCHEMAS_PATH = 'xccdf/1.2/xccdf_1.2.xsd'
17
18
19 1
class SCAPResultsParser():
20 1
    def __init__(self, data):
21 1
        self.root = etree.XML(data)
22 1
        self.ref_values = self._get_ref_values()
23 1
        self._validate_xccdf_or_arf()
24
25 1
    def _validate_xccdf_or_arf(self):
26 1
        is_valid_arf = self.validate(ARF_SCHEMAS_PATH)
27 1
        is_valid_xccdf_1_2 = self.validate(XCCDF_1_2_SCHEMAS_PATH)
28
29 1
        if not is_valid_arf and not is_valid_xccdf_1_2:
30 1
            raise NotSupportedReportingFormat(
31
                "The given input isn't a valid ARF report or XCCDF report!"
32
            )
33 1
        if is_valid_xccdf_1_2:
34 1
            logging.warning(("The given input is the XCCDF report,"
35
                             " some information will not appear in the report."
36
                             " Use the ARF report for the complete report."
37
                             ))
38 1
        self._log_info_about_input_report_type(is_valid_arf, is_valid_xccdf_1_2)
39
40 1
    @staticmethod
41 1
    def _log_info_about_input_report_type(is_valid_arf, is_valid_xccdf_1_2):
42 1
        if is_valid_arf:
43 1
            logging.info("The given input is a valid ARF report.")
44 1
        if is_valid_xccdf_1_2:
45 1
            logging.info("The given input is a valid XCCDF 1.2 report.")
46
47 1
    def validate(self, xsd_path):
48 1
        xsd_path = str(SCHEMAS_DIR / xsd_path)
49 1
        xmlschema_doc = etree.parse(xsd_path)
50 1
        xmlschema = etree.XMLSchema(xmlschema_doc)
51 1
        return xmlschema.validate(self.root)
52
53 1
    def _get_ref_values(self):
54 1
        return {
55
            ref_value.get("idref"): ref_value.text if ref_value.text is not None else ""
56
            for ref_value in self.root.findall('.//xccdf:set-value', NAMESPACES)
57
        }
58
59 1
    @staticmethod
60 1
    def _debug_show_rules(rules):
61 1
        for rule_id, rule in rules.items():
62 1
            logging.debug(rule_id)
63 1
            logging.debug(rule)
64
65 1
    def _get_benchmark_element(self):
66 1
        benchmark_el = self.root.find(".//xccdf:Benchmark", NAMESPACES)
67 1
        if "Benchmark" in self.root.tag:
68 1
            benchmark_el = self.root
69 1
        return benchmark_el
70
71 1
    @staticmethod
72 1
    def _get_oval_definition_references(rules):
73 1
        references = []
74 1
        for rule in rules.values():
75 1
            if rule.oval_reference is not None:
76 1
                references.append(rule.oval_reference)
77 1
        return set(tuple(references))
78
79 1
    @staticmethod
80 1
    def _get_map_oval_var_to_value(test_results_el):
81 1
        return {
82
            check_export.attrib.get("export-name"): check_export.attrib.get("value-id", "")
83
            for check_export in test_results_el.findall(
84
                ".//xccdf:rule-result//xccdf:check//xccdf:check-export", NAMESPACES
85
            )
86
        }
87
88 1
    def parse_report(self):
89 1
        test_results_el = self.root.find('.//xccdf:TestResult', NAMESPACES)
90 1
        benchmark_el = self._get_benchmark_element()
91
92 1
        report_parser = ReportParser(self.root, test_results_el, benchmark_el)
93 1
        report = report_parser.get_report()
94 1
        logging.debug(report)
95
96 1
        group_parser = GroupParser(self.root, self.ref_values, benchmark_el)
97 1
        groups = group_parser.get_groups()
98
99 1
        rule_parser = RuleParser(self.root, test_results_el, self.ref_values)
100 1
        rules = rule_parser.get_rules()
101 1
        oval_definitions_and_results_sources = self._get_oval_definition_references(rules)
102 1
        OVAL_and_CPE_tree_builder = OVALAndCPETreeBuilder(  # pylint: disable=C0103
103
            self.root, group_parser,
104
            report.profile_info.get_list_of_cpe_platforms_that_satisfy_evaluation_target(),
105
            oval_definitions_and_results_sources,
106
            self._get_map_oval_var_to_value(test_results_el),
107
            self.ref_values,
108
        )
109 1
        OVAL_and_CPE_tree_builder.insert_oval_and_cpe_trees_to_rules(rules)
110
111 1
        self._debug_show_rules(rules)
112 1
        report.rules = rules
113 1
        report.groups = groups
114
115 1
        report.profile_info.select_rules(rule_parser.to_select_rule_ids)
116 1
        report.profile_info.deselect_rules(rule_parser.to_deselect_rule_ids)
117
118
        return report
119