Status: | Merged |
---|---|
Approved by: | Jelmer Vernooij |
Approved revision: | no longer in the source branch. |
Merge reported by: | The Breezy Bot |
Merged at revision: | not available |
Proposed branch: | lp:~jelmer/brz/gpg |
Merge into: | lp:brz |
Diff against target: |
782 lines (+138/-241) 11 files modified
breezy/config.py (+0/-17) breezy/errors.py (+0/-24) breezy/gpg.py (+98/-81) breezy/help_topics/en/configuration.txt (+0/-10) breezy/tests/blackbox/test_log.py (+5/-2) breezy/tests/features.py (+3/-1) breezy/tests/test_commit.py (+1/-5) breezy/tests/test_config.py (+0/-2) breezy/tests/test_gpg.py (+24/-97) breezy/tests/test_merge_directive.py (+0/-2) doc/en/release-notes/brz-3.0.txt (+7/-0) |
To merge this branch: | bzr merge lp:~jelmer/brz/gpg |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Martin Packman | Approve | ||
Review via email: mp+326815@code.launchpad.net |
This proposal supersedes a proposal from 2017-07-04.
Commit message
Switch to using python-gpg (part of gpgme) rather than deprecated python-gpgme.
Description of the change
Switch to using python-gpg (part of gpgme) rather than deprecated python-gpgme.
Also, switch to using gpgme for signing, while we're at it.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'breezy/config.py' |
2 | --- breezy/config.py 2017-06-15 01:07:35 +0000 |
3 | +++ breezy/config.py 2017-07-04 21:30:36 +0000 |
4 | @@ -27,7 +27,6 @@ |
5 | email=Your Name <your@email.address> |
6 | check_signatures=require|ignore|check-available(default) |
7 | create_signatures=always|never|when-required(default) |
8 | -gpg_signing_command=name-of-program |
9 | log_format=name-of-format |
10 | validate_signatures_in_log=true|false(default) |
11 | acceptable_keys=pattern1,pattern2 |
12 | @@ -798,10 +797,6 @@ |
13 | else: |
14 | return None |
15 | |
16 | - def _gpg_signing_command(self): |
17 | - """See Config.gpg_signing_command.""" |
18 | - return self._get_user_option('gpg_signing_command') |
19 | - |
20 | def _log_format(self): |
21 | """See Config.log_format.""" |
22 | return self._get_user_option('log_format') |
23 | @@ -1314,10 +1309,6 @@ |
24 | def remove_user_option(self, option_name, section_name=None): |
25 | self._get_branch_data_config().remove_option(option_name, section_name) |
26 | |
27 | - def _gpg_signing_command(self): |
28 | - """See Config.gpg_signing_command.""" |
29 | - return self._get_safe_value('_gpg_signing_command') |
30 | - |
31 | def _post_commit(self): |
32 | """See Config.post_commit.""" |
33 | return self._get_safe_value('_post_commit') |
34 | @@ -2706,14 +2697,6 @@ |
35 | Option('email', override_from_env=['BRZ_EMAIL'], default=default_email, |
36 | help='The users identity')) |
37 | option_registry.register( |
38 | - Option('gpg_signing_command', |
39 | - default='gpg', |
40 | - help="""\ |
41 | -Program to use use for creating signatures. |
42 | - |
43 | -This should support at least the -u and --clearsign options. |
44 | -""")) |
45 | -option_registry.register( |
46 | Option('gpg_signing_key', |
47 | default=None, |
48 | help="""\ |
49 | |
50 | === modified file 'breezy/errors.py' |
51 | --- breezy/errors.py 2017-06-10 18:39:27 +0000 |
52 | +++ breezy/errors.py 2017-07-04 21:30:36 +0000 |
53 | @@ -1771,22 +1771,6 @@ |
54 | self.username = username |
55 | |
56 | |
57 | -class SigningFailed(BzrError): |
58 | - |
59 | - _fmt = 'Failed to GPG sign data with command "%(command_line)s"' |
60 | - |
61 | - def __init__(self, command_line): |
62 | - BzrError.__init__(self, command_line=command_line) |
63 | - |
64 | - |
65 | -class SignatureVerificationFailed(BzrError): |
66 | - |
67 | - _fmt = 'Failed to verify GPG signature data with error "%(error)s"' |
68 | - |
69 | - def __init__(self, error): |
70 | - BzrError.__init__(self, error=error) |
71 | - |
72 | - |
73 | class DependencyNotPresent(BzrError): |
74 | |
75 | _fmt = 'Unable to import library "%(library)s": %(error)s' |
76 | @@ -1795,14 +1779,6 @@ |
77 | BzrError.__init__(self, library=library, error=error) |
78 | |
79 | |
80 | -class GpgmeNotInstalled(DependencyNotPresent): |
81 | - |
82 | - _fmt = 'python-gpgme is not installed, it is needed to verify signatures' |
83 | - |
84 | - def __init__(self, error): |
85 | - DependencyNotPresent.__init__(self, 'gpgme', error) |
86 | - |
87 | - |
88 | class WorkingTreeNotRevision(BzrError): |
89 | |
90 | _fmt = ("The working tree for %(basedir)s has changed since" |
91 | |
92 | === modified file 'breezy/gpg.py' |
93 | --- breezy/gpg.py 2017-06-05 20:48:31 +0000 |
94 | +++ breezy/gpg.py 2017-07-04 21:30:36 +0000 |
95 | @@ -29,7 +29,6 @@ |
96 | |
97 | from breezy import ( |
98 | config, |
99 | - errors, |
100 | trace, |
101 | ui, |
102 | ) |
103 | @@ -39,6 +38,9 @@ |
104 | ) |
105 | """) |
106 | |
107 | +from . import ( |
108 | + errors, |
109 | + ) |
110 | from .sixish import ( |
111 | BytesIO, |
112 | ) |
113 | @@ -51,6 +53,30 @@ |
114 | SIGNATURE_EXPIRED = 4 |
115 | |
116 | |
117 | +class GpgNotInstalled(errors.DependencyNotPresent): |
118 | + |
119 | + _fmt = 'python-gpg is not installed, it is needed to verify signatures' |
120 | + |
121 | + def __init__(self, error): |
122 | + errors.DependencyNotPresent.__init__(self, 'gpg', error) |
123 | + |
124 | + |
125 | +class SigningFailed(errors.BzrError): |
126 | + |
127 | + _fmt = 'Failed to GPG sign data: "%(error)s"' |
128 | + |
129 | + def __init__(self, error): |
130 | + errors.BzrError.__init__(self, error=error) |
131 | + |
132 | + |
133 | +class SignatureVerificationFailed(errors.BzrError): |
134 | + |
135 | + _fmt = 'Failed to verify GPG signature data with error "%(error)s"' |
136 | + |
137 | + def __init__(self, error): |
138 | + errors.BzrError.__init__(self, error=error) |
139 | + |
140 | + |
141 | def bulk_verify_signatures(repository, revids, strategy, |
142 | process_events_callback=None): |
143 | """Do verifications on a set of revisions |
144 | @@ -101,10 +127,10 @@ |
145 | """Real strategies take a configuration.""" |
146 | |
147 | def sign(self, content): |
148 | - raise errors.SigningFailed('Signing is disabled.') |
149 | + raise SigningFailed('Signing is disabled.') |
150 | |
151 | def verify(self, content, testament): |
152 | - raise errors.SignatureVerificationFailed('Signature verification is \ |
153 | + raise SignatureVerificationFailed('Signature verification is \ |
154 | disabled.') |
155 | |
156 | def set_acceptable_keys(self, command_line_input): |
157 | @@ -162,11 +188,32 @@ |
158 | def __init__(self, config_stack): |
159 | self._config_stack = config_stack |
160 | try: |
161 | - import gpgme |
162 | - self.context = gpgme.Context() |
163 | + import gpg |
164 | + self.context = gpg.Context() |
165 | except ImportError as error: |
166 | pass # can't use verify() |
167 | |
168 | + self.context.signers = self._get_signing_keys() |
169 | + |
170 | + def _get_signing_keys(self): |
171 | + import gpg |
172 | + keyname = self._config_stack.get('gpg_signing_key') |
173 | + if keyname: |
174 | + try: |
175 | + return [self.context.get_key(keyname)] |
176 | + except gpg.errors.KeyNotFound: |
177 | + pass |
178 | + |
179 | + if keyname is None or keyname == 'default': |
180 | + # 'default' or not setting gpg_signing_key at all means we should |
181 | + # use the user email address |
182 | + keyname = config.extract_email_address(self._config_stack.get('email')) |
183 | + possible_keys = self.context.keylist(keyname, secret=True) |
184 | + try: |
185 | + return [next(possible_keys)] |
186 | + except StopIteration: |
187 | + return [] |
188 | + |
189 | @staticmethod |
190 | def verify_signatures_available(): |
191 | """ |
192 | @@ -175,55 +222,24 @@ |
193 | :return: boolean if this strategy can verify signatures |
194 | """ |
195 | try: |
196 | - import gpgme |
197 | + import gpg |
198 | return True |
199 | except ImportError as error: |
200 | return False |
201 | |
202 | - def _command_line(self): |
203 | - key = self._config_stack.get('gpg_signing_key') |
204 | - if key is None or key == 'default': |
205 | - # 'default' or not setting gpg_signing_key at all means we should |
206 | - # use the user email address |
207 | - key = config.extract_email_address(self._config_stack.get('email')) |
208 | - return [self._config_stack.get('gpg_signing_command'), '--clearsign', |
209 | - '-u', key] |
210 | - |
211 | def sign(self, content): |
212 | + import gpg |
213 | if isinstance(content, unicode): |
214 | raise errors.BzrBadParameterUnicode('content') |
215 | - ui.ui_factory.clear_term() |
216 | |
217 | - preexec_fn = _set_gpg_tty |
218 | - if sys.platform == 'win32': |
219 | - # Win32 doesn't support preexec_fn, but wouldn't support TTY anyway. |
220 | - preexec_fn = None |
221 | + plain_text = gpg.Data(content) |
222 | try: |
223 | - process = subprocess.Popen(self._command_line(), |
224 | - stdin=subprocess.PIPE, |
225 | - stdout=subprocess.PIPE, |
226 | - preexec_fn=preexec_fn) |
227 | - try: |
228 | - result = process.communicate(content)[0] |
229 | - if process.returncode is None: |
230 | - process.wait() |
231 | - if process.returncode != 0: |
232 | - raise errors.SigningFailed(self._command_line()) |
233 | - return result |
234 | - except OSError as e: |
235 | - if e.errno == errno.EPIPE: |
236 | - raise errors.SigningFailed(self._command_line()) |
237 | - else: |
238 | - raise |
239 | - except ValueError: |
240 | - # bad subprocess parameters, should never happen. |
241 | - raise |
242 | - except OSError as e: |
243 | - if e.errno == errno.ENOENT: |
244 | - # gpg is not installed |
245 | - raise errors.SigningFailed(self._command_line()) |
246 | - else: |
247 | - raise |
248 | + output, result = self.context.sign( |
249 | + plain_text, mode=gpg.constants.sig.mode.CLEAR) |
250 | + except gpg.errors.GPGMEError as error: |
251 | + raise SigningFailed(str(error)) |
252 | + |
253 | + return output |
254 | |
255 | def verify(self, content, testament): |
256 | """Check content has a valid signature. |
257 | @@ -234,74 +250,75 @@ |
258 | :return: SIGNATURE_VALID or a failed SIGNATURE_ value, key uid if valid |
259 | """ |
260 | try: |
261 | - import gpgme |
262 | + import gpg |
263 | except ImportError as error: |
264 | - raise errors.GpgmeNotInstalled(error) |
265 | + raise errors.GpgNotInstalled(error) |
266 | |
267 | - signature = BytesIO(content) |
268 | - plain_output = BytesIO() |
269 | + signature = gpg.Data(content) |
270 | + sink = gpg.Data() |
271 | try: |
272 | - result = self.context.verify(signature, None, plain_output) |
273 | - except gpgme.GpgmeError as error: |
274 | - raise errors.SignatureVerificationFailed(error[2]) |
275 | + plain_output, result = self.context.verify(signature) |
276 | + except gpg.errors.BadSignatures as error: |
277 | + signatures = error.result.signatures |
278 | + fingerprint = signatures[0].fpr |
279 | + if signatures[0].summary & gpg.constants.SIGSUM_KEY_EXPIRED: |
280 | + expires = self.context.get_key(signatures[0].fpr).subkeys[0].expires |
281 | + if expires > signatures[0].timestamp: |
282 | + # The expired key was not expired at time of signing. |
283 | + # test_verify_expired_but_valid() |
284 | + return SIGNATURE_EXPIRED, fingerprint[-8:] |
285 | + else: |
286 | + # I can't work out how to create a test where the signature |
287 | + # was expired at the time of signing. |
288 | + return SIGNATURE_NOT_VALID, None |
289 | + |
290 | + # GPG does not know this key. |
291 | + # test_verify_unknown_key() |
292 | + if signatures[0].summary & gpg.constants.SIGSUM_KEY_MISSING: |
293 | + return SIGNATURE_KEY_MISSING, fingerprint[-8:] |
294 | + |
295 | + return SIGNATURE_NOT_VALID, None |
296 | + except gpg.errors.GPGMEError as error: |
297 | + raise SignatureVerificationFailed(error[2]) |
298 | |
299 | # No result if input is invalid. |
300 | # test_verify_invalid() |
301 | - if len(result) == 0: |
302 | + if len(result.signatures) == 0: |
303 | return SIGNATURE_NOT_VALID, None |
304 | # User has specified a list of acceptable keys, check our result is in |
305 | # it. test_verify_unacceptable_key() |
306 | - fingerprint = result[0].fpr |
307 | + fingerprint = result.signatures[0].fpr |
308 | if self.acceptable_keys is not None: |
309 | if not fingerprint in self.acceptable_keys: |
310 | return SIGNATURE_KEY_MISSING, fingerprint[-8:] |
311 | # Check the signature actually matches the testament. |
312 | # test_verify_bad_testament() |
313 | - if testament != plain_output.getvalue(): |
314 | + if testament != plain_output: |
315 | return SIGNATURE_NOT_VALID, None |
316 | - # Yay gpgme set the valid bit. |
317 | + # Yay gpg set the valid bit. |
318 | # Can't write a test for this one as you can't set a key to be |
319 | - # trusted using gpgme. |
320 | - if result[0].summary & gpgme.SIGSUM_VALID: |
321 | + # trusted using gpg. |
322 | + if result.signatures[0].summary & gpg.constants.SIGSUM_VALID: |
323 | key = self.context.get_key(fingerprint) |
324 | name = key.uids[0].name |
325 | email = key.uids[0].email |
326 | return SIGNATURE_VALID, name + " <" + email + ">" |
327 | # Sigsum_red indicates a problem, unfortunatly I have not been able |
328 | # to write any tests which actually set this. |
329 | - if result[0].summary & gpgme.SIGSUM_RED: |
330 | + if result.signatures[0].summary & gpg.constants.SIGSUM_RED: |
331 | return SIGNATURE_NOT_VALID, None |
332 | - # GPG does not know this key. |
333 | - # test_verify_unknown_key() |
334 | - if result[0].summary & gpgme.SIGSUM_KEY_MISSING: |
335 | - return SIGNATURE_KEY_MISSING, fingerprint[-8:] |
336 | # Summary isn't set if sig is valid but key is untrusted but if user |
337 | # has explicity set the key as acceptable we can validate it. |
338 | - if result[0].summary == 0 and self.acceptable_keys is not None: |
339 | + if result.signatures[0].summary == 0 and self.acceptable_keys is not None: |
340 | if fingerprint in self.acceptable_keys: |
341 | # test_verify_untrusted_but_accepted() |
342 | return SIGNATURE_VALID, None |
343 | # test_verify_valid_but_untrusted() |
344 | - if result[0].summary == 0 and self.acceptable_keys is None: |
345 | - return SIGNATURE_NOT_VALID, None |
346 | - if result[0].summary & gpgme.SIGSUM_KEY_EXPIRED: |
347 | - expires = self.context.get_key(result[0].fpr).subkeys[0].expires |
348 | - if expires > result[0].timestamp: |
349 | - # The expired key was not expired at time of signing. |
350 | - # test_verify_expired_but_valid() |
351 | - return SIGNATURE_EXPIRED, fingerprint[-8:] |
352 | - else: |
353 | - # I can't work out how to create a test where the signature |
354 | - # was expired at the time of signing. |
355 | - return SIGNATURE_NOT_VALID, None |
356 | - # A signature from a revoked key gets this. |
357 | - # test_verify_revoked_signature() |
358 | - if ((result[0].summary & gpgme.SIGSUM_SYS_ERROR |
359 | - or result[0].status.strerror == 'Certificate revoked')): |
360 | + if result.signatures[0].summary == 0 and self.acceptable_keys is None: |
361 | return SIGNATURE_NOT_VALID, None |
362 | # Other error types such as revoked keys should (I think) be caught by |
363 | # SIGSUM_RED so anything else means something is buggy. |
364 | - raise errors.SignatureVerificationFailed( |
365 | + raise SignatureVerificationFailed( |
366 | "Unknown GnuPG key verification result") |
367 | |
368 | def set_acceptable_keys(self, command_line_input): |
369 | |
370 | === modified file 'breezy/help_topics/en/configuration.txt' |
371 | --- breezy/help_topics/en/configuration.txt 2017-06-12 23:25:04 +0000 |
372 | +++ breezy/help_topics/en/configuration.txt 2017-07-04 21:30:36 +0000 |
373 | @@ -498,16 +498,6 @@ |
374 | This section only applies to the branch at this directory and not |
375 | branches below it. |
376 | |
377 | -gpg_signing_command |
378 | -~~~~~~~~~~~~~~~~~~~ |
379 | - |
380 | -(Default: "gpg"). Which program should be used to sign and check revisions. |
381 | -For example:: |
382 | - |
383 | - gpg_signing_command = /usr/bin/gnpg |
384 | - |
385 | -The specified command must accept the options "--clearsign" and "-u <email>". |
386 | - |
387 | bzr_remote_path |
388 | ~~~~~~~~~~~~~~~ |
389 | |
390 | |
391 | === modified file 'breezy/tests/blackbox/test_log.py' |
392 | --- breezy/tests/blackbox/test_log.py 2017-06-22 01:52:28 +0000 |
393 | +++ breezy/tests/blackbox/test_log.py 2017-07-04 21:30:36 +0000 |
394 | @@ -17,6 +17,9 @@ |
395 | |
396 | """Black-box tests for brz log.""" |
397 | |
398 | +from __future__ import absolute_import |
399 | + |
400 | + |
401 | import os |
402 | |
403 | from breezy import ( |
404 | @@ -474,7 +477,7 @@ |
405 | class TestLogSignatures(TestLog): |
406 | |
407 | def test_log_with_signatures(self): |
408 | - self.requireFeature(features.gpgme) |
409 | + self.requireFeature(features.gpg) |
410 | |
411 | tree = self.make_linear_branch(format='dirstate-tags') |
412 | |
413 | @@ -482,7 +485,7 @@ |
414 | self.assertTrue('signature: no signature' in log) |
415 | |
416 | def test_log_without_signatures(self): |
417 | - self.requireFeature(features.gpgme) |
418 | + self.requireFeature(features.gpg) |
419 | |
420 | tree = self.make_linear_branch(format='dirstate-tags') |
421 | |
422 | |
423 | === modified file 'breezy/tests/features.py' |
424 | --- breezy/tests/features.py 2017-06-17 12:58:29 +0000 |
425 | +++ breezy/tests/features.py 2017-07-04 21:30:36 +0000 |
426 | @@ -17,6 +17,8 @@ |
427 | """A collection of commonly used 'Features' to optionally run tests. |
428 | """ |
429 | |
430 | +from __future__ import absolute_import |
431 | + |
432 | import os |
433 | import subprocess |
434 | import stat |
435 | @@ -373,7 +375,7 @@ |
436 | not_running_as_root = _NotRunningAsRoot() |
437 | |
438 | apport = ModuleAvailableFeature('apport') |
439 | -gpgme = ModuleAvailableFeature('gpgme') |
440 | +gpg = ModuleAvailableFeature('gpg') |
441 | lzma = ModuleAvailableFeature('lzma') |
442 | meliae = ModuleAvailableFeature('meliae.scanner') |
443 | paramiko = ModuleAvailableFeature('paramiko') |
444 | |
445 | === modified file 'breezy/tests/test_commit.py' |
446 | --- breezy/tests/test_commit.py 2017-06-18 22:23:02 +0000 |
447 | +++ breezy/tests/test_commit.py 2017-07-04 21:30:36 +0000 |
448 | @@ -33,7 +33,6 @@ |
449 | from ..errors import ( |
450 | PointlessCommit, |
451 | BzrError, |
452 | - SigningFailed, |
453 | LockContention, |
454 | ) |
455 | from . import ( |
456 | @@ -53,7 +52,6 @@ |
457 | |
458 | def __init__(self): |
459 | super(MustSignConfig, self).__init__(''' |
460 | -gpg_signing_command=cat - |
461 | create_signatures=always |
462 | ''') |
463 | |
464 | @@ -431,7 +429,6 @@ |
465 | # monkey patch gpg signing mechanism |
466 | breezy.gpg.GPGStrategy = breezy.gpg.LoopbackGPGStrategy |
467 | conf = config.MemoryStack(''' |
468 | -gpg_signing_command=cat - |
469 | create_signatures=always |
470 | ''') |
471 | commit.Commit(config_stack=conf).commit( |
472 | @@ -457,10 +454,9 @@ |
473 | # monkey patch gpg signing mechanism |
474 | breezy.gpg.GPGStrategy = breezy.gpg.DisabledGPGStrategy |
475 | conf = config.MemoryStack(''' |
476 | -gpg_signing_command=cat - |
477 | create_signatures=always |
478 | ''') |
479 | - self.assertRaises(SigningFailed, |
480 | + self.assertRaises(breezy.gpg.SigningFailed, |
481 | commit.Commit(config_stack=conf).commit, |
482 | message="base", |
483 | allow_pointless=True, |
484 | |
485 | === modified file 'breezy/tests/test_config.py' |
486 | --- breezy/tests/test_config.py 2017-06-12 23:25:04 +0000 |
487 | +++ breezy/tests/test_config.py 2017-07-04 21:30:36 +0000 |
488 | @@ -176,7 +176,6 @@ |
489 | email=Erik B\u00e5gfors <erik@bagfors.nu> |
490 | editor=vim |
491 | change_editor=vimdiff -of @new_path @old_path |
492 | -gpg_signing_command=gnome-gpg |
493 | gpg_signing_key=DD4D5088 |
494 | log_format=short |
495 | validate_signatures_in_log=true |
496 | @@ -232,7 +231,6 @@ |
497 | # test trailing / matching with no children |
498 | [/a/] |
499 | check_signatures=check-available |
500 | -gpg_signing_command=false |
501 | gpg_signing_key=default |
502 | user_local_option=local |
503 | # test trailing / matching |
504 | |
505 | === modified file 'breezy/tests/test_gpg.py' |
506 | --- breezy/tests/test_gpg.py 2017-05-22 00:56:52 +0000 |
507 | +++ breezy/tests/test_gpg.py 2017-07-04 21:30:36 +0000 |
508 | @@ -43,90 +43,17 @@ |
509 | if content is None: |
510 | content = ''' |
511 | gpg_signing_key=amy@example.com |
512 | -gpg_signing_command=false''' |
513 | +''' |
514 | super(FakeConfig, self).__init__(content) |
515 | |
516 | |
517 | -class TestCommandLine(tests.TestCase): |
518 | - |
519 | - def setUp(self): |
520 | - super(TestCommandLine, self).setUp() |
521 | - self.my_gpg = gpg.GPGStrategy(FakeConfig()) |
522 | - |
523 | - def test_signing_command_line(self): |
524 | - self.assertEqual(['false', '--clearsign', '-u', 'amy@example.com'], |
525 | - self.my_gpg._command_line()) |
526 | - |
527 | - def test_signing_command_line_from_default(self): |
528 | - # Using 'default' for gpg_signing_key will use the mail part of 'email' |
529 | - my_gpg = gpg.GPGStrategy(FakeConfig(''' |
530 | -email=Amy <amy@example.com> |
531 | -gpg_signing_key=default |
532 | -gpg_signing_command=false''')) |
533 | - self.assertEqual(['false', '--clearsign', '-u', 'amy@example.com'], |
534 | - my_gpg._command_line()) |
535 | - |
536 | - def test_signing_command_line_from_email(self): |
537 | - # Not setting gpg_signing_key will use the mail part of 'email' |
538 | - my_gpg = gpg.GPGStrategy(FakeConfig(''' |
539 | -email=Amy <amy@example.com> |
540 | -gpg_signing_command=false''')) |
541 | - self.assertEqual(['false', '--clearsign', '-u', 'amy@example.com'], |
542 | - my_gpg._command_line()) |
543 | - |
544 | - def test_checks_return_code(self): |
545 | - # This test needs a unix like platform - one with 'false' to run. |
546 | - # if you have one, please make this work :) |
547 | - self.assertRaises(errors.SigningFailed, self.my_gpg.sign, 'content') |
548 | - |
549 | - def assertProduces(self, content): |
550 | - # This needs a 'cat' command or similar to work. |
551 | - if sys.platform == 'win32': |
552 | - # Windows doesn't come with cat, and we don't require it |
553 | - # so lets try using python instead. |
554 | - # But stupid windows and line-ending conversions. |
555 | - # It is too much work to make sys.stdout be in binary mode. |
556 | - # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65443 |
557 | - self.my_gpg._command_line = lambda:[sys.executable, '-c', |
558 | - 'import sys; sys.stdout.write(sys.stdin.read())'] |
559 | - new_content = content.replace('\n', '\r\n') |
560 | - |
561 | - self.assertEqual(new_content, self.my_gpg.sign(content)) |
562 | - else: |
563 | - self.my_gpg._command_line = lambda:['cat', '-'] |
564 | - self.assertEqual(content, self.my_gpg.sign(content)) |
565 | - |
566 | - def test_returns_output(self): |
567 | - content = "some content\nwith newlines\n" |
568 | - self.assertProduces(content) |
569 | - |
570 | - def test_clears_progress(self): |
571 | - content = "some content\nwith newlines\n" |
572 | - old_clear_term = ui.ui_factory.clear_term |
573 | - clear_term_called = [] |
574 | - def clear_term(): |
575 | - old_clear_term() |
576 | - clear_term_called.append(True) |
577 | - ui.ui_factory.clear_term = clear_term |
578 | - try: |
579 | - self.assertProduces(content) |
580 | - finally: |
581 | - ui.ui_factory.clear_term = old_clear_term |
582 | - self.assertEqual([True], clear_term_called) |
583 | - |
584 | - def test_aborts_on_unicode(self): |
585 | - """You can't sign Unicode text; it must be encoded first.""" |
586 | - self.assertRaises(errors.BzrBadParameterUnicode, |
587 | - self.assertProduces, u'foo') |
588 | - |
589 | - |
590 | class TestVerify(TestCase): |
591 | |
592 | def import_keys(self): |
593 | - import gpgme |
594 | - context = gpgme.Context() |
595 | + import gpg |
596 | + context = gpg.Context() |
597 | |
598 | - key = BytesIO(b"""-----BEGIN PGP PUBLIC KEY BLOCK----- |
599 | + key = gpg.Data(b"""-----BEGIN PGP PUBLIC KEY BLOCK----- |
600 | Version: GnuPG v1.4.11 (GNU/Linux) |
601 | |
602 | mQENBE343IgBCADwzPW7kmKb2bjB+UU+1ER/ABMZspvtoZMPusUw7bk6coXHF/0W |
603 | @@ -158,7 +85,7 @@ |
604 | -----END PGP PUBLIC KEY BLOCK----- |
605 | """) |
606 | |
607 | - secret_key = BytesIO(b"""-----BEGIN PGP PRIVATE KEY BLOCK----- |
608 | + secret_key = gpg.Data(b"""-----BEGIN PGP PRIVATE KEY BLOCK----- |
609 | Version: GnuPG v1.4.11 (GNU/Linux) |
610 | |
611 | lQOYBE343IgBCADwzPW7kmKb2bjB+UU+1ER/ABMZspvtoZMPusUw7bk6coXHF/0W |
612 | @@ -217,7 +144,7 @@ |
613 | -----END PGP PRIVATE KEY BLOCK----- |
614 | """) |
615 | |
616 | - revoked_key = BytesIO(b"""-----BEGIN PGP PUBLIC KEY BLOCK----- |
617 | + revoked_key = gpg.Data(b"""-----BEGIN PGP PUBLIC KEY BLOCK----- |
618 | Version: GnuPG v1.4.11 (GNU/Linux) |
619 | |
620 | mI0ETjlW5gEEAOb/6P+TVM59E897wRtatxys2BhsHCXM4T7xjIiANfDwejDdifqh |
621 | @@ -242,7 +169,7 @@ |
622 | -----END PGP PUBLIC KEY BLOCK----- |
623 | """) |
624 | |
625 | - expired_key = BytesIO(b"""-----BEGIN PGP PUBLIC KEY BLOCK----- |
626 | + expired_key = gpg.Data(b"""-----BEGIN PGP PUBLIC KEY BLOCK----- |
627 | Version: GnuPG v1.4.11 (GNU/Linux) |
628 | |
629 | mI0ETjZ6PAEEALkR4GcFQidCCxV7pgQwQd5MZua0YO2l92fVqHX+PhnZ6egCLKdD |
630 | @@ -263,14 +190,14 @@ |
631 | =p0gt |
632 | -----END PGP PUBLIC KEY BLOCK----- |
633 | """) |
634 | - context.import_(key) |
635 | - context.import_(secret_key) |
636 | - context.import_(revoked_key) |
637 | - context.import_(expired_key) |
638 | + context.op_import(key) |
639 | + context.op_import(secret_key) |
640 | + context.op_import(revoked_key) |
641 | + context.op_import(expired_key) |
642 | |
643 | def test_verify_untrusted_but_accepted(self): |
644 | #untrusted by gpg but listed as acceptable_keys by user |
645 | - self.requireFeature(features.gpgme) |
646 | + self.requireFeature(features.gpg) |
647 | self.import_keys() |
648 | |
649 | content = """-----BEGIN PGP SIGNED MESSAGE----- |
650 | @@ -301,7 +228,7 @@ |
651 | plain)) |
652 | |
653 | def test_verify_unacceptable_key(self): |
654 | - self.requireFeature(features.gpgme) |
655 | + self.requireFeature(features.gpg) |
656 | self.import_keys() |
657 | |
658 | content = """-----BEGIN PGP SIGNED MESSAGE----- |
659 | @@ -332,7 +259,7 @@ |
660 | my_gpg.verify(content, plain)) |
661 | |
662 | def test_verify_valid_but_untrusted(self): |
663 | - self.requireFeature(features.gpgme) |
664 | + self.requireFeature(features.gpg) |
665 | self.import_keys() |
666 | |
667 | content = """-----BEGIN PGP SIGNED MESSAGE----- |
668 | @@ -362,7 +289,7 @@ |
669 | plain)) |
670 | |
671 | def test_verify_bad_testament(self): |
672 | - self.requireFeature(features.gpgme) |
673 | + self.requireFeature(features.gpg) |
674 | self.import_keys() |
675 | |
676 | content = """-----BEGIN PGP SIGNED MESSAGE----- |
677 | @@ -394,7 +321,7 @@ |
678 | |
679 | |
680 | def test_verify_revoked_signature(self): |
681 | - self.requireFeature(features.gpgme) |
682 | + self.requireFeature(features.gpg) |
683 | self.import_keys() |
684 | |
685 | content = """-----BEGIN PGP SIGNED MESSAGE----- |
686 | @@ -418,7 +345,7 @@ |
687 | plain)) |
688 | |
689 | def test_verify_invalid(self): |
690 | - self.requireFeature(features.gpgme) |
691 | + self.requireFeature(features.gpg) |
692 | self.import_keys() |
693 | content = """-----BEGIN PGP SIGNED MESSAGE----- |
694 | Hash: SHA1 |
695 | @@ -443,7 +370,7 @@ |
696 | my_gpg.verify(content, plain)) |
697 | |
698 | def test_verify_expired_but_valid(self): |
699 | - self.requireFeature(features.gpgme) |
700 | + self.requireFeature(features.gpg) |
701 | self.import_keys() |
702 | content = """-----BEGIN PGP SIGNED MESSAGE----- |
703 | Hash: SHA1 |
704 | @@ -470,7 +397,7 @@ |
705 | my_gpg.verify(content, plain)) |
706 | |
707 | def test_verify_unknown_key(self): |
708 | - self.requireFeature(features.gpgme) |
709 | + self.requireFeature(features.gpg) |
710 | self.import_keys() |
711 | content = """-----BEGIN PGP SIGNED MESSAGE----- |
712 | Hash: SHA1 |
713 | @@ -494,7 +421,7 @@ |
714 | my_gpg.verify(content, plain)) |
715 | |
716 | def test_set_acceptable_keys(self): |
717 | - self.requireFeature(features.gpgme) |
718 | + self.requireFeature(features.gpg) |
719 | self.import_keys() |
720 | my_gpg = gpg.GPGStrategy(FakeConfig()) |
721 | my_gpg.set_acceptable_keys("bazaar@example.com") |
722 | @@ -502,7 +429,7 @@ |
723 | [u'B5DEED5FCB15DAE6ECEF919587681B1EE3080E45']) |
724 | |
725 | def test_set_acceptable_keys_from_config(self): |
726 | - self.requireFeature(features.gpgme) |
727 | + self.requireFeature(features.gpg) |
728 | self.import_keys() |
729 | my_gpg = gpg.GPGStrategy(FakeConfig( |
730 | 'acceptable_keys=bazaar@example.com')) |
731 | @@ -511,7 +438,7 @@ |
732 | [u'B5DEED5FCB15DAE6ECEF919587681B1EE3080E45']) |
733 | |
734 | def test_set_acceptable_keys_unknown(self): |
735 | - self.requireFeature(features.gpgme) |
736 | + self.requireFeature(features.gpg) |
737 | my_gpg = gpg.GPGStrategy(FakeConfig()) |
738 | self.notes = [] |
739 | def note(*args): |
740 | @@ -526,10 +453,10 @@ |
741 | class TestDisabled(TestCase): |
742 | |
743 | def test_sign(self): |
744 | - self.assertRaises(errors.SigningFailed, |
745 | + self.assertRaises(gpg.SigningFailed, |
746 | gpg.DisabledGPGStrategy(None).sign, 'content') |
747 | |
748 | def test_verify(self): |
749 | - self.assertRaises(errors.SignatureVerificationFailed, |
750 | + self.assertRaises(gpg.SignatureVerificationFailed, |
751 | gpg.DisabledGPGStrategy(None).verify, 'content', |
752 | 'testament') |
753 | |
754 | === modified file 'breezy/tests/test_merge_directive.py' |
755 | --- breezy/tests/test_merge_directive.py 2017-06-10 00:17:06 +0000 |
756 | +++ breezy/tests/test_merge_directive.py 2017-07-04 21:30:36 +0000 |
757 | @@ -464,8 +464,6 @@ |
758 | class FakeBranch(object): |
759 | def get_config_stack(self): |
760 | return self |
761 | - def gpg_signing_command(self): |
762 | - return 'loopback' |
763 | md = self.make_merge_directive('example:', 'sha', time, timezone, |
764 | 'http://example.com', source_branch="http://example.org", |
765 | patch='booga', patch_type='diff') |
766 | |
767 | === modified file 'doc/en/release-notes/brz-3.0.txt' |
768 | --- doc/en/release-notes/brz-3.0.txt 2017-06-22 01:52:28 +0000 |
769 | +++ doc/en/release-notes/brz-3.0.txt 2017-07-04 21:30:36 +0000 |
770 | @@ -56,6 +56,13 @@ |
771 | This simplifies ``brz init --help``. |
772 | (Neil Martinsen-Burrell, #330494) |
773 | |
774 | + * ``python-gpg`` is now used for checking GPG signatures rather than |
775 | + ``python-gpgme``. (Jelmer Vernooij, #1702308) |
776 | + |
777 | + * ``python-gpg`` is now used for signing commits, rather than shelling |
778 | + out to the gnupg command. The ``gpg_signing_command`` option has been |
779 | + removed. (Jelmer Vernooij, #847388) |
780 | + |
781 | New Features |
782 | ************ |
783 |
Changes look good mostly, a couple of comments inline.