Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft: Support GPG signing #691

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft

Conversation

OdNairy
Copy link

@OdNairy OdNairy commented Jul 3, 2020

Closes: #42
GnuPG Made Easy (gpgme) documentation, source code
Completeness: 85%

Preview binary (use right click - Open to open the app):
GitUp.zip

Checklist (update: 23 Sep, 2022):

  • Skip signing if there were on signature of key id was different (for rebase/rewrite/swaps/etc.)
  • Fix single-commit assertion on some operations
  • Merge libgit2 changes into fork
  • Support iOS SDK
  • Test GPG support on different configurations (need help here)
  • Unit tests
  • Cleanup
  • Apple Silicon Support
  • Support operations
    • Commit
    • Amend
    • Edit message
    • Swap with parent
    • Squash with parent
    • Delete
    • Rewrite
    • Split
    • Undo/Redo
    • Rebase

Technical debt:

  • Operations (amend, edit message, squash with parent) on single-commit repositories. Assert:
    XLOG_DEBUG_CHECK(sqlite3_changes(_database) > 0);
    Repository sample
  • Parse GPG signature in git_commit object for tests and GPG status presentation
    git_commit_extract_signature
Raw commit data sample
tree a014809071940a9e860f33087275346130124b8f
parent 2a63c7ff507940895f4516f2d1f1c6d52a062b53
author Roman Gardukevich <[email protected]> 1603139410 +0300
committer Roman Gardukevich <[email protected]> 1603139580 +0300
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEL3huDZGHfHonBjlwEjx22Be1tNcFAl+N9/0ACgkQEjx22Be1
 tNcWAw//UFrd9DyIP4WnTZsVxmxeeUro6PCIRc4pMCaENxnmIAljHKAh0ofvuKci
 9Mj2aIxyffk5PsOPz0hoNT4jqm9EG8fYcyj+xJ2fGkGLDY+xXLRt44VPeBGoox3i
 Eqeb+SJCGBj7mhVtdAf9LjbexVPSfDHxPVciTKbks4IPN55xLbLebcJUSWRAXiPY
 gjCOAOQJiaaj16C5qEOhoh86k54BrzZK7ZCGI+U3o+YhMbhNj4qARnTdscl1lNDi
 udl3L5jfezWHFoYydpTBrH5StkWsROHjL0h/VKg4MqXRITXYyZlYJYR4yixlLHEf
 C+f1JEvj3mVqksMWf4SE0vkGQ3uudsF9kfHVAenhzBnl0GSy1NvLasrGMzeMqbYj
 iC5nlmr7schgpBDE3dCsW+9LGpcwlgPdZNyLphHkYayNtorM9G3SXH75ay2wj2F1
 MQXThsSsujVx+nSx5yVpcdf9ju8LflX+IARMXFMkV3HOh0rOK+JqyYascGuJ0zoZ
 GAnKLGt2umaN7kKG3Xvxdcsftxj4I85XTNJspaggLuIxdVuNvGghPjmmW9GlHYuA
 F+n8wyvHLnGa55X7ESkTH4759h8+GsE+/1kj3LcZWv25Av0bUGWOlZZ64aUofBTc
 k91ucZnutrVyevkVH9n02RRweM+Moibe40KvFe59WhhNX6RuXcI=
 =u7ec
 -----END PGP SIGNATURE-----
 

Hey!
  • Investigate manual calling gpg with pipelines in favor of gpgme dependency (git example)
  • Investigate replacement of gpgme_op_sign with gpgme_op_sign_start + gpgme_wait for async signature calculation. (doc1, doc2)

Useful links:

Technical references:

How does git sign commits?

Callstack:

  1. sign_buffer - gpg-interface.c
  2. commit_tree_extended - commit.c
  3. cmd_commit - builtin/commit.c

How does libgit2 sign commits?

Unfortunately, there are no overall sign commit support in libgit2. Also, GitUp uses it's own fork which is quite outdated. The good thing is that it gives us enough flexibility to implement custom signature adding functionality to libgit2 and reuse it in GitUpKit.

Dependencies

@OdNairy OdNairy force-pushed the feature/gpg branch 2 times, most recently from 8f40793 to 3d5292e Compare July 3, 2020 19:05
@lucasderraugh
Copy link
Collaborator

Thanks for contributing @OdNairy! This looks like a lot of works so thanks for pursuing it.

}

NSString* plainToSign = [[NSString alloc] initWithCString:body encoding:NSUTF8StringEncoding];
NSString* signature = [key signSignature:plainToSign];
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lucasderraugh I would like to trigger a separate discussion regarding UI blocking calls.
I'm focusing on signing commits functionality in current PR. However, even with the partial support I already observe significant UI regression – the main queue gets blocked for a 0.2-0.3 second when password for the gpg key already stored the keychain. It even can be an infinite period of time when GPG Keychain presents screen for GPG Key Password input.
Do you have any UI/UX related ideas on how we can play around this issue?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lucasderraugh Any ideas?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, didn't realize there was an outstanding question. Let me think about what we could do here and I'll get back to you soon.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lucasderraugh any updates? 🙂

}

if (gpgSignature != NULL) {
CALL_LIBGIT2_FUNCTION_GOTO(cleanupBuffer, git_commit_create_with_signature, &oid, self.private, commitBuffer.ptr, gpgSignature, NULL);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lucasderraugh Separate thread regarding git-up/libgit2 fork.
It looks like libgit2 doesn't implement 100% gpg support yet so I have to implement some additional methods in it.
Is there any process for fork updates? Should it be just PR with functionality or I have to implement some tests in libgit2 as well?

Generally, what was the motivation to link against fork instead of upstream? Would it be possible to rebase on top of upstream? Is there a chance that we may migrate to the upstream instead of the fork?

/cc @pks-t @swisspol

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created a fork of libgit2 because a few patches were needed with some new APIs, bug fixes and change of behavior. Not all would be accepted in upstream and at the time maintainers could take weeks to respond. You can see the 15 or so custom commits here:
https://github.com/git-up/libgit2/commits/gitup

The README in the fork repo explains how to update to upstream.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@swisspol – looks like we standstill with libgit2, maybe suggested override below can help? (i think libgit2 are bit resistant to add features, even signing – they usually say it's more to the clients)

but gosh, I'm missing that in GitUp so much :) hope resolution will be found. Also, please, lmk if we can support somehow?

@amatzen
Copy link

amatzen commented Dec 2, 2020

So great! Can't wait to this being implemented. Thanks 🥇

@nitz
Copy link

nitz commented Aug 24, 2021

Just started using GitUp this week and wondered where the slew of unsigned commits I had were coming from. The existence of this PR explains a lot 😅

Looks like you've put some serious work into this, @OdNairy, hugely appreciated that you decided too. Are you just waiting to hear back from @lucasderraugh on the UI issue?

I'd like to offer my two cents on the topic, if it helps. I use TortoiseGit as my non-terminal interface to Git when I'm on Windows. Combined with Gpg4win, I'm able to sign my commits there. TortoiseGit doesn't actually do the git operations itself, just invokes the standard binary with specific options. That means that when it comes time to commit, git itself respects commit.gpgsign, invoking gpg.program all by itself. It's nice that it just respects my config, but the interop between those layers is slow to say the least. My GPG PK is stored on a smartcard, so the first commit I've made since inserting the card will force gpg-agent to fire up pinentry to unlock the smartcard. Depending on what else my machine is doing at the time, this process takes an agonizingly long time (especially if Gpg4win is firing up it's whole setup because it wasn't already running.) This has had the effect of causing my commit to time out and fail, because it gets tired of waiting.

I tell this ridiculous story to illustrate that the issue you've run into isn't abnormal, and at least in my case is something I'd absolutely expect. A sub half-second hit while it grabs the key from the agent isn't something I'd even blink at. Further, allowing a reasonable wait (20 secs +/-?) for pinentry to complete, and failing if it doesn't is as well par for the course for me. I've long ago accepted that when dealing with gpg, things tend to be a little more "janky" than one might expect, and am personally fully comfortable with that fact by this point.

Cheers

@lucasderraugh
Copy link
Collaborator

lucasderraugh commented Aug 24, 2021

@nitz I don't have tons of time to review the details of PRs these days. But I'm still willing to help move the project forward.

I honestly don't care what the initial UI looks like (UI can easily be iterated on in future releases), but here is the 1 thing I do care about:

Adding in support for GPG signing CANNOT regress the performance or workflows for people not using this feature.

I'm not sure if @OdNairy is willing to keep working on these changes, I personally don't have a good understanding of gpg signing so I'm deferring to those that do to understand a good approach here. I will absolutely test out the final result before merging in anything, but that's where I stand here.

@OdNairy
Copy link
Author

OdNairy commented Aug 24, 2021

Adding in support for GPG signing CANNOT regress the performance or workflows for people not using this feature.

Definitely makes sense. That implementation doesn't impact performance for non-gpg users. Only GitUp binary size would be impacted for everybody.

@robertlacroix
Copy link

@OdNairy this PR looks great! As you probably know Git shells out to gpg, which enabled other implementations, like an x509 one github/smimesign and others. While using a library is obviously better than executing a binary, the downside is that those alternatives don't work out of the box.

Have you considered simplifying this, by just supporting what's configured in gitconfig and executing the configured gpg.program like Git does to handle the signing?

@OdNairy
Copy link
Author

OdNairy commented Sep 22, 2022

Hi all
I have some news – after becoming a dad of twins I'm back to the gpg support 😄
Thanks everybody for your support and comments, it what was motivated me to get back to work.

There are few updates:

  • Rebased on top of the latest GitUp and libgit2 fork
  • Script to build gpgme library as XCFramework artefact
  • Apple Silicon support

I also can confirm that all operations still works as expected. Except the single-commit repository 🤡 . There is something broken with that thing so I probably need help from @lucasderraugh with it.

Stay tuned!

@OdNairy OdNairy force-pushed the feature/gpg branch 2 times, most recently from 10aa199 to af7370c Compare September 23, 2022 11:38
The System Region leads to false positive
test failures in some regions
Supported operations:
* Commit
* Merge
* Cherry-pick
@OdNairy OdNairy force-pushed the feature/gpg branch 2 times, most recently from 96d073e to ac1ce50 Compare September 30, 2022 20:45
@OdNairy
Copy link
Author

OdNairy commented Sep 30, 2022

Update: I was able to eliminate almost all extra code from the libgit2 to support GPG sign. It is a single new function PR now 🎉 git-up/libgit2#3.
Next step is to start writing some unit tests.

@OdNairy
Copy link
Author

OdNairy commented Oct 16, 2022

I've found a serious issue in my PR. When GitUp overwrite commit of some other author, my implementation still signed it with local key. The git doesn't do it. So I have to implement some filtering logic first.

@gelosi
Copy link

gelosi commented May 28, 2023

@OdNairy hi! Any chances to move this rock forward? 👋

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

Support GPG signing
9 participants