def test_repositories_added_can_be_scanned(self, mock_rootdir, repo_to_scan): directory = '{}/repos/{}'.format( mock_rootdir, BaseStorage.hash_filename('Yelp/detect-secrets'), ) mocked_sha = 'aabbcc' # We don't **actually** want to clone the repo per test run. with mock_git_calls( SubprocessMock(expected_input=( 'git clone https://github.com/Yelp/detect-secrets {} --bare' ).format(directory, ), ), # Since there is no prior sha to retrieve SubprocessMock( expected_input='git rev-parse HEAD', mocked_output=mocked_sha, )): assert main([ 'add', 'https://github.com/Yelp/detect-secrets', '--root-dir', mock_rootdir, ]) == 0 with mock_git_calls( # Getting latest changes SubprocessMock( expected_input='git rev-parse --abbrev-ref HEAD', mocked_output='master', ), SubprocessMock( expected_input= 'git fetch --quiet origin master:master --force', ), # Getting relevant diff SubprocessMock( expected_input= 'git diff {} HEAD --name-only --diff-filter ACM'.format( mocked_sha), mocked_output='filenameA', ), SubprocessMock( expected_input='git diff {} HEAD -- filenameA'.format( mocked_sha), mocked_output='', ), # Storing latest sha SubprocessMock(expected_input='git rev-parse HEAD', ), ): assert main([ 'scan', repo_to_scan, '--root-dir', mock_rootdir, ]) == 0
def test_main_scan_repo_scan_success_secrets_found(self, mock_file, mock_scan, mock_log): mock_file.return_value = { 'sha': 'does_not_matter', 'repo': 'repo_name', 'plugins': { 'base64_limit': 3, }, 'cron': '* * * * *', 'baseline_file': '.secrets.baseline', } mock_secret_collection = SecretsCollection() mock_secret_collection.data['junk'] = 'data' mock_scan.return_value = mock_secret_collection with mock.patch('detect_secrets_server.usage.ExternalHook') as hook, \ mock.patch('detect_secrets_server.repos.base_tracked_repo.BaseTrackedRepo.update') as update, \ mock.patch('detect_secrets.core.secrets_collection.SecretsCollection.json') as secrets_json: assert main([ '--scan-repo', 'will-be-mocked', '--output-hook', 'examples/standalone_hook.py', ]) == 0 assert update.call_count == 0 assert hook().alert.call_count == 1 assert secrets_json.call_count == 1
def test_main_initialize_success(self, mock_data, mock_save, mock_repo_url, mock_print): mock_save.return_value = True mock_repo_url.return_value = b'[email protected]:some/random-repo.git' mock_data.return_value = { 'tracked': [ { 'repo': '[email protected]:yelp/detect-secrets.git', 'sha': 'some_sha_value', 'cron': '1 2 3 4 5', }, { 'repo': '/file/to/local/repo', 'is_local_repo': True, 'sha': 'some_other_value', 'cron': '2 3 4 5 6', }, ] } assert main('--initialize --output-hook examples/standalone_hook.py'. split()) == 0 mock_print.assert_has_calls([ mock.call('# detect-secrets scanner'), mock.call( '1 2 3 4 5 detect-secrets-server --scan-repo yelp/detect-secrets ' '--output-hook examples/standalone_hook.py'), mock.call( '2 3 4 5 6 detect-secrets-server --scan-repo some/random-repo --local ' '--output-hook examples/standalone_hook.py'), ]) assert mock_print.call_count == 3
def test_main_initialize_failures(self, mock_print): with mock.patch( 'detect_secrets_server.__main__.initialize_repos_from_repo_yaml' ) as m: m.side_effect = IOError assert main( '--initialize --output-hook examples/standalone_hook.py'.split( )) == 1 with mock.patch( 'detect_secrets_server.__main__.initialize_repos_from_repo_yaml' ) as m: m.return_value = [] assert main( '--initialize --output-hook examples/standalone_hook.py'.split( )) == 0 assert mock_print.call_count == 0
def test_main_add_repo_local(self, mock_subprocess_obj): mock_subprocess_obj.side_effect = mock_subprocess(( # mock out `clone_and_pull_repo` SubprocessMock( expected_input='git clone', mocked_output=b"fatal: destination path 'asdf' already exists", ), SubprocessMock( expected_input='git rev-parse --abbrev-ref', mocked_output=b'master', ), SubprocessMock( expected_input='git fetch -q origin', mocked_output=b'', ), # mock out `update` SubprocessMock( expected_input='git rev-parse HEAD', mocked_output=b'new-sha-hash', ))) m = mock.mock_open() with mock.patch( 'detect_secrets_server.repos.base_tracked_repo.codecs.open', m): assert main([ '--add-repo', '/file/to/local/repo', '--local', '--baseline', '.baseline', ]) == 0 m().write.assert_called_once_with( json.dumps( { 'sha': 'new-sha-hash', 'repo': '/file/to/local/repo', 'plugins': { 'base64_limit': 4.5, 'hex_limit': 3, 'private_key_detector': True, }, 'cron': '', 'baseline_file': '.baseline', }, indent=2))
def test_main_scan_repo_scan_success_no_results_found( self, mock_file, mock_scan, mock_log, mock_subprocess_obj): mock_file.return_value = { 'sha': 'does_not_matter', 'repo': 'repo_name', 'plugins': { 'base64_limit': 3, }, 'cron': '* * * * *', 'baseline_file': '.secrets.baseline', } mock_scan.return_value = SecretsCollection() mock_subprocess_obj.side_effect = mock_subprocess( (SubprocessMock(expected_input='git rev-parse HEAD', mocked_output=b'new_sha'), )) m = mock.mock_open() with mock.patch( 'detect_secrets_server.repos.base_tracked_repo.codecs.open', m): assert main([ '--scan-repo', 'will-be-mocked', '--output-hook', 'examples/standalone_hook.py', ]) == 0 mock_log().info.assert_called_with( 'SCAN COMPLETE - STATUS: clean for %s', 'repo_name', ) m().write.assert_called_once_with( json.dumps( { 'sha': 'new_sha', 'repo': 'repo_name', 'plugins': { 'base64_limit': 3, 'hex_limit': None, 'private_key_detector': False, }, 'cron': '* * * * *', 'baseline_file': '.secrets.baseline', }, indent=2))
def test_main_scan_repo_scan_failed(self, mock_read_file, mock_scan): mock_read_file.return_value = { 'sha': 'does_not_matter', 'repo': 'repo_name', 'plugins': { 'base64_limit': 3, }, 'cron': '* * * * *', 'baseline_file': '.secrets.baseline', } mock_scan.return_value = None assert main([ '--scan-repo', 'will-be-mocked', '--output-hook', 'examples/standalone_hook.py', ]) == 1
def test_actions(self, argument_string, action_executed): """All detailed actions tests are covered in their individual test cases. This just makes sure they run, for coverage. """ with mock.patch( 'detect_secrets_server.__main__.actions', autospec=True, ) as mock_actions, mock.patch( 'detect_secrets_server.core.usage.s3.should_enable_s3_options', return_value=True, ), mock.patch( 'detect_secrets_server.core.usage.common.storage.should_enable_s3_options', return_value=True, ): mock_actions.initialize.return_value = '' mock_actions.scan_repo.return_value = 0 assert main(argument_string.split()) == 0 assert getattr(mock_actions, action_executed).called
def test_main_add_repo_s3(self, mock_subprocess_obj, mock_s3_obj): mock_subprocess_obj.side_effect = mock_subprocess(( # mock out `_get_repo_name` SubprocessMock( expected_input='git remote get-url origin', mocked_output=b'[email protected]:yelp/detect-secrets', ), # mock out `update` SubprocessMock( expected_input='git rev-parse HEAD', mocked_output=b'new-sha-hash', ))) mock_s3_config = { 's3_creds_file': 'filename', 'bucket_name': 'bucketman', 'prefix': 'mister', } final_output = mock.mock_open() s3_config = mock.mock_open(read_data=json.dumps(mock_s3_config)) with mock.patch('detect_secrets_server.repos.base_tracked_repo.codecs.open', final_output),\ mock.patch('detect_secrets_server.__main__.codecs.open', s3_config),\ mock.patch( 'detect_secrets_server.repos.s3_tracked_repo.S3TrackedRepo._initialize_s3_client' ): assert main([ '--add-repo', '[email protected]:yelp/detect-secrets.git', '--s3-config-file', 'will-be-mocked', ]) == 0 mock_s3_obj.list_objects_v2.assert_called_once_with( Bucket='bucketman', Prefix='mister/%s.json' % hashlib.sha512('yelp/detect-secrets'.encode('utf-8')).hexdigest(), ) assert mock_s3_obj.upload_file.call_count == 1
def test_no_args(self): with pytest.raises(SystemExit): main([])
def test_main_no_args(self): # Needed for coverage assert main([]) == 0
def test_main_scan_repo_unconfigured_repo(self, mock_load_from_file): mock_load_from_file.return_value = None assert main([ '--scan-repo', 'will-be-mocked', '--output-hook', 'examples/standalone_hook.py' ]) == 1