Status: | Superseded |
---|---|
Proposed branch: | lp:~jelmer/brz/gpg |
Merge into: | lp:brz |
Diff against target: |
781 lines (+137/-241) 11 files modified
breezy/config.py (+0/-17) breezy/errors.py (+0/-24) breezy/gpg.py (+97/-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 | Pending | ||
Review via email: mp+326812@code.launchpad.net |
This proposal has been superseded by 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:10:26 +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:10:26 +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:10:26 +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 [possible_keys.next()] |
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,74 @@ |
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 | + fingerprint = error.result.signatures[0].fpr |
278 | + if error.result.signatures[0].summary & gpg.constants.SIGSUM_KEY_EXPIRED: |
279 | + expires = self.context.get_key(error.result.signatures[0].fpr).subkeys[0].expires |
280 | + if expires > error.result.signatures[0].timestamp: |
281 | + # The expired key was not expired at time of signing. |
282 | + # test_verify_expired_but_valid() |
283 | + return SIGNATURE_EXPIRED, fingerprint[-8:] |
284 | + else: |
285 | + # I can't work out how to create a test where the signature |
286 | + # was expired at the time of signing. |
287 | + return SIGNATURE_NOT_VALID, None |
288 | + |
289 | + # GPG does not know this key. |
290 | + # test_verify_unknown_key() |
291 | + if error.result.signatures[0].summary & gpg.constants.SIGSUM_KEY_MISSING: |
292 | + return SIGNATURE_KEY_MISSING, fingerprint[-8:] |
293 | + |
294 | + return SIGNATURE_NOT_VALID, None |
295 | + except gpg.errors.GPGMEError as error: |
296 | + raise SignatureVerificationFailed(error[2]) |
297 | |
298 | # No result if input is invalid. |
299 | # test_verify_invalid() |
300 | - if len(result) == 0: |
301 | + if len(result.signatures) == 0: |
302 | return SIGNATURE_NOT_VALID, None |
303 | # User has specified a list of acceptable keys, check our result is in |
304 | # it. test_verify_unacceptable_key() |
305 | - fingerprint = result[0].fpr |
306 | + fingerprint = result.signatures[0].fpr |
307 | if self.acceptable_keys is not None: |
308 | if not fingerprint in self.acceptable_keys: |
309 | return SIGNATURE_KEY_MISSING, fingerprint[-8:] |
310 | # Check the signature actually matches the testament. |
311 | # test_verify_bad_testament() |
312 | - if testament != plain_output.getvalue(): |
313 | + if testament != plain_output: |
314 | return SIGNATURE_NOT_VALID, None |
315 | - # Yay gpgme set the valid bit. |
316 | + # Yay gpg set the valid bit. |
317 | # Can't write a test for this one as you can't set a key to be |
318 | - # trusted using gpgme. |
319 | - if result[0].summary & gpgme.SIGSUM_VALID: |
320 | + # trusted using gpg. |
321 | + if result.signatures[0].summary & gpg.constants.SIGSUM_VALID: |
322 | key = self.context.get_key(fingerprint) |
323 | name = key.uids[0].name |
324 | email = key.uids[0].email |
325 | return SIGNATURE_VALID, name + " <" + email + ">" |
326 | # Sigsum_red indicates a problem, unfortunatly I have not been able |
327 | # to write any tests which actually set this. |
328 | - if result[0].summary & gpgme.SIGSUM_RED: |
329 | + if result.signatures[0].summary & gpg.constants.SIGSUM_RED: |
330 | return SIGNATURE_NOT_VALID, None |
331 | - # GPG does not know this key. |
332 | - # test_verify_unknown_key() |
333 | - if result[0].summary & gpgme.SIGSUM_KEY_MISSING: |
334 | - return SIGNATURE_KEY_MISSING, fingerprint[-8:] |
335 | # Summary isn't set if sig is valid but key is untrusted but if user |
336 | # has explicity set the key as acceptable we can validate it. |
337 | - if result[0].summary == 0 and self.acceptable_keys is not None: |
338 | + if result.signatures[0].summary == 0 and self.acceptable_keys is not None: |
339 | if fingerprint in self.acceptable_keys: |
340 | # test_verify_untrusted_but_accepted() |
341 | return SIGNATURE_VALID, None |
342 | # test_verify_valid_but_untrusted() |
343 | - if result[0].summary == 0 and self.acceptable_keys is None: |
344 | - return SIGNATURE_NOT_VALID, None |
345 | - if result[0].summary & gpgme.SIGSUM_KEY_EXPIRED: |
346 | - expires = self.context.get_key(result[0].fpr).subkeys[0].expires |
347 | - if expires > result[0].timestamp: |
348 | - # The expired key was not expired at time of signing. |
349 | - # test_verify_expired_but_valid() |
350 | - return SIGNATURE_EXPIRED, fingerprint[-8:] |
351 | - else: |
352 | - # I can't work out how to create a test where the signature |
353 | - # was expired at the time of signing. |
354 | - return SIGNATURE_NOT_VALID, None |
355 | - # A signature from a revoked key gets this. |
356 | - # test_verify_revoked_signature() |
357 | - if ((result[0].summary & gpgme.SIGSUM_SYS_ERROR |
358 | - or result[0].status.strerror == 'Certificate revoked')): |
359 | + if result.signatures[0].summary == 0 and self.acceptable_keys is None: |
360 | return SIGNATURE_NOT_VALID, None |
361 | # Other error types such as revoked keys should (I think) be caught by |
362 | # SIGSUM_RED so anything else means something is buggy. |
363 | - raise errors.SignatureVerificationFailed( |
364 | + raise SignatureVerificationFailed( |
365 | "Unknown GnuPG key verification result") |
366 | |
367 | def set_acceptable_keys(self, command_line_input): |
368 | |
369 | === modified file 'breezy/help_topics/en/configuration.txt' |
370 | --- breezy/help_topics/en/configuration.txt 2017-06-12 23:25:04 +0000 |
371 | +++ breezy/help_topics/en/configuration.txt 2017-07-04 21:10:26 +0000 |
372 | @@ -498,16 +498,6 @@ |
373 | This section only applies to the branch at this directory and not |
374 | branches below it. |
375 | |
376 | -gpg_signing_command |
377 | -~~~~~~~~~~~~~~~~~~~ |
378 | - |
379 | -(Default: "gpg"). Which program should be used to sign and check revisions. |
380 | -For example:: |
381 | - |
382 | - gpg_signing_command = /usr/bin/gnpg |
383 | - |
384 | -The specified command must accept the options "--clearsign" and "-u <email>". |
385 | - |
386 | bzr_remote_path |
387 | ~~~~~~~~~~~~~~~ |
388 | |
389 | |
390 | === modified file 'breezy/tests/blackbox/test_log.py' |
391 | --- breezy/tests/blackbox/test_log.py 2017-06-22 01:52:28 +0000 |
392 | +++ breezy/tests/blackbox/test_log.py 2017-07-04 21:10:26 +0000 |
393 | @@ -17,6 +17,9 @@ |
394 | |
395 | """Black-box tests for brz log.""" |
396 | |
397 | +from __future__ import absolute_import |
398 | + |
399 | + |
400 | import os |
401 | |
402 | from breezy import ( |
403 | @@ -474,7 +477,7 @@ |
404 | class TestLogSignatures(TestLog): |
405 | |
406 | def test_log_with_signatures(self): |
407 | - self.requireFeature(features.gpgme) |
408 | + self.requireFeature(features.gpg) |
409 | |
410 | tree = self.make_linear_branch(format='dirstate-tags') |
411 | |
412 | @@ -482,7 +485,7 @@ |
413 | self.assertTrue('signature: no signature' in log) |
414 | |
415 | def test_log_without_signatures(self): |
416 | - self.requireFeature(features.gpgme) |
417 | + self.requireFeature(features.gpg) |
418 | |
419 | tree = self.make_linear_branch(format='dirstate-tags') |
420 | |
421 | |
422 | === modified file 'breezy/tests/features.py' |
423 | --- breezy/tests/features.py 2017-06-17 12:58:29 +0000 |
424 | +++ breezy/tests/features.py 2017-07-04 21:10:26 +0000 |
425 | @@ -17,6 +17,8 @@ |
426 | """A collection of commonly used 'Features' to optionally run tests. |
427 | """ |
428 | |
429 | +from __future__ import absolute_import |
430 | + |
431 | import os |
432 | import subprocess |
433 | import stat |
434 | @@ -373,7 +375,7 @@ |
435 | not_running_as_root = _NotRunningAsRoot() |
436 | |
437 | apport = ModuleAvailableFeature('apport') |
438 | -gpgme = ModuleAvailableFeature('gpgme') |
439 | +gpg = ModuleAvailableFeature('gpg') |
440 | lzma = ModuleAvailableFeature('lzma') |
441 | meliae = ModuleAvailableFeature('meliae.scanner') |
442 | paramiko = ModuleAvailableFeature('paramiko') |
443 | |
444 | === modified file 'breezy/tests/test_commit.py' |
445 | --- breezy/tests/test_commit.py 2017-06-18 22:23:02 +0000 |
446 | +++ breezy/tests/test_commit.py 2017-07-04 21:10:26 +0000 |
447 | @@ -33,7 +33,6 @@ |
448 | from ..errors import ( |
449 | PointlessCommit, |
450 | BzrError, |
451 | - SigningFailed, |
452 | LockContention, |
453 | ) |
454 | from . import ( |
455 | @@ -53,7 +52,6 @@ |
456 | |
457 | def __init__(self): |
458 | super(MustSignConfig, self).__init__(''' |
459 | -gpg_signing_command=cat - |
460 | create_signatures=always |
461 | ''') |
462 | |
463 | @@ -431,7 +429,6 @@ |
464 | # monkey patch gpg signing mechanism |
465 | breezy.gpg.GPGStrategy = breezy.gpg.LoopbackGPGStrategy |
466 | conf = config.MemoryStack(''' |
467 | -gpg_signing_command=cat - |
468 | create_signatures=always |
469 | ''') |
470 | commit.Commit(config_stack=conf).commit( |
471 | @@ -457,10 +454,9 @@ |
472 | # monkey patch gpg signing mechanism |
473 | breezy.gpg.GPGStrategy = breezy.gpg.DisabledGPGStrategy |
474 | conf = config.MemoryStack(''' |
475 | -gpg_signing_command=cat - |
476 | create_signatures=always |
477 | ''') |
478 | - self.assertRaises(SigningFailed, |
479 | + self.assertRaises(breezy.gpg.SigningFailed, |
480 | commit.Commit(config_stack=conf).commit, |
481 | message="base", |
482 | allow_pointless=True, |
483 | |
484 | === modified file 'breezy/tests/test_config.py' |
485 | --- breezy/tests/test_config.py 2017-06-12 23:25:04 +0000 |
486 | +++ breezy/tests/test_config.py 2017-07-04 21:10:26 +0000 |
487 | @@ -176,7 +176,6 @@ |
488 | email=Erik B\u00e5gfors <erik@bagfors.nu> |
489 | editor=vim |
490 | change_editor=vimdiff -of @new_path @old_path |
491 | -gpg_signing_command=gnome-gpg |
492 | gpg_signing_key=DD4D5088 |
493 | log_format=short |
494 | validate_signatures_in_log=true |
495 | @@ -232,7 +231,6 @@ |
496 | # test trailing / matching with no children |
497 | [/a/] |
498 | check_signatures=check-available |
499 | -gpg_signing_command=false |
500 | gpg_signing_key=default |
501 | user_local_option=local |
502 | # test trailing / matching |
503 | |
504 | === modified file 'breezy/tests/test_gpg.py' |
505 | --- breezy/tests/test_gpg.py 2017-05-22 00:56:52 +0000 |
506 | +++ breezy/tests/test_gpg.py 2017-07-04 21:10:26 +0000 |
507 | @@ -43,90 +43,17 @@ |
508 | if content is None: |
509 | content = ''' |
510 | gpg_signing_key=amy@example.com |
511 | -gpg_signing_command=false''' |
512 | +''' |
513 | super(FakeConfig, self).__init__(content) |
514 | |
515 | |
516 | -class TestCommandLine(tests.TestCase): |
517 | - |
518 | - def setUp(self): |
519 | - super(TestCommandLine, self).setUp() |
520 | - self.my_gpg = gpg.GPGStrategy(FakeConfig()) |
521 | - |
522 | - def test_signing_command_line(self): |
523 | - self.assertEqual(['false', '--clearsign', '-u', 'amy@example.com'], |
524 | - self.my_gpg._command_line()) |
525 | - |
526 | - def test_signing_command_line_from_default(self): |
527 | - # Using 'default' for gpg_signing_key will use the mail part of 'email' |
528 | - my_gpg = gpg.GPGStrategy(FakeConfig(''' |
529 | -email=Amy <amy@example.com> |
530 | -gpg_signing_key=default |
531 | -gpg_signing_command=false''')) |
532 | - self.assertEqual(['false', '--clearsign', '-u', 'amy@example.com'], |
533 | - my_gpg._command_line()) |
534 | - |
535 | - def test_signing_command_line_from_email(self): |
536 | - # Not setting gpg_signing_key will use the mail part of 'email' |
537 | - my_gpg = gpg.GPGStrategy(FakeConfig(''' |
538 | -email=Amy <amy@example.com> |
539 | -gpg_signing_command=false''')) |
540 | - self.assertEqual(['false', '--clearsign', '-u', 'amy@example.com'], |
541 | - my_gpg._command_line()) |
542 | - |
543 | - def test_checks_return_code(self): |
544 | - # This test needs a unix like platform - one with 'false' to run. |
545 | - # if you have one, please make this work :) |
546 | - self.assertRaises(errors.SigningFailed, self.my_gpg.sign, 'content') |
547 | - |
548 | - def assertProduces(self, content): |
549 | - # This needs a 'cat' command or similar to work. |
550 | - if sys.platform == 'win32': |
551 | - # Windows doesn't come with cat, and we don't require it |
552 | - # so lets try using python instead. |
553 | - # But stupid windows and line-ending conversions. |
554 | - # It is too much work to make sys.stdout be in binary mode. |
555 | - # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65443 |
556 | - self.my_gpg._command_line = lambda:[sys.executable, '-c', |
557 | - 'import sys; sys.stdout.write(sys.stdin.read())'] |
558 | - new_content = content.replace('\n', '\r\n') |
559 | - |
560 | - self.assertEqual(new_content, self.my_gpg.sign(content)) |
561 | - else: |
562 | - self.my_gpg._command_line = lambda:['cat', '-'] |
563 | - self.assertEqual(content, self.my_gpg.sign(content)) |
564 | - |
565 | - def test_returns_output(self): |
566 | - content = "some content\nwith newlines\n" |
567 | - self.assertProduces(content) |
568 | - |
569 | - def test_clears_progress(self): |
570 | - content = "some content\nwith newlines\n" |
571 | - old_clear_term = ui.ui_factory.clear_term |
572 | - clear_term_called = [] |
573 | - def clear_term(): |
574 | - old_clear_term() |
575 | - clear_term_called.append(True) |
576 | - ui.ui_factory.clear_term = clear_term |
577 | - try: |
578 | - self.assertProduces(content) |
579 | - finally: |
580 | - ui.ui_factory.clear_term = old_clear_term |
581 | - self.assertEqual([True], clear_term_called) |
582 | - |
583 | - def test_aborts_on_unicode(self): |
584 | - """You can't sign Unicode text; it must be encoded first.""" |
585 | - self.assertRaises(errors.BzrBadParameterUnicode, |
586 | - self.assertProduces, u'foo') |
587 | - |
588 | - |
589 | class TestVerify(TestCase): |
590 | |
591 | def import_keys(self): |
592 | - import gpgme |
593 | - context = gpgme.Context() |
594 | + import gpg |
595 | + context = gpg.Context() |
596 | |
597 | - key = BytesIO(b"""-----BEGIN PGP PUBLIC KEY BLOCK----- |
598 | + key = gpg.Data(b"""-----BEGIN PGP PUBLIC KEY BLOCK----- |
599 | Version: GnuPG v1.4.11 (GNU/Linux) |
600 | |
601 | mQENBE343IgBCADwzPW7kmKb2bjB+UU+1ER/ABMZspvtoZMPusUw7bk6coXHF/0W |
602 | @@ -158,7 +85,7 @@ |
603 | -----END PGP PUBLIC KEY BLOCK----- |
604 | """) |
605 | |
606 | - secret_key = BytesIO(b"""-----BEGIN PGP PRIVATE KEY BLOCK----- |
607 | + secret_key = gpg.Data(b"""-----BEGIN PGP PRIVATE KEY BLOCK----- |
608 | Version: GnuPG v1.4.11 (GNU/Linux) |
609 | |
610 | lQOYBE343IgBCADwzPW7kmKb2bjB+UU+1ER/ABMZspvtoZMPusUw7bk6coXHF/0W |
611 | @@ -217,7 +144,7 @@ |
612 | -----END PGP PRIVATE KEY BLOCK----- |
613 | """) |
614 | |
615 | - revoked_key = BytesIO(b"""-----BEGIN PGP PUBLIC KEY BLOCK----- |
616 | + revoked_key = gpg.Data(b"""-----BEGIN PGP PUBLIC KEY BLOCK----- |
617 | Version: GnuPG v1.4.11 (GNU/Linux) |
618 | |
619 | mI0ETjlW5gEEAOb/6P+TVM59E897wRtatxys2BhsHCXM4T7xjIiANfDwejDdifqh |
620 | @@ -242,7 +169,7 @@ |
621 | -----END PGP PUBLIC KEY BLOCK----- |
622 | """) |
623 | |
624 | - expired_key = BytesIO(b"""-----BEGIN PGP PUBLIC KEY BLOCK----- |
625 | + expired_key = gpg.Data(b"""-----BEGIN PGP PUBLIC KEY BLOCK----- |
626 | Version: GnuPG v1.4.11 (GNU/Linux) |
627 | |
628 | mI0ETjZ6PAEEALkR4GcFQidCCxV7pgQwQd5MZua0YO2l92fVqHX+PhnZ6egCLKdD |
629 | @@ -263,14 +190,14 @@ |
630 | =p0gt |
631 | -----END PGP PUBLIC KEY BLOCK----- |
632 | """) |
633 | - context.import_(key) |
634 | - context.import_(secret_key) |
635 | - context.import_(revoked_key) |
636 | - context.import_(expired_key) |
637 | + context.op_import(key) |
638 | + context.op_import(secret_key) |
639 | + context.op_import(revoked_key) |
640 | + context.op_import(expired_key) |
641 | |
642 | def test_verify_untrusted_but_accepted(self): |
643 | #untrusted by gpg but listed as acceptable_keys by user |
644 | - self.requireFeature(features.gpgme) |
645 | + self.requireFeature(features.gpg) |
646 | self.import_keys() |
647 | |
648 | content = """-----BEGIN PGP SIGNED MESSAGE----- |
649 | @@ -301,7 +228,7 @@ |
650 | plain)) |
651 | |
652 | def test_verify_unacceptable_key(self): |
653 | - self.requireFeature(features.gpgme) |
654 | + self.requireFeature(features.gpg) |
655 | self.import_keys() |
656 | |
657 | content = """-----BEGIN PGP SIGNED MESSAGE----- |
658 | @@ -332,7 +259,7 @@ |
659 | my_gpg.verify(content, plain)) |
660 | |
661 | def test_verify_valid_but_untrusted(self): |
662 | - self.requireFeature(features.gpgme) |
663 | + self.requireFeature(features.gpg) |
664 | self.import_keys() |
665 | |
666 | content = """-----BEGIN PGP SIGNED MESSAGE----- |
667 | @@ -362,7 +289,7 @@ |
668 | plain)) |
669 | |
670 | def test_verify_bad_testament(self): |
671 | - self.requireFeature(features.gpgme) |
672 | + self.requireFeature(features.gpg) |
673 | self.import_keys() |
674 | |
675 | content = """-----BEGIN PGP SIGNED MESSAGE----- |
676 | @@ -394,7 +321,7 @@ |
677 | |
678 | |
679 | def test_verify_revoked_signature(self): |
680 | - self.requireFeature(features.gpgme) |
681 | + self.requireFeature(features.gpg) |
682 | self.import_keys() |
683 | |
684 | content = """-----BEGIN PGP SIGNED MESSAGE----- |
685 | @@ -418,7 +345,7 @@ |
686 | plain)) |
687 | |
688 | def test_verify_invalid(self): |
689 | - self.requireFeature(features.gpgme) |
690 | + self.requireFeature(features.gpg) |
691 | self.import_keys() |
692 | content = """-----BEGIN PGP SIGNED MESSAGE----- |
693 | Hash: SHA1 |
694 | @@ -443,7 +370,7 @@ |
695 | my_gpg.verify(content, plain)) |
696 | |
697 | def test_verify_expired_but_valid(self): |
698 | - self.requireFeature(features.gpgme) |
699 | + self.requireFeature(features.gpg) |
700 | self.import_keys() |
701 | content = """-----BEGIN PGP SIGNED MESSAGE----- |
702 | Hash: SHA1 |
703 | @@ -470,7 +397,7 @@ |
704 | my_gpg.verify(content, plain)) |
705 | |
706 | def test_verify_unknown_key(self): |
707 | - self.requireFeature(features.gpgme) |
708 | + self.requireFeature(features.gpg) |
709 | self.import_keys() |
710 | content = """-----BEGIN PGP SIGNED MESSAGE----- |
711 | Hash: SHA1 |
712 | @@ -494,7 +421,7 @@ |
713 | my_gpg.verify(content, plain)) |
714 | |
715 | def test_set_acceptable_keys(self): |
716 | - self.requireFeature(features.gpgme) |
717 | + self.requireFeature(features.gpg) |
718 | self.import_keys() |
719 | my_gpg = gpg.GPGStrategy(FakeConfig()) |
720 | my_gpg.set_acceptable_keys("bazaar@example.com") |
721 | @@ -502,7 +429,7 @@ |
722 | [u'B5DEED5FCB15DAE6ECEF919587681B1EE3080E45']) |
723 | |
724 | def test_set_acceptable_keys_from_config(self): |
725 | - self.requireFeature(features.gpgme) |
726 | + self.requireFeature(features.gpg) |
727 | self.import_keys() |
728 | my_gpg = gpg.GPGStrategy(FakeConfig( |
729 | 'acceptable_keys=bazaar@example.com')) |
730 | @@ -511,7 +438,7 @@ |
731 | [u'B5DEED5FCB15DAE6ECEF919587681B1EE3080E45']) |
732 | |
733 | def test_set_acceptable_keys_unknown(self): |
734 | - self.requireFeature(features.gpgme) |
735 | + self.requireFeature(features.gpg) |
736 | my_gpg = gpg.GPGStrategy(FakeConfig()) |
737 | self.notes = [] |
738 | def note(*args): |
739 | @@ -526,10 +453,10 @@ |
740 | class TestDisabled(TestCase): |
741 | |
742 | def test_sign(self): |
743 | - self.assertRaises(errors.SigningFailed, |
744 | + self.assertRaises(gpg.SigningFailed, |
745 | gpg.DisabledGPGStrategy(None).sign, 'content') |
746 | |
747 | def test_verify(self): |
748 | - self.assertRaises(errors.SignatureVerificationFailed, |
749 | + self.assertRaises(gpg.SignatureVerificationFailed, |
750 | gpg.DisabledGPGStrategy(None).verify, 'content', |
751 | 'testament') |
752 | |
753 | === modified file 'breezy/tests/test_merge_directive.py' |
754 | --- breezy/tests/test_merge_directive.py 2017-06-10 00:17:06 +0000 |
755 | +++ breezy/tests/test_merge_directive.py 2017-07-04 21:10:26 +0000 |
756 | @@ -464,8 +464,6 @@ |
757 | class FakeBranch(object): |
758 | def get_config_stack(self): |
759 | return self |
760 | - def gpg_signing_command(self): |
761 | - return 'loopback' |
762 | md = self.make_merge_directive('example:', 'sha', time, timezone, |
763 | 'http://example.com', source_branch="http://example.org", |
764 | patch='booga', patch_type='diff') |
765 | |
766 | === modified file 'doc/en/release-notes/brz-3.0.txt' |
767 | --- doc/en/release-notes/brz-3.0.txt 2017-06-22 01:52:28 +0000 |
768 | +++ doc/en/release-notes/brz-3.0.txt 2017-07-04 21:10:26 +0000 |
769 | @@ -56,6 +56,13 @@ |
770 | This simplifies ``brz init --help``. |
771 | (Neil Martinsen-Burrell, #330494) |
772 | |
773 | + * ``python-gpg`` is now used for checking GPG signatures rather than |
774 | + ``python-gpgme``. (Jelmer Vernooij, #1702308) |
775 | + |
776 | + * ``python-gpg`` is now used for signing commits, rather than shelling |
777 | + out to the gnupg command. The ``gpg_signing_command`` option has been |
778 | + removed. (Jelmer Vernooij, #847388) |
779 | + |
780 | New Features |
781 | ************ |
782 |