Skip to content

Commit e9a1f1d

Browse files
committed
feat: plugins reuse excludes CLI arg
1 parent 8831fcb commit e9a1f1d

File tree

5 files changed

+51
-0
lines changed

5 files changed

+51
-0
lines changed

detect_secrets/core/baseline.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
def initialize(
1717
path,
1818
plugins,
19+
plugins_reuse_exclude=None,
1920
exclude_files_regex=None,
2021
exclude_lines_regex=None,
2122
word_list_file=None,
@@ -33,6 +34,9 @@ def initialize(
3334
:type plugins: tuple of detect_secrets.plugins.base.BasePlugin
3435
:param plugins: rules to initialize the SecretsCollection with.
3536
37+
:type plugins_reuse_exclude: bool|None
38+
:param plugins_reuse_exclude optional bool indicating whether plugins were forced to reuse excludes.
39+
3640
:type exclude_files_regex: str|None
3741
:type exclude_lines_regex: str|None
3842
@@ -53,6 +57,7 @@ def initialize(
5357
"""
5458
output = SecretsCollection(
5559
plugins,
60+
plugins_reuse_exclude=plugins_reuse_exclude,
5661
exclude_files=exclude_files_regex,
5762
exclude_lines=exclude_lines_regex,
5863
word_list_file=word_list_file,

detect_secrets/core/secrets_collection.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class SecretsCollection:
2121
def __init__(
2222
self,
2323
plugins=(),
24+
plugins_reuse_exclude=None,
2425
exclude_files=None,
2526
exclude_lines=None,
2627
word_list_file=None,
@@ -46,6 +47,7 @@ def __init__(
4647
"""
4748
self.data = {}
4849
self.plugins = plugins
50+
self.plugins_reuse_exclude = plugins_reuse_exclude
4951
self.exclude_files = exclude_files
5052
self.exclude_lines = exclude_lines
5153
self.word_list_file = word_list_file
@@ -342,6 +344,7 @@ def format_for_baseline_output(self):
342344
plugins_used = sorted(plugins_used, key=lambda x: x['name'])
343345

344346
return {
347+
**({"plugins_reuse_excludes": True} if self.plugins_reuse_exclude else {}),
345348
'generated_at': strftime('%Y-%m-%dT%H:%M:%SZ', gmtime()),
346349
'exclude': {
347350
'files': self.exclude_files,

detect_secrets/core/usage.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@
55
from detect_secrets.constants import DEFAULT_GHE_INSTANCE
66

77

8+
def add_plugins_reuse_exclude_flag(parser):
9+
parser.add_argument(
10+
'--plugins-reuse-excludes',
11+
action='store_true',
12+
help='Force plugins to try re-using existing exclude contents.'
13+
)
14+
15+
816
def add_exclude_lines_argument(parser):
917
parser.add_argument(
1018
'--exclude-lines',
@@ -89,6 +97,7 @@ def add_default_arguments(self):
8997

9098
def add_pre_commit_arguments(self):
9199
self._add_filenames_argument()\
100+
._add_plugins_reuse_exclude_flag()\
92101
._add_set_baseline_argument()\
93102
._add_exclude_lines_argument()\
94103
._add_word_list_argument()\
@@ -154,6 +163,10 @@ def _add_set_baseline_argument(self):
154163
)
155164
return self
156165

166+
def _add_plugins_reuse_exclude_flag(self):
167+
add_plugins_reuse_exclude_flag(self.parser)
168+
return self
169+
157170
def _add_exclude_lines_argument(self):
158171
add_exclude_lines_argument(self.parser)
159172
return self
@@ -222,6 +235,10 @@ def _add_initialize_baseline_argument(self):
222235
),
223236
)
224237

238+
# Pairing `--plugins-reuse-excludes` to
239+
# both pre-commit and `--scan` because it can be used for both.
240+
add_plugins_reuse_exclude_flag(self.parser)
241+
225242
# Pairing `--exclude-lines` and `--word-list` to
226243
# both pre-commit and `--scan` because it can be used for both.
227244
add_exclude_lines_argument(self.parser)

detect_secrets/main.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,19 @@ def parse_args(argv, parserBuilder):
1717
return parserBuilder.add_console_use_arguments().parse_args(argv)
1818

1919

20+
def maybe_get_existing_exclude(exclude_files, exclude_lines, old_baseline):
21+
if not old_baseline:
22+
return exclude_files, exclude_lines
23+
24+
previously_included = old_baseline.get("exclude", None)
25+
if not previously_included:
26+
return exclude_files, exclude_lines
27+
28+
files = "|".join(filter(None, (exclude_files, previously_included.get("files",None))))
29+
lines = "|".join(filter(None, (exclude_lines, previously_included.get("lines",None))))
30+
31+
return files, lines
32+
2033
def main(argv=None):
2134
if len(sys.argv) == 1: # pragma: no cover
2235
sys.argv.append('-h')
@@ -36,6 +49,10 @@ def main(argv=None):
3649
if args.word_list_file:
3750
automaton, word_list_hash = build_automaton(args.word_list_file)
3851

52+
_baseline = _get_existing_baseline(args.import_filename)
53+
if args.plugins_reuse_excludes or (_baseline and _baseline.get("plugins_reuse_excludes", False)):
54+
args.exclude_files, args.exclude_lines = maybe_get_existing_exclude(args.exclude_files, args.exclude_lines, _baseline)
55+
3956
# Plugins are *always* rescanned with fresh settings, because
4057
# we want to get the latest updates.
4158
plugins = initialize.from_parser_builder(
@@ -173,13 +190,17 @@ def _perform_scan(args, plugins, automaton, word_list_hash):
173190
if not args.word_list_file and old_baseline.get('word_list'):
174191
args.word_list_file = old_baseline['word_list']['file']
175192

193+
if not args.plugins_reuse_excludes:
194+
args.plugins_reuse_excludes = old_baseline.get('plugins_reuse_excludes', False)
195+
176196
# If we have knowledge of an existing baseline file, we should use
177197
# that knowledge and add it to our exclude_files regex.
178198
if args.import_filename:
179199
_add_baseline_to_exclude_files(args)
180200

181201
new_baseline = baseline.initialize(
182202
plugins=plugins,
203+
plugins_reuse_exclude=args.plugins_reuse_excludes,
183204
exclude_files_regex=args.exclude_files,
184205
exclude_lines_regex=args.exclude_lines,
185206
word_list_file=args.word_list_file,

tests/main_test.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ def test_scan_basic(self, mock_baseline_initialize):
8787

8888
mock_baseline_initialize.assert_called_once_with(
8989
plugins=Any(tuple),
90+
plugins_reuse_excludes=None,
9091
exclude_files_regex=None,
9192
exclude_lines_regex=None,
9293
path='.',
@@ -104,6 +105,7 @@ def test_scan_with_rootdir(self, mock_baseline_initialize):
104105

105106
mock_baseline_initialize.assert_called_once_with(
106107
plugins=Any(tuple),
108+
plugins_reuse_excludes=None,
107109
exclude_files_regex=None,
108110
exclude_lines_regex=None,
109111
path=['test_data'],
@@ -123,6 +125,7 @@ def test_scan_with_exclude_args(self, mock_baseline_initialize):
123125

124126
mock_baseline_initialize.assert_called_once_with(
125127
plugins=Any(tuple),
128+
plugins_reuse_excludes=None,
126129
exclude_files_regex='some_pattern_here',
127130
exclude_lines_regex='other_patt',
128131
path='.',
@@ -208,6 +211,7 @@ def test_scan_with_all_files_flag(self, mock_baseline_initialize):
208211

209212
mock_baseline_initialize.assert_called_once_with(
210213
plugins=Any(tuple),
214+
plugins_reuse_excludes=None,
211215
exclude_files_regex=None,
212216
exclude_lines_regex=None,
213217
path='.',
@@ -265,6 +269,7 @@ def test_reads_non_existed_baseline_from_file(
265269

266270
mock_baseline_initialize.assert_called_once_with(
267271
plugins=Any(tuple),
272+
plugins_reuse_excludes=None,
268273
exclude_files_regex='^non_existed_baseline_file$',
269274
exclude_lines_regex=None,
270275
path='.',

0 commit comments

Comments
 (0)