Skip to content

Commit

Permalink
Add support for GPG-signed commits (mystor#46)
Browse files Browse the repository at this point in the history
GPG-sign commits if option -S/--gpg-sign is given, or if configurations
revise.gpgSign or commit.gpgSign are set to true.

TODO:
  * add support for optional '<keyid>' option argument: -S[<keyid>],
    --gpg-sign[=<keyid>]
  * write a test
  * check if merge commits are also signed properly
  * check for valid mergetag support
  * update corresponding documentation
  • Loading branch information
Nicolas Schier committed Sep 3, 2020
1 parent 7176273 commit 76e44eb
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 2 deletions.
14 changes: 14 additions & 0 deletions git-revise.1
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ Reset target commit\(aqs author to the current user.
.B \-\-ref <gitref>
Working branch to update; defaults to \fBHEAD\fP\&.
.UNINDENT
.INDENT 0.0
.TP
\fB\-\-gpg-sign\fR, \fB\-S\fR, \fB\-\-no\-gpg\-sign
GPG-sign commits. To override the \fIcommit.gpgSign\fR git configuration, use
\fI\-\-no\-gpg\-sign\fR.
.UNINDENT
.SS Main modes of operation
.INDENT 0.0
.TP
Expand Down Expand Up @@ -147,6 +153,14 @@ If set to true, imply \fI\%\-\-autosquash\fP whenever \fI\%\-\-interactive\fP
is specified. Overridden by \fI\%\-\-no\-autosquash\fP\&. Defaults to false. If
not set, the value of \fBrebase.autoSquash\fP is used instead.
.UNINDENT
.INDENT 0.0
.TP
.B revise.gpgSign
If set to true, GPG-sign new commits; defaults to false. This setting
overrides the original git configuration \fBcommit.gpgSign\fR and may be
overridden by the command line options \fI\-\-gpg\-sign\fR and
\fI\-\-no\-gpg\-sign\fR.
.UNINDENT
.SH CONFLICT RESOLUTION
.sp
When a conflict is encountered, \fBgit revise\fP will attempt to resolve
Expand Down
47 changes: 45 additions & 2 deletions gitrevise/odb.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
Tuple,
cast,
)
import subprocess
from sys import stderr, exit
from types import TracebackType
from pathlib import Path
from enum import Enum
Expand Down Expand Up @@ -134,6 +136,15 @@ class Repository:
index: "Index"
"""current index state"""

sign_commits: False
"""sign commits with gpg"""

key_id: ""
"""key ID to be used for commit signing"""

gpg: "gpg"
"""path to GnuPG binary"""

_objects: Dict[int, Dict[Oid, "GitObj"]]
_catfile: Popen
_tempdir: Optional[TemporaryDirectory]
Expand All @@ -144,6 +155,8 @@ class Repository:
"default_author",
"default_committer",
"index",
"sign_commits",
"key_id",
"_objects",
"_catfile",
"_tempdir",
Expand All @@ -162,6 +175,22 @@ def __init__(self, cwd: Optional[Path] = None):

self.index = Index(self)

self.sign_commits = self.bool_config("revise.gpgSign",
default=self.bool_config("commit.gpgSign", default=False))

self.key_id = self.default_committer.name
if self.default_committer.email:
if self.key_id:
self.key_id += b" "
self.key_id += b"<" + self.default_committer.email + b">"
else:
self.key_id = self.default_committer.email

self.key_id = self.bool_config("user.signingKey",
default=self.key_id)

self.gpg = self.config("gpg.program", default="gpg")

self._catfile = Popen(
["git", "cat-file", "--batch"],
bufsize=-1,
Expand Down Expand Up @@ -270,8 +299,22 @@ def new_commit(
body += b"parent " + parent.oid.hex().encode() + b"\n"
body += b"author " + author + b"\n"
body += b"committer " + committer + b"\n"
body += b"\n"
body += message

body_tail = b"\n" + message

if self.sign_commits:
p = subprocess.run([self.gpg, "-bsau", self.key_id],
capture_output=True, input=body + body_tail)
if not p.stdout:
print(p.stderr.decode(), file=stderr, end="")
print("gpg failed to sign commit", file=stderr)
exit(1)

body += b"gpgsig " + p.stdout.replace(b"\n", b"\n ")
body = body[:-1]

body += body_tail

return Commit(self, body)

def new_tree(self, entries: Mapping[bytes, "Entry"]) -> "Tree":
Expand Down
15 changes: 15 additions & 0 deletions gitrevise/tui.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,19 @@ def build_parser() -> ArgumentParser:
action="store_true",
help="interactively cut a commit into two smaller commits",
)

mode_group = parser.add_mutually_exclusive_group()
mode_group.add_argument(
"--gpg-sign",
"-S",
action="store_true",
help="GPG sign commits",
)
index_group.add_argument(
"--no-gpg-sign",
action="store_false",
help="do not GPG sign commits",
)
return parser


Expand Down Expand Up @@ -192,6 +205,8 @@ def inner_main(args: Namespace, repo: Repository):
if args.patch:
repo.git("add", "-p")

repo.sign_commits = args.gpg_sign

# Create a commit with changes from the index
staged = None
if not args.no_index:
Expand Down

0 comments on commit 76e44eb

Please sign in to comment.