File gnome-keysign-gpg-2.1-returncode.patch of Package gnome-keysign

From c01552eb9f15e39e7458ed2ab233385357e2f139 Mon Sep 17 00:00:00 2001
From: Tobias Mueller <muelli@cryptobitch.de>
Date: Thu, 7 Jul 2016 20:24:12 +0200
Subject: [PATCH] gpg: Checking for the return code when signing

It seems that gpg2.1 does not necessarily send GOOD_PASSPHRASE when the
agent has a cached passphrase.

In fact, I can't produce two signatures because of the following
exception:

File "/tmp/gks-foo-install/local/lib/python2.7/site-
packages/gnome_keysign-0.6-py2.7.egg/monkeysign/gpg.py", line 510, in
sign_key
    raise GpgRuntimeError(self.context.returncode, _('unable to prompt
for passphrase, is gpg-agent running?'))
monkeysign.gpg.GpgRuntimeError: [Errno 0] unable to prompt for
passphrase, is gpg-agent running?

We can see the Errno 0. According to the man page, that's no problem,
though.  The modification appears to work with both, gpg1.4 and gpg2.1.
I haven't checked 2.0, though.
---
 monkeysign/gpg.py | 28 +++++++++++++++++++---------
 1 file changed, 19 insertions(+), 9 deletions(-)

diff --git a/monkeysign/gpg.py b/monkeysign/gpg.py
index 56d21a1..8260cb2 100644
--- a/monkeysign/gpg.py
+++ b/monkeysign/gpg.py
@@ -498,10 +498,19 @@ class Keyring():
                 self.context.expect(proc.stderr, 'GOT_IT')
                 # expect the passphrase confirmation
                 # we seek because i have seen a USERID_HINT <keyid> <uid> in some cases
-                try:
-                    self.context.seek(proc.stderr, 'GOOD_PASSPHRASE')
-                except GpgProtocolError:
-                    raise GpgRuntimeError(self.context.returncode, _('unable to prompt for passphrase, is gpg-agent running?'))
+
+                # The GnuPG (1.4 and 2.1) man page states that all is fine
+                # if gpg exits with 0.  So let's assume that once we see
+                # 0, we're good.
+                # We have seen instances in which the GOOD_PASSPHRASE
+                # is not sent with GnuPG 2.1, maybe because the agent
+                # cached the passphrase.
+                if self.context.returncode != 0:
+                    try:
+                        self.context.seek(proc.stderr, 'GOOD_PASSPHRASE')
+                    except GpgProtocolError:
+                        raise GpgRuntimeError(self.context.returncode,
+                                              _('unable to prompt for passphrase, is gpg-agent running?'))
                 return proc.wait() == 0
 
             # don't sign all uids
@@ -540,11 +549,12 @@ class Keyring():
                 raise GpgRuntimeError(self.context.returncode, _('key is expired, cannot sign'))
             else:
                 raise GpgRuntimeError(self.context.returncode, _('unable to signing a single key: %s') % e.found().decode('utf-8') + proc.stderr.read())
-        # expect the passphrase confirmation
-        try:
-            self.context.seek(proc.stderr, 'GOOD_PASSPHRASE')
-        except GpgProtocolError:
-            raise GpgRuntimeError(self.context.returncode, _('password confirmation failed'))
+        # expect the passphrase confirmation if return code indicates problems
+        if self.context.returncode != 0:
+            try:
+                self.context.seek(proc.stderr, 'GOOD_PASSPHRASE')
+            except GpgProtocolError:
+                raise GpgRuntimeError(self.context.returncode, _('password confirmation failed'))
         if multiuid:
             # we save the resulting key in uid selection mode
             self.context.expect(proc.stderr, 'GET_LINE keyedit.prompt')
-- 
2.7.4