Categorias
Desenvolvimento Web Programação Tutoriais

Git + GPG = Assinando suas contribuições

Guia rápido sobre por que e como assinar suas contribuições com git e gpg.

Recentemente o core do PHP passou por uma situação, no mínimo, inusitada: 2 commits foram feitos em nome de personalidades da comunidade. Isso é possível porque quando registramos uma alteração no git através de um commit, ele registra os dados que queremos que sejam registrados, incluindo o usuário e email que você disse ter (git config user.name "Cauan" e git config user.email "[email protected]"). Veja que você não precisa validar email nem nada.

Aplicações que hospedam projetos em git geralmente pedem pra gente validar o email usado nos commits, assim são capazes de inferir que aquele código enviado é de quem disse ter enviado. Mas é apenas uma associação “lógica”. O commit diz que foi feito por fulana, e a fulana é uma usuária válida aqui no Github/Gitlab, então vou exibir a foto e nome dessa fulana aqui na interface.

Se o git não garante que quem fez uma alteração é quem diz ser, como a gente pode garantir? Assinando nossas mudanças com uma chave criptográfica.

Felizmente o git permite que a gente especifique uma chave privada configurada no GPG e cuida de todo o processo de assinar nossas mudanças. Na outra ponta, nós compartilhamos a chave pública com o Github/Gitlab para que valide o commit assinado e então possam garantir que aquele código foi feito por quem diz ter feito.

O pessoal do PHP preparou um guia bem completo sobre como configurar o GPG e git para que o incidente não se repita. Vou colocar aqui o resumo do resumo para quem tiver alguma dificuldade com inglês, mas se tiver alguma dúvida, pode usar os comentários.

Atenção: todos os comando devem ser executados com seu usuário normal. Quando necessário, o sudo vai estar explicitado.

O símbolo $ não faz parte do comando, é só pra diferenciar o que é um comando e o que é uma saída de comando. Sempre que tiver o $, você pode copiar o que está na frente e executar no seu terminal.

Primeiro, instale o GPG:

SistemaComando(s)
macOS com Homebrewbrew install gpg
Ubuntu, Debian, Mint, Kalisudo apt install gnupg
CentOS, Fedora, RHELsudo yum install gnupg

Se você usa Zsh como shell, você precisa configurar um tty para que funcione corretamente os comandos interativos com o GPG:

$ mkdir "${HOME}"/.gnupg
$ chmod 700 "${HOME}"/.gnupg
$ >> "${HOME}"/.zshrc echo 'GPG_TTY="$(tty)" && export GPG_TTY || echo "Could not determine TTY: $?" >&2'
$ source "${HOME}"/.zshrc

Verificando que a instalação funcionou:

$ gpg --version | head -2
gpg (GnuPG) 2.2.21
libgcrypt 1.8.6
$ gpg-connect-agent /bye && echo 'GPG ok' || echo 'ERROR: GPG not running'
GPG ok
$ [ -r "${GPG_TTY}" ] && echo 'TTY ok' || echo 'ERROR: TTY not found'
TTY ok

Agora vamos gerar sua chave de assinatura GPG. É imprescindível escolher uma senha forte para proteger sua chave:

$ gpg --batch --generate-key <(echo '
Key-Type: RSA
Key-Length: 4096
Expire-Date: 0
Name-Real: Fulana de Tal
Name-Email: [email protected]
')

Precisamos descobrir a versão curta do ID da chave gerada:

$ gpg -K --keyid-format SHORT
sec   rsa4096/02783663 2020-08-26 [SCEA]
      79694216A0DECA5B53E94E96910A1F8402783663
uid         [ultimate] Fulana de Tal <[email protected]>

Repare no resultado do comando anterior a primeira linha. O que vem após rsa4096/ é o ID que nós queremos, nesse exemplo: 02783663.

Vamos deixar esse valor em uma variável de ambiente para facilitar o restante das configurações, basta executar:

$ export GPG_KEYID=02783663

Estamos terminando, precisamos dizer ao git para usar essa chave para assinar nossas alterações no repositório:

$ git config --global --replace user.signingkey "${GPG_KEYID}"
$ git config --global --replace commit.gpgsign true
$ git config --global --replace tag.gpgsign true

Por último, precisamos informar ao Github/Gitlab nossa chave, para que ele possa verificar o autor das mudanças:

$ gpg --armor --export "${GPG_KEYID}" | pbcopy

pbcopy é um comando do macOS para jogar informação na área de transferência (equivalente a um Ctrl+C). Substitua essa parte pelo comando equivalente no seu ambiente se for outro, ou simplesmente retire o trecho | pbcopy e a chave será exibe no terminal, daí basta selecionar e copiar.

Com a chave copiada, acesse suas configurações:

Feito isso, todos os seus novos commits deve ser assinados e se tudo ocorreu bem, aparecerão como verificados nos Git da vida:

Imagem com uma lista de commits contendo o selo "verified" do Github

Atualizado em 13/04/2021: eu segui esses passos do artigo original em um macOS sem o gpg previamente instalado e com o git relativamente atualizado. Caso seu ambiente já tenha gpg ou a versão do git seja muito antiga, verifique a seguinte resposta no StackOverflow. Agradecimento ao Elton Minetto pela dica nos comentários.

Atualizado em 01/05/2021: como alertou nos comentários o Adjamilton, depois da gente atualizar o conteúdo do arquivo .zshrc precisamos recarregar seus valores usando o comando source "${HOME}"/.zshrc para que as mudanças surtam efeito. O trecho já está atualizado.

Por Cauan Cabral

Desenvolvedor com 2 dígitos de experiências, especialista em PHP e CakePHP mas com bagagens em JavaEE, Node.js, Javascript (ES6, jQuery, Angular) e Python. Interessado em automação, Machine Learning e cozinha.

4 respostas em “Git + GPG = Assinando suas contribuições”

Ótimo post, bem oportuno.
Testei no MacOS mas encontrei alguns problemas. Fiz uma pesquisa e encontrei esse post com a solução: https://stackoverflow.com/questions/39494631/gpg-failed-to-sign-the-data-fatal-failed-to-write-commit-object-git-2-10-0

O que eu precisei fazer foi:

brew upgrade gnupg # This has a make step which takes a while
brew link –overwrite gnupg
brew install pinentry-mac
echo “pinentry-program /usr/local/bin/pinentry-mac” >> ~/.gnupg/gpg-agent.conf
killall gpg-agent

Para testar se funcionou basta executar o comando:

echo “test” | gpg –clearsign

E se estiver tudo ok vai funcionar no Github.

Cauan, depois do comando abaixo, é preciso dar um source no .zshrc:

$ >> “${HOME}”/.zshrc echo ‘GPG_TTY=”$(tty)” && export GPG_TTY || echo “Could not determine TTY: $?” >&2’

$ source ~/.zshrc

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.