Sempre que executo git push
, tenho que digitar meu nome de usuário e senha manualmente no prompt.
No entanto, quero automatizar esse processo.
Então, tentei passar as credenciais para o comando usando piping:
printf 'username\npassword' | git push
mas a solicitação de nome de usuário e senha ainda não desaparece!
Por que não está funcionando?
Observação:
Eu sei que isso pode ser feito usando: mas estou interessado em saber o que há de errado com o método de tubulação?
git push 'https://username:[email protected]/username/repo.git'
Além disso, para confirmar se esse processo funciona para outros casos, fiz um experimento.
Criei um script b.py
:
b.py
:
#!/usr/bin/env python3
username = input()
password = input()
log = open("log.txt", "w")
print(username + "\n" + password, file=log)
Então, executei printf 'abcd\nefgh' | ./b.py
no terminal que funcionou conforme esperado e resultou no arquivo de log contendo as strings de nome de usuário e senha:
log.txt
:
abcd
efgh
Responder1
Isso funcionaria apenas no caso de prompts sequenciais que são a parte imediata do script, conforme seu exemplo. No entanto, no caso de git
seus valores serem passados para o processo antes de qualquer solicitação de nome de usuário/senha - provavelmente enquanto ele está fazendo tudo (rede, etc.) antes GIT_ASKPASS
- Para referência:
https://git-scm.com/book/en/v2/Git-Internals-Environment-Variables
Responder2
Pré-condições
Há algum tempo, o GitHub parou de aceitar senhas e pediu aos usuários que criassem tokens. Claro, eu não conseguia lembrar o token, mas também não queria armazená-lo como texto simples no formato .git-credentials
. Além disso, eu não queria passar isso como argumento (alguém pode ler /proc
ou .bash_history
encontrar!). Escrevi meu criptografador simples para criptografar o token com uma senha, mas, assim como você, não consegui canalizar o token descriptografado git
e encontrei esta pergunta enquanto procurava uma solução. Infelizmente, não encontrei a resposta aqui. No entanto, tive a sorte de encontrar perguntas não relacionadas que me levaram à resposta. E a resposta éroteiro.
Solução
Podemos usar script
para criar uma sessão automatizada e canalizar credenciais para ela. Este é o script que escrevi para isso:
#!/bin/bash
read -p "Password: " -s password
echo
token=$(echo "$password" | decrypt_token) || exit $?
cmd="git push $@"
echo -e "username\n$token" | script -E never -c "$cmd" /dev/null
-E never
indica que não quero que minhas credenciais sejam repetidas (impressas no terminal). Estou usando /dev/null
como arquivo de log, pois não me importo com o registro.
NOTA IMPORTANTE: echo
é um comando interno no meu shell, o que significa que é seguro passar senha e token como argumentos para ele. Se fosse um programa externo, alguém poderia ler os argumentos do arquivo /proc
. Eu recomendo que você verifique se o comando usado para tubulação está embutido em seu shell. Se você não conseguiu encontrar um integrado adequado, use cat com heredoc:
token=$(
(
cat <<EOF
$password
EOF
) | decrypt_token
)
Parte 2
Depois de copiar minha configuração para uma máquina diferente, recebi um erro estranho:
fatal: could not read Password for 'https://[email protected]': Success
Verifiquei se ambos git
são screen
da mesma versão da máquina original e não consegui encontrar a causa raiz. No entanto,este comentário poderiadê uma dica:
getpass() tries too hard to find the real terminal
Como solução alternativa, criei um script separado para GIT_ASKPASS
(e sinto que é uma solução mais limpa).
Este é o script principal após as alterações:
#!/bin/bash
if ! tty -s; then
echo "Can't operate without tty."
exit 1
fi
TTY=$(tty) GIT_USERNAME=username GIT_ASKPASS=~/git-creds git push $@
E isso é git-creds
:
#!/bin/bash
if echo "$1" | grep -q '^Password'; then
read -p "Password: " -s password < $TTY
echo "$password" | decrypt_token
# put a newline to separate prompt and output
echo > $TTY
else
echo "$GIT_USERNAME"
fi
Ele lê a senha diretamente do seu TTY e fornece o token descriptografado ao git. Para nome de usuário, apenas ecoa GIT_USERNAME env var.
Também é possível adicionar estas linhas .bashrc
(ou qualquer alternativa):
export TTY=$(tty)
export GIT_USERNAME=username
export GIT_ASKPASS=~/git-creds
E você não precisará do wrapper para comandos.