diff --git a/detect_secrets/core/usage.py b/detect_secrets/core/usage.py index ed3b15300..e491fe546 100644 --- a/detect_secrets/core/usage.py +++ b/detect_secrets/core/usage.py @@ -133,14 +133,16 @@ def _add_initialize_baseline_argument(self): add_exclude_lines_argument(self.parser) # Pairing `--exclude-files` with `--scan` because it's only used for the initialization. - # The pre-commit hook framework already has an `exclude` option that can be used instead. + # The pre-commit hook framework already has an `exclude` option that can + # be used instead. self.parser.add_argument( '--exclude-files', type=str, help='Pass in regex to specify ignored paths during initialization scan.', ) - # Pairing `--update` with `--scan` because it's only used for initialization. + # Pairing `--update` with `--scan` because it's only used for + # initialization. self.parser.add_argument( '--update', nargs=1, @@ -149,7 +151,8 @@ def _add_initialize_baseline_argument(self): dest='import_filename', ) - # Pairing `--update` with `--use-all-plugins` to overwrite plugins list from baseline + # Pairing `--update` with `--use-all-plugins` to overwrite plugins list + # from baseline add_use_all_plugins_argument(self.parser) self.parser.add_argument( @@ -228,6 +231,7 @@ class PluginDescriptor(namedtuple( 'related_args', ], )): + def __new__(cls, related_args=None, **kwargs): if not related_args: related_args = [] @@ -272,6 +276,9 @@ class PluginOptions(object): classname='KeywordDetector', disable_flag_text='--no-keyword-scan', disable_help_text='Disables scanning for secret keywords.', + related_args=[ + ('--keyword-exclude', None), + ], ), PluginDescriptor( classname='AWSKeyDetector', @@ -298,6 +305,7 @@ def __init__(self, parser): def add_arguments(self): self._add_custom_limits() self._add_opt_out_options() + self._add_keyword_exclude() return self @@ -414,3 +422,10 @@ def _convert_flag_text_to_argument_name(flag_text): :return: `no_hex_string_scan` """ return flag_text[2:].replace('-', '_') + + def _add_keyword_exclude(self): + self.parser.add_argument( + '--keyword-exclude', + type=str, + help='Pass in regex to exclude false positives found by keyword detector', + ) diff --git a/detect_secrets/plugins/keyword.py b/detect_secrets/plugins/keyword.py index 05dc2f0c2..dd2e0083c 100644 --- a/detect_secrets/plugins/keyword.py +++ b/detect_secrets/plugins/keyword.py @@ -139,9 +139,27 @@ class KeywordDetector(BasePlugin): secret_type = 'Secret Keyword' + def __init__( + self, keyword_exclude=None, + exclude_lines_regex=None, **kwargs + ): + super(KeywordDetector, self).__init__( + exclude_lines_regex, + ) + self.keyword_exclude = None + if keyword_exclude: + self.keyword_exclude = re.compile( + keyword_exclude, + re.IGNORECASE, + ) + def analyze_string_content(self, string, line_num, filename): output = {} - + if ( + self.keyword_exclude + and self.keyword_exclude.search(string) + ): + return output for identifier in self.secret_generator( string, filetype=determine_file_type(filename), diff --git a/tests/core/usage_test.py b/tests/core/usage_test.py index 8c6ee2dec..e3e2b5e9d 100644 --- a/tests/core/usage_test.py +++ b/tests/core/usage_test.py @@ -32,7 +32,9 @@ def test_consolidates_output_basic(self): 'Base64HighEntropyString': { 'base64_limit': 4.5, }, - 'KeywordDetector': {}, + 'KeywordDetector': { + 'keyword_exclude': None, + }, 'PrivateKeyDetector': {}, 'AWSKeyDetector': {}, 'SlackDetector': {}, @@ -59,7 +61,9 @@ def test_custom_limit(self, argument_string, expected_value): if expected_value is not None: args = self.parse_args(argument_string) - assert args.plugins['HexHighEntropyString']['hex_limit'] == expected_value + assert args.plugins['HexHighEntropyString'][ + 'hex_limit' + ] == expected_value else: with pytest.raises(SystemExit): self.parse_args(argument_string)