Skip to content

Commit 1b6a811

Browse files
committed
refactoring code snippet into separate file
1 parent b307e86 commit 1b6a811

File tree

3 files changed

+149
-73
lines changed

3 files changed

+149
-73
lines changed

detect_secrets/core/audit.py

+30-72
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
from __future__ import print_function
22
from __future__ import unicode_literals
33

4-
import codecs
5-
import itertools
64
import json
75
import os
86
import subprocess
@@ -15,6 +13,7 @@
1513
from ..plugins.high_entropy_strings import HighEntropyStringsPlugin
1614
from .baseline import merge_results
1715
from .bidirectional_iterator import BidirectionalIterator
16+
from .code_snippet import CodeSnippetHighlighter
1817
from .color import AnsiColor
1918
from .color import colorize
2019
from .common import write_baseline_to_file
@@ -454,92 +453,59 @@ def _get_secret_with_context(
454453
455454
:raises: SecretNotFoundOnSpecifiedLineError
456455
"""
457-
secret_line_idx = secret['line_number'] - 1
458-
end_line = secret_line_idx + lines_of_context + 1
459-
460-
if secret_line_idx <= lines_of_context:
461-
start_line = 0
462-
index_of_secret_in_output = secret_line_idx
463-
else:
464-
start_line = secret_line_idx - lines_of_context
465-
index_of_secret_in_output = lines_of_context
466-
467-
with codecs.open(filename, encoding='utf-8') as file:
468-
output = list(
469-
itertools.islice(
470-
file.read().splitlines(),
471-
start_line,
472-
end_line,
473-
),
474-
)
456+
snippet = CodeSnippetHighlighter().get_code_snippet(
457+
filename,
458+
secret['line_number'],
459+
lines_of_context=lines_of_context,
460+
)
475461

476462
try:
477-
output[index_of_secret_in_output] = _highlight_secret(
478-
output[index_of_secret_in_output],
479-
secret['line_number'],
463+
raw_secret_value = get_raw_secret_value(
464+
snippet.target_line,
480465
secret,
481-
filename,
482466
plugin_settings,
467+
filename,
483468
)
469+
470+
snippet.highlight_line(raw_secret_value)
484471
except SecretNotFoundOnSpecifiedLineError:
485472
if not force:
486473
raise
487474

488-
output[index_of_secret_in_output] = '{}'.format(
489-
colorize(
490-
output[index_of_secret_in_output],
491-
AnsiColor.BOLD,
492-
),
475+
snippet.target_line = colorize(
476+
snippet.target_line,
477+
AnsiColor.BOLD,
493478
)
494479

495-
# Adding line numbers
496-
return '\n'.join(
497-
map(
498-
lambda x: '{}:{}'.format(
499-
colorize(
500-
str(int(x[0]) + start_line + 1),
501-
AnsiColor.LIGHT_GREEN,
502-
),
503-
x[1],
504-
),
505-
enumerate(output),
506-
),
507-
)
480+
return str(snippet.add_line_numbers())
508481

509482

510-
def _highlight_secret(
483+
def get_raw_secret_value(
511484
secret_line,
512-
secret_lineno,
513485
secret,
514-
filename,
515486
plugin_settings,
487+
filename,
516488
):
517489
"""
518490
:type secret_line: str
519491
:param secret_line: the line on which the secret is found
520492
521-
:type secret_lineno: int
522-
:param secret_lineno: secret_line's line number in the source file
523-
524493
:type secret: dict
525494
:param secret: see caller's docstring
526495
527-
:type filename: str
528-
:param filename: this is needed, because PotentialSecret uses this
529-
as a means of comparing whether two secrets are equal.
530-
531496
:type plugin_settings: list
532497
:param plugin_settings: see caller's docstring
533498
534-
:rtype: str
535-
:returns: secret_line, but with the actual secret highlighted.
499+
:type filename: str
500+
:param filename: this is needed, because PotentialSecret uses this
501+
as a means of comparing whether two secrets are equal.
536502
"""
537503
plugin = initialize.from_secret_type(
538504
secret['type'],
539505
plugin_settings,
540506
)
541507

542-
for raw_secret in _raw_secret_generator(
508+
for raw_secret in raw_secret_generator(
543509
plugin,
544510
secret_line,
545511
filetype=determine_file_type(filename),
@@ -553,26 +519,18 @@ def _highlight_secret(
553519
# There could be more than two secrets on the same line.
554520
# We only want to highlight the right one.
555521
if secret_obj.secret_hash == secret['hashed_secret']:
556-
break
522+
return raw_secret
557523
else:
558-
raise SecretNotFoundOnSpecifiedLineError(secret_lineno)
559-
560-
index_of_secret = secret_line.lower().index(raw_secret.lower())
561-
end_of_secret = index_of_secret + len(raw_secret)
562-
return '{}{}{}'.format(
563-
secret_line[:index_of_secret],
564-
colorize(
565-
# copy the secret out of the line because .lower() from secret
566-
# generator may be different from the original value:
567-
secret_line[index_of_secret:end_of_secret],
568-
AnsiColor.RED_BACKGROUND,
569-
),
570-
secret_line[index_of_secret + len(raw_secret):],
571-
)
524+
raise SecretNotFoundOnSpecifiedLineError(secret['line_number'])
572525

573526

574-
def _raw_secret_generator(plugin, secret_line, filetype):
575-
"""Generates raw secrets by re-scanning the line, with the specified plugin"""
527+
def raw_secret_generator(plugin, secret_line, filetype):
528+
"""Generates raw secrets by re-scanning the line, with the specified plugin
529+
530+
:type plugin: BasePlugin
531+
:type secret_line: str
532+
:type filetype: FileType
533+
"""
576534
for raw_secret in plugin.secret_generator(secret_line, filetype=filetype):
577535
yield raw_secret
578536

detect_secrets/core/code_snippet.py

+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import codecs
2+
import itertools
3+
4+
from .color import AnsiColor
5+
from .color import colorize
6+
7+
8+
class CodeSnippetHighlighter:
9+
10+
def get_code_snippet(self, filename, line_number, lines_of_context=5):
11+
"""
12+
:type filename: str
13+
14+
:type line_number: int
15+
:param line_number: line which you want to focus on
16+
17+
:type lines_of_context: int
18+
:param lines_of_context: how many lines to display around the line you want
19+
to focus on.
20+
21+
:rtype: CodeSnippet
22+
"""
23+
secret_line_index = line_number - 1
24+
end_line = secret_line_index + lines_of_context + 1
25+
26+
if secret_line_index <= lines_of_context:
27+
start_line = 0
28+
index_of_secret_in_output = secret_line_index
29+
else:
30+
start_line = secret_line_index - lines_of_context
31+
index_of_secret_in_output = lines_of_context
32+
33+
return CodeSnippet(
34+
list(
35+
itertools.islice(
36+
self._get_lines_in_file(filename),
37+
start_line,
38+
end_line,
39+
),
40+
),
41+
start_line,
42+
index_of_secret_in_output,
43+
)
44+
45+
def _get_lines_in_file(self, filename):
46+
"""
47+
:rtype: list
48+
"""
49+
with codecs.open(filename, encoding='utf-8') as file:
50+
return file.read().splitlines()
51+
52+
53+
class CodeSnippet:
54+
55+
def __init__(self, snippet, start_line, target_index):
56+
"""
57+
:type snippet: list
58+
:param snippet: lines of code extracted from file
59+
60+
:type start_line: int
61+
:param start_line: first line number in segment
62+
63+
:type target_index: int
64+
:param target_index: index in snippet of target line
65+
"""
66+
self.lines = snippet
67+
self.start_line = start_line
68+
self.target_index = target_index
69+
70+
@property
71+
def target_line(self):
72+
return self.lines[self.target_index]
73+
74+
@target_line.setter
75+
def target_line(self, value):
76+
self.lines[self.target_index] = value
77+
78+
def add_line_numbers(self):
79+
for index, line in enumerate(self.lines):
80+
self.lines[index] = '{}:{}'.format(
81+
self.get_line_number(self.start_line + index + 1),
82+
line,
83+
)
84+
85+
return self
86+
87+
def highlight_line(self, payload):
88+
"""
89+
:type payload: str
90+
:param payload: string to highlight, on chosen line
91+
"""
92+
index_of_payload = self.target_line.lower().index(payload.lower())
93+
end_of_payload = index_of_payload + len(payload)
94+
95+
self.target_line = '{}{}{}'.format(
96+
self.target_line[:index_of_payload],
97+
self.apply_highlight(self.target_line[index_of_payload:end_of_payload]),
98+
self.target_line[end_of_payload:],
99+
)
100+
101+
return self
102+
103+
def get_line_number(self, line_number):
104+
"""Broken out, for custom colorization."""
105+
return colorize(
106+
str(line_number),
107+
AnsiColor.LIGHT_GREEN,
108+
)
109+
110+
def apply_highlight(self, payload):
111+
"""Broken out, for custom colorization."""
112+
return colorize(
113+
payload,
114+
AnsiColor.RED_BACKGROUND,
115+
)
116+
117+
def __str__(self):
118+
return '\n'.join(self.lines)

tests/core/audit_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,7 @@ def mock_open(
519519
string.ascii_letters[:(end_line - secret_line)][::-1],
520520
),
521521
)
522-
return mock_open_base(data, 'detect_secrets.core.audit.codecs.open')
522+
return mock_open_base(data, 'detect_secrets.core.code_snippet.codecs.open')
523523

524524
@staticmethod
525525
def _make_string_into_individual_lines(string):

0 commit comments

Comments
 (0)