Skip to content

Commit

Permalink
Detect git authentication failure (#5420)
Browse files Browse the repository at this point in the history
Co-authored-by: Michael Oliveira <[email protected]>
  • Loading branch information
Jan200101 and Flame442 authored Dec 24, 2023
1 parent da8caba commit ecccea6
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 1 deletion.
14 changes: 14 additions & 0 deletions redbot/cogs/downloader/downloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,20 @@ async def _repo_add(
await ctx.send(
_("The repo name you provided is already in use. Please choose another name.")
)
except errors.AuthenticationError as err:
await ctx.send(
_(
"Failed to authenticate or repository does not exist."
" See logs for more information."
)
)
log.exception(
"Something went wrong whilst cloning %s (to revision: %s)",
repo_url,
branch,
exc_info=err,
)

except errors.CloningError as err:
await ctx.send(
_(
Expand Down
10 changes: 10 additions & 0 deletions redbot/cogs/downloader/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"CopyingError",
"ExistingGitRepo",
"MissingGitRepo",
"AuthenticationError",
"CloningError",
"CurrentHashError",
"HardResetError",
Expand Down Expand Up @@ -79,6 +80,15 @@ class MissingGitRepo(DownloaderException):
pass


class AuthenticationError(GitException):
"""
Thrown when git failed to authenticate with
the server
"""

pass


class CloningError(GitException):
"""
Thrown when git clone returns a non zero exit code.
Expand Down
20 changes: 19 additions & 1 deletion redbot/cogs/downloader/repo_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,17 @@ def _existing_git_repo(self) -> Tuple[bool, Path]:
git_path = self.folder_path / ".git"
return git_path.exists(), git_path

def _parse_git_error(self, git_command: str, stderr: str) -> errors.GitException:
stderr = stderr.lower()
# Expected to catch:
# Could not read from remote repository
# could not read X for 'URL': terminal prompts disabled
# Authentication failed
if "could not read" in stderr or "authentication failed" in stderr:
return errors.AuthenticationError("Failed to Authenticate", git_command)

return errors.CloningError("Error when running git clone.", git_command)

async def is_ancestor(self, maybe_ancestor_rev: str, descendant_rev: str) -> bool:
"""
Check if the first is an ancestor of the second.
Expand Down Expand Up @@ -548,13 +559,20 @@ async def _run(
"""
env = os.environ.copy()
env["GIT_TERMINAL_PROMPT"] = "0"
env["GIT_TRACE"] = "0"
# make sure we never enter an askpass routine
# https://github.com/git/git/blob/1424303/prompt.c#L56
env.pop("GIT_ASKPASS", None)
env.pop("SSH_ASKPASS", None)
# attempt to force all output to plain ascii english
# some methods that parse output may expect it
# according to gettext manual both variables have to be set:
# https://www.gnu.org/software/gettext/manual/gettext.html#Locale-Environment-Variables
env["LC_ALL"] = "C"
env["LANGUAGE"] = "C"
# Make sure git does not consider us smart
# https://github.com/git/git/blob/a7312d1a2/editor.c#L11-L15
env["TERM"] = "dumb"
kwargs["env"] = env
async with self._repo_lock:
p: CompletedProcess = await asyncio.get_running_loop().run_in_executor(
Expand Down Expand Up @@ -659,7 +677,7 @@ async def clone(self) -> Tuple[Installable, ...]:
if p.returncode:
# Try cleaning up folder
shutil.rmtree(str(self.folder_path), ignore_errors=True)
raise errors.CloningError("Error when running git clone.", git_command)
raise self._parse_git_error(git_command, p.stderr.decode(**DECODE_PARAMS))

if self.branch is None:
self.branch = await self.current_branch()
Expand Down

0 comments on commit ecccea6

Please sign in to comment.