Merge branch 'js/git-gui-msgfmt-on-windows'
[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 GPG 'no certificate for a signed push with no update' '
75         prepare_dst &&
76         mkdir -p dst/.git/hooks &&
77         write_script dst/.git/hooks/post-receive <<-\EOF &&
78         if test -n "${GIT_PUSH_CERT-}"
79         then
80                 git cat-file blob $GIT_PUSH_CERT >../push-cert
81         fi
82         EOF
83         git push dst noop &&
84         ! test -f dst/push-cert
85 '
86
87 test_expect_success GPG 'signed push sends push certificate' '
88         prepare_dst &&
89         mkdir -p dst/.git/hooks &&
90         git -C dst config receive.certnonceseed sekrit &&
91         write_script dst/.git/hooks/post-receive <<-\EOF &&
92         # discard the update list
93         cat >/dev/null
94         # record the push certificate
95         if test -n "${GIT_PUSH_CERT-}"
96         then
97                 git cat-file blob $GIT_PUSH_CERT >../push-cert
98         fi &&
99
100         cat >../push-cert-status <<E_O_F
101         SIGNER=${GIT_PUSH_CERT_SIGNER-nobody}
102         KEY=${GIT_PUSH_CERT_KEY-nokey}
103         STATUS=${GIT_PUSH_CERT_STATUS-nostatus}
104         NONCE_STATUS=${GIT_PUSH_CERT_NONCE_STATUS-nononcestatus}
105         NONCE=${GIT_PUSH_CERT_NONCE-nononce}
106         E_O_F
107
108         EOF
109
110         git push --signed dst noop ff +noff &&
111
112         (
113                 cat <<-\EOF &&
114                 SIGNER=C O Mitter <committer@example.com>
115                 KEY=13B6F51ECDDE430D
116                 STATUS=G
117                 NONCE_STATUS=OK
118                 EOF
119                 sed -n -e "s/^nonce /NONCE=/p" -e "/^$/q" dst/push-cert
120         ) >expect &&
121
122         noop=$(git rev-parse noop) &&
123         ff=$(git rev-parse ff) &&
124         noff=$(git rev-parse noff) &&
125         grep "$noop $ff refs/heads/ff" dst/push-cert &&
126         grep "$noop $noff refs/heads/noff" dst/push-cert &&
127         test_cmp expect dst/push-cert-status
128 '
129
130 test_expect_success GPG 'inconsistent push options in signed push not allowed' '
131         # First, invoke receive-pack with dummy input to obtain its preamble.
132         prepare_dst &&
133         git -C dst config receive.certnonceseed sekrit &&
134         git -C dst config receive.advertisepushoptions 1 &&
135         printf xxxx | test_might_fail git receive-pack dst >preamble &&
136
137         # Then, invoke push. Simulate a receive-pack that sends the preamble we
138         # obtained, followed by a dummy packet.
139         write_script myscript <<-\EOF &&
140                 cat preamble &&
141                 printf xxxx &&
142                 cat >push
143         EOF
144         test_might_fail git push --push-option="foo" --push-option="bar" \
145                 --receive-pack="\"$(pwd)/myscript\"" --signed dst --delete ff &&
146
147         # Replay the push output on a fresh dst, checking that ff is truly
148         # deleted.
149         prepare_dst &&
150         git -C dst config receive.certnonceseed sekrit &&
151         git -C dst config receive.advertisepushoptions 1 &&
152         git receive-pack dst <push &&
153         test_must_fail git -C dst rev-parse ff &&
154
155         # Tweak the push output to make the push option outside the cert
156         # different, then replay it on a fresh dst, checking that ff is not
157         # deleted.
158         perl -pe "s/([^ ])bar/\$1baz/" push >push.tweak &&
159         prepare_dst &&
160         git -C dst config receive.certnonceseed sekrit &&
161         git -C dst config receive.advertisepushoptions 1 &&
162         git receive-pack dst <push.tweak >out &&
163         git -C dst rev-parse ff &&
164         grep "inconsistent push options" out
165 '
166
167 test_expect_success GPG 'fail without key and heed user.signingkey' '
168         prepare_dst &&
169         mkdir -p dst/.git/hooks &&
170         git -C dst config receive.certnonceseed sekrit &&
171         write_script dst/.git/hooks/post-receive <<-\EOF &&
172         # discard the update list
173         cat >/dev/null
174         # record the push certificate
175         if test -n "${GIT_PUSH_CERT-}"
176         then
177                 git cat-file blob $GIT_PUSH_CERT >../push-cert
178         fi &&
179
180         cat >../push-cert-status <<E_O_F
181         SIGNER=${GIT_PUSH_CERT_SIGNER-nobody}
182         KEY=${GIT_PUSH_CERT_KEY-nokey}
183         STATUS=${GIT_PUSH_CERT_STATUS-nostatus}
184         NONCE_STATUS=${GIT_PUSH_CERT_NONCE_STATUS-nononcestatus}
185         NONCE=${GIT_PUSH_CERT_NONCE-nononce}
186         E_O_F
187
188         EOF
189
190         unset GIT_COMMITTER_EMAIL &&
191         git config user.email hasnokey@nowhere.com &&
192         test_must_fail git push --signed dst noop ff +noff &&
193         git config user.signingkey committer@example.com &&
194         git push --signed dst noop ff +noff &&
195
196         (
197                 cat <<-\EOF &&
198                 SIGNER=C O Mitter <committer@example.com>
199                 KEY=13B6F51ECDDE430D
200                 STATUS=G
201                 NONCE_STATUS=OK
202                 EOF
203                 sed -n -e "s/^nonce /NONCE=/p" -e "/^$/q" dst/push-cert
204         ) >expect &&
205
206         noop=$(git rev-parse noop) &&
207         ff=$(git rev-parse ff) &&
208         noff=$(git rev-parse noff) &&
209         grep "$noop $ff refs/heads/ff" dst/push-cert &&
210         grep "$noop $noff refs/heads/noff" dst/push-cert &&
211         test_cmp expect dst/push-cert-status
212 '
213
214 test_done