Documentation/RelNotes/2.45.0.txt: fix typo
[git.git] / t / t5534-push-signed.sh
blobc91a62b77afcfba1bf1228c33717db77c7e45318
1 #!/bin/sh
3 test_description='signed push'
5 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
6 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
8 . ./test-lib.sh
9 . "$TEST_DIRECTORY"/lib-gpg.sh
11 prepare_dst () {
12 rm -fr dst &&
13 test_create_repo dst &&
15 git push dst main:noop main:ff main:noff
18 test_expect_success setup '
19 # main, ff and noff branches pointing at the same commit
20 test_tick &&
21 git commit --allow-empty -m initial &&
23 git checkout -b noop &&
24 git checkout -b ff &&
25 git checkout -b noff &&
27 # noop stays the same, ff advances, noff rewrites
28 test_tick &&
29 git commit --allow-empty --amend -m rewritten &&
30 git checkout ff &&
32 test_tick &&
33 git commit --allow-empty -m second
36 test_expect_success 'unsigned push does not send push certificate' '
37 prepare_dst &&
38 test_hook -C dst post-receive <<-\EOF &&
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
46 EOF
48 git push dst noop ff +noff &&
49 ! test -f dst/push-cert
52 test_expect_success 'talking with a receiver without push certificate support' '
53 prepare_dst &&
54 test_hook -C dst post-receive <<-\EOF &&
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
62 EOF
64 git push dst noop ff +noff &&
65 ! test -f dst/push-cert
68 test_expect_success 'push --signed fails with a receiver without push certificate support' '
69 prepare_dst &&
70 test_must_fail git push --signed dst noop ff +noff 2>err &&
71 test_grep "the receiving end does not support" err
74 test_expect_success 'push --signed=1 is accepted' '
75 prepare_dst &&
76 test_must_fail git push --signed=1 dst noop ff +noff 2>err &&
77 test_grep "the receiving end does not support" err
80 test_expect_success GPG 'no certificate for a signed push with no update' '
81 prepare_dst &&
82 test_hook -C dst post-receive <<-\EOF &&
83 if test -n "${GIT_PUSH_CERT-}"
84 then
85 git cat-file blob $GIT_PUSH_CERT >../push-cert
87 EOF
88 git push dst noop &&
89 ! test -f dst/push-cert
92 test_expect_success GPG 'signed push sends push certificate' '
93 prepare_dst &&
94 git -C dst config receive.certnonceseed sekrit &&
95 test_hook -C dst post-receive <<-\EOF &&
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
102 fi &&
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}
108 NONCE_STATUS=${GIT_PUSH_CERT_NONCE_STATUS-nononcestatus}
109 NONCE=${GIT_PUSH_CERT_NONCE-nononce}
110 E_O_F
114 git push --signed dst noop ff +noff &&
117 cat <<-\EOF &&
118 SIGNER=C O Mitter <committer@example.com>
119 KEY=13B6F51ECDDE430D
120 STATUS=G
121 NONCE_STATUS=OK
123 sed -n -e "s/^nonce /NONCE=/p" -e "/^$/q" dst/push-cert
124 ) >expect &&
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 &&
131 test_cmp expect dst/push-cert-status
134 test_expect_success GPGSSH 'ssh signed push sends push certificate' '
135 prepare_dst &&
136 git -C dst config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
137 git -C dst config receive.certnonceseed sekrit &&
138 test_hook -C dst post-receive <<-\EOF &&
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 &&
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
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 &&
163 cat <<-\EOF &&
164 SIGNER=principal with number 1
165 KEY=FINGERPRINT
166 STATUS=G
167 NONCE_STATUS=OK
169 sed -n -e "s/^nonce /NONCE=/p" -e "/^$/q" dst/push-cert
170 ) | sed -e "s|FINGERPRINT|$FINGERPRINT|" >expect &&
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
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 &&
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
194 test_might_fail git push --push-option="foo" --push-option="bar" \
195 --receive-pack="\"$(pwd)/myscript\"" --signed dst --delete ff &&
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 &&
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
217 test_expect_success GPG 'fail without key and heed user.signingkey' '
218 prepare_dst &&
219 git -C dst config receive.certnonceseed sekrit &&
220 test_hook -C dst post-receive <<-\EOF &&
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 &&
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
239 test_config user.email hasnokey@nowhere.com &&
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 &&
245 git push --signed dst noop ff +noff &&
248 cat <<-\EOF &&
249 SIGNER=C O Mitter <committer@example.com>
250 KEY=13B6F51ECDDE430D
251 STATUS=G
252 NONCE_STATUS=OK
254 sed -n -e "s/^nonce /NONCE=/p" -e "/^$/q" dst/push-cert
255 ) >expect &&
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 &&
262 test_cmp expect dst/push-cert-status
265 test_expect_success GPGSM 'fail without key and heed user.signingkey x509' '
266 test_config gpg.format x509 &&
267 prepare_dst &&
268 git -C dst config receive.certnonceseed sekrit &&
269 test_hook -C dst post-receive <<-\EOF &&
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 &&
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
288 test_config user.email hasnokey@nowhere.com &&
289 test_config user.signingkey "" &&
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 &&
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
304 sed -n -e "s/^nonce /NONCE=/p" -e "/^$/q" dst/push-cert
305 ) >expect.in &&
306 key=$(cut -d" " -f1 <"${GNUPGHOME}/trustlist.txt" | tr -d ":") &&
307 sed -e "s/^KEY=/KEY=${key}/" expect.in >expect &&
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
317 test_expect_success GPGSSH 'fail without key and heed user.signingkey ssh' '
318 test_config gpg.format ssh &&
319 prepare_dst &&
320 git -C dst config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
321 git -C dst config receive.certnonceseed sekrit &&
322 test_hook -C dst post-receive <<-\EOF &&
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 &&
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
341 test_config user.email hasnokey@nowhere.com &&
342 test_config gpg.format ssh &&
343 test_config user.signingkey "" &&
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 &&
353 cat <<-\EOF &&
354 SIGNER=principal with number 1
355 KEY=FINGERPRINT
356 STATUS=G
357 NONCE_STATUS=OK
359 sed -n -e "s/^nonce /NONCE=/p" -e "/^$/q" dst/push-cert
360 ) | sed -e "s|FINGERPRINT|$FINGERPRINT|" >expect &&
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
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
377 test_must_fail env PATH="$TRASH_DIRECTORY:$PATH" git push \
378 --signed --atomic --porcelain \
379 dst noop ff noff >out 2>err &&
381 test_grep ! "gpg failed to sign" err &&
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
389 test_cmp expect out
392 test_done