ARFXMLParser.__init__()   A
last analyzed

Complexity

Conditions 3

Size

Total Lines 22
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 22
dl 0
loc 22
rs 9.352
c 0
b 0
f 0
ccs 19
cts 19
cp 1
cc 3
nop 2
crap 3
1
"""
2
    This file contains a class for creating OVAL graph from ARF XML source
3
"""
4
5 1
import sys
6 1
from pathlib import Path
7
8 1
from lxml import etree as ET
9
10 1
from ..exceptions import NotTestedRule
11 1
from ..oval_tree.builder import Builder
12 1
from ._oval_scan_definitions import _OVALScanDefinitions
13 1
from .global_namespaces import namespaces
14
15 1
LOCAL_DATA_DIR = Path(__file__).parent.parent / "schemas"
16
17
18 1
class ARFXMLParser:
19 1
    def __init__(self, src):
20 1
        self.src = src
21 1
        self.tree = ET.parse(self.src)
22 1
        self.root = self.tree.getroot()
23 1
        self.arf_schemas_path = 'arf/1.1/asset-reporting-format_1.1.0.xsd'
24 1
        if not self.validate(self.arf_schemas_path):
25 1
            start_red_color = '\033[91m'
26 1
            end_red_color = '\033[0m'
27 1
            message = "Warning: This file is not valid arf report."
28 1
            print(f"{start_red_color}{message}{end_red_color}", file=sys.stderr)
29 1
        try:
30 1
            self.used_rules, self.not_tested_rules = self._get_rules_in_profile()
31 1
            self.report_data_href = list(self.used_rules.values())[0]['href']
32 1
            self.report_data = self._get_report_data(self.report_data_href)
33 1
            self.definitions = self._get_definitions()
34 1
            self.oval_definitions = self._get_oval_definitions()
35 1
            self.scan_definitions = _OVALScanDefinitions(
36
                self.definitions, self.oval_definitions, self.report_data).get_scan()
37 1
        except BaseException as error:
38 1
            raise ValueError(
39
                f'This file "{self.src}" is not arf report file or there are no results'
40
            ) from error
41
42 1
    def validate(self, xsd_path):
43 1
        xsd_path = str(LOCAL_DATA_DIR / xsd_path)
44 1
        xmlschema_doc = ET.parse(xsd_path)
45 1
        xmlschema = ET.XMLSchema(xmlschema_doc)
46 1
        return xmlschema.validate(self.tree)
47
48 1
    @staticmethod
49
    def _get_rule_dict(rule_result, result, id_def, check_content_ref):
50 1
        message = rule_result.find('.//xccdf:message', namespaces)
51 1
        rule_dict = {}
52 1
        rule_dict['id_def'] = id_def
53 1
        rule_dict['href'] = check_content_ref.attrib.get('href')
54 1
        rule_dict['result'] = result.text
55 1
        if message is not None:
56
            rule_dict['message'] = message.text
57 1
        return rule_dict
58
59 1
    def _get_rules_in_profile(self):
60 1
        rules_results = self.root.findall(
61
            './/xccdf:TestResult/xccdf:rule-result', namespaces)
62 1
        rules = {}
63 1
        not_tested_rules = {}
64 1
        for rule_result in rules_results:
65 1
            result = rule_result.find('.//xccdf:result', namespaces)
66 1
            check_content_ref = rule_result.find(
67
                './/xccdf:check/xccdf:check-content-ref', namespaces)
68 1
            if check_content_ref is not None:
69 1
                id_ = rule_result.get('idref')
70 1
                id_def = check_content_ref.attrib.get('name')
71 1
                if id_def is not None:
72 1
                    rules[id_] = self._get_rule_dict(
73
                        rule_result, result, id_def, check_content_ref)
74 1
                    continue
75 1
            not_tested_rules[rule_result.get('idref')] = result.text
76 1
        return (rules, not_tested_rules)
77
78 1
    def _get_report_data(self, href):
79 1
        report_data = None
80 1
        reports = self.root.find('.//arf:reports', namespaces)
81 1
        for report in reports:
82 1
            if "#" + str(report.get("id")) == href:
83 1
                report_data = report
84 1
        return report_data
85
86 1
    def _get_definitions(self):
87 1
        return self.report_data.find(
88
            ('.//XMLSchema:oval_results/XMLSchema:results/'
89
             'XMLSchema:system/XMLSchema:definitions'), namespaces)
90
91 1
    def _get_oval_definitions(self):
92 1
        return self.root.find(
93
            './/arf:report-requests/arf:report-request/'
94
            'arf:content/scap:data-stream-collection/'
95
            'scap:component/oval-definitions:oval_definitions/'
96
            'oval-definitions:definitions', namespaces)
97
98 1
    def _get_definition_of_rule(self, rule_id):
99 1
        if rule_id in self.used_rules:
100 1
            rule_info = self.used_rules[rule_id]
101 1
            return dict(rule_id=rule_id,
102
                        definition_id=rule_info['id_def'],
103
                        definition=self.scan_definitions[rule_info['id_def']])
104
105 1
        if rule_id in self.not_tested_rules:
106 1
            raise NotTestedRule(
107
                f'Rule "{rule_id}" is {self.not_tested_rules[rule_id]}, so there are no results.'
108
            )
109 1
        raise ValueError(f'404 rule "{rule_id}" not found!')
110
111 1
    def get_oval_tree(self, rule_id):
112 1
        return Builder.dict_of_rule_to_oval_tree(
113
            self._get_definition_of_rule(rule_id))
114