extrawurst/gitui

GPG sign commits

nbigaouette opened this issue ยท 51 comments

All my commits are required to be signed at work. It would be awesome to be able to commit directly in gitui; for now I can stage files/hunk and commit using git directly.

Thanks!

Hi @nbigaouette thanks for your interest in the project. I did not even know that feature existed ๐Ÿ™ˆ. I am going to need support by someone having experience with using signing in git for this.

stale commented

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

Yes. I saw that after I commented. Hence the deletion of the comment. Sorry for that. ๐Ÿ˜‡

@nils-a But as you can see in the PR it is non trivial and could use some support, so if you want to chime in...
so to your initial question: I posted references for people to pick up. as usual in open source: when you want something done - do it :)

yes.. love to. Need to buy a book on rust first :-)

@nils-a that's an easy step - see you soon then :P

stale commented

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

Is anybody still working on this?
For me this is currently a blocker as well because I usually sign all my commits.

I used gpgme with git2 in one of my projects before and could probably integrate this rather quick.

Not me. I'm still reading that book on rust to begin with... But there is also some discussion in #219

@dnaka91 absolutely have a go at it

Sorry, I didn't have a chance to continue on this as I'm currently quite occupied with other things.

I definitely have this on my to-do list though.

Shouldn't the following lines in the .gitconfig cause all commits to be signed regardless of the program doing the commit?

[user]
  name = YOUR_NAME
  email = YOUR_EMAIL
  signingkey = YOUR_SIGNING_KEY
[gpg]
  program = GPG_BINARY_PATH
[commit]
  gpgsign = true

Any ideas why that isn't the case and does not with gitui?

@bluefireoly gitui uses libgit2 a c++ implementation of git and not the git-cli. libgit2 does not do anything automagically and the necessary implementation was not done yet

@bluefireoly I added #740 - it should not even allow you to commit now iff you have this config defined. this way it prevents you from generating unsigned commits even though you expressed that you need them to be signed

Alright thank you, maybe that will prevent some people from finding this out when it is too late.

I came across this issue today as I was still on v0.15 and was surprised when it let me commit without signing even with config set.

Looking into it more, I came across this:
https://libgit2.org/libgit2/#HEAD/group/commit/git_commit_create_with_signature

Not sure if this issue is on libgit2 or the git2-rs, so not sure if any help or not.

I came across this issue today as I was still on v0.15

this was part of 0.16 release: https://github.com/extrawurst/gitui/releases/tag/v0.16.0

@extrawurst Hi! I guess we can try just calling gpg using Command::new("gpg"), pass the signature as a parameter like gpg --sign --default-key [SIGNATURE] and then pass the commit buffer inside stdin and get the signed data through stdout. Then we can probably just use commit_signed of git2-rs.

I will try to implement something like that on the next week, it can be a lot easier that trying to use heavy libs like sequoia.

I prefer we find a native solution (sequoia or gpgme). One design philosophy for gitui so far was to not rely on the git cli, I am not intending to change that as long as we did not exhaust all options

Sorry, I didn't update my progress on this in a long time. I have the changes working locally but don't know what to do about the amend function. That doesn't allow to sign again (which we have to as the commit contents change).

Therefore we would have to do the whole amend from scratch which takes time to implement. Basically it's more or less the same as a normal commit, just changing the state back to the previous commit first. But it's problematic as soon as something goes wrong and we have to make sure we don't lose any data in the process and restore the old state before trying the amend.

@dnaka91 would be great if you could put that into a PR draft ๐Ÿ‘

Sure I'll open a draft PR later today. It's still quite messy and missing tests to cover the new code, but it's better to have some code as basis for further discussions ๐Ÿ‘

Has there been any progress on this?

@basbebe latest work happened in #817

Hi, is there any way I could help? Although in a completely different context, I had to add support to GPG signatures to one of my own projects ( https://avatar-cli.dev ), so maybe I could help here.

I did it the "dirty way" (by relying on the external git binary), but I guess it wouldn't be too complicated if I have to rely on a librarized version of it for this project.

EDIT: I see that there were at least 3 PRs focused on that, all of them stalled. So... maybe it is that complicated. My take on this is that maybe we should find a way to split this feature into smaller ones, if that's even possible, so we can go one small step at a time.

Also, for reference, I think that the last work on this topic actually belongs to this other PR: #910 , as #817 was closed.

@castarco indeed, this is not a trivial thing to implement. I'd like to second your idea of splitting the feature into multiple smaller parts; some could even be merged while hidden behind a feature toggle (can be as simple as a comment).


Before writing any code, I would propose to work on the following and sign each one off with @extrawurst:

  1. Define the requirements
  2. Evaluate technology to aid the implementation
  3. Verbally express the implementation path(s)

The following are my partial proposals for discussion:

1) Define the requirements

  • re-use existing configuration in a user's .gitconfig, i.e. user.signingKey
  • integrate with the gpg agent, including:
  • allowance for interactive pin-entry

2) Evaluate technology to aid the implementation

  • @extrawurst already mentioned that only solutions leveraging either gpgme or sequoia will be accepted
  • looking at the metric of open-source "stars", sequoia wins (gpgme 55, sequoia 306)
  • gpgme is a crate that provides bindings to lower level dependencies, while sequoia is a complete re-implementation in Rust; I'd prefer sequoia
  • sequoia has a positive testimonial from the creator of PGP, Phil Zimmermann
  • both crates provide plenty of examples
  • gpg-tui (~1 year old) uses gpgme

I'd propose to move forward with sequoia because of it being a Rust-native solution + being more popular.

3) Verbally express the implementation path(s)

To be honest, I did not yet dive into the codebase, because there are too many open questions.
Once we have more decisions, it would be nice to get the folks back into the loop who have already submitted pr's. No matter if they abandoned them or not, their feedback and input is valuable nontheless.

hi @hendrikmaus and thanks for wrapping this up. this topic is long running and arguably one of the most requested features. I am glad you are going to approach this with such a thought out structure.

since I am not using commit signing myself, my opinion on this is rather high level. my biggest concern is cross-platform support and testability. we need to make sure we come up with something that works on all three platforms and is well covered in tests, so that A) I can us the tests as a life raft if I need to maintain the code after potential contributors sailed away and B) to guarantee stability on the platforms I am not using myself.

your points so far seem reasonable to me. I personally had no tendency for either gpgme or sequoia but I can follow your assessment!

I assume in terms of slicing this I would make a first iteration without support of interactive pin entry, because adding that should be easy, we do a similar thing already for https credential input on demand.

Update: I have started to study the source code of https://gitlab.com/sequoia-pgp/sequoia-octopus-librnp which the Sequoia-based OpenPGP Backend for Thunderbird.
This is useful to get to know how the crate is supposed to be used in real life, as the project is driven by the engineers behind Sequoia itself. Also, the project demonstrates an integration with the local gpg agent.

D3PSI commented

Any updates/progress on this? Is this feature actively being worked on? Am considering to start working on this myself

I am doing research on the side to then propose an implementation verbally before writing code.

Commits now can also be signed with ssh keys, if you specify gpg.format=ssh in git config. Does that complicate or maybe simplify the problem somehow?

My research on the topic is going slow, but steady.

I want to share where I am currently at, so that I can gather feedback and we can iterate on the plan.

I think we can assume that a user already signs commits using the git binary and hence has gpg and likely also the gpg-agent setup. We should not interfere with it, but, as a first baby step, try to use this infra.
So let's assume the gpg-agent is there and we can relay all cryptographic operations to it. That includes decrypting the key if it is locked as a user will have configured their gpg-agent with a pinentry program. Gitui does not have to take of the password input and key decryption - great.
Also, a user does not have to store an unencrypted passphrase-less private key on disk, which many folks wouldn't be comfortable with anyway.

Aside: the git source code actually shells out to the gpg.progam, e.g. gpg itself, to do all this. Then gpg takes care of talking to its own agent.

Now, Sequoia comes with a crate for IPC (inter process communication), which in turn comes with an implementation to talk to an existing gpg-agent. So gitui can try to connect and error out if there is an issue on the way.

If we can connect, Sequoia needs the public key to sign with. This is where we have to deviate from what git usually does: it reads the keyid from .gitconfig (last 8 bytes of the key fingerprint) and passes that to gpg which is able retrieve the public key somehow.

I talked to the folks in the Sequoia IRC and, so far, the conclusion was that one technically only needs the keygrip (which is yet another thing gpg --list-keys --with-keygrip if you're curious), but Sequoia IPC always needs the public key. So, if gitui doesn't have it already, I would propose we create a custom config section in .gitconfig that allows us to retrieve:

  • method of signing, e.g. gpg-agent
    • this key could indicate other methods in the future, like one that iusses another keystore backend etc.
  • if method of signing is set to gpg-agent, then the path to the public key pem data to use on disk

So, if gitui is instructed to sign the commit, we reach out to the .gitconfig to read our config. If that is good, we try to reach out to the gpg-agent. If that is good, we tell the gpg-agent to sign our buffer. After some more implementation details, we are able to write the commit.

A suggestion from the Sequoia IRC was to not store the gpg public key on disk. Because it might get out of sync and/or cause additional confusion later when the extra step for gitui is forgotten.

The proposal was to do at least one shellout to gpg in this case to get the public key pem data by the normal user.signingKey config value from .gitconfig, i.e. we'd call gpg --export --armor <keyid> and grab the pem data.

What do you think?
a. no shellout, user has to export public key to disk
b. a single shellout to gpg to have it "just work"?

I had another chat with @extrawurst and we concluded to start with the existing shellout implementations. Anyone with an existing gpg signing setup can then start to use gitui without any additional setup. In #1544 gpg itself is added.

The PR provides entrypoints for ssh as well as x509 signing.

However, we discussed to add a new option to gitconfig, which will gate pure Rust implementations (or as close as we can reasonably get).

thanks @hendrikmaus for taking a crack at it. Everyone subscribed here please take a go at the PR: #1544

I realize that I'm very late to the party, but I also had some trouble implementing signed commit's in ripasso ( https://github.com/cortex/ripasso/blob/master/src/git.rs#L50 ) and wrote this blog post about it: https://blog.hackeriet.no/signing-git-commits-in-rust/

It might help someone.

How about signing with SSH key. Is this easier than use GPG?

Git 2.34 includes support to take advantage of this feature and allows you to sign your work using SSH keys.

https://github.blog/2021-11-15-highlights-from-git-2-34/#tidbits

github also supports it https://docs.github.com/en/authentication/managing-commit-signature-verification/telling-git-about-your-signing-key#telling-git-about-your-ssh-key

How about signing with SSH key?

AFAIK, it is much less popular than gpg signing.

AFAIK, it is much less popular than gpg signing.

I disagree. We simply don't know IMO.

SSH signing has a PR: #2047

This is merged, please everyone give the recent master a try to make the next release rock solid!

This works just tested on master with the default config (I haven't installed gitui or tried out since GPG-signing is a must for me).
Looking forward for a tag release so I can ditch lazygit.

Hey everyone in case you were hesitant to test this by having to build from source, please use our new nightly releases to give it a spin: https://github.com/extrawurst/gitui/blob/master/NIGHTLIES.md

I am happy to report that the nightly gitui.exe was compatible with my signed commit on Windows! (The link to the windows versions in nightlies.md is wrong but that's really a footnote here).

@mlabbe thanks for the hint, fixed the windows links

I can also report that this worked for me on my Linux workstation.