def test_baseline_filters_out_known_secrets(): secrets = SecretsCollection() secrets.scan_file('test_data/each_secret.py') with tempfile.NamedTemporaryFile() as f: baseline.save_to_file(secrets, f.name) f.seek(0) # This succeeds, because all the secrets are known. assert_commit_succeeds([ 'test_data/each_secret.py', '--baseline', f.name, ]) # Remove one arbitrary secret, so that it won't be the full set. secrets.data['test_data/each_secret.py'].pop() with tempfile.NamedTemporaryFile() as f: baseline.save_to_file(secrets, f.name) f.seek(0) # Test that it isn't the case that a baseline is provided, and everything passes. # import pdb; pdb.set_trace() assert_commit_blocked([ 'test_data/each_secret.py', '--baseline', f.name, ])
def test_saves_to_baseline(): # We create an empty baseline, with customized settings. # This way, we expect the engine to use the settings configured by the baseline, # but have the results replaced by the new scan. with transient_settings({ 'plugins_used': [ { 'name': 'Base64HighEntropyString', 'limit': 4.5, }, ], }): secrets = SecretsCollection() old_secrets = baseline.format_for_output(secrets) with mock_printer( main_module) as printer, tempfile.NamedTemporaryFile() as f: baseline.save_to_file(old_secrets, f.name) f.seek(0) # We also test setting the root directory through this test. main_module.main(['scan', 'test_data', '--baseline', f.name]) f.seek(0) new_secrets = json.loads(f.read()) assert not secrets.exactly_equals( baseline.load(new_secrets, f.name)) assert new_secrets['plugins_used'] == [ { 'name': 'Base64HighEntropyString', 'limit': 4.5, }, ] assert not printer.message
def run_logic(secretsA: SecretsCollection, secretsB: SecretsCollection): with tempfile.NamedTemporaryFile() as f, tempfile.NamedTemporaryFile( ) as g: baseline.save_to_file(secretsA, f.name) baseline.save_to_file(secretsB, g.name) main(['audit', '--diff', f.name, g.name])
def test_no_divide_by_zero(secret): secrets = SecretsCollection() secrets['file'].add(secret) with tempfile.NamedTemporaryFile() as f: baseline.save_to_file(secrets, f.name) f.seek(0) main(['audit', f.name, '--stats', '--json'])
def test_modifies_baseline(self, modified_baseline): with tempfile.NamedTemporaryFile() as f: baseline.save_to_file(modified_baseline, f.name) assert_commit_blocked_with_diff_exit_code([ self.FILENAME, '--baseline', f.name, ])
def test_does_not_modify_slim_baseline(self, modified_baseline): with tempfile.NamedTemporaryFile() as f: baseline.save_to_file( baseline.format_for_output(modified_baseline, is_slim_mode=True), f.name, ) assert_commit_succeeds([ self.FILENAME, '--baseline', f.name, ])
def main(argv: Optional[List[str]] = None) -> int: try: args = parse_args(argv) except ValueError: return 1 if args.verbose: # pragma: no cover log.set_debug_level(args.verbose) # Find all secrets in files to be committed secrets = SecretsCollection() for filename in args.filenames: secrets.scan_file(filename) new_secrets = secrets if args.baseline: new_secrets = secrets - args.baseline if new_secrets: pretty_print_diagnostics(new_secrets) return 1 if not args.baseline: return 0 # Only attempt baseline modifications if we don't find any new secrets. is_modified = should_update_baseline( args.baseline, scanned_results=secrets, filelist=args.filenames, baseline_version=args.baseline_version, ) if is_modified: if args.baseline_version != VERSION: with open(args.baseline_filename) as f: old_baseline = json.loads(f.read()) # Override the results, because this has been updated in `should_update_baseline`. old_baseline['results'] = args.baseline.json() args.baseline = baseline.upgrade(old_baseline) baseline.save_to_file(args.baseline, filename=args.baseline_filename) print( 'The baseline file was updated.\n' 'Probably to keep line numbers of secrets up-to-date.\n' 'Please `git add {}`, thank you.\n\n'.format( args.baseline_filename), ) return 3 return 0
def get_baseline_file(self, formatter=baseline.format_for_output): secrets = SecretsCollection() secrets.scan_file(self.FILENAME) with tempfile.NamedTemporaryFile() as f: with mock.patch('detect_secrets.core.baseline.VERSION', '0.0.1'): data = formatter(secrets) # Simulating old version data['plugins_used'][0]['base64_limit'] = data['plugins_used'][0].pop('limit') baseline.save_to_file(data, f.name) yield f
def test_only_verified_overrides_baseline_settings(parser): secrets = SecretsCollection() with tempfile.NamedTemporaryFile() as f, transient_settings({ 'filters_used': [{ 'path': 'detect_secrets.filters.common.is_ignored_due_to_verification_policies', 'min_level': VerifiedResult.UNVERIFIED.value, }], }): baseline.save_to_file(secrets, f.name) f.seek(0) parser.parse_args(['scan', '--baseline', f.name, '--only-verified']) assert get_settings().filters[ 'detect_secrets.filters.common.is_ignored_due_to_verification_policies'][ 'min_level'] == VerifiedResult.VERIFIED_TRUE.value
def test_no_verify_overrides_baseline_settings(parser): secrets = SecretsCollection() with tempfile.NamedTemporaryFile() as f, transient_settings({ 'filters_used': [{ 'path': 'detect_secrets.filters.common.is_ignored_due_to_verification_policies', 'min_level': VerifiedResult.UNVERIFIED.value, }], }): baseline.save_to_file(secrets, f.name) f.seek(0) parser.parse_args(['scan', '--baseline', f.name, '--no-verify']) for filter_path in get_settings().filters: assert filter_path.rsplit( '.')[-1] != 'is_ignored_due_to_verification_policies'
def labelled_secrets(): # Create our own SecretsCollection manually, so that we have fine-tuned control. secrets = SecretsCollection() secrets['fileA'] = { potential_secret_factory(), potential_secret_factory(is_secret=True), potential_secret_factory(is_secret=False), } secrets['fileB'] = { potential_secret_factory(is_secret=False), } with tempfile.NamedTemporaryFile() as f: baseline.save_to_file(secrets, f.name) f.seek(0) yield f.name
def test_success(parser): # Ensure it serializes accordingly. parser.parse_args(['-p', 'testing/plugins.py']) with tempfile.NamedTemporaryFile() as f: baseline.save_to_file(SecretsCollection(), f.name) f.seek(0) get_settings().clear() plugins.util.get_mapping_from_secret_type_to_class.cache_clear() assert 'HippoDetector' not in get_settings().plugins parser.parse_args(['--baseline', f.name]) assert get_settings().plugins['HippoDetector'] == { 'path': f'file://{os.path.abspath("testing/plugins.py")}', } assert plugins.initialize.from_plugin_classname('HippoDetector')
def baseline_file(): # Create our own SecretsCollection manually, so that we have fine-tuned control. first_content = textwrap.dedent(f""" url = {url_format.format(first_secret)} example = {url_format.format(random_secret)} link = {url_format.format(first_secret)} """)[1:] second_content = textwrap.dedent(f""" url = {url_format.format(second_secret)} example = {url_format.format(random_secret)} """)[1:] with create_file_with_content(first_content) as first_file, \ create_file_with_content(second_content) as second_file, \ tempfile.NamedTemporaryFile() as baseline_file, \ transient_settings({ 'plugins_used': [ {'name': 'BasicAuthDetector'}, {'name': 'JwtTokenDetector'}, ], }): secrets = SecretsCollection() secrets.scan_file(first_file) secrets.scan_file(second_file) labels = { (first_file, BasicAuthDetector.secret_type, 1): True, (first_file, BasicAuthDetector.secret_type, 2): None, (first_file, BasicAuthDetector.secret_type, 3): True, (second_file, JwtTokenDetector.secret_type, 1): True, (second_file, BasicAuthDetector.secret_type, 1): False, (second_file, BasicAuthDetector.secret_type, 2): False, } for item in secrets: _, secret = item secret.is_secret = labels[(secret.filename, secret.type, secret.line_number)] baseline.save_to_file(secrets, baseline_file.name) baseline_file.seek(0) yield baseline_file.name
def run_logic( secrets: SecretsCollection, input: Optional[str] = None, ) -> SecretsCollection: """ :param input: if provided, will automatically quit at the end of input string. otherwise, will assert that no user input is requested. """ with tempfile.NamedTemporaryFile() as f: baseline.save_to_file(secrets, f.name) f.seek(0) with mock.patch('detect_secrets.audit.io.input') as m: if input is not None: m.side_effect = list(input) + ['q'] main(['audit', f.name]) if input is None: assert not m.called return baseline.load(baseline.load_from_file(f.name), f.name)