Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More intelligent upgrade of baselines #58

Merged
merged 2 commits into from
Jul 11, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions detect_secrets/core/usage.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,12 @@ def _add_initialize_baseline_argument(self):
help='Pass in regex to specify ignored paths during initialization scan.',
)

# Pairing `--import` with `--scan` because it's only used for initialization.
# Pairing `--update` with `--scan` because it's only used for initialization.
self.parser.add_argument(
'--import',
'--update',
nargs=1,
metavar='OLD_BASELINE_FILE',
help='Import settings from previous existing baseline.',
help='Update existing baseline by importing settings from it.',
dest='import_filename',
)

Expand Down
36 changes: 27 additions & 9 deletions detect_secrets/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,17 @@ def main(argv=None):
log.set_debug_level(args.verbose)

if args.action == 'scan':
print(
json.dumps(
_perform_scan(args),
indent=2,
sort_keys=True,
),
output = json.dumps(
_perform_scan(args),
indent=2,
sort_keys=True,
)

if args.import_filename:
_write_to_file(args.import_filename[0], output)
else:
print(output)

elif args.action == 'audit':
audit.audit_baseline(args.filename[0])

Expand All @@ -53,6 +56,11 @@ def _perform_scan(args):
elif old_baseline and old_baseline.get('exclude_regex'):
args.exclude = old_baseline['exclude_regex']

# If we have knowledge of an existing baseline file, we should use
# that knowledge and *not* scan that file.
if args.import_filename and args.exclude:
args.exclude += r'|^{}$'.format(args.import_filename[0])

new_baseline = baseline.initialize(
plugins,
args.exclude,
Expand All @@ -71,12 +79,22 @@ def _perform_scan(args):
def _get_existing_baseline(import_filename):
# Favors --import argument over stdin.
if import_filename:
with open(import_filename[0]) as f:
return json.loads(f.read())

return _read_from_file(import_filename[0])
if not sys.stdin.isatty():
return json.loads(sys.stdin.read())


def _read_from_file(filename):
"""Used for mocking."""
with open(filename[0]) as f:
return json.loads(f.read())


def _write_to_file(filename, content):
"""Used for mocking."""
with open(filename, 'w') as f:
f.write(content)


if __name__ == '__main__':
sys.exit(main())
48 changes: 41 additions & 7 deletions tests/main_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
from detect_secrets.main import main
from testing.factories import secrets_collection_factory
from testing.mocks import Any
from testing.mocks import mock_open
from testing.mocks import mock_printer


Expand Down Expand Up @@ -83,18 +82,53 @@ def test_reads_from_stdin(self, mock_merge_baseline):
)

def test_reads_old_baseline_from_file(self, mock_merge_baseline):
with mock_stdin(), mock_open(
json.dumps({'key': 'value'}),
'detect_secrets.main.open',
) as m:
assert main('scan --import old_baseline_file'.split()) == 0
assert m.call_args[0][0] == 'old_baseline_file'
with mock_stdin(), mock.patch(
'detect_secrets.main._read_from_file',
return_value={'key': 'value'},
) as m_read, mock.patch(
'detect_secrets.main._write_to_file',
) as m_write:
assert main('scan --update old_baseline_file'.split()) == 0
assert m_read.call_args[0][0] == 'old_baseline_file'
assert m_write.call_args[0] == ('old_baseline_file', Any(str))

mock_merge_baseline.assert_called_once_with(
{'key': 'value'},
Any(dict),
)

@pytest.mark.parametrize(
'exclude_param, expected_regex',
[
(
'',
'^old_baseline_file$',
),
(
'--exclude "secrets/.*"',
'secrets/.*|^old_baseline_file$',
),
],
)
def test_old_baseline_ignored_with_update_flag(
self,
mock_baseline_initialize,
exclude_param,
expected_regex,
):
with mock_stdin(), mock.patch(
'detect_secrets.main._read_from_file',
return_value={},
), mock.patch(
# We don't want to be creating a file during test
'detect_secrets.main._write_to_file',
):
assert main(
'scan --update old_baseline_file {}'.format(
exclude_param,
).split(),
) == 0

@pytest.mark.parametrize(
'filename, expected_output',
[
Expand Down