Skip to content

Commit

Permalink
Prevent interactive prompts during git fetch
Browse files Browse the repository at this point in the history
We set the shell into MONITOR mode to prevent password prompts (either
SSH or pinentry) from hijacking the TTY. If the command is suspended we
know it's trying something not nice. So we kill it.

This seems a bit crazy, but at least it does not seem to affect
performance (relatively). I also have found no other way to work around
these issues.

Although we already set:

```
export GIT_SSH_COMMAND="${GIT_SSH_COMMAND:-"ssh"} -o BatchMode=yes"
```

It is not sufficient. For example, when a SSH configuration entry
contains the ProxyJump option it will usually invoke a new instance of
ssh which does not obey the BatchMode option we specified. Pinentry is
a whole nother beast and can't even be disabled (to my knowledge).

I tried both zsh 4.3.17 and 5.0.2 to be sure it doesn't break easily...

Fixes sindresorhus#366 and sindresorhus#373 (hopefully).
  • Loading branch information
mafredri committed Apr 28, 2018
1 parent 0d137f7 commit c684bcc
Showing 1 changed file with 42 additions and 17 deletions.
59 changes: 42 additions & 17 deletions pure.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,27 @@ prompt_pure_async_git_fetch() {
# set ssh BachMode to disable all interactive ssh password prompting
export GIT_SSH_COMMAND="${GIT_SSH_COMMAND:-"ssh"} -o BatchMode=yes"

command git -c gc.auto=0 fetch &>/dev/null || return 99
# Default return code, indicates Git fetch failure.
local fail_code=99

# Guard against all forms of password prompts. By setting the shell into
# MONITOR mode we can notice when a child process prompts for user input
# because will be suspended. Since we are inside an async worker, we
# have no way of transmitting the password and the only option is to
# kill it. If we don't, it will interfere with the async worker.
setopt localtraps monitor
trap '
# Unset trap to prevent infinite loop
trap - CHLD
if [[ $jobstates = suspended* ]]; then
# Set fail code to password prompt and kill the fetch.
fail_code=98
kill %%
fi
' CHLD

command git -c gc.auto=0 fetch &
wait $! || return $fail_code

# check arrow status after a successful git fetch
prompt_pure_async_git_arrows $1
Expand Down Expand Up @@ -416,22 +436,27 @@ prompt_pure_async_callback() {
prompt_pure_async_git_fetch|prompt_pure_async_git_arrows)
# prompt_pure_async_git_fetch executes prompt_pure_async_git_arrows
# after a successful fetch.
if (( code == 0 )); then
local REPLY
prompt_pure_check_git_arrows ${(ps:\t:)output}
if [[ $prompt_pure_git_arrows != $REPLY ]]; then
typeset -g prompt_pure_git_arrows=$REPLY
do_render=1
fi
elif (( code != 99 )); then
# Unless the exit code is 99, prompt_pure_async_git_arrows
# failed with a non-zero exit status, meaning there is no
# upstream configured.
if [[ -n $prompt_pure_git_arrows ]]; then
unset prompt_pure_git_arrows
do_render=1
fi
fi
case $code in
0)
local REPLY
prompt_pure_check_git_arrows ${(ps:\t:)output}
if [[ $prompt_pure_git_arrows != $REPLY ]]; then
typeset -g prompt_pure_git_arrows=$REPLY
do_render=1
fi
;;
99|98)
# Git fetch failed.
;;
*)
# Non-zero exit status from prompt_pure_async_git_arrows,
# indicating that there is no upstream configured.
if [[ -n $prompt_pure_git_arrows ]]; then
unset prompt_pure_git_arrows
do_render=1
fi
;;
esac
;;
esac

Expand Down

0 comments on commit c684bcc

Please sign in to comment.