]>
Commit | Line | Data |
---|---|---|
a85b377d JH |
1 | #!/bin/sh |
2 | ||
3 | test_description='signed push' | |
4 | ||
3ac8f630 | 5 | GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main |
334afbc7 JS |
6 | export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME |
7 | ||
b8849e23 | 8 | TEST_PASSES_SANITIZE_LEAK=true |
a85b377d JH |
9 | . ./test-lib.sh |
10 | . "$TEST_DIRECTORY"/lib-gpg.sh | |
11 | ||
12 | prepare_dst () { | |
13 | rm -fr dst && | |
14 | test_create_repo dst && | |
15 | ||
3ac8f630 | 16 | git push dst main:noop main:ff main:noff |
a85b377d JH |
17 | } |
18 | ||
19 | test_expect_success setup ' | |
3ac8f630 | 20 | # main, ff and noff branches pointing at the same commit |
a85b377d JH |
21 | test_tick && |
22 | git commit --allow-empty -m initial && | |
23 | ||
24 | git checkout -b noop && | |
25 | git checkout -b ff && | |
26 | git checkout -b noff && | |
27 | ||
28 | # noop stays the same, ff advances, noff rewrites | |
29 | test_tick && | |
30 | git commit --allow-empty --amend -m rewritten && | |
31 | git checkout ff && | |
32 | ||
33 | test_tick && | |
34 | git commit --allow-empty -m second | |
35 | ' | |
36 | ||
37 | test_expect_success 'unsigned push does not send push certificate' ' | |
38 | prepare_dst && | |
bef805b7 | 39 | test_hook -C dst post-receive <<-\EOF && |
a85b377d JH |
40 | # discard the update list |
41 | cat >/dev/null | |
42 | # record the push certificate | |
43 | if test -n "${GIT_PUSH_CERT-}" | |
44 | then | |
45 | git cat-file blob $GIT_PUSH_CERT >../push-cert | |
46 | fi | |
47 | EOF | |
48 | ||
49 | git push dst noop ff +noff && | |
50 | ! test -f dst/push-cert | |
51 | ' | |
52 | ||
53 | test_expect_success 'talking with a receiver without push certificate support' ' | |
54 | prepare_dst && | |
bef805b7 | 55 | test_hook -C dst post-receive <<-\EOF && |
a85b377d JH |
56 | # discard the update list |
57 | cat >/dev/null | |
58 | # record the push certificate | |
59 | if test -n "${GIT_PUSH_CERT-}" | |
60 | then | |
61 | git cat-file blob $GIT_PUSH_CERT >../push-cert | |
62 | fi | |
63 | EOF | |
64 | ||
65 | git push dst noop ff +noff && | |
66 | ! test -f dst/push-cert | |
67 | ' | |
68 | ||
69 | test_expect_success 'push --signed fails with a receiver without push certificate support' ' | |
70 | prepare_dst && | |
a85b377d | 71 | test_must_fail git push --signed dst noop ff +noff 2>err && |
6789275d | 72 | test_grep "the receiving end does not support" err |
a85b377d JH |
73 | ' |
74 | ||
46667418 | 75 | test_expect_success 'push --signed=1 is accepted' ' |
c4b71a77 | 76 | prepare_dst && |
c4b71a77 | 77 | test_must_fail git push --signed=1 dst noop ff +noff 2>err && |
6789275d | 78 | test_grep "the receiving end does not support" err |
c4b71a77 MÅ |
79 | ' |
80 | ||
20a7558f JH |
81 | test_expect_success GPG 'no certificate for a signed push with no update' ' |
82 | prepare_dst && | |
bef805b7 | 83 | test_hook -C dst post-receive <<-\EOF && |
20a7558f JH |
84 | if test -n "${GIT_PUSH_CERT-}" |
85 | then | |
86 | git cat-file blob $GIT_PUSH_CERT >../push-cert | |
87 | fi | |
88 | EOF | |
89 | git push dst noop && | |
90 | ! test -f dst/push-cert | |
91 | ' | |
92 | ||
a85b377d JH |
93 | test_expect_success GPG 'signed push sends push certificate' ' |
94 | prepare_dst && | |
b89363e4 | 95 | git -C dst config receive.certnonceseed sekrit && |
bef805b7 | 96 | test_hook -C dst post-receive <<-\EOF && |
a85b377d JH |
97 | # discard the update list |
98 | cat >/dev/null | |
99 | # record the push certificate | |
100 | if test -n "${GIT_PUSH_CERT-}" | |
101 | then | |
102 | git cat-file blob $GIT_PUSH_CERT >../push-cert | |
d05b9618 JH |
103 | fi && |
104 | ||
105 | cat >../push-cert-status <<E_O_F | |
106 | SIGNER=${GIT_PUSH_CERT_SIGNER-nobody} | |
107 | KEY=${GIT_PUSH_CERT_KEY-nokey} | |
108 | STATUS=${GIT_PUSH_CERT_STATUS-nostatus} | |
b89363e4 JH |
109 | NONCE_STATUS=${GIT_PUSH_CERT_NONCE_STATUS-nononcestatus} |
110 | NONCE=${GIT_PUSH_CERT_NONCE-nononce} | |
d05b9618 JH |
111 | E_O_F |
112 | ||
113 | EOF | |
114 | ||
a85b377d | 115 | git push --signed dst noop ff +noff && |
b89363e4 JH |
116 | |
117 | ( | |
118 | cat <<-\EOF && | |
119 | SIGNER=C O Mitter <committer@example.com> | |
120 | KEY=13B6F51ECDDE430D | |
121 | STATUS=G | |
122 | NONCE_STATUS=OK | |
123 | EOF | |
124 | sed -n -e "s/^nonce /NONCE=/p" -e "/^$/q" dst/push-cert | |
125 | ) >expect && | |
126 | ||
8722947e JS |
127 | noop=$(git rev-parse noop) && |
128 | ff=$(git rev-parse ff) && | |
129 | noff=$(git rev-parse noff) && | |
130 | grep "$noop $ff refs/heads/ff" dst/push-cert && | |
131 | grep "$noop $noff refs/heads/noff" dst/push-cert && | |
d05b9618 | 132 | test_cmp expect dst/push-cert-status |
a85b377d JH |
133 | ' |
134 | ||
f265f2d6 FS |
135 | test_expect_success GPGSSH 'ssh signed push sends push certificate' ' |
136 | prepare_dst && | |
f265f2d6 FS |
137 | git -C dst config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && |
138 | git -C dst config receive.certnonceseed sekrit && | |
bef805b7 | 139 | test_hook -C dst post-receive <<-\EOF && |
f265f2d6 FS |
140 | # discard the update list |
141 | cat >/dev/null | |
142 | # record the push certificate | |
143 | if test -n "${GIT_PUSH_CERT-}" | |
144 | then | |
145 | git cat-file blob $GIT_PUSH_CERT >../push-cert | |
146 | fi && | |
147 | ||
148 | cat >../push-cert-status <<E_O_F | |
149 | SIGNER=${GIT_PUSH_CERT_SIGNER-nobody} | |
150 | KEY=${GIT_PUSH_CERT_KEY-nokey} | |
151 | STATUS=${GIT_PUSH_CERT_STATUS-nostatus} | |
152 | NONCE_STATUS=${GIT_PUSH_CERT_NONCE_STATUS-nononcestatus} | |
153 | NONCE=${GIT_PUSH_CERT_NONCE-nononce} | |
154 | E_O_F | |
155 | ||
156 | EOF | |
157 | ||
158 | test_config gpg.format ssh && | |
159 | test_config user.signingkey "${GPGSSH_KEY_PRIMARY}" && | |
160 | FINGERPRINT=$(ssh-keygen -lf "${GPGSSH_KEY_PRIMARY}" | awk "{print \$2;}") && | |
161 | git push --signed dst noop ff +noff && | |
162 | ||
163 | ( | |
164 | cat <<-\EOF && | |
165 | SIGNER=principal with number 1 | |
166 | KEY=FINGERPRINT | |
167 | STATUS=G | |
168 | NONCE_STATUS=OK | |
169 | EOF | |
170 | sed -n -e "s/^nonce /NONCE=/p" -e "/^$/q" dst/push-cert | |
171 | ) | sed -e "s|FINGERPRINT|$FINGERPRINT|" >expect && | |
172 | ||
173 | noop=$(git rev-parse noop) && | |
174 | ff=$(git rev-parse ff) && | |
175 | noff=$(git rev-parse noff) && | |
176 | grep "$noop $ff refs/heads/ff" dst/push-cert && | |
177 | grep "$noop $noff refs/heads/noff" dst/push-cert && | |
178 | test_cmp expect dst/push-cert-status | |
179 | ' | |
180 | ||
cbaf82cc JT |
181 | test_expect_success GPG 'inconsistent push options in signed push not allowed' ' |
182 | # First, invoke receive-pack with dummy input to obtain its preamble. | |
183 | prepare_dst && | |
184 | git -C dst config receive.certnonceseed sekrit && | |
185 | git -C dst config receive.advertisepushoptions 1 && | |
186 | printf xxxx | test_might_fail git receive-pack dst >preamble && | |
187 | ||
188 | # Then, invoke push. Simulate a receive-pack that sends the preamble we | |
189 | # obtained, followed by a dummy packet. | |
190 | write_script myscript <<-\EOF && | |
191 | cat preamble && | |
192 | printf xxxx && | |
193 | cat >push | |
194 | EOF | |
195 | test_might_fail git push --push-option="foo" --push-option="bar" \ | |
196 | --receive-pack="\"$(pwd)/myscript\"" --signed dst --delete ff && | |
197 | ||
198 | # Replay the push output on a fresh dst, checking that ff is truly | |
199 | # deleted. | |
200 | prepare_dst && | |
201 | git -C dst config receive.certnonceseed sekrit && | |
202 | git -C dst config receive.advertisepushoptions 1 && | |
203 | git receive-pack dst <push && | |
204 | test_must_fail git -C dst rev-parse ff && | |
205 | ||
206 | # Tweak the push output to make the push option outside the cert | |
207 | # different, then replay it on a fresh dst, checking that ff is not | |
208 | # deleted. | |
209 | perl -pe "s/([^ ])bar/\$1baz/" push >push.tweak && | |
210 | prepare_dst && | |
211 | git -C dst config receive.certnonceseed sekrit && | |
212 | git -C dst config receive.advertisepushoptions 1 && | |
213 | git receive-pack dst <push.tweak >out && | |
214 | git -C dst rev-parse ff && | |
215 | grep "inconsistent push options" out | |
216 | ' | |
217 | ||
b9459019 MG |
218 | test_expect_success GPG 'fail without key and heed user.signingkey' ' |
219 | prepare_dst && | |
b9459019 | 220 | git -C dst config receive.certnonceseed sekrit && |
bef805b7 | 221 | test_hook -C dst post-receive <<-\EOF && |
b9459019 MG |
222 | # discard the update list |
223 | cat >/dev/null | |
224 | # record the push certificate | |
225 | if test -n "${GIT_PUSH_CERT-}" | |
226 | then | |
227 | git cat-file blob $GIT_PUSH_CERT >../push-cert | |
228 | fi && | |
229 | ||
230 | cat >../push-cert-status <<E_O_F | |
231 | SIGNER=${GIT_PUSH_CERT_SIGNER-nobody} | |
232 | KEY=${GIT_PUSH_CERT_KEY-nokey} | |
233 | STATUS=${GIT_PUSH_CERT_STATUS-nostatus} | |
234 | NONCE_STATUS=${GIT_PUSH_CERT_NONCE_STATUS-nononcestatus} | |
235 | NONCE=${GIT_PUSH_CERT_NONCE-nononce} | |
236 | E_O_F | |
237 | ||
238 | EOF | |
239 | ||
53fc9993 HS |
240 | test_config user.email hasnokey@nowhere.com && |
241 | ( | |
242 | sane_unset GIT_COMMITTER_EMAIL && | |
243 | test_must_fail git push --signed dst noop ff +noff | |
244 | ) && | |
245 | test_config user.signingkey $GIT_COMMITTER_EMAIL && | |
b9459019 MG |
246 | git push --signed dst noop ff +noff && |
247 | ||
248 | ( | |
249 | cat <<-\EOF && | |
250 | SIGNER=C O Mitter <committer@example.com> | |
251 | KEY=13B6F51ECDDE430D | |
252 | STATUS=G | |
253 | NONCE_STATUS=OK | |
254 | EOF | |
255 | sed -n -e "s/^nonce /NONCE=/p" -e "/^$/q" dst/push-cert | |
256 | ) >expect && | |
257 | ||
8722947e JS |
258 | noop=$(git rev-parse noop) && |
259 | ff=$(git rev-parse ff) && | |
260 | noff=$(git rev-parse noff) && | |
261 | grep "$noop $ff refs/heads/ff" dst/push-cert && | |
262 | grep "$noop $noff refs/heads/noff" dst/push-cert && | |
b9459019 MG |
263 | test_cmp expect dst/push-cert-status |
264 | ' | |
265 | ||
53fc9993 HS |
266 | test_expect_success GPGSM 'fail without key and heed user.signingkey x509' ' |
267 | test_config gpg.format x509 && | |
268 | prepare_dst && | |
53fc9993 | 269 | git -C dst config receive.certnonceseed sekrit && |
bef805b7 | 270 | test_hook -C dst post-receive <<-\EOF && |
53fc9993 HS |
271 | # discard the update list |
272 | cat >/dev/null | |
273 | # record the push certificate | |
274 | if test -n "${GIT_PUSH_CERT-}" | |
275 | then | |
276 | git cat-file blob $GIT_PUSH_CERT >../push-cert | |
277 | fi && | |
278 | ||
279 | cat >../push-cert-status <<E_O_F | |
280 | SIGNER=${GIT_PUSH_CERT_SIGNER-nobody} | |
281 | KEY=${GIT_PUSH_CERT_KEY-nokey} | |
282 | STATUS=${GIT_PUSH_CERT_STATUS-nostatus} | |
283 | NONCE_STATUS=${GIT_PUSH_CERT_NONCE_STATUS-nononcestatus} | |
284 | NONCE=${GIT_PUSH_CERT_NONCE-nononce} | |
285 | E_O_F | |
286 | ||
287 | EOF | |
288 | ||
289 | test_config user.email hasnokey@nowhere.com && | |
290 | test_config user.signingkey "" && | |
291 | ( | |
292 | sane_unset GIT_COMMITTER_EMAIL && | |
293 | test_must_fail git push --signed dst noop ff +noff | |
294 | ) && | |
295 | test_config user.signingkey $GIT_COMMITTER_EMAIL && | |
296 | git push --signed dst noop ff +noff && | |
297 | ||
298 | ( | |
299 | cat <<-\EOF && | |
300 | SIGNER=/CN=C O Mitter/O=Example/SN=C O/GN=Mitter | |
301 | KEY= | |
302 | STATUS=G | |
303 | NONCE_STATUS=OK | |
304 | EOF | |
305 | sed -n -e "s/^nonce /NONCE=/p" -e "/^$/q" dst/push-cert | |
306 | ) >expect.in && | |
f636d25d | 307 | key=$(cut -d" " -f1 <"${GNUPGHOME}/trustlist.txt" | tr -d ":") && |
53fc9993 HS |
308 | sed -e "s/^KEY=/KEY=${key}/" expect.in >expect && |
309 | ||
310 | noop=$(git rev-parse noop) && | |
311 | ff=$(git rev-parse ff) && | |
312 | noff=$(git rev-parse noff) && | |
313 | grep "$noop $ff refs/heads/ff" dst/push-cert && | |
314 | grep "$noop $noff refs/heads/noff" dst/push-cert && | |
315 | test_cmp expect dst/push-cert-status | |
316 | ' | |
317 | ||
f265f2d6 FS |
318 | test_expect_success GPGSSH 'fail without key and heed user.signingkey ssh' ' |
319 | test_config gpg.format ssh && | |
320 | prepare_dst && | |
f265f2d6 FS |
321 | git -C dst config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && |
322 | git -C dst config receive.certnonceseed sekrit && | |
bef805b7 | 323 | test_hook -C dst post-receive <<-\EOF && |
f265f2d6 FS |
324 | # discard the update list |
325 | cat >/dev/null | |
326 | # record the push certificate | |
327 | if test -n "${GIT_PUSH_CERT-}" | |
328 | then | |
329 | git cat-file blob $GIT_PUSH_CERT >../push-cert | |
330 | fi && | |
331 | ||
332 | cat >../push-cert-status <<E_O_F | |
333 | SIGNER=${GIT_PUSH_CERT_SIGNER-nobody} | |
334 | KEY=${GIT_PUSH_CERT_KEY-nokey} | |
335 | STATUS=${GIT_PUSH_CERT_STATUS-nostatus} | |
336 | NONCE_STATUS=${GIT_PUSH_CERT_NONCE_STATUS-nononcestatus} | |
337 | NONCE=${GIT_PUSH_CERT_NONCE-nononce} | |
338 | E_O_F | |
339 | ||
340 | EOF | |
341 | ||
342 | test_config user.email hasnokey@nowhere.com && | |
343 | test_config gpg.format ssh && | |
344 | test_config user.signingkey "" && | |
345 | ( | |
346 | sane_unset GIT_COMMITTER_EMAIL && | |
347 | test_must_fail git push --signed dst noop ff +noff | |
348 | ) && | |
349 | test_config user.signingkey "${GPGSSH_KEY_PRIMARY}" && | |
350 | FINGERPRINT=$(ssh-keygen -lf "${GPGSSH_KEY_PRIMARY}" | awk "{print \$2;}") && | |
351 | git push --signed dst noop ff +noff && | |
352 | ||
353 | ( | |
354 | cat <<-\EOF && | |
355 | SIGNER=principal with number 1 | |
356 | KEY=FINGERPRINT | |
357 | STATUS=G | |
358 | NONCE_STATUS=OK | |
359 | EOF | |
360 | sed -n -e "s/^nonce /NONCE=/p" -e "/^$/q" dst/push-cert | |
361 | ) | sed -e "s|FINGERPRINT|$FINGERPRINT|" >expect && | |
362 | ||
363 | noop=$(git rev-parse noop) && | |
364 | ff=$(git rev-parse ff) && | |
365 | noff=$(git rev-parse noff) && | |
366 | grep "$noop $ff refs/heads/ff" dst/push-cert && | |
367 | grep "$noop $noff refs/heads/noff" dst/push-cert && | |
368 | test_cmp expect dst/push-cert-status | |
369 | ' | |
370 | ||
a4f324a4 HX |
371 | test_expect_success GPG 'failed atomic push does not execute GPG' ' |
372 | prepare_dst && | |
373 | git -C dst config receive.certnonceseed sekrit && | |
374 | write_script gpg <<-EOF && | |
375 | # should check atomic push locally before running GPG. | |
376 | exit 1 | |
377 | EOF | |
378 | test_must_fail env PATH="$TRASH_DIRECTORY:$PATH" git push \ | |
379 | --signed --atomic --porcelain \ | |
2cd6e1d5 | 380 | dst noop ff noff >out 2>err && |
a4f324a4 | 381 | |
6789275d | 382 | test_grep ! "gpg failed to sign" err && |
a4f324a4 HX |
383 | cat >expect <<-EOF && |
384 | To dst | |
385 | = refs/heads/noop:refs/heads/noop [up to date] | |
386 | ! refs/heads/ff:refs/heads/ff [rejected] (atomic push failed) | |
387 | ! refs/heads/noff:refs/heads/noff [rejected] (non-fast-forward) | |
388 | Done | |
389 | EOF | |
2cd6e1d5 | 390 | test_cmp expect out |
a4f324a4 HX |
391 | ' |
392 | ||
a85b377d | 393 | test_done |