Passed
Pull Request — master (#187)
by Jan
03:54
created

oval_graph.arf_xml_parser.xml_parser   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 131
Duplicated Lines 0 %

Test Coverage

Coverage 98.81%

Importance

Changes 0
Metric Value
eloc 107
dl 0
loc 131
ccs 83
cts 84
cp 0.9881
rs 10
c 0
b 0
f 0
wmc 20

10 Methods

Rating   Name   Duplication   Size   Complexity  
A XmlParser.get_src() 0 4 1
A XmlParser.__init__() 0 22 3
A XmlParser.validate() 0 9 1
A XmlParser._get_rule_dict() 0 10 2
A XmlParser._get_oval_definitions() 0 6 1
A XmlParser._get_used_rules() 0 18 4
A XmlParser._get_definitions() 0 5 1
A XmlParser._get_report_data() 0 7 3
A XmlParser._get_definition_of_rule() 0 13 3
A XmlParser.get_oval_tree() 0 3 1
1
"""
2
    This file contains a class for creating OVAL graph from ARF XML source
3
"""
4
5 1
import os
6 1
import sys
7
8 1
from lxml import etree as ET
9
10 1
from .._builder_oval_tree import _BuilderOvalTree
11 1
from ..exceptions import NotTestedRule
12 1
from ._xml_parser_oval_scan_definitions import _XmlParserScanDefinitions
13
14 1
ns = {
15
    'XMLSchema': 'http://oval.mitre.org/XMLSchema/oval-results-5',
16
    'xccdf': 'http://checklists.nist.gov/xccdf/1.2',
17
    'arf': 'http://scap.nist.gov/schema/asset-reporting-format/1.1',
18
    'oval-definitions': 'http://oval.mitre.org/XMLSchema/oval-definitions-5',
19
    'scap': 'http://scap.nist.gov/schema/scap/source/1.2',
20
    'oval-characteristics': 'http://oval.mitre.org/XMLSchema/oval-system-characteristics-5',
21
}
22
23
24 1
class XmlParser:
0 ignored issues
show
best-practice introduced by
Too many instance attributes (11/7)
Loading history...
25 1
    def __init__(self, src):
26 1
        self.src = src
27 1
        self.tree = ET.parse(self.src)
28 1
        self.root = self.tree.getroot()
29 1
        self.arf_schemas_src = '../schemas/arf/1.1/asset-reporting-format_1.1.0.xsd'
30 1
        if not self.validate(self.arf_schemas_src):
31 1
            CRED = '\033[91m'
0 ignored issues
show
Coding Style Naming introduced by
Variable name "CRED" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]2,|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
32 1
            CEND = '\033[0m'
0 ignored issues
show
Coding Style Naming introduced by
Variable name "CEND" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]2,|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
33 1
            message = CRED + "Warning: This file is not valid arf report." + CEND
34 1
            print(message, file=sys.stderr)
35 1
        try:
36 1
            self.used_rules, self.not_tested_rules = self._get_used_rules()
37 1
            self.report_data_href = list(self.used_rules.values())[0]['href']
38 1
            self.report_data = self._get_report_data(self.report_data_href)
39 1
            self.definitions = self._get_definitions()
40 1
            self.oval_definitions = self._get_oval_definitions()
41 1
            self.scan_definitions = _XmlParserScanDefinitions(
42
                self.definitions, self.oval_definitions, self.report_data).get_scan()
43 1
        except BaseException as error:
44 1
            raise ValueError(
45
                'This file "{}" is not arf report file or there are no results'.format(
46
                    self.src)) from error
47
48 1
    def get_src(self, src):
0 ignored issues
show
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
49 1
        _dir = os.path.dirname(os.path.realpath(__file__))
50 1
        FIXTURE_DIR = os.path.join(_dir, src)
0 ignored issues
show
Coding Style Naming introduced by
Variable name "FIXTURE_DIR" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]2,|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
51 1
        return str(FIXTURE_DIR)
52
53 1
    def validate(self, xsd_path):
54 1
        xsd_path = self.get_src(xsd_path)
55 1
        xmlschema_doc = ET.parse(xsd_path)
56 1
        xmlschema = ET.XMLSchema(xmlschema_doc)
57
58 1
        xml_doc = self.tree
59 1
        result = xmlschema.validate(xml_doc)
60
61 1
        return result
62
63 1
    def _get_rule_dict(self, rule_result, result, id_def, check_content_ref):
0 ignored issues
show
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
64 1
        message = rule_result.find(
65
            './/xccdf:message', ns)
66 1
        rule_dict = {}
67 1
        rule_dict['id_def'] = id_def
68 1
        rule_dict['href'] = check_content_ref.attrib.get('href')
69 1
        rule_dict['result'] = result.text
70 1
        if message is not None:
71
            rule_dict['message'] = message.text
72 1
        return rule_dict
73
74 1
    def _get_used_rules(self):
75 1
        rules_results = self.root.findall(
76
            './/xccdf:TestResult/xccdf:rule-result', ns)
77 1
        rules = {}
78 1
        not_tested_rules = {}
79 1
        for rule_result in rules_results:
80 1
            result = rule_result.find('.//xccdf:result', ns)
81 1
            check_content_ref = rule_result.find(
82
                './/xccdf:check/xccdf:check-content-ref', ns)
83 1
            if check_content_ref is not None:
84 1
                id_ = rule_result.get('idref')
85 1
                id_def = check_content_ref.attrib.get('name')
86 1
                if id_def is not None:
87 1
                    rules[id_] = self._get_rule_dict(
88
                        rule_result, result, id_def, check_content_ref)
89 1
                    continue
90 1
            not_tested_rules[rule_result.get('idref')] = result.text
91 1
        return (rules, not_tested_rules)
92
93 1
    def _get_report_data(self, href):
94 1
        report_data = None
95 1
        reports = self.root.find('.//arf:reports', ns)
96 1
        for report in reports:
97 1
            if "#" + str(report.get("id")) == href:
98 1
                report_data = report
99 1
        return report_data
100
101 1
    def _get_definitions(self):
102 1
        data = self.report_data.find(
103
            ('.//XMLSchema:oval_results/XMLSchema:results/'
104
             'XMLSchema:system/XMLSchema:definitions'), ns)
105 1
        return data
106
107 1
    def _get_oval_definitions(self):
108 1
        return self.root.find(
109
            './/arf:report-requests/arf:report-request/'
110
            'arf:content/scap:data-stream-collection/'
111
            'scap:component/oval-definitions:oval_definitions/'
112
            'oval-definitions:definitions', ns)
113
114 1
    def _get_definition_of_rule(self, rule_id):
115 1
        if rule_id in self.used_rules:
0 ignored issues
show
unused-code introduced by
Unnecessary "elif" after "return"
Loading history...
116 1
            rule_info = self.used_rules[rule_id]
117 1
            return dict(rule_id=rule_id,
118
                        definition_id=rule_info['id_def'],
119
                        definition=self.scan_definitions[rule_info['id_def']])
120 1
        elif rule_id in self.not_tested_rules:
121 1
            raise NotTestedRule(
122
                'Rule "{}" is {}, so there are no results.'
123
                .format(rule_id, self.not_tested_rules[rule_id]))
124
        else:
125 1
            print(self.not_tested_rules)
126 1
            raise ValueError('404 rule "{}" not found!'.format(rule_id))
127
128 1
    def get_oval_tree(self, rule_id):
129 1
        return _BuilderOvalTree.get_oval_tree_from_dict_of_rule(
130
            self._get_definition_of_rule(rule_id))
131