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