Passed
Pull Request — master (#24)
by Jan
03:15
created

oscap_report.cli.CommandLineAPI._setup_logging()   A

Complexity

Conditions 1

Size

Total Lines 6
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 6
nop 1
dl 0
loc 6
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1 1
import argparse
2 1
import logging
3 1
from sys import exit as sys_exit
4 1
from sys import stdin, stdout
5
6 1
from lxml.etree import XMLSyntaxError
7
8 1
from . import __version__
9 1
from .html_report.report_generator import ReportGenerator
10 1
from .old_html_report_style.report_generator import \
11
    ReportGenerator as OldOSCAPReportGenerator
12 1
from .scap_results_parser.scap_results_parser import SCAPResultsParser
13
14 1
DESCRIPTION = ("Generate a HTML (JSON, PDF?, Printable HTML, etc) document (HTML report)"
15
               " from an ARF (or XCCDF file) containing results of oscap scan. Unless"
16
               " the --output option is specified it will be written to standard output.")
17 1
LOG_LEVES_DESCRIPTION = (
18
    "LOG LEVELS:\n"
19
    "\tDEBUG - Detailed information, typically of interest only when diagnosing problems.\n"
20
    "\tINFO - Confirmation that things are working as expected.\n"
21
    "\tWARING -  An indication that something unexpected happened, or indicative of"
22
    " some problem in the near future. The software is still working as expected.\n"
23
    "\tERROR - Due to a more serious problem, the software has not been able to perform "
24
    "some function.\n"
25
    "\tCRITICAL - A serious error, indicating that the program itself may be unable "
26
    "to continue running.\n"
27
)
28 1
MASSAGE_FORMAT = '%(levelname)s: %(message)s'
29 1
EXPECTED_ERRORS = (XMLSyntaxError, )
30 1
EXIT_FAILURE_CODE = 1
31 1
EXIT_SUCCESS_CODE = 0
32
33
34 1
class CommandLineAPI():
35 1
    def __init__(self):
36 1
        self.arguments = self._parse_arguments()
37 1
        self.log_file = self.arguments.log_file
38 1
        self.log_level = self.arguments.log_level
39 1
        self._setup_logging()
40 1
        logging.debug("Args: %s", self.arguments)
41 1
        self.report_file = self.arguments.FILE
42 1
        self.output_file = self.arguments.output
43 1
        self.output_format = self.arguments.format.upper()
44
45 1
    def _parse_arguments(self):
46 1
        parser = argparse.ArgumentParser(
47
            prog="oscap-report",
48
            formatter_class=argparse.RawTextHelpFormatter,
49
            description=DESCRIPTION,
50
            add_help=False,
51
        )
52 1
        self._prepare_arguments(parser)
53 1
        return parser.parse_args()
54
55 1
    @staticmethod
56 1
    def _prepare_arguments(parser):
57 1
        parser.add_argument(
58
            "--version",
59
            action="version",
60
            version="%(prog)s " + __version__,
61
            help="Show program's version number and exit.")
62 1
        parser.add_argument(
63
            '-h',
64
            '--help',
65
            action='help',
66
            default=argparse.SUPPRESS,
67
            help='Show this help message and exit.')
68 1
        parser.add_argument(
69
            'FILE',
70
            type=argparse.FileType("r"),
71
            nargs='?',
72
            default=stdin,
73
            help="ARF file, stdin if not provided.")
74 1
        parser.add_argument(
75
            "-o",
76
            "--output",
77
            action="store",
78
            type=argparse.FileType("wb+", 0),
79
            default=stdout,
80
            help="write the report to this file instead of standard output.")
81 1
        parser.add_argument(
82
            "--log-file",
83
            action="store",
84
            default=None,
85
            help="if not provided - stderr.")
86 1
        parser.add_argument(
87
            "--log-level",
88
            action="store",
89
            default="WARNING",
90
            choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
91
            help=(
92
                "creates LOG_FILE file with log information depending on LOG_LEVEL."
93
                f"\n{LOG_LEVES_DESCRIPTION}")
94
        )
95 1
        parser.add_argument(
96
            "-f",
97
            "--format",
98
            action="store",
99
            default="HTML",
100
            choices=["HTML", "OLD-STYLE-HTML", "DEBUG-HTML"],
101
            help="FORMAT: %(choices)s (default: %(default)s)."
102
        )
103
104 1
    def _setup_logging(self):
105 1
        logging.basicConfig(
106
            format=MASSAGE_FORMAT,
107
            filename=self.log_file,
108
            filemode='w',
109
            level=self.log_level.upper()
110
        )
111
112 1
    def generate_report(self, report_parser):
113 1
        logging.info("Generate report")
114 1
        if self.output_format == "OLD-STYLE-HTML":
115
            report_generator = OldOSCAPReportGenerator(report_parser)
116
            return report_generator.generate_html_report()
117 1
        report_generator = ReportGenerator(report_parser)
118 1
        minify = True
119 1
        if self.output_format == "DEBUG-HTML":
120
            minify = False
121 1
        return report_generator.generate_html_report(minify)
122
123 1
    def load_file(self):
124 1
        logging.info("Loading file: %s", self.report_file)
125 1
        return self.report_file.read().encode()
126
127 1
    def store_file(self, data):
128 1
        logging.info("Store report")
129 1
        if self.output_file.name == "<stdout>":
130 1
            logging.info("Output is stdout, converting bytes output to str")
131 1
            data = data.read().decode("utf-8")
132 1
        self.output_file.writelines(data)
133
134 1
    def close_files(self):
135 1
        logging.info("Close files")
136 1
        self.report_file.close()
137 1
        self.output_file.close()
138
139
140 1
def main():
141 1
    exit_code = EXIT_SUCCESS_CODE
142 1
    api = CommandLineAPI()
143 1
    arf_report = api.load_file()
144
145 1
    logging.info("Parse file")
146 1
    try:
147 1
        parser = SCAPResultsParser(arf_report)
148
149 1
        report = api.generate_report(parser)
150
151 1
        api.store_file(report)
152 1
    except EXPECTED_ERRORS as error:
153 1
        logging.fatal("%s", error)
154 1
        exit_code = EXIT_FAILURE_CODE
155 1
    api.close_files()
156 1
    sys_exit(exit_code)
157
158
159 1
if __name__ == '__main__':
160
    main()
161