Skip to content

Commit

Permalink
Use analyze to find plaintext secret in audit mode
Browse files Browse the repository at this point in the history
In audit mode, we were using secret_generator to find the
plaintext secret. This was problematic because it led to
inconsistences between what the scan functionality would
find and what the audit functionality would find, leading
to user errors.

Using the same plugin function for both scan and audit
will lead to fewer user errors.
  • Loading branch information
Victor Zhou committed Jul 12, 2019
1 parent f8d478d commit 2b40c99
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 54 deletions.
52 changes: 11 additions & 41 deletions detect_secrets/core/audit.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@
from copy import deepcopy

from ..plugins.common import initialize
from ..plugins.common.filetype import determine_file_type
from ..plugins.common.util import get_mapping_from_secret_type_to_class_name
from ..plugins.high_entropy_strings import HighEntropyStringsPlugin
from ..util import get_git_remotes
from ..util import get_git_sha
from .baseline import merge_results
Expand All @@ -22,7 +20,6 @@
from .color import AnsiColor
from .color import colorize
from .common import write_baseline_to_file
from .potential_secret import PotentialSecret


class SecretNotFoundOnSpecifiedLineError(Exception):
Expand Down Expand Up @@ -228,16 +225,14 @@ def determine_audit_results(baseline, baseline_path):
secret_type_to_plugin_name = get_mapping_from_secret_type_to_class_name()

for filename, secret in all_secrets:
plaintext_line = _get_file_line(filename, secret['line_number'])
try:
secret_plaintext = get_raw_secret_value(
secret_line=plaintext_line,
secret=secret,
plugin_settings=baseline['plugins_used'],
filename=filename,
)
except SecretNotFoundOnSpecifiedLineError:
secret_plaintext = plaintext_line
secret_plaintext = _get_file_line(filename, secret['line_number'])

plugin_name = secret_type_to_plugin_name[secret['type']]
audit_result = AUDIT_RESULT_TO_STRING[secret.get('is_secret')]
Expand Down Expand Up @@ -568,7 +563,6 @@ def _get_secret_with_context(

try:
raw_secret_value = get_raw_secret_value(
snippet.target_line,
secret,
plugin_settings,
filename,
Expand All @@ -588,15 +582,11 @@ def _get_secret_with_context(


def get_raw_secret_value(
secret_line,
secret,
plugin_settings,
filename,
):
"""
:type secret_line: str
:param secret_line: the line on which the secret is found
:type secret: dict
:param secret: see caller's docstring
Expand All @@ -612,36 +602,16 @@ def get_raw_secret_value(
plugin_settings,
)

for raw_secret in raw_secret_generator(
plugin,
secret_line,
filetype=determine_file_type(filename),
):
secret_obj = PotentialSecret(
plugin.secret_type,
filename,
secret=raw_secret,
)
with codecs.open(filename, encoding='utf-8') as f:
plugin_secrets = plugin.analyze(f, filename)

# There could be more than two secrets on the same line.
# We only want to highlight the right one.
if secret_obj.secret_hash == secret['hashed_secret']:
return raw_secret
else:
raise SecretNotFoundOnSpecifiedLineError(secret['line_number'])


def raw_secret_generator(plugin, secret_line, filetype):
"""Generates raw secrets by re-scanning the line, with the specified plugin
matching_secret = [
plugin_secret.secret_value
for plugin_secret in plugin_secrets
if plugin_secret.secret_hash == secret['hashed_secret']
]

:type plugin: BasePlugin
:type secret_line: str
:type filetype: FileType
"""
for raw_secret in plugin.secret_generator(secret_line, filetype=filetype):
yield raw_secret
if not matching_secret:
raise SecretNotFoundOnSpecifiedLineError(secret['line_number'])

if issubclass(plugin.__class__, HighEntropyStringsPlugin):
with plugin.non_quoted_string_regex(strict=False):
for raw_secret in plugin.secret_generator(secret_line):
yield raw_secret
return matching_secret[0]
41 changes: 28 additions & 13 deletions tests/core/audit_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -698,15 +698,15 @@ def test_print_audit_results_none(

class TestPrintContext(object):

def run_logic(self, secret=None, secret_lineno=15, settings=None):
def run_logic(self, secret=None, secret_lineno=15, settings=None, should_find_secret=True):
# Setup default arguments
if not secret:
secret = potential_secret_factory(
type_='Private Key',
filename='filenameA',
secret='BEGIN PRIVATE KEY',
lineno=secret_lineno,
).json()
)

if not settings:
settings = [
Expand All @@ -715,13 +715,27 @@ def run_logic(self, secret=None, secret_lineno=15, settings=None):
},
]

audit._print_context(
secret['filename'],
secret,
count=1,
total=2,
plugin_settings=settings,
)
with self.mock_get_raw_secret_value(
secret.secret_value,
secret_lineno,
should_find_secret,
):
audit._print_context(
secret.filename,
secret.json(),
count=1,
total=2,
plugin_settings=settings,
)

@contextmanager
def mock_get_raw_secret_value(self, secret_value, secret_lineno, should_find_secret):
with mock.patch.object(audit, 'get_raw_secret_value', autospec=True) as m:
if should_find_secret:
m.return_value = secret_value
else:
m.side_effect = audit.SecretNotFoundOnSpecifiedLineError(secret_lineno)
yield m

def mock_open(
self,
Expand Down Expand Up @@ -816,7 +830,8 @@ def test_secret_not_found(self, mock_printer):
filename='filenameA',
secret='BEGIN RSA PRIVATE KEY',
lineno=15,
).json(),
),
should_find_secret=False,
)

assert uncolor(mock_printer.message) == textwrap.dedent("""
Expand All @@ -840,7 +855,7 @@ def test_hex_high_entropy_secret_in_yaml_file(self, mock_printer):
filename='filenameB',
secret='123456789a',
lineno=15,
).json(),
),
settings=[
{
'name': 'HexHighEntropyString',
Expand Down Expand Up @@ -879,7 +894,7 @@ def test_keyword_secret_in_yaml_file(self, mock_printer):
filename='filenameB',
secret='yerba',
lineno=15,
).json(),
),
settings=[
{
'name': 'KeywordDetector',
Expand Down Expand Up @@ -916,7 +931,7 @@ def test_unicode_in_output(self, mock_printer):
filename='test_data/config.md',
secret='ToCynx5Se4e2PtoZxEhW7lUJcOX15c54',
lineno=10,
).json(),
),
settings=[
{
'base64_limit': 4.5,
Expand Down

0 comments on commit 2b40c99

Please sign in to comment.