-
-
Notifications
You must be signed in to change notification settings - Fork 585
/
screen.py
200 lines (150 loc) · 6.19 KB
/
screen.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# Copyright (c) 2015 Hewlett Packard Enterprise
# -*- coding:utf-8 -*-
#
# SPDX-License-Identifier: Apache-2.0
r"""
================
Screen formatter
================
This formatter outputs the issues as color coded text to screen.
:Example:
.. code-block:: none
>> Issue: [B506: yaml_load] Use of unsafe yaml load. Allows
instantiation of arbitrary objects. Consider yaml.safe_load().
Severity: Medium Confidence: High
Location: examples/yaml_load.py:5
More Info: https://bandit.readthedocs.io/en/latest/
4 ystr = yaml.dump({'a' : 1, 'b' : 2, 'c' : 3})
5 y = yaml.load(ystr)
6 yaml.dump(y)
.. versionadded:: 0.9.0
"""
from __future__ import print_function
import datetime
import logging
import sys
from bandit.core import constants
from bandit.core import docs_utils
from bandit.core import test_properties
IS_WIN_PLATFORM = sys.platform.startswith('win32')
COLORAMA = False
# This fixes terminal colors not displaying properly on Windows systems.
# Colorama will intercept any ANSI escape codes and convert them to the
# proper Windows console API calls to change text color.
if IS_WIN_PLATFORM:
try:
import colorama
except ImportError:
pass
else:
COLORAMA = True
LOG = logging.getLogger(__name__)
COLOR = {
'DEFAULT': '\033[0m',
'HEADER': '\033[95m',
'LOW': '\033[94m',
'MEDIUM': '\033[93m',
'HIGH': '\033[91m',
}
def header(text, *args):
return u'%s%s%s' % (COLOR['HEADER'], (text % args), COLOR['DEFAULT'])
def get_verbose_details(manager):
bits = []
bits.append(header(u'Files in scope (%i):', len(manager.files_list)))
tpl = u"\t%s (score: {SEVERITY: %i, CONFIDENCE: %i})"
bits.extend([tpl % (item, sum(score['SEVERITY']), sum(score['CONFIDENCE']))
for (item, score)
in zip(manager.files_list, manager.scores)])
bits.append(header(u'Files excluded (%i):', len(manager.excluded_files)))
bits.extend([u"\t%s" % fname for fname in manager.excluded_files])
return '\n'.join([str(bit) for bit in bits])
def get_metrics(manager):
bits = []
bits.append(header("\nRun metrics:"))
for (criteria, _) in constants.CRITERIA:
bits.append("\tTotal issues (by %s):" % (criteria.lower()))
for rank in constants.RANKING:
bits.append("\t\t%s: %s" % (
rank.capitalize(),
manager.metrics.data['_totals']['%s.%s' % (criteria, rank)]))
return '\n'.join([str(bit) for bit in bits])
def _output_issue_str(issue, indent, show_lineno=True, show_code=True,
lines=-1):
# returns a list of lines that should be added to the existing lines list
bits = []
bits.append("%s%s>> Issue: [%s:%s] %s" % (
indent, COLOR[issue.severity], issue.test_id, issue.test,
issue.text))
bits.append("%s Severity: %s CWE: %i Confidence: %s" % (
indent, issue.severity.capitalize(), issue.cwe,
issue.confidence.capitalize()))
bits.append("%s Location: %s:%s" % (
indent, issue.fname,
issue.lineno if show_lineno else ""))
bits.append("%s More Info: %s%s" % (
indent, docs_utils.get_url(issue.test_id), COLOR['DEFAULT']))
if show_code:
bits.extend([indent + x for x in
issue.get_code(lines, True).split('\n')])
return '\n'.join([bit for bit in bits])
def get_results(manager, sev_level, conf_level, lines):
bits = []
issues = manager.get_issue_list(sev_level, conf_level)
baseline = not isinstance(issues, list)
candidate_indent = ' ' * 10
if not len(issues):
return u"\tNo issues identified."
for issue in issues:
# if not a baseline or only one candidate we know the issue
if not baseline or len(issues[issue]) == 1:
bits.append(_output_issue_str(issue, "", lines=lines))
# otherwise show the finding and the candidates
else:
bits.append(_output_issue_str(issue, "",
show_lineno=False,
show_code=False))
bits.append(u'\n-- Candidate Issues --')
for candidate in issues[issue]:
bits.append(_output_issue_str(candidate,
candidate_indent,
lines=lines))
bits.append('\n')
bits.append(u'-' * 50)
return '\n'.join([bit for bit in bits])
def do_print(bits):
# needed so we can mock this stuff
print('\n'.join([bit for bit in bits]))
@test_properties.accepts_baseline
def report(manager, fileobj, sev_level, conf_level, lines=-1):
"""Prints discovered issues formatted for screen reading
This makes use of VT100 terminal codes for colored text.
:param manager: the bandit manager object
:param fileobj: The output file object, which may be sys.stdout
:param sev_level: Filtering severity level
:param conf_level: Filtering confidence level
:param lines: Number of lines to report, -1 for all
"""
if IS_WIN_PLATFORM and COLORAMA:
colorama.init()
bits = []
if not manager.quiet or manager.results_count(sev_level, conf_level):
bits.append(header("Run started:%s", datetime.datetime.utcnow()))
if manager.verbose:
bits.append(get_verbose_details(manager))
bits.append(header("\nTest results:"))
bits.append(get_results(manager, sev_level, conf_level, lines))
bits.append(header("\nCode scanned:"))
bits.append('\tTotal lines of code: %i' %
(manager.metrics.data['_totals']['loc']))
bits.append('\tTotal lines skipped (#nosec): %i' %
(manager.metrics.data['_totals']['nosec']))
bits.append(get_metrics(manager))
skipped = manager.get_skipped()
bits.append(header("Files skipped (%i):", len(skipped)))
bits.extend(["\t%s (%s)" % skip for skip in skipped])
do_print(bits)
if fileobj.name != sys.stdout.name:
LOG.info("Screen formatter output was not written to file: %s, "
"consider '-f txt'", fileobj.name)
if IS_WIN_PLATFORM and COLORAMA:
colorama.deinit()