From 8756b385f66c1ab2e0c5880bd21cd5c0a2feb2ef Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Sat, 28 Apr 2018 23:38:38 +0300 Subject: [PATCH] Prevent interactive prompts during git fetch We set the shell into MONITOR mode to prevent password prompts 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. I tried both zsh 4.3.17 and 5.0.2 to be sure it doesn't break easily... Fixes #373. --- pure.zsh | 62 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 17 deletions(-) diff --git a/pure.zsh b/pure.zsh index 93b7f58b..3f0cf135 100644 --- a/pure.zsh +++ b/pure.zsh @@ -271,7 +271,30 @@ 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 it 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 do it this way, the process will corrupt 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 >/dev/null & + wait $! || return $fail_code + + unsetopt monitor # check arrow status after a successful git fetch prompt_pure_async_git_arrows $1 @@ -416,22 +439,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