Add OpenPGP and X.509 commit signing - #2827
Open
anandghegde wants to merge 1 commit into
Open
anandghegde wants to merge 1 commit into
anandghegde wants to merge 1 commit into
Conversation
SSH commit signing landed in git-up#2789, which deliberately left the other two formats alone: a repository configured with commit.gpgsign and an OpenPGP or X.509 gpg.format silently produced an unsigned commit. This extends the same machinery to cover both, so GitUp now honours commit.gpgsign for every format Git itself supports. The signature is produced by running the configured signing program the way Git runs it, "<program> --status-fd=2 -bsau <key>", with the commit buffer on stdin. Program resolution follows Git's rules: gpg.openpgp.program then gpg.program (its legacy synonym) then "gpg" for OpenPGP, and gpg.x509.program then "gpgsm" for X.509, with gpg.program deliberately not applying to X.509. When user.signingkey is unset, the committer identity is passed as the user ID, which is what Git does so that GnuPG selects the key matching the commit rather than whichever key it considers its own default. Success is decided by GnuPG's machine-readable status rather than its exit code alone, because GnuPG can exit zero without having produced a signature. That is the reason for --status-fd=2, and it matches how Git validates the same invocation. An unrecognised gpg.format is now an error instead of quietly producing an unsigned commit. Git rejects it too, and silently dropping the signature is the worst available outcome for someone who asked for signed commits. Every one of these rules was verified against git 2.50.1 by pointing gpg.program at a recording stub and comparing the resulting argument vector.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
I AGREE TO THE GITUP CONTRIBUTOR LICENSE AGREEMENT
Closes #42.
SSH commit signing landed in #2789. That change deliberately scoped itself to SSH and left a comment saying so:
This picks up the other two formats, so
commit.gpgsignis now honoured for everygpg.formatGit supports. That closes the long-standing request in #42, where people have been dropping to the command line just to commit.The signing call
The signature comes from running the configured program exactly the way Git runs it —
<program> --status-fd=2 -bsau <key>with the commit buffer on stdin — reusing theGCTaskplumbing and the once-per-operationPATHrefresh that #2789 already put in place.Program resolution follows Git's rules:
openpgp(and unset)gpg.openpgp.program, thengpg.programgpgx509gpg.x509.programgpgsmgpg.programis Git's legacy synonym forgpg.openpgp.programand deliberately does not apply to X.509 — easy to get wrong, so there's a test pinning it.When
user.signingkeyis unset, the committer identity is passed as the user ID. Git does this so GnuPG picks the key matching the commit rather than whichever key GnuPG considers its own default; omitting-uentirely would quietly sign with a different key thangit commitwould have used.Why
--status-fd=2GnuPG can exit zero without having produced a signature. Git guards against that by asking for the machine-readable status and requiring
SIG_CREATED, and this does the same. Trusting the exit code alone would mean writing a commit with a garbagegpgsigheader.Behaviour change worth calling out
An unrecognised
gpg.formatis now an error rather than a silently unsigned commit. Git rejects it too (error: invalid value for 'gpg.format': 'pgp'), and for someone who explicitly asked for signed commits, silently dropping the signature is the worst of the available outcomes. The existing test that asserted "OpenPGP config remains unsigned" is updated accordingly — it now covers the still-correct case of a format configured withoutcommit.gpgsign.Verification
Every rule above was checked against the real thing rather than against the documentation. I pointed
gpg.program/gpg.openpgp.program/gpg.x509.programat a stub that records its argument vector, rangit commitunder git 2.50.1, and compared:--status-fd=2 -bsau <key>, in that orderuser.signingkeyforwarded verbatim when setBot <bot@example.com>— the committer identity — when it is genuinely unsetgpg.openpgp.programbeatinggpg.programgpg.x509.programused for X.509 withgpg.programignoredThe unit tests drive the same stub through
GCCreateCommitFromTreeWithOptionalSignatureand assert the same argument vectors, so the parity is pinned rather than just observed once.Seven new tests in
GCCommitSigning-Tests.mcover the default format, program precedence, the signing key fallback, X.509, a GnuPG that exits zero without signing, a GnuPG that fails outright, and an invalidgpg.format../format-source.shis clean and the app builds.One gap I want to be upfront about: there is no end-to-end test against a real
gpg, because that would need a throwaway keyring generated at test time and GnuPG isn't guaranteed on the runner. The stub tests pin the invocation; they can't prove GnuPG is happy with it. The SSH tests could go further there only becausessh-keygenis always present.Unrelated:
GCSingleCommitRepositoryTests/testClonefails for me on a cleanmastertoo — it clones over the network.