Search code examples
gitgnupgkeybase

Can I sign git commits with keybase.io?


I am setting up a new machine and would prefer to use keybase for various pgp activities like signing commits. I can run a command like

$ keybase pgp sign -m foo > x
$ gpg --verify x 2>&1 | grep -oF 'Good signature'
Good signature

I could sign things directly with gpg, but it's convenient to let keybase manage the thing. So can I somehow make git use keybase?

Git configuration doesn't seem to have a way to customize the gpg command that it uses to sign commits. All you can do is provide the key. Is there any way to do it?


Solution

  • Thanks to the link in Xavier's answer I learned that I can override the gpg program with the gpg.program configuration:

    git config --global gpg.program /path/to/something
    

    So I can use this to write a wrapper around keybase.

    But git is, as it turns out, pretty finicky about what that something is. Git expects to partially parse the output that results from the --fd-status flag, which causes gpg to output special status codes at an alternate filehandle.

    Fortunately, at least for my first pass, git doesn't parse everything that gpg produces, so I was able to emulate it. Here's a gist with a functional wrapper, and here's the meat of it:

    # Copy the commit message from stdin to a file. 
    d=$(mktmp -d "${TMPDIR:-/tmp}/gitsig.XXXXXXXXX")
    cat > "$d/commit.msg"
    
    # Have Keybase write the signature to another file.
    keybase pgp sign --detached \
                     --key "$1" \
                     --infile "$d/commit.msg" \
                     --outfile "$d/commit.sig"
    
    # Have gpg verify the signature right away.
    # Capture its status in a file.
    gpg --verify --status-fd=2 \
        "$d/commit.sig" "$d/commit.msg" \
        > /dev/null 2> "$d/gpgstatus.txt"
    
    # Copy the KEY_CONSIDERED lines to stderr. Git wants that.
    grep '^\[GNUPG:\] KEY_CONSIDERED' "$d/gpgstatus.txt" >&2
    
    # Produce a minimal SIG_CREATED line to stderr. Git also wants that.
    printf '[GNUPG:] SIG_CREATED ' >&2