Test Failed
Pull Request — master (#142)
by Jan
02:26
created

oval_graph.client.Client.__init__()   B

Complexity

Conditions 7

Size

Total Lines 36
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 31
CRAP Score 7

Importance

Changes 0
Metric Value
cc 7
eloc 31
nop 2
dl 0
loc 36
ccs 31
cts 31
cp 1
crap 7
rs 7.736
c 0
b 0
f 0
1 1
import re
2 1
import argparse
3 1
import tempfile
4 1
import os
5 1
import webbrowser
6 1
from datetime import datetime
7 1
import sys
8
9 1
from .xml_parser import XmlParser
10 1
from .exceptions import NotChecked
11 1
from ._builder_html_graph import BuilderHtmlGraph
12 1
from .__init__ import __version__
13
14
15 1
class Client():
16 1
    def __init__(self, args):
17 1
        self.parser = None
18 1
        self.MESSAGES = self._get_message()
19 1
        self.arg = self.parse_arguments(args)
20 1
        self.hide_passing_tests = self.arg.hide_passing_tests
21 1
        self.source_filename = self.arg.source_filename
22 1
        self.rule_name = self.arg.rule_id
23 1
        self.out = self.arg.output
24 1
        self.verbose = self.arg.verbose
25
26 1
        self.parts = self.get_src('parts')
27 1
        self.START_OF_FILE_NAME = 'graph-of-'
28 1
        self.date = str(datetime.now().strftime("-%d_%m_%Y-%H_%M_%S"))
29 1
        self.isatty = sys.stdout.isatty()
30
31 1
        self.all_rules = self.arg.all
32 1
        self.all_in_one = None
33 1
        self.display_html = None
34 1
        if type(self).__name__ in ('ArfToHtml', 'JsonToHtml'):
35 1
            self.all_in_one = self.arg.all_in_one
36 1
            self.all_rules = True if self.all_in_one else self.arg.all
37 1
            self.display_html = True if self.out is None else self.arg.display
38
39 1
        self.show_failed_rules = False
40 1
        self.show_not_selected_rules = False
41 1
        if type(self).__name__ in ('ArfToHtml', 'ArfToJson'):
42 1
            self.show_failed_rules = self.arg.show_failed_rules
43 1
            self.show_not_selected_rules = self.arg.show_not_selected_rules
44
45 1
        self.xml_parser = None
46 1
        if type(self).__name__ != 'JsonToHtml':
47 1
            self.xml_parser = XmlParser(self.source_filename)
48
49 1
        self.html_builder = None
50 1
        if type(self).__name__ != 'ArfToJson':
51 1
            self.html_builder = BuilderHtmlGraph(self.parts, self.verbose)
52
53 1
    def _get_message(self):
54 1
        MESSAGES = {
55
            'description': '',
56
            'source_filename': '',
57
        }
58 1
        return MESSAGES
59
60 1
    def print_red_text(self, text):
61
        CRED = '\033[91m'
62
        CEND = '\033[0m'
63
        print(CRED + str(text) + CEND)
64
65 1
    def run_gui_and_return_answers(self):
66 1
        if self.isatty:
67 1
            if self.all_rules:
68
                return self._get_rules()
69
            else:
70 1
                try:
71 1
                    import inquirer
72 1
                    return inquirer.prompt(self.get_questions())
73 1
                except ImportError:
74 1
                    print(self.get_selection_rules())
75 1
                    return None
76
        else:
77 1
            return self._get_rules()
78
79 1
    def _get_rules(self):
80 1
        return {
81
            'rules': self._get_only_fail_rule(
82
                self.search_rules_id())} if self.show_failed_rules else {
83
            'rules': self.search_rules_id()}
84
85 1
    def get_list_of_matched_rules(self):
86 1
        return self._get_only_fail_rule(
87
            self.search_rules_id()) if self.show_failed_rules else self.search_rules_id()
88
89 1
    def get_list_of_lines(self):
90 1
        lines = ['== The Rule ID regular expressions ==']
91 1
        for rule in self.get_list_of_matched_rules():
92 1
            lines.append("^" + rule + "$")
93 1
        if self.show_not_selected_rules:
94 1
            for line in self.get_lines_of_wanted_not_selected_rules():
95 1
                lines.append(line)
96 1
        lines.append(
97
            "Interactive rule selection is not available,"
98
            " because inquirer is not installed."
99
            " Copy id of the rule you want to visualize and"
100
            " paste it into a command with regular"
101
            " expression characters(^$).\n"
102
            "Alternatively, use the --all or --all-in-one arguments.")
103 1
        return lines
104
105 1
    def get_selection_rules(self):
106 1
        return "\n".join(self.get_list_of_lines())
107
108 1
    def get_lines_of_wanted_not_selected_rules(self):
109 1
        out = []
110 1
        out.append('== The not selected rule IDs ==')
111 1
        for rule in self._get_wanted_rules_from_array_of_IDs(
112
                self.xml_parser.notselected_rules):
113 1
            out.append(rule + '(Not selected)')
114 1
        return out
115
116 1
    def get_choices(self):
117 1
        if self.show_not_selected_rules:
118 1
            print("\n".join(self.get_lines_of_wanted_not_selected_rules()))
119 1
        return self.get_list_of_matched_rules()
120
121 1
    def get_questions(self):
122 1
        choices = self.get_choices()
123 1
        from inquirer.questions import Checkbox as checkbox
124 1
        questions = [
125
            checkbox(
126
                'rules',
127
                message=(
128
                    "= The Rules IDs = (move - UP and DOWN arrows,"
129
                    " select - SPACE or LEFT and RIGHT arrows, submit - ENTER)"),
130
                choices=choices,
131
            ),
132
        ]
133 1
        return questions
134
135 1
    def _get_only_fail_rule(self, rules):
136 1
        return list(
137
            filter(
138
                lambda rule: self.xml_parser.used_rules[rule]['result'] == 'fail',
139
                rules))
140
141 1
    def _get_wanted_rules_from_array_of_IDs(self, rules):
142 1
        return [
143
            x for x in rules if re.search(
144
                self.rule_name, x)]
145
146 1
    def search_rules_id(self):
147 1
        return self._check_rules_id(
148
            self._get_wanted_rules_from_array_of_IDs(
149
                self.xml_parser.used_rules.keys()),
150
            self._get_wanted_rules_from_array_of_IDs(
151
                self.xml_parser.notselected_rules))
152
153 1
    def _check_rules_id(self, rules, notselected_rules):
154 1
        if len(notselected_rules) and not rules:
155
            raise ValueError(
156
                ('Rule(s) "{}" was not selected, '
157
                 "so there are no results. The rule is"
158
                 ' "notselected" because it'
159
                 " wasn't a part of the executed profile"
160
                 " and therefore it wasn't evaluated "
161
                 "during the scan.")
162
                .format(notselected_rules))
163 1
        elif not notselected_rules and not rules:
164
            raise ValueError('404 rule "{}" not found!'.format(self.rule_name))
165
        else:
166 1
            return rules
167
168 1
    def get_save_src(self, rule):
169
        if self.out is not None:
170
            os.makedirs(self.out, exist_ok=True)
171
            return os.path.join(
172
                self.out,
173
                self.START_OF_FILE_NAME + rule + '.html')
174
        return os.path.join(
175
            tempfile.gettempdir(),
176
            self.START_OF_FILE_NAME + rule + '.html')
177
178 1
    def get_src(self, src):
179 1
        _dir = os.path.dirname(os.path.realpath(__file__))
180 1
        return str(os.path.join(_dir, src))
181
182 1
    def _build_and_save_html(self, dict_oval_trees, src, rules, out_src):
183
        self.html_builder.save_html(dict_oval_trees, src, rules)
184
        out_src.append(src)
185
186 1
    def open_html(self, out):
187
        for src in out:
188
            self.open_web_browser(src)
189
190 1
    def open_web_browser(self, src):
191
        if self.display_html:
192
            try:
193
                webbrowser.get('firefox').open_new_tab(src)
194
            except BaseException:
195
                webbrowser.open_new_tab(src)
196
197 1
    def _prepare_data(self, rules, dict_oval_trees, out_src):
198
        for rule in rules['rules']:
199
            try:
200
                self._put_to_dict_oval_trees(dict_oval_trees, rule)
201
                if not self.all_in_one:
202
                    self._build_and_save_html(
203
                        dict_oval_trees, self._get_src_for_one_graph(
204
                            rule), dict(
205
                            rules=[rule]), out_src)
206
                    dict_oval_trees = {}
207
            except NotChecked as error:
208
                self.print_red_text(error)
209
        if self.all_in_one:
210
            self._build_and_save_html(
211
                dict_oval_trees, self.get_save_src(
212
                    'rules' + self.date), rules, out_src)
213
214 1
    def prepare_data(self, rules):
215
        out_src = []
216
        oval_tree_dict = dict()
217
        self._prepare_data(rules, oval_tree_dict, out_src)
218
        self.open_html(out_src)
219
        return out_src
220
221 1
    def parse_arguments(self, args):
222 1
        self.prepare_parser()
223 1
        return self.parser.parse_args(args)
224
225 1
    def prepare_args_when_output_is_html(self):
226 1
        self.parser.add_argument(
227
            '-i',
228
            '--all-in-one',
229
            action="store_true",
230
            default=False,
231
            help="Processes all rules into one file.")
232 1
        self.parser.add_argument(
233
            '-d',
234
            '--display',
235
            action="store_true",
236
            default=False,
237
            help="Enables opening a web browser with a graph, when is used --output.")
238
239 1
    def prepare_args_when_user_can_list_in_rules(self):
240 1
        self.parser.add_argument(
241
            '--show-failed-rules',
242
            action="store_true",
243
            default=False,
244
            help="Show only FAILED rules")
245 1
        self.parser.add_argument(
246
            '--show-not-selected-rules',
247
            action="store_true",
248
            default=False,
249
            help="Show notselected rules. These rules will not be visualized.")
250
251 1
    def prepare_parser(self):
252 1
        self.parser = argparse.ArgumentParser(
253
            prog='oval-graph',
254
            description=self.MESSAGES.get('description'))
255 1
        self.parser.add_argument(
256
            '--version',
257
            action='version',
258
            version='%(prog)s ' + __version__)
259 1
        self.parser.add_argument(
260
            '-a',
261
            '--all',
262
            action="store_true",
263
            default=False,
264
            help="Process all matched rules.")
265 1
        self.parser.add_argument(
266
            '--hide-passing-tests',
267
            action="store_true",
268
            default=False,
269
            help=(
270
                "Do not display passing tests for better orientation in"
271
                " graphs that contain a large amount of nodes."))
272 1
        self.parser.add_argument(
273
            '-v',
274
            '--verbose',
275
            action="store_true",
276
            default=False,
277
            help="Displays details about the results of the running command.")
278 1
        self.parser.add_argument(
279
            '-o',
280
            '--output',
281
            action="store",
282
            default=None,
283
            help='The file where to save output.')
284 1
        self.parser.add_argument(
285
            "source_filename",
286
            help=self.MESSAGES.get('source_filename'))
287 1
        self.parser.add_argument(
288
            "rule_id", help=(
289
                "Rule ID to be visualized. A part from the full rule ID"
290
                " a part of the ID or a regular expression can be used."
291
                " If brackets are used in the regular expression "
292
                "the regular expression must be quoted."))
293