Skip to content

Commit

Permalink
signed push: teach smart-HTTP to pass "git push --signed" around
Browse files Browse the repository at this point in the history
The "--signed" option received by "git push" is first passed to the
transport layer, which the native transport directly uses to notice
that a push certificate needs to be sent.  When the transport-helper
is involved, however, the option needs to be told to the helper with
set_helper_option(), and the helper needs to take necessary action.
For the smart-HTTP helper, the "necessary action" involves spawning
the "git send-pack" subprocess with the "--signed" option.

Once the above all gets wired in, the smart-HTTP transport now can
use the push certificate mechanism to authenticate its pushes.

Add a test that is modeled after tests for the native transport in
t5534-push-signed.sh to t5541-http-push-smart.sh.  Update the test
Apache configuration to pass GNUPGHOME environment variable through.
As PassEnv would trigger warnings for an environment variable that
is not set, export it from test-lib.sh set to a harmless value when
GnuPG is not being used in the tests.

Note that the added test is deliberately loose and does not check
the nonce in this step.  This is because the stateless RPC mode is
inevitably flaky and a nonce that comes back in the actual push
processing is one issued by a different process; if the two
interactions with the server crossed a second boundary, the nonces
will not match and such a check will fail.  A later patch in the
series will work around this shortcoming.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Junio C Hamano committed Sep 17, 2014
1 parent b89363e commit 0ea47f9
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 3 deletions.
4 changes: 4 additions & 0 deletions builtin/send-pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
args.verbose = 1;
continue;
}
if (!strcmp(arg, "--signed")) {
args.push_cert = 1;
continue;
}
if (!strcmp(arg, "--progress")) {
progress = 1;
continue;
Expand Down
13 changes: 12 additions & 1 deletion remote-curl.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ struct options {
update_shallow : 1,
followtags : 1,
dry_run : 1,
thin : 1;
thin : 1,
push_cert : 1;
};
static struct options options;
static struct string_list cas_options = STRING_LIST_INIT_DUP;
Expand Down Expand Up @@ -106,6 +107,14 @@ static int set_option(const char *name, const char *value)
else
return -1;
return 0;
} else if (!strcmp(name, "pushcert")) {
if (!strcmp(value, "true"))
options.push_cert = 1;
else if (!strcmp(value, "false"))
options.push_cert = 0;
else
return -1;
return 0;
} else {
return 1 /* unsupported */;
}
Expand Down Expand Up @@ -872,6 +881,8 @@ static int push_git(struct discovery *heads, int nr_spec, char **specs)
argv_array_push(&args, "--thin");
if (options.dry_run)
argv_array_push(&args, "--dry-run");
if (options.push_cert)
argv_array_push(&args, "--signed");
if (options.verbosity == 0)
argv_array_push(&args, "--quiet");
else if (options.verbosity > 1)
Expand Down
1 change: 1 addition & 0 deletions t/lib-httpd/apache.conf
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ LockFile accept.lock

PassEnv GIT_VALGRIND
PassEnv GIT_VALGRIND_OPTIONS
PassEnv GNUPGHOME

Alias /dumb/ www/
Alias /auth/dumb/ www/auth/dumb/
Expand Down
36 changes: 36 additions & 0 deletions t/t5541-http-push-smart.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ if test -n "$NO_CURL"; then
fi

ROOT_PATH="$PWD"
. "$TEST_DIRECTORY"/lib-gpg.sh
. "$TEST_DIRECTORY"/lib-httpd.sh
. "$TEST_DIRECTORY"/lib-terminal.sh
start_httpd
Expand Down Expand Up @@ -323,5 +324,40 @@ test_expect_success 'push into half-auth-complete requires password' '
test_cmp expect actual
'

test_expect_success GPG 'push with post-receive to inspect certificate' '
(
cd "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git &&
mkdir -p hooks &&
write_script hooks/post-receive <<-\EOF &&
# discard the update list
cat >/dev/null
# record the push certificate
if test -n "${GIT_PUSH_CERT-}"
then
git cat-file blob $GIT_PUSH_CERT >../push-cert
fi &&
cat >../push-cert-status <<E_O_F
SIGNER=${GIT_PUSH_CERT_SIGNER-nobody}
KEY=${GIT_PUSH_CERT_KEY-nokey}
STATUS=${GIT_PUSH_CERT_STATUS-nostatus}
E_O_F
EOF
git config receive.certnonceseed sekrit
) &&
cd "$ROOT_PATH/test_repo_clone" &&
test_commit cert-test &&
git push --signed "$HTTPD_URL/smart/test_repo.git" &&
(
cd "$HTTPD_DOCUMENT_ROOT_PATH" &&
cat <<-\EOF
SIGNER=C O Mitter <committer@example.com>
KEY=13B6F51ECDDE430D
STATUS=G
EOF
) >expect &&
test_cmp expect "$HTTPD_DOCUMENT_ROOT_PATH/push-cert-status"
'

stop_httpd
test_done
3 changes: 2 additions & 1 deletion t/test-lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -813,7 +813,8 @@ rm -fr "$TRASH_DIRECTORY" || {
}

HOME="$TRASH_DIRECTORY"
export HOME
GNUPGHOME="$HOME/gnupg-home-not-used"
export HOME GNUPGHOME

if test -z "$TEST_NO_CREATE_REPO"
then
Expand Down
9 changes: 8 additions & 1 deletion transport-helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,8 @@ static const char *unsupported_options[] = {
static const char *boolean_options[] = {
TRANS_OPT_THIN,
TRANS_OPT_KEEP,
TRANS_OPT_FOLLOWTAGS
TRANS_OPT_FOLLOWTAGS,
TRANS_OPT_PUSH_CERT
};

static int set_helper_option(struct transport *transport,
Expand Down Expand Up @@ -835,6 +836,9 @@ static int push_refs_with_push(struct transport *transport,
if (flags & TRANSPORT_PUSH_DRY_RUN) {
if (set_helper_option(transport, "dry-run", "true") != 0)
die("helper %s does not support dry-run", data->name);
} else if (flags & TRANSPORT_PUSH_CERT) {
if (set_helper_option(transport, TRANS_OPT_PUSH_CERT, "true") != 0)
die("helper %s does not support --signed", data->name);
}

strbuf_addch(&buf, '\n');
Expand All @@ -859,6 +863,9 @@ static int push_refs_with_export(struct transport *transport,
if (flags & TRANSPORT_PUSH_DRY_RUN) {
if (set_helper_option(transport, "dry-run", "true") != 0)
die("helper %s does not support dry-run", data->name);
} else if (flags & TRANSPORT_PUSH_CERT) {
if (set_helper_option(transport, TRANS_OPT_PUSH_CERT, "true") != 0)
die("helper %s does not support dry-run", data->name);
}

if (flags & TRANSPORT_PUSH_FORCE) {
Expand Down

0 comments on commit 0ea47f9

Please sign in to comment.