Passed
Push — master ( f240f4...fa02d7 )
by Matěj
02:43 queued 11s
created

xml_parser.get_notselected_rules()   A

Complexity

Conditions 3

Size

Total Lines 12
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 11
nop 1
dl 0
loc 12
ccs 9
cts 9
cp 1
crap 3
rs 9.85
c 0
b 0
f 0
1
'''
2
    Modules for create node IDs and parsing xml
3
'''
4
5 1
from lxml import etree as ET
6 1
import uuid
7 1
import graph.oval_graph
8
9
10 1
class xml_parser():
11 1
    def __init__(self, src):
12 1
        self.src = src
13 1
        self.tree = ET.parse(self.src)
14 1
        self.root = self.tree.getroot()
15 1
        if not self.validate(
16
                './schemas/arf/1.1/asset-reporting-format_1.1.0.xsd'):
17 1
            raise ValueError("err- This is not arf report file.")
18
19 1
    def validate(self, xsd_path):
20 1
        xmlschema_doc = ET.parse(xsd_path)
21 1
        xmlschema = ET.XMLSchema(xmlschema_doc)
22
23 1
        xml_doc = self.tree
24 1
        result = xmlschema.validate(xml_doc)
25
26 1
        return result
27
28 1
    def get_data(self, href):
29 1
        ns = {
30
            'XMLSchema': 'http://oval.mitre.org/XMLSchema/oval-results-5',
31
            'arf': 'http://scap.nist.gov/schema/asset-reporting-format/1.1'
32
        }
33
34 1
        report_data = None
35 1
        reports = self.root.find('.//arf:reports', ns)
36 1
        for report in reports:
37 1
            if "#" + str(report.get("id")) == href:
38 1
                report_data = report
39
40 1
        trees_data = report_data.find(
41
            ('.//XMLSchema:oval_results/XMLSchema:results/'
42
             'XMLSchema:system/XMLSchema:definitions'), ns)
43 1
        return trees_data
44
45 1
    def get_used_rules(self):
46 1
        ns = {
47
            'xccdf': 'http://checklists.nist.gov/xccdf/1.2',
48
        }
49 1
        rulesResults = self.root.findall(
50
            './/xccdf:TestResult/xccdf:rule-result', ns)
51 1
        rules = []
52 1
        for ruleResult in rulesResults:
53 1
            result = ruleResult.find('.//xccdf:result', ns)
54 1
            if result.text != "notselected":
55 1
                check_content_ref = ruleResult.find(
56
                    './/xccdf:check/xccdf:check-content-ref', ns)
57 1
                if check_content_ref is not None:
58 1
                    rules.append(dict(
59
                        id_rule=ruleResult.get('idref'),
60
                        id_def=check_content_ref.attrib.get('name'),
61
                        href=check_content_ref.attrib.get('href'),
62
                        result=result.text))
63 1
        return rules
64
65 1
    def get_notselected_rules(self):
66 1
        ns = {
67
            'xccdf': 'http://checklists.nist.gov/xccdf/1.2',
68
        }
69 1
        rulesResults = self.root.findall(
70
            './/xccdf:TestResult/xccdf:rule-result', ns)
71 1
        rules = []
72 1
        for ruleResult in rulesResults:
73 1
            result = ruleResult.find('.//xccdf:result', ns)
74 1
            if result.text == "notselected":
75 1
                rules.append(dict(id_rule=ruleResult.get('idref')))
76 1
        return rules
77
78 1
    def parse_data_to_dict(self, rule_id):
79 1
        scan = dict(definitions=[])
80 1
        used_rules = self.get_used_rules()
81 1
        for i in self.get_data(used_rules[0]['href']):
82 1
            scan['definitions'].append(self.build_graph(i))
83 1
        definitions = self._fill_extend_definition(scan)
84 1
        for definition in definitions['definitions']:
85 1
            if self.get_def_id_by_rule_id(rule_id) == definition['id']:
86 1
                return dict(rule_id=rule_id, definition=definition)
87
88 1
    def _xml_dict_to_node(self, dict_of_definition):
89 1
        children = []
90 1
        for child in dict_of_definition['node']:
91 1
            if 'operator' in child and 'id':
92 1
                children.append(self._xml_dict_to_node(child))
93
            else:
94 1
                children.append(
95
                    graph.oval_graph.OvalNode(
96
                        child['value_id'],
97
                        'value',
98
                        child['value'],
99
                        child['negate']))
100
101 1
        if 'id' in dict_of_definition:
102 1
            children[0].node_id = dict_of_definition['id']
103 1
            return children[0]
104
        else:
105 1
            return graph.oval_graph.OvalNode(
106
                str(uuid.uuid4()),
107
                'operator',
108
                dict_of_definition['operator'],
109
                dict_of_definition['negate'],
110
                children
111
            )
112
113 1
    def get_def_id_by_rule_id(self, rule_id):
114 1
        used_rules = self.get_used_rules()
115 1
        notselected_rules = self.get_notselected_rules()
116 1
        for rule in notselected_rules:
117 1
            if rule['id_rule'] == rule_id:
118 1
                raise ValueError(
119
                    'err- rule "{}" was not selected, so there are no results.'
120
                    .format(rule_id))
121 1
        for rule in used_rules:
122 1
            if rule['id_rule'] == rule_id:
123 1
                return rule['id_def']
124 1
        raise ValueError('err- 404 rule not found!')
125
126 1
    def get_rule_dict(self, rule_id):
127 1
        return self.parse_data_to_dict(rule_id)
128
129 1
    def xml_dict_of_rule_to_node(self, rule):
130 1
        dict_of_definition = rule['definition']
131 1
        return graph.oval_graph.OvalNode(
132
            rule['rule_id'],
133
            'operator',
134
            'and',
135
            False,
136
            [self._xml_dict_to_node(dict_of_definition)]
137
        )
138
139 1
    def get_oval_graph(self, rule_id=None):
140 1
        return self.xml_dict_of_rule_to_node(self.parse_data_to_dict(rule_id))
141
142 1
    def build_graph(self, tree_data):
143 1
        graph = dict(
144
            id=tree_data.get('definition_id'),
145
            node=[])
146 1
        for tree in tree_data:
147 1
            negate_status = False
148 1
            if tree.get('negate') is not None:
149 1
                negate_status = self._str_to_bool(tree.get('negate'))
150 1
            graph['negate'] = negate_status
151 1
            graph['node'].append(self._build_node(tree))
152 1
        return graph
153
154 1
    def _str_to_bool(self, s):
155 1
        if s == 'true':
156 1
            return True
157 1
        elif s == 'false':
158 1
            return False
159
        else:
160 1
            raise ValueError('err- negation is not bool')
161
162 1
    def _build_node(self, tree):
163 1
        negate_status = False
164 1
        if tree.get('negate') is not None:
165 1
            negate_status = self._str_to_bool(tree.get('negate'))
166
167 1
        node = dict(
168
            operator=tree.get('operator'),
169
            negate=negate_status,
170
            result=tree.get('result'),
171
            node=[])
172 1
        for child in tree:
173 1
            if child.get('operator') is not None:
174 1
                node['node'].append(self._build_node(child))
175
            else:
176 1
                negate_status = False
177 1
                if child.get('negate') is not None:
178 1
                    negate_status = self._str_to_bool(child.get('negate'))
179
180 1
                if child.get('definition_ref') is not None:
181 1
                    node['node'].append(
182
                        dict(
183
                            extend_definition=child.get('definition_ref'),
184
                            result=child.get('result'),
185
                            negate=negate_status))
186
                else:
187 1
                    node['node'].append(
188
                        dict(
189
                            value_id=child.get('test_ref'),
190
                            value=child.get('result'),
191
                            negate=negate_status))
192 1
        return node
193
194 1
    def _fill_extend_definition(self, scan):
195 1
        out = dict(definitions=[])
196 1
        for definition in scan['definitions']:
197 1
            nodes = []
198 1
            for value in definition['node']:
199 1
                nodes.append(self._operator_as_child(value, scan))
200 1
            out['definitions'].append(dict(id=definition['id'], node=nodes))
201 1
        return out
202
203 1
    def _operator_as_child(self, value, scan):
204 1
        out = dict(
205
            operator=value['operator'],
206
            negate=value['negate'],
207
            result=value['negate'],
208
            node=[])
209 1
        for child in value['node']:
210 1
            if 'operator' in child:
211 1
                out['node'].append(self._operator_as_child(child, scan))
212 1
            elif 'extend_definition' in child:
213 1
                out['node'].append(
214
                    self._find_definition_by_id(
215
                        scan, child['extend_definition'], child['negate']))
216 1
            elif 'value_id' in child:
217 1
                out['node'].append(child)
218
            else:
219
                raise ValueError('error - unknown child')
220 1
        return out
221
222 1
    def _find_definition_by_id(self, scan, id, negate_status):
223 1
        for definition in scan['definitions']:
224 1
            if definition['id'] == id:
225 1
                definition['node'][0]['negate'] = negate_status
226
                return self._operator_as_child(definition['node'][0], scan)
227