def test_echo_result_echos_all_when_not_json(self, mock_click, mock_scanner): options = generate_options(GlobalOptions, json=False, verbose=0) mock_scanner.exclude_signatures = [] mock_scanner.issues = [1, 2, 3, 4] util.echo_result(options, mock_scanner, "", "") mock_click.echo.assert_called_once_with("1\n2\n3\n4")
def test_echo_result_echos_exclusions_verbose(self, mock_time, mock_click, mock_scanner): mock_time.now.return_value.isoformat.return_value = "now:now:now" exclude_signatures = [ "fffffffffffff", "ooooooooooooo", ] options = generate_options( GlobalOptions, json=False, quiet=False, verbose=1, exclude_signatures=exclude_signatures, ) mock_scanner.issues = [] mock_scanner.excluded_paths = [ re.compile("package-lock.json"), re.compile("poetry.lock"), ] util.echo_result(options, mock_scanner, "", "") mock_click.echo.assert_has_calls( ( mock.call( "Time: now:now:now\nAll clear. No secrets detected."), mock.call("\nExcluded paths:"), mock.call("package-lock.json\npoetry.lock"), mock.call("\nExcluded signatures:"), mock.call("fffffffffffff\nooooooooooooo"), ), any_order=False, )
def test_echo_result_outputs_proper_json_when_requested( self, mock_time, mock_scanner, ): mock_time.now.return_value.isoformat.return_value = "now:now:now" issue_1 = scanner.Issue(types.IssueType.Entropy, "foo", types.Chunk("foo", "/bar", {})) issue_2 = scanner.Issue(types.IssueType.RegEx, "bar", types.Chunk("foo", "/bar", {})) mock_scanner.scan.return_value = (issue_1, issue_2) mock_scanner.excluded_paths = [] options = generate_options( GlobalOptions, output_format=types.OutputFormat.Json.value, exclude_signatures=[], exclude_entropy_patterns=[], ) # We're generating JSON piecemeal, so if we want to be safe we'll recover # the entire output, deserialize it (to confirm it's valid syntax) and # compare the result to the original input dictionary. with mock.patch("sys.stdout", new=StringIO()) as mock_stdout: util.echo_result(options, mock_scanner, "/repo", "/output") actual_output = mock_stdout.getvalue() self.assertEqual( json.loads(actual_output), { "scan_time": "now:now:now", "project_path": "/repo", "output_dir": "/output", "excluded_paths": [], "excluded_signatures": [], "exclude_entropy_patterns": [], "found_issues": [ { "issue_type": "High Entropy", "issue_detail": None, "diff": "foo", "matched_string": "foo", "signature": "4db0024275a64ac2bf5e7d061e130e283b0b37a44167b605643e06e33177f74e", "file_path": "/bar", }, { "issue_type": "Regular Expression Match", "issue_detail": None, "diff": "foo", "matched_string": "bar", "signature": "1516f2c3395943be40811573bb63ed1e2b8fe3a0e6dcc8dbb43351ca90ba6822", "file_path": "/bar", }, ], }, )
def process_issues( ctx: click.Context, result: Tuple[str, scanner.ScannerBase], **kwargs: config.OptionTypes, ): repo_path, scan = result options = types.GlobalOptions(**kwargs) # type: ignore now = datetime.now().isoformat("T", "microseconds") output_dir = None if options.output_dir: if platform.system().lower() == "windows": # pragma: no cover # Make sure we aren't using illegal characters for Windows folder names now = now.replace(":", "") output_dir = pathlib.Path( options.output_dir) / f"tartufo-scan-results-{now}" output_dir.mkdir(parents=True) util.echo_result(options, scan, repo_path, output_dir) if output_dir: util.write_outputs(scan.issues, output_dir) if not options.json: click.echo(f"Results have been saved in {output_dir}") if scan.issues: ctx.exit(1) ctx.exit(0)
def test_echo_result_echos_no_message_when_quiet(self, mock_click, mock_scanner): options = generate_options(GlobalOptions, quiet=True, verbose=0) mock_scanner.issues = [] mock_scanner.exclude_signatures = [] util.echo_result(options, mock_scanner, "", "") mock_click.echo.assert_not_called()
def test_echo_result_echos_all_when_not_json(self, mock_click, mock_scanner): options = generate_options(GlobalOptions, json=False, verbose=0) mock_scanner.exclude_signatures = [] mock_scanner.issues = [1, 2, 3, 4] util.echo_result(options, mock_scanner, "", "") mock_click.echo.assert_has_calls( (mock.call(1), mock.call(2), mock.call(3), mock.call(4)), any_order=False )
def test_echo_result_echos_message_when_clean(self, mock_time, mock_click, mock_scanner): mock_time.now.return_value.isoformat.return_value = "now:now:now" options = generate_options(GlobalOptions, quiet=False, verbose=0) mock_scanner.exclude_signatures = [] mock_scanner.issue_count = 0 mock_scanner.issues = [] util.echo_result(options, mock_scanner, "", "") mock_click.echo.assert_called_once_with( "Time: now:now:now\nAll clear. No secrets detected.")
def test_echo_result_outputs_proper_json_when_requested_pathtype( self, mock_time, mock_json, mock_scanner): mock_time.now.return_value.isoformat.return_value = "now:now:now" issue_1 = scanner.Issue(types.IssueType.Entropy, "foo", types.Chunk("foo", "/bar", {})) issue_2 = scanner.Issue(types.IssueType.RegEx, "bar", types.Chunk("foo", "/bar", {})) mock_scanner.issues = [issue_1, issue_2] mock_scanner.excluded_paths = [ re.compile("package-lock.json"), re.compile("poetry.lock"), ] exclude_signatures = [ "fffffffffffff", "ooooooooooooo", ] options = generate_options(GlobalOptions, json=True, exclude_signatures=exclude_signatures) util.echo_result(options, mock_scanner, "/repo", Path("/tmp")) mock_json.dumps.assert_called_once_with({ "scan_time": "now:now:now", "project_path": "/repo", "output_dir": str(Path("/tmp")), "excluded_paths": ["package-lock.json", "poetry.lock"], "excluded_signatures": [ "fffffffffffff", "ooooooooooooo", ], "found_issues": [ { "issue_type": "High Entropy", "issue_detail": None, "diff": "foo", "matched_string": "foo", "signature": "4db0024275a64ac2bf5e7d061e130e283b0b37a44167b605643e06e33177f74e", "file_path": "/bar", }, { "issue_type": "Regular Expression Match", "issue_detail": None, "diff": "foo", "matched_string": "bar", "signature": "1516f2c3395943be40811573bb63ed1e2b8fe3a0e6dcc8dbb43351ca90ba6822", "file_path": "/bar", }, ], })
def test_echo_result_echos_exclusions_verbose(self, mock_time, mock_click, mock_scanner): mock_time.now.return_value.isoformat.return_value = "now:now:now" options = generate_options( GlobalOptions, quiet=False, verbose=1, ) mock_scanner.issues = [] mock_scanner.issue_count = 0 mock_scanner.excluded_paths = [ re.compile("package-lock.json"), re.compile("poetry.lock"), ] mock_scanner.excluded_signatures = [ "fffffffffffff", "ooooooooooooo", ] rule_1 = (Rule( name="Rule-1", pattern="aaaa", path_pattern="bbbb", re_match_type=MatchType.Search, re_match_scope=Scope.Line, ), ) rule_2 = (Rule( name="Rule-1", pattern="cccc", path_pattern="dddd", re_match_type=MatchType.Search, re_match_scope=Scope.Line, ), ) mock_scanner.excluded_entropy = [rule_1, rule_2] util.echo_result(options, mock_scanner, "", "") mock_click.echo.assert_has_calls( ( mock.call( "Time: now:now:now\nAll clear. No secrets detected."), mock.call("\nExcluded paths:"), mock.call( "re.compile('package-lock.json')\nre.compile('poetry.lock')" ), mock.call("\nExcluded signatures:"), mock.call("fffffffffffff\nooooooooooooo"), mock.call("\nExcluded entropy patterns:"), mock.call(f"{rule_1}\n{rule_2}"), ), any_order=False, )
def test_echo_result_echos_all_when_not_json(self, mock_click, mock_scanner): options = generate_options(GlobalOptions, verbose=0) mock_scanner.exclude_signatures = [] mock_scanner.scan.return_value = (1, 2, 3, 4) util.echo_result(options, mock_scanner, "", "") # Ensure that the issues are output as a byte stream mock_click.echo.assert_has_calls([ mock.call(bytes(1)), mock.call(bytes(2)), mock.call(bytes(3)), mock.call(bytes(4)), ]) self.assertEqual(mock_click.echo.call_count, 4)
def test_echo_result_outputs_compact_format(self, mock_click, mock_scanner): options = generate_options(GlobalOptions, verbose=0, output_format="compact") issue1 = scanner.Issue(types.IssueType.Entropy, "foo", types.Chunk("fullfoobar", "/what/foo", {})) issue2 = scanner.Issue(types.IssueType.RegEx, "bar", types.Chunk("fullfoobar", "/what/bar", {})) issue2.issue_detail = "Meets the bar" mock_scanner.scan.return_value = (issue1, issue2) util.echo_result(options, mock_scanner, "", "") mock_click.echo.assert_has_calls([ mock.call( "[High Entropy] /what/foo: foo (ea29b8c0f8a478f260689899393107cca188fbbff1c5a5bd4ff32c102cb60226, None)" ), mock.call( "[Regular Expression Match] /what/bar: bar (fa692eebc3d60e67a9f22b4b877d5939cb2ec96c0c26c7e5168b3b8b660c573c, Meets the bar)" ), ], )