openscap_report.scap_results_parser.parsers.oval_result_parser   A
last analyzed

Complexity

Total Complexity 27

Size/Duplication

Total Lines 182
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 27
eloc 143
dl 0
loc 182
ccs 98
cts 98
cp 1
rs 10
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A OVALResultParser._fill_extend_definition_help() 0 19 4
A OVALResultParser._get_result() 0 11 3
A OVALResultParser._find_definition_by_id() 0 6 1
A OVALResultParser.get_oval_trees_by_oval_reports() 0 15 3
A OVALResultParser._build_node() 0 26 4
A OVALResultParser.__init__() 0 6 1
A OVALResultParser._get_oval_reports() 0 20 4
A OVALResultParser._get_oval_results() 0 4 1
A OVALResultParser._fill_extend_definition() 0 6 2
A OVALResultParser._get_test_node() 0 12 1
A OVALResultParser._get_negation() 0 6 2
A OVALResultParser._get_extend_definition_node() 0 9 1
1
# Copyright 2022, Red Hat, Inc.
2
# SPDX-License-Identifier: LGPL-2.1-or-later
3
4 1
import logging
5 1
import uuid
6
7 1
from lxml.etree import Element
8
9 1
from openscap_report.dataclasses import dataclass
10
11 1
from ..data_structures import OvalNode
12 1
from ..exceptions import MissingOVALResult
13 1
from ..namespaces import NAMESPACES
14 1
from .oval_test_parser import OVALTestParser
15
16 1
STR_TO_BOOL = {'true': True, 'false': False}
17 1
STR_NEGATION_BOOL = {'true': 'false', 'false': 'true'}
18
19
20 1
@dataclass
21 1
class OVALReport:
22 1
    oval_report_id: str
23 1
    oval_report_element: Element
24 1
    oval_results_element: Element
25 1
    oval_test_parser: OVALTestParser
26
27
28 1
class OVALResultParser:
29 1
    def __init__(self, root, oval_var_id_to_value_id, ref_values):
30 1
        self.root = root
31 1
        self.oval_var_id_to_value_id = oval_var_id_to_value_id
32 1
        self.ref_values = ref_values
33 1
        self.oval_reports = self._get_oval_reports()
34 1
        logging.info(self.oval_reports)
35
36 1
    def _get_oval_reports(self):
37 1
        oval_reports = {}
38 1
        reports = self.root.find('.//arf:reports', NAMESPACES)
39 1
        if reports is None:
40 1
            raise MissingOVALResult("all_OVAL_results")
41
42 1
        for report_element in reports:
43 1
            report_id = report_element.get("id")
44 1
            if "oval" in report_id:
45 1
                oval_results = self._get_oval_results(report_element)
46 1
                oval_test_parser = OVALTestParser(
47
                    report_element, self.oval_var_id_to_value_id, self.ref_values
48
                )
49 1
                oval_reports[report_id] = OVALReport(
50
                    report_id,
51
                    report_element,
52
                    oval_results,
53
                    oval_test_parser
54
                )
55 1
        return oval_reports
56
57 1
    def _get_oval_results(self, oval_report):
58 1
        return oval_report.find(
59
            ('.//XMLSchema:oval_results/XMLSchema:results/'
60
             'XMLSchema:system/XMLSchema:definitions'), NAMESPACES)
61
62 1
    def get_oval_trees_by_oval_reports(self):
63 1
        dict_of_oval_reports = {}
64 1
        for report_id, report in self.oval_reports.items():
65 1
            dict_of_oval_results = {}
66 1
            for definition in report.oval_results_element:
67 1
                id_definition = definition.get('definition_id')
68 1
                criteria_result = definition[0]
69 1
                dict_of_oval_results[id_definition] = self._build_node(
70
                    criteria_result,
71
                    "Definition",
72
                    id_definition,
73
                    report_id
74
                )
75 1
            dict_of_oval_reports[report_id] = self._fill_extend_definition(dict_of_oval_results)
76 1
        return dict_of_oval_reports
77
78 1
    @staticmethod
79 1
    def _get_negation(node):
80 1
        negation = False
81 1
        if node.get('negate') is not None:
82 1
            negation = STR_TO_BOOL[node.get('negate')]
83 1
        return negation
84
85 1
    @staticmethod
86 1
    def _get_result(negation, tree):
87
        """
88
            This  method  removes  the  negation of
89
            the result. Because negation is already
90
            included in the result in ARF file.
91
        """
92 1
        result = tree.get('result')
93 1
        if negation and result in ('true', 'false'):
94 1
            result = STR_NEGATION_BOOL[result]
95 1
        return result
96
97 1
    def _get_extend_definition_node(self, child):
98 1
        negation = self._get_negation(child)
99 1
        result_of_node = self._get_result(negation, child)
100 1
        return OvalNode(
101
            node_id=child.get('definition_ref'),
102
            node_type="extend_definition",
103
            value=result_of_node,
104
            negation=negation,
105
            tag="Extend definition",
106
        )
107
108 1
    def _get_test_node(self, child, oval_report_id):
109 1
        negation = self._get_negation(child)
110 1
        result_of_node = self._get_result(negation, child)
111 1
        test_id = child.get('test_ref')
112 1
        oval_test_parser = self.oval_reports[oval_report_id].oval_test_parser
113 1
        return OvalNode(
114
            node_id=test_id,
115
            node_type="value",
116
            value=result_of_node,
117
            negation=negation,
118
            tag="Test",
119
            test_info=oval_test_parser.get_test_info(test_id),
120
        )
121
122 1
    def _build_node(self, tree, tag, id_definition, oval_report_id):
123 1
        negation = self._get_negation(tree)
124 1
        node = OvalNode(
125
            node_id=id_definition,
126
            node_type=tree.get('operator'),
127
            negation=negation,
128
            value=self._get_result(negation, tree),
129
            tag=tag,
130
            children=[],
131
        )
132 1
        for child in tree:
133 1
            if child.get('operator') is not None:
134 1
                node.children.append(
135
                    self._build_node(
136
                        child,
137
                        "Criteria",
138
                        f"no-id-criteria-{uuid.uuid4()}",
139
                        oval_report_id
140
                    )
141
                )
142
            else:
143 1
                if child.get('definition_ref') is not None:
144 1
                    node.children.append(self._get_extend_definition_node(child))
145
                else:
146 1
                    node.children.append(self._get_test_node(child, oval_report_id))
147 1
        return node
148
149 1
    def _fill_extend_definition(self, dict_of_oval_definitions):
150 1
        out = {}
151 1
        for id_definition, definition in dict_of_oval_definitions.items():
152 1
            out[id_definition] = self._fill_extend_definition_help(
153
                definition, dict_of_oval_definitions)
154 1
        return out
155
156 1
    def _fill_extend_definition_help(self, node, dict_of_oval_definitions):
157 1
        out = OvalNode(
158
            node_id=node.node_id,
159
            node_type=node.node_type,
160
            negation=node.negation,
161
            value=node.value,
162
            tag=node.tag,
163
            children=[],
164
        )
165 1
        for child in node.children:
166 1
            if child.node_type in ("AND", "OR", "ONE", "XOR"):
167 1
                out.children.append(
168
                    self._fill_extend_definition_help(child, dict_of_oval_definitions))
169 1
            elif child.node_type == "extend_definition":
170 1
                out.children.append(
171
                    self._find_definition_by_id(child, dict_of_oval_definitions))
172
            else:
173 1
                out.children.append(child)
174 1
        return out
175
176 1
    def _find_definition_by_id(self, node, dict_of_oval_definitions):
177 1
        extend_definition_id = node.node_id
178 1
        dict_of_oval_definitions[extend_definition_id].negation = node.negation
179 1
        dict_of_oval_definitions[extend_definition_id].tag = node.tag
180 1
        return self._fill_extend_definition_help(
181
            dict_of_oval_definitions[extend_definition_id], dict_of_oval_definitions)
182