Skip to content

Commit 2bc8413

Browse files
bcallerBen Caller
authored and
Ben Caller
committed
Add colourful formatter "screen"
Prints vulnerabilities with ANSI colour codes for the terminal. Not crazily colourful: just tries to highlight the important stuff. Repeated filenames aren't printed. Colour scheme might not be to everyone's taste.
1 parent f56e761 commit 2bc8413

File tree

2 files changed

+105
-0
lines changed

2 files changed

+105
-0
lines changed

.coveragerc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@ source =
1515
./tests
1616
omit =
1717
pyt/formatters/json.py
18+
pyt/formatters/screen.py
1819
pyt/formatters/text.py

pyt/formatters/screen.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
"""This formatter outputs the issues as color-coded text."""
2+
from ..vulnerabilities.vulnerability_helper import SanitisedVulnerability, UnknownVulnerability
3+
4+
RESET = '\033[0m'
5+
BOLD = '\033[1m'
6+
UNDERLINE = '\033[4m'
7+
DANGER = '\033[31m'
8+
GOOD = '\033[32m'
9+
HIGHLIGHT = '\033[45;1m'
10+
RED_ON_WHITE = '\033[31m\033[107m'
11+
12+
13+
def color(string, color_string):
14+
return color_string + str(string) + RESET
15+
16+
17+
def report(
18+
vulnerabilities,
19+
fileobj,
20+
print_sanitised,
21+
):
22+
"""
23+
Prints issues in color-coded text format.
24+
25+
Args:
26+
vulnerabilities: list of vulnerabilities to report
27+
fileobj: The output file object, which may be sys.stdout
28+
"""
29+
n_vulnerabilities = len(vulnerabilities)
30+
unsanitised_vulnerabilities = [v for v in vulnerabilities if not isinstance(v, SanitisedVulnerability)]
31+
n_unsanitised = len(unsanitised_vulnerabilities)
32+
n_sanitised = n_vulnerabilities - n_unsanitised
33+
heading = "{} vulnerabilit{} found{}.\n".format(
34+
'No' if n_unsanitised == 0 else n_unsanitised,
35+
'y' if n_unsanitised == 1 else 'ies',
36+
" (plus {} sanitised)".format(n_sanitised) if n_sanitised else "",
37+
)
38+
vulnerabilities_to_print = vulnerabilities if print_sanitised else unsanitised_vulnerabilities
39+
with fileobj:
40+
for i, vulnerability in enumerate(vulnerabilities_to_print, start=1):
41+
fileobj.write(vulnerability_to_str(i, vulnerability))
42+
43+
if n_unsanitised == 0:
44+
fileobj.write(color(heading, GOOD))
45+
else:
46+
fileobj.write(color(heading, DANGER))
47+
48+
49+
def vulnerability_to_str(i, vulnerability):
50+
lines = []
51+
lines.append(color('Vulnerability {}'.format(i), UNDERLINE))
52+
lines.append('File: {}'.format(color(vulnerability.source.path, BOLD)))
53+
lines.append(
54+
'User input at line {}, source "{}":'.format(
55+
vulnerability.source.line_number,
56+
color(vulnerability.source_trigger_word, HIGHLIGHT),
57+
)
58+
)
59+
lines.append('\t{}'.format(color(vulnerability.source.label, RED_ON_WHITE)))
60+
if vulnerability.reassignment_nodes:
61+
previous_path = None
62+
lines.append('Reassigned in:')
63+
for node in vulnerability.reassignment_nodes:
64+
if node.path != previous_path:
65+
lines.append('\tFile: {}'.format(node.path))
66+
previous_path = node.path
67+
label = node.label
68+
if (
69+
isinstance(vulnerability, SanitisedVulnerability) and
70+
node.label == vulnerability.sanitiser.label
71+
):
72+
label = color(label, GOOD)
73+
lines.append(
74+
'\t Line {}:\t{}'.format(
75+
node.line_number,
76+
label,
77+
)
78+
)
79+
if vulnerability.source.path != vulnerability.sink.path:
80+
lines.append('File: {}'.format(color(vulnerability.sink.path, BOLD)))
81+
lines.append(
82+
'Reaches line {}, sink "{}"'.format(
83+
vulnerability.sink.line_number,
84+
color(vulnerability.sink_trigger_word, HIGHLIGHT),
85+
)
86+
)
87+
lines.append('\t{}'.format(
88+
color(vulnerability.sink.label, RED_ON_WHITE)
89+
))
90+
if isinstance(vulnerability, SanitisedVulnerability):
91+
lines.append(
92+
'This vulnerability is {}{} by {}'.format(
93+
color('potentially ', BOLD) if not vulnerability.confident else '',
94+
color('sanitised', GOOD),
95+
color(vulnerability.sanitiser.label, BOLD),
96+
)
97+
)
98+
elif isinstance(vulnerability, UnknownVulnerability):
99+
lines.append(
100+
'This vulnerability is unknown due to "{}"'.format(
101+
color(vulnerability.unknown_assignment.label, BOLD),
102+
)
103+
)
104+
return '\n'.join(lines) + '\n\n'

0 commit comments

Comments
 (0)