From f5aeec87cca786dc9654c77fd87a47e4c7b055f1 Mon Sep 17 00:00:00 2001 From: behnazh-w Date: Wed, 2 Aug 2023 15:54:34 +1000 Subject: [PATCH] fix: handle cloning issues when repo is in an unexpected state Signed-off-by: behnazh-w --- src/macaron/slsa_analyzer/analyzer.py | 1 + .../slsa_analyzer/git_service/gitlab.py | 35 ++++++++++++++++--- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/macaron/slsa_analyzer/analyzer.py b/src/macaron/slsa_analyzer/analyzer.py index 25d239fa5..8fa18b546 100644 --- a/src/macaron/slsa_analyzer/analyzer.py +++ b/src/macaron/slsa_analyzer/analyzer.py @@ -700,6 +700,7 @@ def _prepare_repo( try: git_service.check_out_repo(git_obj, branch_name, digest, not is_remote) except RepoCheckOutError as error: + logger.error("Failed to check out repository at %s", resolved_local_path) logger.error(error) return None diff --git a/src/macaron/slsa_analyzer/git_service/gitlab.py b/src/macaron/slsa_analyzer/git_service/gitlab.py index 2c5abb756..17597e026 100644 --- a/src/macaron/slsa_analyzer/git_service/gitlab.py +++ b/src/macaron/slsa_analyzer/git_service/gitlab.py @@ -23,6 +23,7 @@ from abc import abstractmethod from urllib.parse import ParseResult, urlunparse +from git import GitError from pydriller.git import Git from macaron.errors import CloneError, ConfigurationError, RepoCheckOutError @@ -129,7 +130,7 @@ def clone_repo(self, clone_dir: str, url: str) -> None: # Therefore, we don't need to catch and handle the CloneError exceptions here. repo = git_url.clone_remote_repo(clone_dir, clone_url) - # If ``git_url.clone_remote_repo`` returns an Repo instance, this means that the repository is freshly cloned + # If ``git_url.clone_remote_repo`` returns a Repo instance, this means that the repository is freshly cloned # with the token embedded URL. We will set its value back to the original non-token URL. # If ``git_url.clone_remote_repo`` returns None, it means that the repository already exists so we don't need # to do anything. @@ -139,7 +140,16 @@ def clone_repo(self, clone_dir: str, url: str) -> None: except ValueError as error: raise CloneError("Cannot find the remote origin for this repository.") from error - origin_remote.set_url(url) + try: + # Even though the documentation of ``set_url`` function does not explicitly mention + # ``ValueError`` or ``GitError`` as raised errors, these errors might be raised based + # on the implementation. + origin_remote.set_url(url) + except (ValueError, GitError) as error: + raise CloneError( + "Failed to set the remote origin URL because this repository is in an unexpected state." + f" Consider removing the cloned repository at {clone_dir}." + ) from error def check_out_repo(self, git_obj: Git, branch: str, digest: str, offline_mode: bool) -> Git: """Checkout the branch and commit specified by the user of a repository. @@ -168,7 +178,7 @@ def check_out_repo(self, git_obj: Git, branch: str, digest: str, offline_mode: b Raises ------ - RepoError + RepoCheckOutError If there is error while checkout the specific branch and digest. """ remote_origin_url = git_url.get_remote_origin_of_local_repo(git_obj) @@ -183,11 +193,26 @@ def check_out_repo(self, git_obj: Git, branch: str, digest: str, offline_mode: b except CloneError as error: raise RepoCheckOutError("Cannot parse the remote origin URL of this repository.") from error - origin_remote.set_url(reconstructed_url, remote_origin_url) + try: + # Even though the documentation of ``set_url`` function does not explicitly mention + # ``ValueError`` or ``GitError`` as raised errors, these errors might be raised based + # on the implementation. + origin_remote.set_url(reconstructed_url, remote_origin_url) + except (ValueError, GitError) as error: + raise RepoCheckOutError( + "Failed to set the remote origin URL because this repository is in an unexpected state." + " Consider removing the cloned repository." + ) from error check_out_status = git_url.check_out_repo_target(git_obj, branch, digest, offline_mode) - origin_remote.set_url(remote_origin_url, reconstructed_url) + try: + origin_remote.set_url(remote_origin_url, reconstructed_url) + except (ValueError, GitError) as error: + raise RepoCheckOutError( + "Failed to set the remote origin URL because this repository is in an unexpected state." + " Consider removing the cloned repository." + ) from error if not check_out_status: raise RepoCheckOutError(