Merge branch 'jc/worktree-add-short-help'
[git] / t / t5534-push-signed.sh
1 #!/bin/sh
2
3 test_description='signed push'
4
5 . ./test-lib.sh
6 . "$TEST_DIRECTORY"/lib-gpg.sh
7
8 prepare_dst () {
9         rm -fr dst &&
10         test_create_repo dst &&
11
12         git push dst master:noop master:ff master:noff
13 }
14
15 test_expect_success setup '
16         # master, ff and noff branches pointing at the same commit
17         test_tick &&
18         git commit --allow-empty -m initial &&
19
20         git checkout -b noop &&
21         git checkout -b ff &&
22         git checkout -b noff &&
23
24         # noop stays the same, ff advances, noff rewrites
25         test_tick &&
26         git commit --allow-empty --amend -m rewritten &&
27         git checkout ff &&
28
29         test_tick &&
30         git commit --allow-empty -m second
31 '
32
33 test_expect_success 'unsigned push does not send push certificate' '
34         prepare_dst &&
35         mkdir -p dst/.git/hooks &&
36         write_script dst/.git/hooks/post-receive <<-\EOF &&
37         # discard the update list
38         cat >/dev/null
39         # record the push certificate
40         if test -n "${GIT_PUSH_CERT-}"
41         then
42                 git cat-file blob $GIT_PUSH_CERT >../push-cert
43         fi
44         EOF
45
46         git push dst noop ff +noff &&
47         ! test -f dst/push-cert
48 '
49
50 test_expect_success 'talking with a receiver without push certificate support' '
51         prepare_dst &&
52         mkdir -p dst/.git/hooks &&
53         write_script dst/.git/hooks/post-receive <<-\EOF &&
54         # discard the update list
55         cat >/dev/null
56         # record the push certificate
57         if test -n "${GIT_PUSH_CERT-}"
58         then
59                 git cat-file blob $GIT_PUSH_CERT >../push-cert
60         fi
61         EOF
62
63         git push dst noop ff +noff &&
64         ! test -f dst/push-cert
65 '
66
67 test_expect_success 'push --signed fails with a receiver without push certificate support' '
68         prepare_dst &&
69         mkdir -p dst/.git/hooks &&
70         test_must_fail git push --signed dst noop ff +noff 2>err &&
71         test_i18ngrep "the receiving end does not support" err
72 '
73
74 test_expect_success 'push --signed=1 is accepted' '
75         prepare_dst &&
76         mkdir -p dst/.git/hooks &&
77         test_must_fail git push --signed=1 dst noop ff +noff 2>err &&
78         test_i18ngrep "the receiving end does not support" err
79 '
80
81 test_expect_success GPG 'no certificate for a signed push with no update' '
82         prepare_dst &&
83         mkdir -p dst/.git/hooks &&
84         write_script dst/.git/hooks/post-receive <<-\EOF &&
85         if test -n "${GIT_PUSH_CERT-}"
86         then
87                 git cat-file blob $GIT_PUSH_CERT >../push-cert
88         fi
89         EOF
90         git push dst noop &&
91         ! test -f dst/push-cert
92 '
93
94 test_expect_success GPG 'signed push sends push certificate' '
95         prepare_dst &&
96         mkdir -p dst/.git/hooks &&
97         git -C dst config receive.certnonceseed sekrit &&
98         write_script dst/.git/hooks/post-receive <<-\EOF &&
99         # discard the update list
100         cat >/dev/null
101         # record the push certificate
102         if test -n "${GIT_PUSH_CERT-}"
103         then
104                 git cat-file blob $GIT_PUSH_CERT >../push-cert
105         fi &&
106
107         cat >../push-cert-status <<E_O_F
108         SIGNER=${GIT_PUSH_CERT_SIGNER-nobody}
109         KEY=${GIT_PUSH_CERT_KEY-nokey}
110         STATUS=${GIT_PUSH_CERT_STATUS-nostatus}
111         NONCE_STATUS=${GIT_PUSH_CERT_NONCE_STATUS-nononcestatus}
112         NONCE=${GIT_PUSH_CERT_NONCE-nononce}
113         E_O_F
114
115         EOF
116
117         git push --signed dst noop ff +noff &&
118
119         (
120                 cat <<-\EOF &&
121                 SIGNER=C O Mitter <committer@example.com>
122                 KEY=13B6F51ECDDE430D
123                 STATUS=G
124                 NONCE_STATUS=OK
125                 EOF
126                 sed -n -e "s/^nonce /NONCE=/p" -e "/^$/q" dst/push-cert
127         ) >expect &&
128
129         noop=$(git rev-parse noop) &&
130         ff=$(git rev-parse ff) &&
131         noff=$(git rev-parse noff) &&
132         grep "$noop $ff refs/heads/ff" dst/push-cert &&
133         grep "$noop $noff refs/heads/noff" dst/push-cert &&
134         test_cmp expect dst/push-cert-status
135 '
136
137 test_expect_success GPG 'inconsistent push options in signed push not allowed' '
138         # First, invoke receive-pack with dummy input to obtain its preamble.
139         prepare_dst &&
140         git -C dst config receive.certnonceseed sekrit &&
141         git -C dst config receive.advertisepushoptions 1 &&
142         printf xxxx | test_might_fail git receive-pack dst >preamble &&
143
144         # Then, invoke push. Simulate a receive-pack that sends the preamble we
145         # obtained, followed by a dummy packet.
146         write_script myscript <<-\EOF &&
147                 cat preamble &&
148                 printf xxxx &&
149                 cat >push
150         EOF
151         test_might_fail git push --push-option="foo" --push-option="bar" \
152                 --receive-pack="\"$(pwd)/myscript\"" --signed dst --delete ff &&
153
154         # Replay the push output on a fresh dst, checking that ff is truly
155         # deleted.
156         prepare_dst &&
157         git -C dst config receive.certnonceseed sekrit &&
158         git -C dst config receive.advertisepushoptions 1 &&
159         git receive-pack dst <push &&
160         test_must_fail git -C dst rev-parse ff &&
161
162         # Tweak the push output to make the push option outside the cert
163         # different, then replay it on a fresh dst, checking that ff is not
164         # deleted.
165         perl -pe "s/([^ ])bar/\$1baz/" push >push.tweak &&
166         prepare_dst &&
167         git -C dst config receive.certnonceseed sekrit &&
168         git -C dst config receive.advertisepushoptions 1 &&
169         git receive-pack dst <push.tweak >out &&
170         git -C dst rev-parse ff &&
171         grep "inconsistent push options" out
172 '
173
174 test_expect_success GPG 'fail without key and heed user.signingkey' '
175         prepare_dst &&
176         mkdir -p dst/.git/hooks &&
177         git -C dst config receive.certnonceseed sekrit &&
178         write_script dst/.git/hooks/post-receive <<-\EOF &&
179         # discard the update list
180         cat >/dev/null
181         # record the push certificate
182         if test -n "${GIT_PUSH_CERT-}"
183         then
184                 git cat-file blob $GIT_PUSH_CERT >../push-cert
185         fi &&
186
187         cat >../push-cert-status <<E_O_F
188         SIGNER=${GIT_PUSH_CERT_SIGNER-nobody}
189         KEY=${GIT_PUSH_CERT_KEY-nokey}
190         STATUS=${GIT_PUSH_CERT_STATUS-nostatus}
191         NONCE_STATUS=${GIT_PUSH_CERT_NONCE_STATUS-nononcestatus}
192         NONCE=${GIT_PUSH_CERT_NONCE-nononce}
193         E_O_F
194
195         EOF
196
197         unset GIT_COMMITTER_EMAIL &&
198         git config user.email hasnokey@nowhere.com &&
199         test_must_fail git push --signed dst noop ff +noff &&
200         git config user.signingkey committer@example.com &&
201         git push --signed dst noop ff +noff &&
202
203         (
204                 cat <<-\EOF &&
205                 SIGNER=C O Mitter <committer@example.com>
206                 KEY=13B6F51ECDDE430D
207                 STATUS=G
208                 NONCE_STATUS=OK
209                 EOF
210                 sed -n -e "s/^nonce /NONCE=/p" -e "/^$/q" dst/push-cert
211         ) >expect &&
212
213         noop=$(git rev-parse noop) &&
214         ff=$(git rev-parse ff) &&
215         noff=$(git rev-parse noff) &&
216         grep "$noop $ff refs/heads/ff" dst/push-cert &&
217         grep "$noop $noff refs/heads/noff" dst/push-cert &&
218         test_cmp expect dst/push-cert-status
219 '
220
221 test_done