GitHub Codespaces is an instant, cloud-based development environment that uses a container to provide you with common languages, tools, and utilities for development.
When you commit a change with Git, it accepts as an author whatever value you want: you could claim to be whoever you want when you create a commit. Thus, when you see an unsigned commit, you have no guarantee that the author is really the person whose name is on the log and that the change you see is really what the author wrote. By signing your Git commits, you have the ability to prove that you were the author of a specific code change, and you can ensure that no one can modify your commit or its metadata. Attacks on the software supply chain are getting more common, and their potential consequences have become more dangerous.
You can allow GitHub to automatically use GPG to sign commits you make in your codespaces, so other people can be confident that the changes come from a trusted source.
However, while you can configure GitHub to sign your commits, it looks like it is not possible (at least now) to sign tags.
To test signing, I created a test repository, opened it in a codespace, and created a test commit:
git log
confirms that the commit is signed, although it cannot verify the signature because of the missing key (the “E” letter).
If we look at the commit log in the GitHub UI, we will see that the commit was indeed signed — with GitHub’s verified signature. This makes sense: GitHub doesn’t have access to my private signing keys, and that is why it cannot sign the commit with my key.
Now let’s imagine we want to create a release. To do that, we create a tag and sign it: git tag -s 1.0.0 -m 1.0.0
. And this fails.
Setting the GIT_TRACE
environment variable does not help much:
$ GIT_TRACE=1 git tag -s 1.0.0 -m 1.0.0 17:38:12.073051 git.c:439 trace: built-in: git tag -s 1.0.0 -m 1.0.0 17:38:12.073795 run-command.c:663 trace: run_command: /.codespaces/bin/gh-gpgsign --status-fd=2 -bsau 'GitHub <[email protected]>' error: gpg failed to sign the data error: unable to sign the tag
This is a bit strange because when you sign a commit, git
invokes the same command:
$ GIT_TRACE=1 git commit -a -S -m "Update test.txt" 17:40:02.995489 git.c:439 trace: built-in: git commit -a -S -m 'Update test.txt' 17:40:02.998058 run-command.c:663 trace: run_command: /.codespaces/bin/gh-gpgsign --status-fd=2 -bsau 'GitHub <[email protected]>' 17:40:03.302086 run-command.c:663 trace: run_command: git gc --auto 17:40:03.303635 git.c:439 trace: built-in: git gc --auto [master 91f54b3] Update test.txt Author: Volodymyr Kolesnykov <[email protected]> 1 file changed, 1 insertion(+)
Unfortunately, the Troubleshooting GPG verification for GitHub Codespaces article does not help. However, I still need to be able to sign tags. What should I do?
The scenario I have come up with is not perfect, but it works; it is probably possible to automate it with the help of dotfiles.
First, I created a secret for codespaces here (more about encrypted secrets for codespaces), put my private GPG key into it, and made it available for my test repository. Then I restarted the codespace. Next, I imported the GPG key from the secret:
echo "${GPG_KEY}" > ~/key.asc gpg --batch --import ~/key.asc rm -f ~/key.asc
Then I had to set the environment variables to the values gpg
expects:
export GPG_TTY=$(tty) export GIT_COMMITTER_NAME="$(git config --get user.name)" export GIT_COMMITTER_EMAIL="$(git config --get user.email)"
By default, GPG_COMMITTER_EMAIL
is set to [email protected]
; because I don’t have a signing key matching that email, I need to set it to my email address.
Finally, I had to replace the gpg.program
in Git and set it to /usr/bin/gpg
:
git config --global gpg.program /usr/bin/gpg
And after that, I was able to sign tags in Git:
Things to do:
- Remove the private key from secrets after it has been imported. Codespace secrets live in
/workspaces/.codespaces/shared/.env-secrets
assecret_name=base64(secret_value)
pairs. However, the key still lives in~/.gnupg/private-keys-v1.d/
, so this probably won’t add more security. - If you close and open the terminal, the
GIT_COMMITTER_NAME
andGIT_COMMITTER_EMAIL
environment variables will be reset to their initial values. This probably happens because both are stored as secrets, and secrets got restored by the/etc/profile.d/00-restore-secrets.sh
script. - Try to automate the entire process with dotfiles.