From 1fc63c27ca9cdfc503d740ea575eb7c58ccef4e8 Mon Sep 17 00:00:00 2001 From: Joey Wilhelm Date: Thu, 9 Dec 2021 19:48:53 -0500 Subject: [PATCH] =?UTF-8?q?Actually=20determine=20if=20we=20are=20dealing?= =?UTF-8?q?=20with=20a=20shallow=20clone=20instead=20of=20=E2=80=A6=20(#29?= =?UTF-8?q?8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Actually determine if we are dealing with a shallow clone instead of assuming * Switch tests to check the new shallow assumptions * Mock out is_shallow_clone for all our tests --- tartufo/scanner.py | 5 ++--- tartufo/util.py | 14 ++++++++++++++ tests/test_git_repo_scanner.py | 9 +++++++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/tartufo/scanner.py b/tartufo/scanner.py index f512d141..bbebc9ba 100755 --- a/tartufo/scanner.py +++ b/tartufo/scanner.py @@ -767,9 +767,8 @@ def chunks(self) -> Generator[types.Chunk, None, None]: branches = [self.git_options.branch] else: # Everything - if not self._repo.listall_branches(): - # If no local branches are found, assume that this is a - # shallow clone and examine the repo head as a single + if util.is_shallow_clone(self._repo): + # If this is a shallow clone, examine the repo head as a single # commit to scan all files at once branches = ["HEAD"] else: diff --git a/tartufo/util.py b/tartufo/util.py index 40c764cd..a6cf26f7 100644 --- a/tartufo/util.py +++ b/tartufo/util.py @@ -242,3 +242,17 @@ def process_issues( write_outputs(scan.issues, output_dir) if options.output_format != types.OutputFormat.Json.value: click.echo(f"Results have been saved in {output_dir}") + + +def is_shallow_clone(repo: pygit2.Repository) -> bool: + """Determine whether a repository is a shallow clone + + :param repo: The repository to check for "shallowness" + + This is used to work around https://github.com/libgit2/libgit2/issues/3058 + Basically, any time a git repository is a "shallow" clone (it was cloned + with `--max-depth N`), git will create a file at `.git/shallow`. So we + simply need to test whether that file exists to know whether we are + interacting with a shallow repository. + """ + return (pathlib.Path(repo.path) / "shallow").exists() diff --git a/tests/test_git_repo_scanner.py b/tests/test_git_repo_scanner.py index 8b751240..7dcbbfe7 100644 --- a/tests/test_git_repo_scanner.py +++ b/tests/test_git_repo_scanner.py @@ -151,12 +151,17 @@ class ChunkGeneratorTests(ScannerTestCase): def setUp(self) -> None: self.diff_patcher = mock.patch("tartufo.scanner.GitScanner._iter_diff_index") self.repo_patcher = mock.patch("pygit2.Repository") + self.shallow_patcher = mock.patch("tartufo.scanner.util.is_shallow_clone") self.mock_iter_diff = self.diff_patcher.start() self.mock_repo = self.repo_patcher.start() + self.mock_shallow = self.shallow_patcher.start() + + self.mock_shallow.return_value = False self.addCleanup(self.diff_patcher.stop) self.addCleanup(self.repo_patcher.stop) + self.addCleanup(self.shallow_patcher.stop) return super().setUp() def test_single_branch_is_loaded_if_specified(self): @@ -306,8 +311,8 @@ def test_error_is_raised_when_specified_branch_is_not_found(self): for _ in test_scanner.chunks: pass - def test_head_is_scanned_when_no_local_branches_are_found(self): - self.mock_repo.return_value.listall_branches.return_value = [] + def test_head_is_scanned_when_shallow_clone_is_found(self): + self.mock_shallow.return_value = True self.mock_iter_diff.return_value = [] self.mock_repo.return_value.head.target = "commit-hash" mock_head = mock.MagicMock(spec=pygit2.Commit)