Skip to content

Commit 7e4c804

Browse files
authored
CM-20749 - print results refactor (#69)
1 parent 81e7d81 commit 7e4c804

6 files changed

Lines changed: 119 additions & 63 deletions

File tree

cli/config.yaml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,13 @@ scans:
66
- sca
77
- sast
88
result_printer:
9-
lines_to_display: 3
10-
show_secret: False
9+
default:
10+
lines_to_display: 3
11+
show_secret: False
12+
secret:
13+
pre_receive:
14+
lines_to_display: 1
15+
show_secret: False
16+
commit_history:
17+
lines_to_display: 1
18+
show_secret: False

cli/cycode.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ def code_scan(context: click.Context, scan_type, client_id, secret, show_secret,
7474
if show_secret:
7575
context.obj["show_secret"] = show_secret
7676
else:
77-
context.obj["show_secret"] = config["result_printer"]["show_secret"]
77+
context.obj["show_secret"] = config["result_printer"]["default"]["show_secret"]
7878

7979
if soft_fail:
8080
context.obj["soft_fail"] = soft_fail

cli/printers/base_printer.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@
66

77
class BasePrinter(ABC):
88

9+
context: click.Context
10+
11+
def __init__(self, context: click.Context):
12+
self.context = context
13+
914
@abstractmethod
10-
def print_results(self, context: click.Context, results: List[DocumentDetections]):
15+
def print_results(self, results: List[DocumentDetections]):
1116
pass

cli/printers/json_printer.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,23 @@
77

88

99
class JsonPrinter(BasePrinter):
10-
def print_results(self, context: click.Context, results: List[DocumentDetections]):
10+
11+
scan_id: str
12+
13+
def __init__(self, context: click.Context):
14+
super().__init__(context)
15+
self.scan_id = context.obj.get('scan_id')
16+
17+
def print_results(self, results: List[DocumentDetections]):
1118
detections = [detection for document_detections in results for detection in document_detections.detections]
1219
detections_schema = DetectionSchema(many=True)
1320
detections_dict = detections_schema.dump(detections)
14-
json_result = self._get_json_result(context, detections_dict)
21+
json_result = self._get_json_result(detections_dict)
1522
click.secho(json_result)
1623

17-
def _get_json_result(self, context, detections):
18-
scan_id = context.obj.get('scan_id')
24+
def _get_json_result(self, detections):
1925
result = {
20-
'scan_id': str(scan_id),
26+
'scan_id': str(self.scan_id),
2127
'detections': detections
2228
}
2329

cli/printers/results_printer.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,19 @@
66

77
class ResultsPrinter:
88
printers = {
9-
'text': TextPrinter(),
10-
'json': JsonPrinter()
9+
'text': TextPrinter,
10+
'json': JsonPrinter
1111
}
1212

1313
def print_results(self, context: click.Context, detections_results_list: List[DocumentDetections],
1414
output_type: str):
15-
printer = self.get_printer(output_type)
16-
printer.print_results(context, detections_results_list)
15+
printer = self.get_printer(output_type, context)
16+
printer.print_results(detections_results_list)
1717

18-
def get_printer(self, output_type: str):
18+
def get_printer(self, output_type: str, context: click.Context):
1919
printer = self.printers.get(output_type)
2020
if not printer:
2121
raise ValueError(f'the provided output is not supported - {output_type}')
2222

23-
return printer
23+
return printer(context)
2424

cli/printers/text_printer.py

Lines changed: 85 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -13,32 +13,40 @@ class TextPrinter(BasePrinter):
1313
WHITE_COLOR_NAME = 'white'
1414
GREEN_COLOR_NAME = 'green'
1515

16-
def print_results(self, context: click.Context, results: List[DocumentDetections]):
17-
scan_id = context.obj.get('scan_id')
18-
click.secho(f"Scan Results: (scan_id: {scan_id})")
16+
scan_id: str
17+
scan_type: str
18+
command_scan_type: str
19+
show_secret: bool = False
20+
21+
def __init__(self, context: click.Context):
22+
super().__init__(context)
23+
self.scan_id = context.obj.get('scan_id')
24+
self.scan_type = context.obj.get('scan_type')
25+
self.command_scan_type = context.info_name
26+
self.show_secret = context.obj.get('show_secret', False)
27+
28+
def print_results(self, results: List[DocumentDetections]):
29+
click.secho(f"Scan Results: (scan_id: {self.scan_id})")
1930

2031
if not results:
2132
click.secho("Good job! No issues were found!!! 👏👏👏", fg=self.GREEN_COLOR_NAME)
2233
return
2334

24-
scan_type = context.obj.get('scan_type')
25-
show_secret = context.obj.get('show_secret', False)
26-
lines_to_display = config.get('result_printer', {}).get('lines_to_display')
2735
for document_detections in results:
28-
self._print_document_detections(document_detections, scan_type, show_secret, lines_to_display)
36+
self._print_document_detections(document_detections)
2937

30-
if context.obj.get('report_url'):
31-
click.secho(f"Report URL: {context.obj.get('report_url')}")
38+
if self.context.obj.get('report_url'):
39+
click.secho(f"Report URL: {self.context.obj.get('report_url')}")
3240

33-
def _print_document_detections(self, document_detections: DocumentDetections, scan_type: str, show_secret: bool,
34-
lines_to_display: int):
41+
def _print_document_detections(self, document_detections: DocumentDetections):
3542
document = document_detections.document
43+
lines_to_display = self._get_lines_to_display_count()
3644
for detection in document_detections.detections:
37-
self._print_detection_summary(detection, document.path, scan_type)
38-
self._print_detection_code_segment(detection, document, scan_type, show_secret, lines_to_display)
45+
self._print_detection_summary(detection, document.path)
46+
self._print_detection_code_segment(detection, document, lines_to_display)
3947

40-
def _print_detection_summary(self, detection: Detection, document_path: str, scan_type: str):
41-
detection_name = detection.type if scan_type == SECRET_SCAN_TYPE else detection.message
48+
def _print_detection_summary(self, detection: Detection, document_path: str):
49+
detection_name = detection.type if self.scan_type == SECRET_SCAN_TYPE else detection.message
4250
detection_sha = detection.detection_details.get('sha512')
4351
detection_sha_message = f'\nSecret SHA: {detection_sha}' if detection_sha else ''
4452
detection_commit_id = detection.detection_details.get('commit_id')
@@ -48,62 +56,41 @@ def _print_detection_summary(self, detection: Detection, document_path: str, sca
4856
f'(rule ID: {detection.detection_rule_id}) in file: {click.format_filename(document_path)} ' +
4957
f'{detection_sha_message}{detection_commit_id_message} ⛔ ')
5058

51-
def _print_detection_code_segment(self, detection: Detection, document: Document, scan_type: str,
52-
show_secret: bool, code_segment_size: int):
53-
detection_details = detection.detection_details
54-
detection_line = detection_details.get('line', -1) if scan_type == SECRET_SCAN_TYPE else \
55-
detection_details.get('line_in_file', -1)
56-
detection_position = detection_details.get('start_position', -1)
57-
violation_length = detection_details.get('length', -1)
58-
59-
document_content = document.content
60-
document_lines = document_content.splitlines()
61-
start_line = self._get_code_segment_start_line(detection_line, code_segment_size)
62-
detection_position_in_line = self._get_position_in_line(document_content, detection_position)
63-
64-
click.echo()
65-
for i in range(code_segment_size):
66-
current_line_index = start_line + i
67-
if current_line_index >= len(document_lines):
68-
break
59+
def _print_detection_code_segment(self, detection: Detection, document: Document, code_segment_size: int):
60+
if document.is_git_diff_format:
61+
self._print_detection_from_git_diff(detection, document)
62+
return
6963

70-
current_line = document_lines[current_line_index]
71-
is_detection_line = current_line_index == detection_line
72-
self._print_line_of_code_segment(document, current_line, current_line_index + 1, detection_position_in_line,
73-
violation_length, show_secret, scan_type, is_detection_line)
74-
click.echo()
64+
self._print_detection_from_file(detection, document, code_segment_size)
7565

7666
def _get_code_segment_start_line(self, detection_line: int, code_segment_size: int):
7767
start_line = detection_line - math.ceil(code_segment_size / 2)
7868
return 0 if start_line < 0 else start_line
7969

8070
def _print_line_of_code_segment(self, document: Document, line: str, line_number: int,
81-
detection_position_in_line: int, violation_length: int, show_secret: bool,
82-
scan_type: str, is_detection_line: bool):
71+
detection_position_in_line: int, violation_length: int, is_detection_line: bool):
8372
if is_detection_line:
84-
self._print_detection_line(document, line, line_number, detection_position_in_line, violation_length,
85-
show_secret, scan_type)
73+
self._print_detection_line(document, line, line_number, detection_position_in_line, violation_length)
8674
else:
8775
self._print_line(document, line, line_number)
8876

8977
def _print_detection_line(self, document: Document, line: str, line_number: int, detection_position_in_line: int,
90-
violation_length: int, show_secret: bool, scan_type: str):
78+
violation_length: int):
9179
click.echo(
9280
f'{self._get_line_number_style(line_number)} '
93-
f'{self._get_detection_line_style(line, document.is_git_diff_format, scan_type, detection_position_in_line, violation_length, show_secret)}')
81+
f'{self._get_detection_line_style(line, document.is_git_diff_format, detection_position_in_line, violation_length)}')
9482

9583
def _print_line(self, document: Document, line: str, line_number: int):
9684
click.echo(
9785
f'{self._get_line_number_style(line_number)} {self._get_line_style(line, document.is_git_diff_format)}')
9886

99-
def _get_detection_line_style(self, line: str, is_git_diff: bool, scan_type: str, start_position: int, length: int,
100-
show_secret: bool = False):
87+
def _get_detection_line_style(self, line: str, is_git_diff: bool, start_position: int, length: int):
10188
line_color = self._get_line_color(line, is_git_diff)
102-
if scan_type != SECRET_SCAN_TYPE or start_position < 0 or length < 0:
89+
if self.scan_type != SECRET_SCAN_TYPE or start_position < 0 or length < 0:
10390
return self._get_line_style(line, is_git_diff, line_color)
10491

10592
violation = line[start_position: start_position + length]
106-
if not show_secret:
93+
if not self.show_secret:
10794
violation = obfuscate_text(violation)
10895
line_to_violation = line[0: start_position]
10996
line_from_violation = line[start_position + length:]
@@ -132,3 +119,53 @@ def _get_position_in_line(self, text: str, position: int) -> int:
132119

133120
def _get_line_number_style(self, line_number: int):
134121
return f'{click.style(str(line_number), fg=self.WHITE_COLOR_NAME, bold=False)} {click.style("|", fg=self.RED_COLOR_NAME, bold=False)}'
122+
123+
def _get_lines_to_display_count(self) -> int:
124+
result_printer_configuration = config.get('result_printer')
125+
lines_to_display_of_scan = result_printer_configuration.get(self.scan_type, {}) \
126+
.get(self.command_scan_type, {}).get('lines_to_display')
127+
if lines_to_display_of_scan:
128+
return lines_to_display_of_scan
129+
130+
return result_printer_configuration.get('default').get('lines_to_display')
131+
132+
def _print_detection_from_file(self, detection: Detection, document: Document, code_segment_size: int):
133+
detection_details = detection.detection_details
134+
detection_line = detection_details.get('line', -1) if self.scan_type == SECRET_SCAN_TYPE else \
135+
detection_details.get('line_in_file', -1)
136+
detection_position = detection_details.get('start_position', -1)
137+
violation_length = detection_details.get('length', -1)
138+
139+
file_content = document.content
140+
file_lines = file_content.splitlines()
141+
start_line = self._get_code_segment_start_line(detection_line, code_segment_size)
142+
detection_position_in_line = self._get_position_in_line(file_content, detection_position)
143+
144+
click.echo()
145+
for i in range(code_segment_size):
146+
current_line_index = start_line + i
147+
if current_line_index >= len(file_lines):
148+
break
149+
150+
current_line = file_lines[current_line_index]
151+
is_detection_line = current_line_index == detection_line
152+
self._print_line_of_code_segment(document, current_line, current_line_index + 1, detection_position_in_line,
153+
violation_length, is_detection_line)
154+
click.echo()
155+
156+
def _print_detection_from_git_diff(self, detection: Detection, document: Document):
157+
detection_details = detection.detection_details
158+
detection_line_number = detection_details.get('line', -1)
159+
detection_line_number_in_original_file = detection_details.get('line_in_file', -1)
160+
detection_position = detection_details.get('start_position', -1)
161+
violation_length = detection_details.get('length', -1)
162+
163+
git_diff_content = document.content
164+
git_diff_lines = git_diff_content.splitlines()
165+
detection_line = git_diff_lines[detection_line_number]
166+
detection_position_in_line = self._get_position_in_line(git_diff_content, detection_position)
167+
168+
click.echo()
169+
self._print_detection_line(document, detection_line, detection_line_number_in_original_file,
170+
detection_position_in_line, violation_length)
171+
click.echo()

0 commit comments

Comments
 (0)