Skip to content

Commit

Permalink
ensure changes to baseline file is added to commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Aaron Loo committed Mar 22, 2018
1 parent 383bc63 commit e936dba
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 9 deletions.
45 changes: 40 additions & 5 deletions detect_secrets/pre_commit_hook.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import absolute_import

import subprocess
import sys
import textwrap

Expand All @@ -25,7 +26,7 @@ def main(argv=None):
# If baseline is provided, we first want to make sure
# it's valid, before doing any further computation.
baseline_collection = get_baseline(args.baseline[0])
except IOError:
except (IOError, ValueError):
# Error logs handled in load_baseline_from_file logic.
return 1

Expand All @@ -38,19 +39,54 @@ def main(argv=None):
)

if len(results.data) > 0:
# TODO: Need to print baseline updated if so.
pretty_print_diagnostics(results)
return 1

return 0


def get_baseline(baseline_filename):
"""
:raises: IOError
:raises: ValueError
"""
if not baseline_filename:
return

raise_exception_if_baseline_file_is_not_up_to_date(baseline_filename)

return SecretsCollection.load_baseline_from_file(baseline_filename)


def raise_exception_if_baseline_file_is_not_up_to_date(filename):
"""We want to make sure that if there are changes to the baseline
file, they will be included in the commit. This way, we can keep
our baselines up-to-date.
:raises: ValueError
"""
try:
files_changed_but_not_staged = subprocess.check_output(
'git diff --name-only'.split()
).split()
except subprocess.CalledProcessError:
# Since we don't pipe stderr, we get free logging through git.
raise ValueError

if filename.encode() in files_changed_but_not_staged:
CustomLog(formatter='%(message)s').getLogger()\
.error((
'Your baseline file ({}) is unstaged.\n'
'`git add {}` to fix this.'
).format(
filename,
filename,
))

raise ValueError


def find_secrets_in_files(args):
plugins = initialize_plugins(args.plugins)
collection = SecretsCollection(plugins)
Expand Down Expand Up @@ -84,14 +120,13 @@ def _print_warning_header(log):
)

log.error(textwrap.fill(message))
log.error('\n\n')
log.error('')


def _print_secrets_found(log, secrets):
for filename in secrets.data:
for secret in secrets.data[filename].values():
log.error(secret)
log.error('\n')


def _print_mitigation_suggestions(log):
Expand All @@ -110,8 +145,8 @@ def _print_mitigation_suggestions(log):

for suggestion in suggestions:
log.error(wrapper.fill(suggestion))
log.error('\n')
log.error('\n')

log.error('')

log.error(
textwrap.fill(
Expand Down
27 changes: 24 additions & 3 deletions tests/pre_commit_hook_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
from tests.util.factories import secrets_collection_factory
from tests.util.mock_util import mock_log as mock_log_base
from tests.util.mock_util import mock_open
from tests.util.mock_util import mock_subprocess
from tests.util.mock_util import SubprocessMock


@pytest.fixture
Expand All @@ -32,7 +34,7 @@ def error(self, message):
"""Currently, this is the only function that is used
when obtaining the logger.
"""
self.message += str(message)
self.message += str(message) + '\n'

with mock_log_base('detect_secrets.pre_commit_hook.CustomLog') as m:
wrapper = MockLogWrapper()
Expand Down Expand Up @@ -100,9 +102,28 @@ def test_ignore_baseline_file(self, mock_get_baseline):
assert_commit_blocked('./test_data/baseline.file')
assert_commit_succeeds('--baseline baseline.file baseline.file')

def test_quit_if_baseline_is_changed_but_not_staged(self, mock_log):
with mock.patch('detect_secrets.pre_commit_hook.subprocess.check_output') as \
mock_subprocess_obj:
mock_subprocess_obj.side_effect = mock_subprocess((
SubprocessMock(
expected_input='git diff --name-only',
mocked_output=b'baseline.file',
),
))

assert_commit_blocked(
'--baseline baseline.file test_data/file_with_secrets.py'
)

assert mock_log.message == (
'Your baseline file (baseline.file) is unstaged.\n'
'`git add baseline.file` to fix this.\n'
)

@staticmethod
def _create_baseline():
base64_hash = 'c3VwZXIgbG9uZyBzdHJpbmcgc2hvdWxkIGNhdXNlIGVub3VnaCBlbnRyb3B5'
base64_secret = 'c3VwZXIgbG9uZyBzdHJpbmcgc2hvdWxkIGNhdXNlIGVub3VnaCBlbnRyb3B5'
baseline = {
'generated_at': 'does_not_matter',
'exclude_regex': '',
Expand All @@ -111,7 +132,7 @@ def _create_baseline():
{
'type': 'High Entropy String',
'line_number': 4,
'hashed_secret': PotentialSecret.hash_secret(base64_hash),
'hashed_secret': PotentialSecret.hash_secret(base64_secret),
},
],
},
Expand Down
2 changes: 1 addition & 1 deletion tests/util/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def mock_repo_factory():
# TODO: I will fix this, when I turn the repo tests to use pytest (and
# subsequently, factory patterns)
class Temporary:
def get_blame(self):
def get_blame(self): # pragma: no cover
pass

return Temporary()
Expand Down

0 comments on commit e936dba

Please sign in to comment.