Merge lp:~jelmer/brz/gpg-detached-sign into lp:~brz/brz/base
- gpg-detached-sign
- Merge into base
Proposed by
Jelmer Vernooij
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Jelmer Vernooij | ||||
Approved revision: | no longer in the source branch. | ||||
Merged at revision: | 6892 | ||||
Proposed branch: | lp:~jelmer/brz/gpg-detached-sign | ||||
Merge into: | lp:~brz/brz/base | ||||
Diff against target: |
442 lines (+72/-109) 8 files modified
breezy/bzr/remote.py (+5/-3) breezy/gpg.py (+38/-29) breezy/merge_directive.py (+1/-1) breezy/repository.py (+6/-5) breezy/tests/per_repository/test_signatures.py (+1/-1) breezy/tests/test_commit.py (+2/-1) breezy/tests/test_gpg.py (+13/-54) breezy/tests/test_log.py (+6/-15) |
||||
To merge this branch: | bzr merge lp:~jelmer/brz/gpg-detached-sign | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jelmer Vernooij | Approve | ||
Review via email: mp+341598@code.launchpad.net |
Commit message
Add support for passing mode argument to GPGSignature.sign.
Description of the change
Add support for passing mode argument to GPGSignature.sign.
This is necessary for brz-git, which needs to create detached signatures.
To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'breezy/bzr/remote.py' | |||
2 | --- breezy/bzr/remote.py 2017-11-23 20:02:55 +0000 | |||
3 | +++ breezy/bzr/remote.py 2018-03-18 20:19:21 +0000 | |||
4 | @@ -2692,7 +2692,7 @@ | |||
5 | 2692 | 2692 | ||
6 | 2693 | def store_revision_signature(self, gpg_strategy, plaintext, revision_id): | 2693 | def store_revision_signature(self, gpg_strategy, plaintext, revision_id): |
7 | 2694 | with self.lock_write(): | 2694 | with self.lock_write(): |
9 | 2695 | signature = gpg_strategy.sign(plaintext) | 2695 | signature = gpg_strategy.sign(plaintext, gpg.MODE_CLEAR) |
10 | 2696 | self.add_signature_text(revision_id, signature) | 2696 | self.add_signature_text(revision_id, signature) |
11 | 2697 | 2697 | ||
12 | 2698 | def add_signature_text(self, revision_id, signature): | 2698 | def add_signature_text(self, revision_id, signature): |
13 | @@ -2737,9 +2737,11 @@ | |||
14 | 2737 | signature = self.get_signature_text(revision_id) | 2737 | signature = self.get_signature_text(revision_id) |
15 | 2738 | 2738 | ||
16 | 2739 | testament = _mod_testament.Testament.from_revision(self, revision_id) | 2739 | testament = _mod_testament.Testament.from_revision(self, revision_id) |
17 | 2740 | plaintext = testament.as_short_text() | ||
18 | 2741 | 2740 | ||
20 | 2742 | return gpg_strategy.verify(signature, plaintext) | 2741 | (status, key, signed_plaintext) = gpg_strategy.verify(signature) |
21 | 2742 | if testament.as_short_text() != signed_plaintext: | ||
22 | 2743 | return gpg.SIGNATURE_NOT_VALID, None | ||
23 | 2744 | return (status, key) | ||
24 | 2743 | 2745 | ||
25 | 2744 | def item_keys_introduced_by(self, revision_ids, _files_pb=None): | 2746 | def item_keys_introduced_by(self, revision_ids, _files_pb=None): |
26 | 2745 | self._ensure_real() | 2747 | self._ensure_real() |
27 | 2746 | 2748 | ||
28 | === modified file 'breezy/gpg.py' | |||
29 | --- breezy/gpg.py 2018-02-24 15:50:23 +0000 | |||
30 | +++ breezy/gpg.py 2018-03-18 20:19:21 +0000 | |||
31 | @@ -52,6 +52,10 @@ | |||
32 | 52 | SIGNATURE_NOT_SIGNED = 3 | 52 | SIGNATURE_NOT_SIGNED = 3 |
33 | 53 | SIGNATURE_EXPIRED = 4 | 53 | SIGNATURE_EXPIRED = 4 |
34 | 54 | 54 | ||
35 | 55 | MODE_NORMAL = 0 | ||
36 | 56 | MODE_DETACH = 1 | ||
37 | 57 | MODE_CLEAR = 2 | ||
38 | 58 | |||
39 | 55 | 59 | ||
40 | 56 | class GpgNotInstalled(errors.DependencyNotPresent): | 60 | class GpgNotInstalled(errors.DependencyNotPresent): |
41 | 57 | 61 | ||
42 | @@ -123,10 +127,10 @@ | |||
43 | 123 | def __init__(self, ignored): | 127 | def __init__(self, ignored): |
44 | 124 | """Real strategies take a configuration.""" | 128 | """Real strategies take a configuration.""" |
45 | 125 | 129 | ||
47 | 126 | def sign(self, content): | 130 | def sign(self, content, mode): |
48 | 127 | raise SigningFailed('Signing is disabled.') | 131 | raise SigningFailed('Signing is disabled.') |
49 | 128 | 132 | ||
51 | 129 | def verify(self, content, testament): | 133 | def verify(self, signed_data, signature=None): |
52 | 130 | raise SignatureVerificationFailed('Signature verification is \ | 134 | raise SignatureVerificationFailed('Signature verification is \ |
53 | 131 | disabled.') | 135 | disabled.') |
54 | 132 | 136 | ||
55 | @@ -146,12 +150,14 @@ | |||
56 | 146 | def __init__(self, ignored): | 150 | def __init__(self, ignored): |
57 | 147 | """Real strategies take a configuration.""" | 151 | """Real strategies take a configuration.""" |
58 | 148 | 152 | ||
60 | 149 | def sign(self, content): | 153 | def sign(self, content, mode): |
61 | 150 | return ("-----BEGIN PSEUDO-SIGNED CONTENT-----\n" + content + | 154 | return ("-----BEGIN PSEUDO-SIGNED CONTENT-----\n" + content + |
62 | 151 | "-----END PSEUDO-SIGNED CONTENT-----\n") | 155 | "-----END PSEUDO-SIGNED CONTENT-----\n") |
63 | 152 | 156 | ||
66 | 153 | def verify(self, content, testament): | 157 | def verify(self, signed_data, signature=None): |
67 | 154 | return SIGNATURE_VALID, None | 158 | plain_text = signed_data.replace("-----BEGIN PSEUDO-SIGNED CONTENT-----\n", "") |
68 | 159 | plain_text = plain_text.replace("-----END PSEUDO-SIGNED CONTENT-----\n", "") | ||
69 | 160 | return SIGNATURE_VALID, None, plain_text | ||
70 | 155 | 161 | ||
71 | 156 | def set_acceptable_keys(self, command_line_input): | 162 | def set_acceptable_keys(self, command_line_input): |
72 | 157 | if command_line_input is not None: | 163 | if command_line_input is not None: |
73 | @@ -187,6 +193,7 @@ | |||
74 | 187 | try: | 193 | try: |
75 | 188 | import gpg | 194 | import gpg |
76 | 189 | self.context = gpg.Context() | 195 | self.context = gpg.Context() |
77 | 196 | self.context.armor = True | ||
78 | 190 | except ImportError as error: | 197 | except ImportError as error: |
79 | 191 | pass # can't use verify() | 198 | pass # can't use verify() |
80 | 192 | 199 | ||
81 | @@ -224,7 +231,7 @@ | |||
82 | 224 | except ImportError as error: | 231 | except ImportError as error: |
83 | 225 | return False | 232 | return False |
84 | 226 | 233 | ||
86 | 227 | def sign(self, content): | 234 | def sign(self, content, mode): |
87 | 228 | import gpg | 235 | import gpg |
88 | 229 | if isinstance(content, unicode): | 236 | if isinstance(content, unicode): |
89 | 230 | raise errors.BzrBadParameterUnicode('content') | 237 | raise errors.BzrBadParameterUnicode('content') |
90 | @@ -232,29 +239,34 @@ | |||
91 | 232 | plain_text = gpg.Data(content) | 239 | plain_text = gpg.Data(content) |
92 | 233 | try: | 240 | try: |
93 | 234 | output, result = self.context.sign( | 241 | output, result = self.context.sign( |
95 | 235 | plain_text, mode=gpg.constants.sig.mode.CLEAR) | 242 | plain_text, mode={ |
96 | 243 | MODE_DETACH: gpg.constants.sig.mode.DETACH, | ||
97 | 244 | MODE_CLEAR: gpg.constants.sig.mode.CLEAR, | ||
98 | 245 | MODE_NORMAL: gpg.constants.sig.mode.NORMAL, | ||
99 | 246 | }[mode]) | ||
100 | 236 | except gpg.errors.GPGMEError as error: | 247 | except gpg.errors.GPGMEError as error: |
101 | 237 | raise SigningFailed(str(error)) | 248 | raise SigningFailed(str(error)) |
102 | 238 | 249 | ||
103 | 239 | return output | 250 | return output |
104 | 240 | 251 | ||
106 | 241 | def verify(self, content, testament): | 252 | def verify(self, signed_data, signature=None): |
107 | 242 | """Check content has a valid signature. | 253 | """Check content has a valid signature. |
108 | 243 | 254 | ||
111 | 244 | :param content: the commit signature | 255 | :param signed_data; Signed data |
112 | 245 | :param testament: the valid testament string for the commit | 256 | :param signature: optional signature (if detached) |
113 | 246 | 257 | ||
115 | 247 | :return: SIGNATURE_VALID or a failed SIGNATURE_ value, key uid if valid | 258 | :return: SIGNATURE_VALID or a failed SIGNATURE_ value, key uid if valid, plain text |
116 | 248 | """ | 259 | """ |
117 | 249 | try: | 260 | try: |
118 | 250 | import gpg | 261 | import gpg |
119 | 251 | except ImportError as error: | 262 | except ImportError as error: |
120 | 252 | raise errors.GpgNotInstalled(error) | 263 | raise errors.GpgNotInstalled(error) |
121 | 253 | 264 | ||
124 | 254 | signature = gpg.Data(content) | 265 | signed_data = gpg.Data(signed_data) |
125 | 255 | sink = gpg.Data() | 266 | if signature: |
126 | 267 | signature = gpg.Data(signature) | ||
127 | 256 | try: | 268 | try: |
129 | 257 | plain_output, result = self.context.verify(signature) | 269 | plain_output, result = self.context.verify(signed_data, signature) |
130 | 258 | except gpg.errors.BadSignatures as error: | 270 | except gpg.errors.BadSignatures as error: |
131 | 259 | fingerprint = error.result.signatures[0].fpr | 271 | fingerprint = error.result.signatures[0].fpr |
132 | 260 | if error.result.signatures[0].summary & gpg.constants.SIGSUM_KEY_EXPIRED: | 272 | if error.result.signatures[0].summary & gpg.constants.SIGSUM_KEY_EXPIRED: |
133 | @@ -262,35 +274,32 @@ | |||
134 | 262 | if expires > error.result.signatures[0].timestamp: | 274 | if expires > error.result.signatures[0].timestamp: |
135 | 263 | # The expired key was not expired at time of signing. | 275 | # The expired key was not expired at time of signing. |
136 | 264 | # test_verify_expired_but_valid() | 276 | # test_verify_expired_but_valid() |
138 | 265 | return SIGNATURE_EXPIRED, fingerprint[-8:] | 277 | return SIGNATURE_EXPIRED, fingerprint[-8:], None |
139 | 266 | else: | 278 | else: |
140 | 267 | # I can't work out how to create a test where the signature | 279 | # I can't work out how to create a test where the signature |
141 | 268 | # was expired at the time of signing. | 280 | # was expired at the time of signing. |
143 | 269 | return SIGNATURE_NOT_VALID, None | 281 | return SIGNATURE_NOT_VALID, None, None |
144 | 270 | 282 | ||
145 | 271 | # GPG does not know this key. | 283 | # GPG does not know this key. |
146 | 272 | # test_verify_unknown_key() | 284 | # test_verify_unknown_key() |
147 | 273 | if error.result.signatures[0].summary & gpg.constants.SIGSUM_KEY_MISSING: | 285 | if error.result.signatures[0].summary & gpg.constants.SIGSUM_KEY_MISSING: |
149 | 274 | return SIGNATURE_KEY_MISSING, fingerprint[-8:] | 286 | return SIGNATURE_KEY_MISSING, fingerprint[-8:], None |
150 | 275 | 287 | ||
152 | 276 | return SIGNATURE_NOT_VALID, None | 288 | return SIGNATURE_NOT_VALID, None, None |
153 | 277 | except gpg.errors.GPGMEError as error: | 289 | except gpg.errors.GPGMEError as error: |
155 | 278 | raise SignatureVerificationFailed(error[2]) | 290 | raise SignatureVerificationFailed(error) |
156 | 279 | 291 | ||
157 | 280 | # No result if input is invalid. | 292 | # No result if input is invalid. |
158 | 281 | # test_verify_invalid() | 293 | # test_verify_invalid() |
159 | 282 | if len(result.signatures) == 0: | 294 | if len(result.signatures) == 0: |
161 | 283 | return SIGNATURE_NOT_VALID, None | 295 | return SIGNATURE_NOT_VALID, None, plain_output |
162 | 296 | |||
163 | 284 | # User has specified a list of acceptable keys, check our result is in | 297 | # User has specified a list of acceptable keys, check our result is in |
164 | 285 | # it. test_verify_unacceptable_key() | 298 | # it. test_verify_unacceptable_key() |
165 | 286 | fingerprint = result.signatures[0].fpr | 299 | fingerprint = result.signatures[0].fpr |
166 | 287 | if self.acceptable_keys is not None: | 300 | if self.acceptable_keys is not None: |
167 | 288 | if not fingerprint in self.acceptable_keys: | 301 | if not fingerprint in self.acceptable_keys: |
173 | 289 | return SIGNATURE_KEY_MISSING, fingerprint[-8:] | 302 | return SIGNATURE_KEY_MISSING, fingerprint[-8:], plain_output |
169 | 290 | # Check the signature actually matches the testament. | ||
170 | 291 | # test_verify_bad_testament() | ||
171 | 292 | if testament != plain_output: | ||
172 | 293 | return SIGNATURE_NOT_VALID, None | ||
174 | 294 | # Yay gpg set the valid bit. | 303 | # Yay gpg set the valid bit. |
175 | 295 | # Can't write a test for this one as you can't set a key to be | 304 | # Can't write a test for this one as you can't set a key to be |
176 | 296 | # trusted using gpg. | 305 | # trusted using gpg. |
177 | @@ -298,20 +307,20 @@ | |||
178 | 298 | key = self.context.get_key(fingerprint) | 307 | key = self.context.get_key(fingerprint) |
179 | 299 | name = key.uids[0].name | 308 | name = key.uids[0].name |
180 | 300 | email = key.uids[0].email | 309 | email = key.uids[0].email |
182 | 301 | return SIGNATURE_VALID, name + " <" + email + ">" | 310 | return SIGNATURE_VALID, name.decode('utf-8') + u" <" + email.decode('utf-8') + u">", plain_output |
183 | 302 | # Sigsum_red indicates a problem, unfortunatly I have not been able | 311 | # Sigsum_red indicates a problem, unfortunatly I have not been able |
184 | 303 | # to write any tests which actually set this. | 312 | # to write any tests which actually set this. |
185 | 304 | if result.signatures[0].summary & gpg.constants.SIGSUM_RED: | 313 | if result.signatures[0].summary & gpg.constants.SIGSUM_RED: |
187 | 305 | return SIGNATURE_NOT_VALID, None | 314 | return SIGNATURE_NOT_VALID, None, plain_output |
188 | 306 | # Summary isn't set if sig is valid but key is untrusted but if user | 315 | # Summary isn't set if sig is valid but key is untrusted but if user |
189 | 307 | # has explicity set the key as acceptable we can validate it. | 316 | # has explicity set the key as acceptable we can validate it. |
190 | 308 | if result.signatures[0].summary == 0 and self.acceptable_keys is not None: | 317 | if result.signatures[0].summary == 0 and self.acceptable_keys is not None: |
191 | 309 | if fingerprint in self.acceptable_keys: | 318 | if fingerprint in self.acceptable_keys: |
192 | 310 | # test_verify_untrusted_but_accepted() | 319 | # test_verify_untrusted_but_accepted() |
194 | 311 | return SIGNATURE_VALID, None | 320 | return SIGNATURE_VALID, None, plain_output |
195 | 312 | # test_verify_valid_but_untrusted() | 321 | # test_verify_valid_but_untrusted() |
196 | 313 | if result.signatures[0].summary == 0 and self.acceptable_keys is None: | 322 | if result.signatures[0].summary == 0 and self.acceptable_keys is None: |
198 | 314 | return SIGNATURE_NOT_VALID, None | 323 | return SIGNATURE_NOT_VALID, None, plain_output |
199 | 315 | # Other error types such as revoked keys should (I think) be caught by | 324 | # Other error types such as revoked keys should (I think) be caught by |
200 | 316 | # SIGSUM_RED so anything else means something is buggy. | 325 | # SIGSUM_RED so anything else means something is buggy. |
201 | 317 | raise SignatureVerificationFailed( | 326 | raise SignatureVerificationFailed( |
202 | 318 | 327 | ||
203 | === modified file 'breezy/merge_directive.py' | |||
204 | --- breezy/merge_directive.py 2017-10-27 00:18:42 +0000 | |||
205 | +++ breezy/merge_directive.py 2018-03-18 20:19:21 +0000 | |||
206 | @@ -251,7 +251,7 @@ | |||
207 | 251 | :return: a string | 251 | :return: a string |
208 | 252 | """ | 252 | """ |
209 | 253 | my_gpg = gpg.GPGStrategy(branch.get_config_stack()) | 253 | my_gpg = gpg.GPGStrategy(branch.get_config_stack()) |
211 | 254 | return my_gpg.sign(''.join(self.to_lines())) | 254 | return my_gpg.sign(''.join(self.to_lines()), gpg.MODE_CLEAR) |
212 | 255 | 255 | ||
213 | 256 | def to_email(self, mail_to, branch, sign=False): | 256 | def to_email(self, mail_to, branch, sign=False): |
214 | 257 | """Serialize as an email message. | 257 | """Serialize as an email message. |
215 | 258 | 258 | ||
216 | === modified file 'breezy/repository.py' | |||
217 | --- breezy/repository.py 2018-02-24 15:50:23 +0000 | |||
218 | +++ breezy/repository.py 2018-03-18 20:19:21 +0000 | |||
219 | @@ -887,7 +887,7 @@ | |||
220 | 887 | 887 | ||
221 | 888 | def store_revision_signature(self, gpg_strategy, plaintext, revision_id): | 888 | def store_revision_signature(self, gpg_strategy, plaintext, revision_id): |
222 | 889 | with self.lock_write(): | 889 | with self.lock_write(): |
224 | 890 | signature = gpg_strategy.sign(plaintext) | 890 | signature = gpg_strategy.sign(plaintext, gpg.MODE_CLEAR) |
225 | 891 | self.add_signature_text(revision_id, signature) | 891 | self.add_signature_text(revision_id, signature) |
226 | 892 | 892 | ||
227 | 893 | def add_signature_text(self, revision_id, signature): | 893 | def add_signature_text(self, revision_id, signature): |
228 | @@ -1104,11 +1104,12 @@ | |||
229 | 1104 | return gpg.SIGNATURE_NOT_SIGNED, None | 1104 | return gpg.SIGNATURE_NOT_SIGNED, None |
230 | 1105 | signature = self.get_signature_text(revision_id) | 1105 | signature = self.get_signature_text(revision_id) |
231 | 1106 | 1106 | ||
235 | 1107 | testament = _mod_testament.Testament.from_revision( | 1107 | testament = _mod_testament.Testament.from_revision(self, revision_id) |
233 | 1108 | self, revision_id) | ||
234 | 1109 | plaintext = testament.as_short_text() | ||
236 | 1110 | 1108 | ||
238 | 1111 | return gpg_strategy.verify(signature, plaintext) | 1109 | (status, key, signed_plaintext) = gpg_strategy.verify(signature) |
239 | 1110 | if testament.as_short_text() != signed_plaintext: | ||
240 | 1111 | return gpg.SIGNATURE_NOT_VALID, None | ||
241 | 1112 | return (status, key) | ||
242 | 1112 | 1113 | ||
243 | 1113 | def verify_revision_signatures(self, revision_ids, gpg_strategy): | 1114 | def verify_revision_signatures(self, revision_ids, gpg_strategy): |
244 | 1114 | """Verify revision signatures for a number of revisions. | 1115 | """Verify revision signatures for a number of revisions. |
245 | 1115 | 1116 | ||
246 | === modified file 'breezy/tests/per_repository/test_signatures.py' | |||
247 | --- breezy/tests/per_repository/test_signatures.py 2017-08-07 19:09:47 +0000 | |||
248 | +++ breezy/tests/per_repository/test_signatures.py 2018-03-18 20:19:21 +0000 | |||
249 | @@ -123,7 +123,7 @@ | |||
250 | 123 | '-----END PSEUDO-SIGNED CONTENT-----\n', | 123 | '-----END PSEUDO-SIGNED CONTENT-----\n', |
251 | 124 | repo.get_signature_text(a)) | 124 | repo.get_signature_text(a)) |
252 | 125 | self.assertEqual( | 125 | self.assertEqual( |
254 | 126 | (gpg.SIGNATURE_VALID, None, ), | 126 | (gpg.SIGNATURE_VALID, None), |
255 | 127 | repo.verify_revision_signature(a, strategy)) | 127 | repo.verify_revision_signature(a, strategy)) |
256 | 128 | 128 | ||
257 | 129 | def test_verify_revision_signatures(self): | 129 | def test_verify_revision_signatures(self): |
258 | 130 | 130 | ||
259 | === modified file 'breezy/tests/test_commit.py' | |||
260 | --- breezy/tests/test_commit.py 2018-02-15 19:38:33 +0000 | |||
261 | +++ breezy/tests/test_commit.py 2018-03-18 20:19:21 +0000 | |||
262 | @@ -435,7 +435,8 @@ | |||
263 | 435 | message="base", allow_pointless=True, rev_id='B', | 435 | message="base", allow_pointless=True, rev_id='B', |
264 | 436 | working_tree=wt) | 436 | working_tree=wt) |
265 | 437 | def sign(text): | 437 | def sign(text): |
267 | 438 | return breezy.gpg.LoopbackGPGStrategy(None).sign(text) | 438 | return breezy.gpg.LoopbackGPGStrategy(None).sign( |
268 | 439 | text, breezy.gpg.MODE_CLEAR) | ||
269 | 439 | self.assertEqual(sign(Testament.from_revision(branch.repository, | 440 | self.assertEqual(sign(Testament.from_revision(branch.repository, |
270 | 440 | 'B').as_short_text()), | 441 | 'B').as_short_text()), |
271 | 441 | branch.repository.get_signature_text('B')) | 442 | branch.repository.get_signature_text('B')) |
272 | 442 | 443 | ||
273 | === modified file 'breezy/tests/test_gpg.py' | |||
274 | --- breezy/tests/test_gpg.py 2017-07-04 20:03:11 +0000 | |||
275 | +++ breezy/tests/test_gpg.py 2018-03-18 20:19:21 +0000 | |||
276 | @@ -224,8 +224,7 @@ | |||
277 | 224 | """ | 224 | """ |
278 | 225 | my_gpg = gpg.GPGStrategy(FakeConfig()) | 225 | my_gpg = gpg.GPGStrategy(FakeConfig()) |
279 | 226 | my_gpg.set_acceptable_keys("bazaar@example.com") | 226 | my_gpg.set_acceptable_keys("bazaar@example.com") |
282 | 227 | self.assertEqual((gpg.SIGNATURE_VALID, None), my_gpg.verify(content, | 227 | self.assertEqual((gpg.SIGNATURE_VALID, None, plain), my_gpg.verify(content)) |
281 | 228 | plain)) | ||
283 | 229 | 228 | ||
284 | 230 | def test_verify_unacceptable_key(self): | 229 | def test_verify_unacceptable_key(self): |
285 | 231 | self.requireFeature(features.gpg) | 230 | self.requireFeature(features.gpg) |
286 | @@ -255,8 +254,8 @@ | |||
287 | 255 | """ | 254 | """ |
288 | 256 | my_gpg = gpg.GPGStrategy(FakeConfig()) | 255 | my_gpg = gpg.GPGStrategy(FakeConfig()) |
289 | 257 | my_gpg.set_acceptable_keys("foo@example.com") | 256 | my_gpg.set_acceptable_keys("foo@example.com") |
292 | 258 | self.assertEqual((gpg.SIGNATURE_KEY_MISSING, u'E3080E45'), | 257 | self.assertEqual((gpg.SIGNATURE_KEY_MISSING, u'E3080E45', plain), |
293 | 259 | my_gpg.verify(content, plain)) | 258 | my_gpg.verify(content)) |
294 | 260 | 259 | ||
295 | 261 | def test_verify_valid_but_untrusted(self): | 260 | def test_verify_valid_but_untrusted(self): |
296 | 262 | self.requireFeature(features.gpg) | 261 | self.requireFeature(features.gpg) |
297 | @@ -285,40 +284,7 @@ | |||
298 | 285 | sha1: 6411f9bdf6571200357140c9ce7c0f50106ac9a4 | 284 | sha1: 6411f9bdf6571200357140c9ce7c0f50106ac9a4 |
299 | 286 | """ | 285 | """ |
300 | 287 | my_gpg = gpg.GPGStrategy(FakeConfig()) | 286 | my_gpg = gpg.GPGStrategy(FakeConfig()) |
335 | 288 | self.assertEqual((gpg.SIGNATURE_NOT_VALID, None), my_gpg.verify(content, | 287 | self.assertEqual((gpg.SIGNATURE_NOT_VALID, None, plain), my_gpg.verify(content)) |
302 | 289 | plain)) | ||
303 | 290 | |||
304 | 291 | def test_verify_bad_testament(self): | ||
305 | 292 | self.requireFeature(features.gpg) | ||
306 | 293 | self.import_keys() | ||
307 | 294 | |||
308 | 295 | content = """-----BEGIN PGP SIGNED MESSAGE----- | ||
309 | 296 | Hash: SHA1 | ||
310 | 297 | |||
311 | 298 | bazaar-ng testament short form 1 | ||
312 | 299 | revision-id: amy@example.com-20110527185938-hluafawphszb8dl1 | ||
313 | 300 | sha1: 6411f9bdf6571200357140c9ce7c0f50106ac9a4 | ||
314 | 301 | -----BEGIN PGP SIGNATURE----- | ||
315 | 302 | Version: GnuPG v1.4.11 (GNU/Linux) | ||
316 | 303 | |||
317 | 304 | iQEcBAEBAgAGBQJN+ekFAAoJEIdoGx7jCA5FGtEH/i+XxJRvqU6wdBtLVrGBMAGk | ||
318 | 305 | FZ5VP+KyXYtymSbgSstj/vM12NeMIeFs3xGnNnYuX1MIcY6We5TKtCH0epY6ym5+ | ||
319 | 306 | 6g2Q2QpQ5/sT2d0mWzR0K4uVngmxVQaXTdk5PdZ40O7ULeDLW6CxzxMHyUL1rsIx | ||
320 | 307 | 7UBUTBh1O/1n3ZfD99hUkm3hVcnsN90uTKH59zV9NWwArU0cug60+5eDKJhSJDbG | ||
321 | 308 | rIwlqbFAjDZ7L/48e+IaYIJwBZFzMBpJKdCxzALLtauMf+KK8hGiL2hrRbWm7ty6 | ||
322 | 309 | NgxfkMYOB4rDPdSstT35N+5uBG3n/UzjxHssi0svMfVETYYX40y57dm2eZQXFp8= | ||
323 | 310 | =iwsn | ||
324 | 311 | -----END PGP SIGNATURE----- | ||
325 | 312 | """ | ||
326 | 313 | plain = """bazaar-ng testament short form 1 | ||
327 | 314 | revision-id: doctor@example.com-20110527185938-hluafawphszb8dl1 | ||
328 | 315 | sha1: 6411f9bdf6571200357140c9ce7c0f50106ac9a4 | ||
329 | 316 | """ | ||
330 | 317 | my_gpg = gpg.GPGStrategy(FakeConfig()) | ||
331 | 318 | my_gpg.set_acceptable_keys("bazaar@example.com") | ||
332 | 319 | self.assertEqual((gpg.SIGNATURE_NOT_VALID, None), my_gpg.verify(content, | ||
333 | 320 | plain)) | ||
334 | 321 | |||
336 | 322 | 288 | ||
337 | 323 | def test_verify_revoked_signature(self): | 289 | def test_verify_revoked_signature(self): |
338 | 324 | self.requireFeature(features.gpg) | 290 | self.requireFeature(features.gpg) |
339 | @@ -341,8 +307,7 @@ | |||
340 | 341 | plain = """asdf\n""" | 307 | plain = """asdf\n""" |
341 | 342 | my_gpg = gpg.GPGStrategy(FakeConfig()) | 308 | my_gpg = gpg.GPGStrategy(FakeConfig()) |
342 | 343 | my_gpg.set_acceptable_keys("test@example.com") | 309 | my_gpg.set_acceptable_keys("test@example.com") |
345 | 344 | self.assertEqual((gpg.SIGNATURE_NOT_VALID, None), my_gpg.verify(content, | 310 | self.assertEqual((gpg.SIGNATURE_NOT_VALID, None, None), my_gpg.verify(content)) |
344 | 345 | plain)) | ||
346 | 346 | 311 | ||
347 | 347 | def test_verify_invalid(self): | 312 | def test_verify_invalid(self): |
348 | 348 | self.requireFeature(features.gpg) | 313 | self.requireFeature(features.gpg) |
349 | @@ -366,8 +331,8 @@ | |||
350 | 366 | sha1: 6411f9bdf6571200357140c9ce7c0f50106ac9a4 | 331 | sha1: 6411f9bdf6571200357140c9ce7c0f50106ac9a4 |
351 | 367 | """ | 332 | """ |
352 | 368 | my_gpg = gpg.GPGStrategy(FakeConfig()) | 333 | my_gpg = gpg.GPGStrategy(FakeConfig()) |
355 | 369 | self.assertEqual((gpg.SIGNATURE_NOT_VALID, None), | 334 | self.assertEqual((gpg.SIGNATURE_NOT_VALID, None, plain), |
356 | 370 | my_gpg.verify(content, plain)) | 335 | my_gpg.verify(content)) |
357 | 371 | 336 | ||
358 | 372 | def test_verify_expired_but_valid(self): | 337 | def test_verify_expired_but_valid(self): |
359 | 373 | self.requireFeature(features.gpg) | 338 | self.requireFeature(features.gpg) |
360 | @@ -388,13 +353,9 @@ | |||
361 | 388 | =uHen | 353 | =uHen |
362 | 389 | -----END PGP SIGNATURE----- | 354 | -----END PGP SIGNATURE----- |
363 | 390 | """ | 355 | """ |
364 | 391 | plain = """bazaar-ng testament short form 1 | ||
365 | 392 | revision-id: test@example.com-20110801100657-f1dr1nompeex723z | ||
366 | 393 | sha1: 59ab434be4c2d5d646dee84f514aa09e1b72feeb | ||
367 | 394 | """ | ||
368 | 395 | my_gpg = gpg.GPGStrategy(FakeConfig()) | 356 | my_gpg = gpg.GPGStrategy(FakeConfig()) |
371 | 396 | self.assertEqual((gpg.SIGNATURE_EXPIRED, u'4F8D1513'), | 357 | self.assertEqual((gpg.SIGNATURE_EXPIRED, u'4F8D1513', None), |
372 | 397 | my_gpg.verify(content, plain)) | 358 | my_gpg.verify(content)) |
373 | 398 | 359 | ||
374 | 399 | def test_verify_unknown_key(self): | 360 | def test_verify_unknown_key(self): |
375 | 400 | self.requireFeature(features.gpg) | 361 | self.requireFeature(features.gpg) |
376 | @@ -415,10 +376,9 @@ | |||
377 | 415 | =RNR5 | 376 | =RNR5 |
378 | 416 | -----END PGP SIGNATURE----- | 377 | -----END PGP SIGNATURE----- |
379 | 417 | """ | 378 | """ |
380 | 418 | plain = "asdf\n" | ||
381 | 419 | my_gpg = gpg.GPGStrategy(FakeConfig()) | 379 | my_gpg = gpg.GPGStrategy(FakeConfig()) |
384 | 420 | self.assertEqual((gpg.SIGNATURE_KEY_MISSING, u'5D51E56F'), | 380 | self.assertEqual((gpg.SIGNATURE_KEY_MISSING, u'5D51E56F', None), |
385 | 421 | my_gpg.verify(content, plain)) | 381 | my_gpg.verify(content)) |
386 | 422 | 382 | ||
387 | 423 | def test_set_acceptable_keys(self): | 383 | def test_set_acceptable_keys(self): |
388 | 424 | self.requireFeature(features.gpg) | 384 | self.requireFeature(features.gpg) |
389 | @@ -454,9 +414,8 @@ | |||
390 | 454 | 414 | ||
391 | 455 | def test_sign(self): | 415 | def test_sign(self): |
392 | 456 | self.assertRaises(gpg.SigningFailed, | 416 | self.assertRaises(gpg.SigningFailed, |
394 | 457 | gpg.DisabledGPGStrategy(None).sign, 'content') | 417 | gpg.DisabledGPGStrategy(None).sign, 'content', gpg.MODE_CLEAR) |
395 | 458 | 418 | ||
396 | 459 | def test_verify(self): | 419 | def test_verify(self): |
397 | 460 | self.assertRaises(gpg.SignatureVerificationFailed, | 420 | self.assertRaises(gpg.SignatureVerificationFailed, |
400 | 461 | gpg.DisabledGPGStrategy(None).verify, 'content', | 421 | gpg.DisabledGPGStrategy(None).verify, 'content') |
399 | 462 | 'testament') | ||
401 | 463 | 422 | ||
402 | === modified file 'breezy/tests/test_log.py' | |||
403 | --- breezy/tests/test_log.py 2017-12-04 00:25:02 +0000 | |||
404 | +++ breezy/tests/test_log.py 2018-03-18 20:19:21 +0000 | |||
405 | @@ -317,31 +317,22 @@ | |||
406 | 317 | 317 | ||
407 | 318 | 318 | ||
408 | 319 | class TestFormatSignatureValidity(tests.TestCaseWithTransport): | 319 | class TestFormatSignatureValidity(tests.TestCaseWithTransport): |
419 | 320 | class UTFLoopbackGPGStrategy(gpg.LoopbackGPGStrategy): | 320 | |
420 | 321 | def verify(self, content, testament): | 321 | def verify_revision_signature(self, revid, gpg_strategy): |
421 | 322 | return (gpg.SIGNATURE_VALID, | 322 | return (gpg.SIGNATURE_VALID, |
422 | 323 | u'UTF8 Test \xa1\xb1\xc1\xd1\xe1\xf1 <jrandom@example.com>') | 323 | u'UTF8 Test \xa1\xb1\xc1\xd1\xe1\xf1 <jrandom@example.com>') |
413 | 324 | |||
414 | 325 | def has_signature_for_revision_id(self, revision_id): | ||
415 | 326 | return True | ||
416 | 327 | |||
417 | 328 | def get_signature_text(self, revision_id): | ||
418 | 329 | return '' | ||
423 | 330 | 324 | ||
424 | 331 | def test_format_signature_validity_utf(self): | 325 | def test_format_signature_validity_utf(self): |
425 | 332 | """Check that GPG signatures containing UTF-8 names are formatted | 326 | """Check that GPG signatures containing UTF-8 names are formatted |
426 | 333 | correctly.""" | 327 | correctly.""" |
427 | 334 | # Monkey patch to use our UTF-8 generating GPGStrategy | ||
428 | 335 | self.overrideAttr(gpg, 'GPGStrategy', self.UTFLoopbackGPGStrategy) | ||
429 | 336 | wt = self.make_branch_and_tree('.') | 328 | wt = self.make_branch_and_tree('.') |
430 | 337 | revid = wt.commit('empty commit') | 329 | revid = wt.commit('empty commit') |
431 | 338 | repo = wt.branch.repository | 330 | repo = wt.branch.repository |
432 | 339 | # Monkey patch out checking if this rev is actually signed, since we | 331 | # Monkey patch out checking if this rev is actually signed, since we |
433 | 340 | # can't sign it without a heavier TestCase and LoopbackGPGStrategy | 332 | # can't sign it without a heavier TestCase and LoopbackGPGStrategy |
434 | 341 | # doesn't care anyways. | 333 | # doesn't care anyways. |
438 | 342 | self.overrideAttr(repo, 'has_signature_for_revision_id', | 334 | self.overrideAttr(repo, 'verify_revision_signature', |
439 | 343 | self.has_signature_for_revision_id) | 335 | self.verify_revision_signature) |
437 | 344 | self.overrideAttr(repo, 'get_signature_text', self.get_signature_text) | ||
440 | 345 | out = log.format_signature_validity(revid, wt.branch) | 336 | out = log.format_signature_validity(revid, wt.branch) |
441 | 346 | self.assertEqual( | 337 | self.assertEqual( |
442 | 347 | u'valid signature from UTF8 Test \xa1\xb1\xc1\xd1\xe1\xf1 <jrandom@example.com>', | 338 | u'valid signature from UTF8 Test \xa1\xb1\xc1\xd1\xe1\xf1 <jrandom@example.com>', |