Skip to content

Commit

Permalink
odb.Repository.sign_buffer: Support gpg.format = ssh [fixes mystor#123]
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremy-w committed Apr 16, 2024
1 parent 5a10920 commit bdcb254
Showing 1 changed file with 51 additions and 17 deletions.
68 changes: 51 additions & 17 deletions gitrevise/odb.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from enum import Enum
from pathlib import Path
from subprocess import DEVNULL, PIPE, CalledProcessError, Popen, run
from tempfile import TemporaryDirectory
from tempfile import TemporaryDirectory, NamedTemporaryFile
from types import TracebackType
from typing import (
TYPE_CHECKING,
Expand Down Expand Up @@ -328,25 +328,59 @@ def sign_buffer(self, buffer: bytes) -> bytes:
key_id = self.config(
"user.signingKey", default=self.default_committer.signing_key
)
gpg = None
try:
gpg = sh_run(
(self.gpg, "--status-fd=2", "-bsau", key_id),
stdout=PIPE,
stderr=PIPE,
input=buffer,
check=True,
)
except CalledProcessError as gpg:
print(gpg.stderr.decode(), file=sys.stderr, end="")
print("gpg failed to sign commit", file=sys.stderr)
raise
fmt = self.config("gpg.format", "gpg")
signer = None
if self.config("gpg.format", "gpg") == b"ssh":
program = self.config("gpg.ssh.program", "ssh-keygen")
is_literal_ssh_key = key_id.startswith(b'ssh-') or key_id.startswith(b'key::')
if is_literal_ssh_key and key_id.startswith(b'key::'):
key_id = key_id[5:]
if is_literal_ssh_key:
cm = NamedTemporaryFile(prefix=".git_signing_key_tmp")
else:
cm = open(key_id, 'rb')
with cm as key_file:
if is_literal_ssh_key:
key_file.write(key_id)
key_file.flush()
key_id = key_file.name
try:
args = [program, "-Y", "sign", "-n", "git", "-f", key_id]
if is_literal_ssh_key:
args.append("-U")
signer = sh_run(
args,
stdout=PIPE,
stderr=PIPE,
input=buffer,
check=True
)
except CalledProcessError as signer:
e = signer.stderr.decode()
print(e, file=sys.stderr, end="")
print(f"{program} failed to sign commit", file=sys.stderr)
if "usage:" in e:
print("ssh-keygen -Y sign is needed for ssh signing (available in openssh version 8.2p1+)", file=sys.stderr)
raise
else:
try:
signer = sh_run(
(self.gpg, "--status-fd=2", "-bsau", key_id),
stdout=PIPE,
stderr=PIPE,
input=buffer,
check=True,
)
except CalledProcessError as signer:
print(signer.stderr.decode(), file=sys.stderr, end="")
print("gpg failed to sign commit", file=sys.stderr)
raise

if b"\n[GNUPG:] SIG_CREATED " not in gpg.stderr:
raise GPGSignError(gpg.stderr.decode())
if b"\n[GNUPG:] SIG_CREATED " not in signer.stderr:
raise GPGSignError(signer.stderr.decode())

signature = b"gpgsig"
for line in gpg.stdout.splitlines():
for line in signer.stdout.splitlines():
signature += b" " + line + b"\n"
return signature

Expand Down

0 comments on commit bdcb254

Please sign in to comment.