]> git.ipfire.org Git - thirdparty/git.git/commitdiff
send-pack: run GPG after atomic push checking
authorHan Xin <hanxin.hx@alibaba-inc.com>
Sat, 19 Sep 2020 14:47:50 +0000 (22:47 +0800)
committerJunio C Hamano <gitster@pobox.com>
Sat, 19 Sep 2020 22:56:39 +0000 (15:56 -0700)
The refs update commands can be sent to the server side in two different
ways: GPG-signed or unsigned.  We should run these two operations in the
same "Finally, tell the other end!" code block, but they are seperated
by the "Clear the status for each ref" code block.  This will result in
a slight performance loss, because the failed atomic push will still
perform unnecessary preparations for shallow advertise and GPG-signed
commands buffers, and user may have to be bothered by the (possible) GPG
passphrase input when there is nothing to sign.

Add a new test case to t5534 to ensure GPG will not be called when the
GPG-signed atomic push fails.

Signed-off-by: Han Xin <hanxin.hx@alibaba-inc.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
send-pack.c
t/t5534-push-signed.sh

index 632f1580cab9acd38daaa25e3f7172e098410f56..772d425d25d153d5fcc5a15bf8a7cf1a8f4cd31d 100644 (file)
@@ -244,7 +244,12 @@ static int check_to_send_update(const struct ref *ref, const struct send_pack_ar
                return CHECK_REF_STATUS_REJECTED;
        case REF_STATUS_UPTODATE:
                return CHECK_REF_UPTODATE;
+
        default:
+       case REF_STATUS_EXPECTING_REPORT:
+               /* already passed checks on the local side */
+       case REF_STATUS_OK:
+               /* of course this is OK */
                return 0;
        }
 }
@@ -447,13 +452,6 @@ int send_pack(struct send_pack_args *args,
                if (ref->deletion && !allow_deleting_refs)
                        ref->status = REF_STATUS_REJECT_NODELETE;
 
-       if (!args->dry_run)
-               advertise_shallow_grafts_buf(&req_buf);
-
-       if (!args->dry_run && push_cert_nonce)
-               cmds_sent = generate_push_cert(&req_buf, remote_refs, args,
-                                              cap_buf.buf, push_cert_nonce);
-
        /*
         * Clear the status for each ref and see if we need to send
         * the pack data.
@@ -489,31 +487,35 @@ int send_pack(struct send_pack_args *args,
                        ref->status = REF_STATUS_EXPECTING_REPORT;
        }
 
+       if (!args->dry_run)
+               advertise_shallow_grafts_buf(&req_buf);
+
        /*
         * Finally, tell the other end!
         */
-       for (ref = remote_refs; ref; ref = ref->next) {
-               char *old_hex, *new_hex;
-
-               if (args->dry_run || push_cert_nonce)
-                       continue;
-
-               if (check_to_send_update(ref, args) < 0)
-                       continue;
-
-               old_hex = oid_to_hex(&ref->old_oid);
-               new_hex = oid_to_hex(&ref->new_oid);
-               if (!cmds_sent) {
-                       packet_buf_write(&req_buf,
-                                        "%s %s %s%c%s",
-                                        old_hex, new_hex, ref->name, 0,
-                                        cap_buf.buf);
-                       cmds_sent = 1;
-               } else {
-                       packet_buf_write(&req_buf, "%s %s %s",
-                                        old_hex, new_hex, ref->name);
+       if (!args->dry_run && push_cert_nonce)
+               cmds_sent = generate_push_cert(&req_buf, remote_refs, args,
+                                              cap_buf.buf, push_cert_nonce);
+       else if (!args->dry_run)
+               for (ref = remote_refs; ref; ref = ref->next) {
+                       char *old_hex, *new_hex;
+
+                       if (check_to_send_update(ref, args) < 0)
+                               continue;
+
+                       old_hex = oid_to_hex(&ref->old_oid);
+                       new_hex = oid_to_hex(&ref->new_oid);
+                       if (!cmds_sent) {
+                               packet_buf_write(&req_buf,
+                                                "%s %s %s%c%s",
+                                                old_hex, new_hex, ref->name, 0,
+                                                cap_buf.buf);
+                               cmds_sent = 1;
+                       } else {
+                               packet_buf_write(&req_buf, "%s %s %s",
+                                                old_hex, new_hex, ref->name);
+                       }
                }
-       }
 
        if (use_push_options) {
                struct string_list_item *item;
index 030331f1c51fc2a962fffd04c84d8f31d096311c..7e928aff669e550a01dafc8c0afc4bbd271d1d07 100755 (executable)
@@ -273,4 +273,27 @@ test_expect_success GPGSM 'fail without key and heed user.signingkey x509' '
        test_cmp expect dst/push-cert-status
 '
 
+test_expect_success GPG 'failed atomic push does not execute GPG' '
+       prepare_dst &&
+       git -C dst config receive.certnonceseed sekrit &&
+       write_script gpg <<-EOF &&
+       # should check atomic push locally before running GPG.
+       exit 1
+       EOF
+       test_must_fail env PATH="$TRASH_DIRECTORY:$PATH" git push \
+                       --signed --atomic --porcelain \
+                       dst noop ff noff >out 2>&1 &&
+
+       test_i18ngrep ! "gpg failed to sign" out &&
+       sed -n -e "/^To dst/,$ p" out >actual &&
+       cat >expect <<-EOF &&
+       To dst
+       =       refs/heads/noop:refs/heads/noop [up to date]
+       !       refs/heads/ff:refs/heads/ff     [rejected] (atomic push failed)
+       !       refs/heads/noff:refs/heads/noff [rejected] (non-fast-forward)
+       Done
+       EOF
+       test_i18ncmp expect actual
+'
+
 test_done