2009-10-31 00:47:47 +00:00
|
|
|
#!/bin/sh
|
|
|
|
#
|
|
|
|
# Copyright (c) 2008 Clemens Buchacher <drizzd@aon.at>
|
|
|
|
#
|
|
|
|
|
|
|
|
test_description='test smart pushing over http via http-backend'
|
2020-11-18 23:44:34 +00:00
|
|
|
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
|
tests: mark tests relying on the current default for `init.defaultBranch`
In addition to the manual adjustment to let the `linux-gcc` CI job run
the test suite with `master` and then with `main`, this patch makes sure
that GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME is set in all test scripts
that currently rely on the initial branch name being `master by default.
To determine which test scripts to mark up, the first step was to
force-set the default branch name to `master` in
- all test scripts that contain the keyword `master`,
- t4211, which expects `t/t4211/history.export` with a hard-coded ref to
initialize the default branch,
- t5560 because it sources `t/t556x_common` which uses `master`,
- t8002 and t8012 because both source `t/annotate-tests.sh` which also
uses `master`)
This trick was performed by this command:
$ sed -i '/^ *\. \.\/\(test-lib\|lib-\(bash\|cvs\|git-svn\)\|gitweb-lib\)\.sh$/i\
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master\
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\
' $(git grep -l master t/t[0-9]*.sh) \
t/t4211*.sh t/t5560*.sh t/t8002*.sh t/t8012*.sh
After that, careful, manual inspection revealed that some of the test
scripts containing the needle `master` do not actually rely on a
specific default branch name: either they mention `master` only in a
comment, or they initialize that branch specificially, or they do not
actually refer to the current default branch. Therefore, the
aforementioned modification was undone in those test scripts thusly:
$ git checkout HEAD -- \
t/t0027-auto-crlf.sh t/t0060-path-utils.sh \
t/t1011-read-tree-sparse-checkout.sh \
t/t1305-config-include.sh t/t1309-early-config.sh \
t/t1402-check-ref-format.sh t/t1450-fsck.sh \
t/t2024-checkout-dwim.sh \
t/t2106-update-index-assume-unchanged.sh \
t/t3040-subprojects-basic.sh t/t3301-notes.sh \
t/t3308-notes-merge.sh t/t3423-rebase-reword.sh \
t/t3436-rebase-more-options.sh \
t/t4015-diff-whitespace.sh t/t4257-am-interactive.sh \
t/t5323-pack-redundant.sh t/t5401-update-hooks.sh \
t/t5511-refspec.sh t/t5526-fetch-submodules.sh \
t/t5529-push-errors.sh t/t5530-upload-pack-error.sh \
t/t5548-push-porcelain.sh \
t/t5552-skipping-fetch-negotiator.sh \
t/t5572-pull-submodule.sh t/t5608-clone-2gb.sh \
t/t5614-clone-submodules-shallow.sh \
t/t7508-status.sh t/t7606-merge-custom.sh \
t/t9302-fast-import-unpack-limit.sh
We excluded one set of test scripts in these commands, though: the range
of `git p4` tests. The reason? `git p4` stores the (foreign) remote
branch in the branch called `p4/master`, which is obviously not the
default branch. Manual analysis revealed that only five of these tests
actually require a specific default branch name to pass; They were
modified thusly:
$ sed -i '/^ *\. \.\/lib-git-p4\.sh$/i\
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master\
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\
' t/t980[0167]*.sh t/t9811*.sh
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-11-18 23:44:19 +00:00
|
|
|
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
|
|
|
|
|
2024-09-24 21:56:34 +00:00
|
|
|
TEST_PASSES_SANITIZE_LEAK=true
|
2009-10-31 00:47:47 +00:00
|
|
|
. ./test-lib.sh
|
|
|
|
|
|
|
|
ROOT_PATH="$PWD"
|
2014-09-15 21:59:00 +00:00
|
|
|
. "$TEST_DIRECTORY"/lib-gpg.sh
|
2009-10-31 00:47:47 +00:00
|
|
|
. "$TEST_DIRECTORY"/lib-httpd.sh
|
2012-01-08 21:06:21 +00:00
|
|
|
. "$TEST_DIRECTORY"/lib-terminal.sh
|
2009-10-31 00:47:47 +00:00
|
|
|
start_httpd
|
|
|
|
|
|
|
|
test_expect_success 'setup remote repository' '
|
|
|
|
cd "$ROOT_PATH" &&
|
|
|
|
mkdir test_repo &&
|
|
|
|
cd test_repo &&
|
|
|
|
git init &&
|
|
|
|
: >path1 &&
|
|
|
|
git add path1 &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m initial &&
|
|
|
|
cd - &&
|
|
|
|
git clone --bare test_repo test_repo.git &&
|
|
|
|
cd test_repo.git &&
|
|
|
|
git config http.receivepack true &&
|
2012-03-30 07:01:30 +00:00
|
|
|
git config core.logallrefupdates true &&
|
2009-10-31 00:47:47 +00:00
|
|
|
ORIG_HEAD=$(git rev-parse --verify HEAD) &&
|
|
|
|
cd - &&
|
|
|
|
mv test_repo.git "$HTTPD_DOCUMENT_ROOT_PATH"
|
|
|
|
'
|
|
|
|
|
2012-08-27 13:25:36 +00:00
|
|
|
setup_askpass_helper
|
|
|
|
|
2010-04-08 02:15:16 +00:00
|
|
|
test_expect_success 'clone remote repository' '
|
|
|
|
rm -rf test_repo_clone &&
|
2012-06-24 11:01:37 +00:00
|
|
|
git clone $HTTPD_URL/smart/test_repo.git test_repo_clone &&
|
|
|
|
(
|
|
|
|
cd test_repo_clone && git config push.default matching
|
|
|
|
)
|
2009-10-31 00:47:47 +00:00
|
|
|
'
|
|
|
|
|
2011-05-04 17:19:50 +00:00
|
|
|
test_expect_success 'push to remote repository (standard)' '
|
t5541: run "used receive-pack service" test earlier
There's a test in t5541 that confirms that "git push" makes two requests
(a GET to /info/refs, and a POST to /git-receive-pack). However, it's a
noop unless GIT_TEST_PROTOCOL_VERSION is set to "0", due to 8a1b0978ab
(test: request GIT_TEST_PROTOCOL_VERSION=0 when appropriate,
2019-12-23).
This means that almost nobody runs it. And indeed, it has been broken
since b0c4adcdd7 (remote-curl: send Accept-Language header to server,
2022-07-11). But the fault is not in that commit, but in how brittle the
test is. It runs after several operations have been performed, which
means that it expects to see the complete set of requests made so far in
the script. Commit b0c4adcdd7 added a new test, which means that the
"used receive-pack service" test must be updated, too.
Let's fix this by making the test less brittle. We'll move it higher in
the script, right after the first push has completed. And we'll clear
the access log right before doing the push, so we'll see only the
requests from that command.
This is technically testing less, in that we won't check that all of
those other requests also correctly used smart http. But there's no
particular reason think that if the first one did, the others wouldn't.
After this patch, running:
GIT_TEST_PROTOCOL_VERSION=0 ./t5541-http-push-smart.sh
passes, whereas it did not before.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2023-02-23 10:49:47 +00:00
|
|
|
# Clear the log, so that the "used receive-pack service" test below
|
|
|
|
# sees just what we did here.
|
|
|
|
>"$HTTPD_ROOT_PATH"/access.log &&
|
|
|
|
|
2009-10-31 00:47:47 +00:00
|
|
|
cd "$ROOT_PATH"/test_repo_clone &&
|
|
|
|
: >path2 &&
|
|
|
|
git add path2 &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m path2 &&
|
|
|
|
HEAD=$(git rev-parse --verify HEAD) &&
|
2016-09-05 10:24:41 +00:00
|
|
|
GIT_TRACE_CURL=true git push -v -v 2>err &&
|
2011-05-04 17:19:50 +00:00
|
|
|
! grep "Expect: 100-continue" err &&
|
|
|
|
grep "POST git-receive-pack ([0-9]* bytes)" err &&
|
2009-10-31 00:47:47 +00:00
|
|
|
(cd "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git &&
|
|
|
|
test $HEAD = $(git rev-parse --verify HEAD))
|
|
|
|
'
|
|
|
|
|
t5541: run "used receive-pack service" test earlier
There's a test in t5541 that confirms that "git push" makes two requests
(a GET to /info/refs, and a POST to /git-receive-pack). However, it's a
noop unless GIT_TEST_PROTOCOL_VERSION is set to "0", due to 8a1b0978ab
(test: request GIT_TEST_PROTOCOL_VERSION=0 when appropriate,
2019-12-23).
This means that almost nobody runs it. And indeed, it has been broken
since b0c4adcdd7 (remote-curl: send Accept-Language header to server,
2022-07-11). But the fault is not in that commit, but in how brittle the
test is. It runs after several operations have been performed, which
means that it expects to see the complete set of requests made so far in
the script. Commit b0c4adcdd7 added a new test, which means that the
"used receive-pack service" test must be updated, too.
Let's fix this by making the test less brittle. We'll move it higher in
the script, right after the first push has completed. And we'll clear
the access log right before doing the push, so we'll see only the
requests from that command.
This is technically testing less, in that we won't check that all of
those other requests also correctly used smart http. But there's no
particular reason think that if the first one did, the others wouldn't.
After this patch, running:
GIT_TEST_PROTOCOL_VERSION=0 ./t5541-http-push-smart.sh
passes, whereas it did not before.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2023-02-23 10:49:47 +00:00
|
|
|
test_expect_success 'used receive-pack service' '
|
|
|
|
cat >exp <<-\EOF &&
|
|
|
|
GET /smart/test_repo.git/info/refs?service=git-receive-pack HTTP/1.1 200
|
|
|
|
POST /smart/test_repo.git/git-receive-pack HTTP/1.1 200
|
|
|
|
EOF
|
|
|
|
|
2023-02-23 10:50:36 +00:00
|
|
|
check_access_log exp
|
t5541: run "used receive-pack service" test earlier
There's a test in t5541 that confirms that "git push" makes two requests
(a GET to /info/refs, and a POST to /git-receive-pack). However, it's a
noop unless GIT_TEST_PROTOCOL_VERSION is set to "0", due to 8a1b0978ab
(test: request GIT_TEST_PROTOCOL_VERSION=0 when appropriate,
2019-12-23).
This means that almost nobody runs it. And indeed, it has been broken
since b0c4adcdd7 (remote-curl: send Accept-Language header to server,
2022-07-11). But the fault is not in that commit, but in how brittle the
test is. It runs after several operations have been performed, which
means that it expects to see the complete set of requests made so far in
the script. Commit b0c4adcdd7 added a new test, which means that the
"used receive-pack service" test must be updated, too.
Let's fix this by making the test less brittle. We'll move it higher in
the script, right after the first push has completed. And we'll clear
the access log right before doing the push, so we'll see only the
requests from that command.
This is technically testing less, in that we won't check that all of
those other requests also correctly used smart http. But there's no
particular reason think that if the first one did, the others wouldn't.
After this patch, running:
GIT_TEST_PROTOCOL_VERSION=0 ./t5541-http-push-smart.sh
passes, whereas it did not before.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2023-02-23 10:49:47 +00:00
|
|
|
'
|
|
|
|
|
2022-07-11 05:58:54 +00:00
|
|
|
test_expect_success 'push to remote repository (standard) with sending Accept-Language' '
|
|
|
|
cat >exp <<-\EOF &&
|
|
|
|
=> Send header: Accept-Language: ko-KR, *;q=0.9
|
|
|
|
=> Send header: Accept-Language: ko-KR, *;q=0.9
|
|
|
|
EOF
|
|
|
|
|
|
|
|
cd "$ROOT_PATH"/test_repo_clone &&
|
|
|
|
: >path_lang &&
|
|
|
|
git add path_lang &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m path_lang &&
|
|
|
|
HEAD=$(git rev-parse --verify HEAD) &&
|
|
|
|
GIT_TRACE_CURL=true LANGUAGE="ko_KR.UTF-8" git push -v -v 2>err &&
|
|
|
|
! grep "Expect: 100-continue" err &&
|
|
|
|
|
|
|
|
grep "=> Send header: Accept-Language:" err >err.language &&
|
|
|
|
test_cmp exp err.language
|
|
|
|
'
|
|
|
|
|
2009-10-31 00:47:47 +00:00
|
|
|
test_expect_success 'push already up-to-date' '
|
|
|
|
git push
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'create and delete remote branch' '
|
|
|
|
cd "$ROOT_PATH"/test_repo_clone &&
|
|
|
|
git checkout -b dev &&
|
|
|
|
: >path3 &&
|
|
|
|
git add path3 &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m dev &&
|
|
|
|
git push origin dev &&
|
|
|
|
git push origin :dev &&
|
|
|
|
test_must_fail git show-ref --verify refs/remotes/origin/dev
|
|
|
|
'
|
|
|
|
|
2022-03-17 10:13:15 +00:00
|
|
|
test_expect_success 'setup rejected update hook' '
|
|
|
|
test_hook --setup -C "$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git" update <<-\EOF &&
|
|
|
|
exit 1
|
|
|
|
EOF
|
remote-curl: Fix push status report when all branches fail
The protocol between transport-helper.c and remote-curl requires
remote-curl to always print a blank line after the push command
has run. If the blank line is ommitted, transport-helper kills its
container process (the git push the user started) with exit(128)
and no message indicating a problem, assuming the helper already
printed reasonable error text to the console.
However if the remote rejects all branches with "ng" commands in the
report-status reply, send-pack terminates with non-zero status, and
in turn remote-curl exited with non-zero status before outputting
the blank line after the helper status printed by send-pack. No
error messages reach the user.
This caused users to see the following from git push over HTTP
when the remote side's update hook rejected the branch:
$ git push http://... master
Counting objects: 4, done.
Delta compression using up to 6 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 301 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
$
Always print a blank line after the send-pack process terminates,
ensuring the helper status report (if it was output) will be
correctly parsed by the calling transport-helper.c. This ensures
the helper doesn't abort before the status report can be shown to
the user.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-01-20 03:12:09 +00:00
|
|
|
|
2022-03-17 10:13:15 +00:00
|
|
|
cat >exp <<-EOF
|
|
|
|
remote: error: hook declined to update refs/heads/dev2
|
|
|
|
To http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git
|
|
|
|
! [remote rejected] dev2 -> dev2 (hook declined)
|
|
|
|
error: failed to push some refs to '\''http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git'\''
|
|
|
|
EOF
|
|
|
|
'
|
remote-curl: Fix push status report when all branches fail
The protocol between transport-helper.c and remote-curl requires
remote-curl to always print a blank line after the push command
has run. If the blank line is ommitted, transport-helper kills its
container process (the git push the user started) with exit(128)
and no message indicating a problem, assuming the helper already
printed reasonable error text to the console.
However if the remote rejects all branches with "ng" commands in the
report-status reply, send-pack terminates with non-zero status, and
in turn remote-curl exited with non-zero status before outputting
the blank line after the helper status printed by send-pack. No
error messages reach the user.
This caused users to see the following from git push over HTTP
when the remote side's update hook rejected the branch:
$ git push http://... master
Counting objects: 4, done.
Delta compression using up to 6 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 301 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
$
Always print a blank line after the send-pack process terminates,
ensuring the helper status report (if it was output) will be
correctly parsed by the calling transport-helper.c. This ensures
the helper doesn't abort before the status report can be shown to
the user.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-01-20 03:12:09 +00:00
|
|
|
|
|
|
|
test_expect_success 'rejected update prints status' '
|
|
|
|
cd "$ROOT_PATH"/test_repo_clone &&
|
|
|
|
git checkout -b dev2 &&
|
|
|
|
: >path4 &&
|
|
|
|
git add path4 &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m dev2 &&
|
|
|
|
test_must_fail git push origin dev2 2>act &&
|
|
|
|
sed -e "/^remote: /s/ *$//" <act >cmp &&
|
2021-02-11 01:53:53 +00:00
|
|
|
test_cmp exp cmp
|
remote-curl: Fix push status report when all branches fail
The protocol between transport-helper.c and remote-curl requires
remote-curl to always print a blank line after the push command
has run. If the blank line is ommitted, transport-helper kills its
container process (the git push the user started) with exit(128)
and no message indicating a problem, assuming the helper already
printed reasonable error text to the console.
However if the remote rejects all branches with "ng" commands in the
report-status reply, send-pack terminates with non-zero status, and
in turn remote-curl exited with non-zero status before outputting
the blank line after the helper status printed by send-pack. No
error messages reach the user.
This caused users to see the following from git push over HTTP
when the remote side's update hook rejected the branch:
$ git push http://... master
Counting objects: 4, done.
Delta compression using up to 6 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 301 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
$
Always print a blank line after the send-pack process terminates,
ensuring the helper status report (if it was output) will be
correctly parsed by the calling transport-helper.c. This ensures
the helper doesn't abort before the status report can be shown to
the user.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-01-20 03:12:09 +00:00
|
|
|
'
|
|
|
|
rm -f "$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update"
|
|
|
|
|
2010-03-02 10:49:26 +00:00
|
|
|
test_http_push_nonff "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git \
|
2020-11-18 23:44:34 +00:00
|
|
|
"$ROOT_PATH"/test_repo_clone main success
|
2010-01-08 02:12:40 +00:00
|
|
|
|
2010-01-08 02:12:44 +00:00
|
|
|
test_expect_success 'push fails for non-fast-forward refs unmatched by remote helper' '
|
2010-01-08 02:12:41 +00:00
|
|
|
# create a dissimilarly-named remote ref so that git is unable to match the
|
|
|
|
# two refs (viz. local, remote) unless an explicit refspec is provided.
|
2020-11-18 23:44:34 +00:00
|
|
|
git push origin main:niam &&
|
2010-01-08 02:12:41 +00:00
|
|
|
|
|
|
|
echo "change changed" > path2 &&
|
|
|
|
git commit -a -m path2 --amend &&
|
|
|
|
|
2020-11-18 23:44:34 +00:00
|
|
|
# push main too; this ensures there is at least one '"'push'"' command to
|
2010-01-08 02:12:41 +00:00
|
|
|
# the remote helper and triggers interaction with the helper.
|
2020-11-18 23:44:34 +00:00
|
|
|
test_must_fail git push -v origin +main main:niam >output 2>&1'
|
2010-01-08 02:12:41 +00:00
|
|
|
|
2011-02-22 23:42:12 +00:00
|
|
|
test_expect_success 'push fails for non-fast-forward refs unmatched by remote helper: remote output' '
|
2020-11-18 23:44:34 +00:00
|
|
|
grep "^ + [a-f0-9]*\.\.\.[a-f0-9]* *main -> main (forced update)$" output &&
|
|
|
|
grep "^ ! \[rejected\] *main -> niam (non-fast-forward)$" output
|
2011-02-22 23:42:12 +00:00
|
|
|
'
|
2010-01-08 02:12:41 +00:00
|
|
|
|
2011-04-12 23:33:39 +00:00
|
|
|
test_expect_success 'push fails for non-fast-forward refs unmatched by remote helper: our output' '
|
2023-10-31 05:23:30 +00:00
|
|
|
test_grep "Updates were rejected because" \
|
2010-01-25 07:42:23 +00:00
|
|
|
output
|
2010-01-08 02:12:41 +00:00
|
|
|
'
|
|
|
|
|
2011-05-04 17:19:50 +00:00
|
|
|
test_expect_success 'push (chunked)' '
|
2020-11-18 23:44:34 +00:00
|
|
|
git checkout main &&
|
2011-05-04 17:19:50 +00:00
|
|
|
test_commit commit path3 &&
|
|
|
|
HEAD=$(git rev-parse --verify HEAD) &&
|
2013-03-24 21:06:08 +00:00
|
|
|
test_config http.postbuffer 4 &&
|
2011-05-04 17:19:50 +00:00
|
|
|
git push -v -v origin $BRANCH 2>err &&
|
|
|
|
grep "POST git-receive-pack (chunked)" err &&
|
|
|
|
(cd "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git &&
|
|
|
|
test $HEAD = $(git rev-parse --verify HEAD))
|
|
|
|
'
|
|
|
|
|
2020-11-18 23:44:34 +00:00
|
|
|
## References of remote: atomic1(1) main(2) collateral(2) other(2)
|
|
|
|
## References of local : atomic2(2) main(1) collateral(3) other(2) collateral1(3) atomic(1)
|
|
|
|
## Atomic push : main(1) collateral(3) atomic(1)
|
2020-04-17 09:45:35 +00:00
|
|
|
test_expect_success 'push --atomic also prevents branch creation, reports collateral' '
|
2019-07-11 21:19:19 +00:00
|
|
|
# Setup upstream repo - empty for now
|
|
|
|
d=$HTTPD_DOCUMENT_ROOT_PATH/atomic-branches.git &&
|
|
|
|
git init --bare "$d" &&
|
|
|
|
test_config -C "$d" http.receivepack true &&
|
|
|
|
up="$HTTPD_URL"/smart/atomic-branches.git &&
|
|
|
|
|
remote-curl: pass on atomic capability to remote side
When pushing more than one reference with the --atomic option, the
server is supposed to perform a single atomic transaction to update the
references, leaving them either all to succeed or all to fail. This
works fine when pushing locally or over SSH, but when pushing over HTTP,
we fail to pass the atomic capability to the remote side. In fact, we
have not reported this capability to any remote helpers during the life
of the feature.
Now normally, things happen to work nevertheless, since we actually
check for most types of failures, such as non-fast-forward updates, on
the client side, and just abort the entire attempt. However, if the
server side reports a problem, such as the inability to lock a ref, the
transaction isn't atomic, because we haven't passed the appropriate
capability over and the remote side has no way of knowing that we wanted
atomic behavior.
Fix this by passing the option from the transport code through to remote
helpers, and from the HTTP remote helper down to send-pack. With this
change, we can detect if the server side rejects the push and report
back appropriately. Note the difference in the messages: the remote
side reports "atomic transaction failed", while our own checking rejects
pushes with the message "atomic push failed".
Document the atomic option in the remote helper documentation, so other
implementers can implement it if they like.
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-10-16 23:45:34 +00:00
|
|
|
# Tell "$up" about three branches for now
|
2019-07-11 21:19:19 +00:00
|
|
|
test_commit atomic1 &&
|
|
|
|
test_commit atomic2 &&
|
|
|
|
git branch collateral &&
|
remote-curl: pass on atomic capability to remote side
When pushing more than one reference with the --atomic option, the
server is supposed to perform a single atomic transaction to update the
references, leaving them either all to succeed or all to fail. This
works fine when pushing locally or over SSH, but when pushing over HTTP,
we fail to pass the atomic capability to the remote side. In fact, we
have not reported this capability to any remote helpers during the life
of the feature.
Now normally, things happen to work nevertheless, since we actually
check for most types of failures, such as non-fast-forward updates, on
the client side, and just abort the entire attempt. However, if the
server side reports a problem, such as the inability to lock a ref, the
transaction isn't atomic, because we haven't passed the appropriate
capability over and the remote side has no way of knowing that we wanted
atomic behavior.
Fix this by passing the option from the transport code through to remote
helpers, and from the HTTP remote helper down to send-pack. With this
change, we can detect if the server side rejects the push and report
back appropriately. Note the difference in the messages: the remote
side reports "atomic transaction failed", while our own checking rejects
pushes with the message "atomic push failed".
Document the atomic option in the remote helper documentation, so other
implementers can implement it if they like.
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-10-16 23:45:34 +00:00
|
|
|
git branch other &&
|
2020-11-18 23:44:34 +00:00
|
|
|
git push "$up" atomic1 main collateral other &&
|
2020-04-17 09:45:35 +00:00
|
|
|
git tag -d atomic1 &&
|
2019-07-11 21:19:19 +00:00
|
|
|
|
|
|
|
# collateral is a valid push, but should be failed by atomic push
|
|
|
|
git checkout collateral &&
|
|
|
|
test_commit collateral1 &&
|
|
|
|
|
2020-11-18 23:44:34 +00:00
|
|
|
# Make main incompatible with upstream to provoke atomic
|
|
|
|
git checkout main &&
|
2019-07-11 21:19:19 +00:00
|
|
|
git reset --hard HEAD^ &&
|
|
|
|
|
|
|
|
# Add a new branch which should be failed by atomic push. This is a
|
|
|
|
# regression case.
|
|
|
|
git branch atomic &&
|
|
|
|
|
|
|
|
# --atomic should cause entire push to be rejected
|
2020-11-18 23:44:34 +00:00
|
|
|
test_must_fail git push --atomic "$up" main atomic collateral 2>output &&
|
2019-07-11 21:19:19 +00:00
|
|
|
|
|
|
|
# the new branch should not have been created upstream
|
|
|
|
test_must_fail git -C "$d" show-ref --verify refs/heads/atomic &&
|
|
|
|
|
|
|
|
# upstream should still reflect atomic2, the last thing we pushed
|
|
|
|
# successfully
|
|
|
|
git rev-parse atomic2 >expected &&
|
2020-11-18 23:44:34 +00:00
|
|
|
# on main...
|
|
|
|
git -C "$d" rev-parse refs/heads/main >actual &&
|
2019-07-11 21:19:19 +00:00
|
|
|
test_cmp expected actual &&
|
|
|
|
# ...and collateral.
|
|
|
|
git -C "$d" rev-parse refs/heads/collateral >actual &&
|
|
|
|
test_cmp expected actual &&
|
|
|
|
|
|
|
|
# the failed refs should be indicated to the user
|
2020-11-18 23:44:34 +00:00
|
|
|
grep "^ ! .*rejected.* main -> main" output &&
|
2019-07-11 21:19:19 +00:00
|
|
|
|
|
|
|
# the collateral failure refs should be indicated to the user
|
|
|
|
grep "^ ! .*rejected.* atomic -> atomic .*atomic push failed" output &&
|
2020-04-17 09:45:35 +00:00
|
|
|
grep "^ ! .*rejected.* collateral -> collateral .*atomic push failed" output &&
|
|
|
|
|
|
|
|
# never report what we do not push
|
|
|
|
! grep "^ ! .*rejected.* atomic1 " output &&
|
|
|
|
! grep "^ ! .*rejected.* other " output
|
2019-07-11 21:19:19 +00:00
|
|
|
'
|
|
|
|
|
remote-curl: pass on atomic capability to remote side
When pushing more than one reference with the --atomic option, the
server is supposed to perform a single atomic transaction to update the
references, leaving them either all to succeed or all to fail. This
works fine when pushing locally or over SSH, but when pushing over HTTP,
we fail to pass the atomic capability to the remote side. In fact, we
have not reported this capability to any remote helpers during the life
of the feature.
Now normally, things happen to work nevertheless, since we actually
check for most types of failures, such as non-fast-forward updates, on
the client side, and just abort the entire attempt. However, if the
server side reports a problem, such as the inability to lock a ref, the
transaction isn't atomic, because we haven't passed the appropriate
capability over and the remote side has no way of knowing that we wanted
atomic behavior.
Fix this by passing the option from the transport code through to remote
helpers, and from the HTTP remote helper down to send-pack. With this
change, we can detect if the server side rejects the push and report
back appropriately. Note the difference in the messages: the remote
side reports "atomic transaction failed", while our own checking rejects
pushes with the message "atomic push failed".
Document the atomic option in the remote helper documentation, so other
implementers can implement it if they like.
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-10-16 23:45:34 +00:00
|
|
|
test_expect_success 'push --atomic fails on server-side errors' '
|
|
|
|
# Use previously set up repository
|
|
|
|
d=$HTTPD_DOCUMENT_ROOT_PATH/atomic-branches.git &&
|
|
|
|
test_config -C "$d" http.receivepack true &&
|
|
|
|
up="$HTTPD_URL"/smart/atomic-branches.git &&
|
|
|
|
|
2024-01-11 20:24:30 +00:00
|
|
|
# Create d/f conflict to break ref updates for other on the remote site.
|
|
|
|
git -C "$d" update-ref -d refs/heads/other &&
|
|
|
|
git -C "$d" update-ref refs/heads/other/conflict HEAD &&
|
remote-curl: pass on atomic capability to remote side
When pushing more than one reference with the --atomic option, the
server is supposed to perform a single atomic transaction to update the
references, leaving them either all to succeed or all to fail. This
works fine when pushing locally or over SSH, but when pushing over HTTP,
we fail to pass the atomic capability to the remote side. In fact, we
have not reported this capability to any remote helpers during the life
of the feature.
Now normally, things happen to work nevertheless, since we actually
check for most types of failures, such as non-fast-forward updates, on
the client side, and just abort the entire attempt. However, if the
server side reports a problem, such as the inability to lock a ref, the
transaction isn't atomic, because we haven't passed the appropriate
capability over and the remote side has no way of knowing that we wanted
atomic behavior.
Fix this by passing the option from the transport code through to remote
helpers, and from the HTTP remote helper down to send-pack. With this
change, we can detect if the server side rejects the push and report
back appropriately. Note the difference in the messages: the remote
side reports "atomic transaction failed", while our own checking rejects
pushes with the message "atomic push failed".
Document the atomic option in the remote helper documentation, so other
implementers can implement it if they like.
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-10-16 23:45:34 +00:00
|
|
|
|
|
|
|
# add the new commit to other
|
|
|
|
git branch -f other collateral &&
|
|
|
|
|
|
|
|
# --atomic should cause entire push to be rejected
|
|
|
|
test_must_fail git push --atomic "$up" atomic other 2>output &&
|
|
|
|
|
2024-01-11 20:24:30 +00:00
|
|
|
# The atomic and other branches should not be created upstream.
|
remote-curl: pass on atomic capability to remote side
When pushing more than one reference with the --atomic option, the
server is supposed to perform a single atomic transaction to update the
references, leaving them either all to succeed or all to fail. This
works fine when pushing locally or over SSH, but when pushing over HTTP,
we fail to pass the atomic capability to the remote side. In fact, we
have not reported this capability to any remote helpers during the life
of the feature.
Now normally, things happen to work nevertheless, since we actually
check for most types of failures, such as non-fast-forward updates, on
the client side, and just abort the entire attempt. However, if the
server side reports a problem, such as the inability to lock a ref, the
transaction isn't atomic, because we haven't passed the appropriate
capability over and the remote side has no way of knowing that we wanted
atomic behavior.
Fix this by passing the option from the transport code through to remote
helpers, and from the HTTP remote helper down to send-pack. With this
change, we can detect if the server side rejects the push and report
back appropriately. Note the difference in the messages: the remote
side reports "atomic transaction failed", while our own checking rejects
pushes with the message "atomic push failed".
Document the atomic option in the remote helper documentation, so other
implementers can implement it if they like.
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-10-16 23:45:34 +00:00
|
|
|
test_must_fail git -C "$d" show-ref --verify refs/heads/atomic &&
|
2024-01-11 20:24:30 +00:00
|
|
|
test_must_fail git -C "$d" show-ref --verify refs/heads/other &&
|
remote-curl: pass on atomic capability to remote side
When pushing more than one reference with the --atomic option, the
server is supposed to perform a single atomic transaction to update the
references, leaving them either all to succeed or all to fail. This
works fine when pushing locally or over SSH, but when pushing over HTTP,
we fail to pass the atomic capability to the remote side. In fact, we
have not reported this capability to any remote helpers during the life
of the feature.
Now normally, things happen to work nevertheless, since we actually
check for most types of failures, such as non-fast-forward updates, on
the client side, and just abort the entire attempt. However, if the
server side reports a problem, such as the inability to lock a ref, the
transaction isn't atomic, because we haven't passed the appropriate
capability over and the remote side has no way of knowing that we wanted
atomic behavior.
Fix this by passing the option from the transport code through to remote
helpers, and from the HTTP remote helper down to send-pack. With this
change, we can detect if the server side rejects the push and report
back appropriately. Note the difference in the messages: the remote
side reports "atomic transaction failed", while our own checking rejects
pushes with the message "atomic push failed".
Document the atomic option in the remote helper documentation, so other
implementers can implement it if they like.
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-10-16 23:45:34 +00:00
|
|
|
|
|
|
|
# the failed refs should be indicated to the user
|
|
|
|
grep "^ ! .*rejected.* other -> other .*atomic transaction failed" output &&
|
|
|
|
|
|
|
|
# the collateral failure refs should be indicated to the user
|
|
|
|
grep "^ ! .*rejected.* atomic -> atomic .*atomic transaction failed" output
|
|
|
|
'
|
|
|
|
|
remote-curl: don't pass back fake refs
When receive-pack advertises its list of refs, it generally hides the
capabilities information after a NUL at the end of the first ref.
However, when we have an empty repository, there are no refs, and
therefore receive-pack writes a fake ref "capabilities^{}" with the
capabilities afterwards.
On the client side, git reads the result with get_remote_heads(). We pick
the capabilities from the end of the line, and then call check_ref() to
make sure the ref name is valid. We see that it isn't, and don't bother
adding it to our list of refs.
However, the call to check_ref() is enabled by passing the REF_NORMAL flag
to get_remote_heads. For the regular git transport, we pass REF_NORMAL in
get_refs_via_connect() if we are doing a push (since only receive-pack
uses this fake ref). But in remote-curl, we never use this flag, and we
accept the fake ref as a real one, passing it back from the helper to the
parent git-push.
Most of the time this bug goes unnoticed, as the fake ref won't match our
refspecs. However, if "--mirror" is used, then we see it as remote cruft
to be pruned, and try to pass along a deletion refspec for it. Of course
this refspec has bogus syntax (because of the ^{}), and the helper
complains, aborting the push.
Let's have remote-curl mirror what the builtin get_refs_via_connect() does
(at least for the case of using git protocol; we can leave the dumb
info/refs reader as it is).
This also fixes pushing with --mirror to a smart-http remote that uses
alternates. The fake ".have" refs the server gives to avoid unnecessary
network transfer has a similar bad interactions with the machinery.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-12-17 10:45:39 +00:00
|
|
|
test_expect_success 'push --all can push to empty repo' '
|
|
|
|
d=$HTTPD_DOCUMENT_ROOT_PATH/empty-all.git &&
|
|
|
|
git init --bare "$d" &&
|
|
|
|
git --git-dir="$d" config http.receivepack true &&
|
|
|
|
git push --all "$HTTPD_URL"/smart/empty-all.git
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'push --mirror can push to empty repo' '
|
|
|
|
d=$HTTPD_DOCUMENT_ROOT_PATH/empty-mirror.git &&
|
|
|
|
git init --bare "$d" &&
|
|
|
|
git --git-dir="$d" config http.receivepack true &&
|
|
|
|
git push --mirror "$HTTPD_URL"/smart/empty-mirror.git
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'push --all to repo with alternates' '
|
|
|
|
s=$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git &&
|
|
|
|
d=$HTTPD_DOCUMENT_ROOT_PATH/alternates-all.git &&
|
|
|
|
git clone --bare --shared "$s" "$d" &&
|
|
|
|
git --git-dir="$d" config http.receivepack true &&
|
|
|
|
git --git-dir="$d" repack -adl &&
|
|
|
|
git push --all "$HTTPD_URL"/smart/alternates-all.git
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'push --mirror to repo with alternates' '
|
|
|
|
s=$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git &&
|
|
|
|
d=$HTTPD_DOCUMENT_ROOT_PATH/alternates-mirror.git &&
|
|
|
|
git clone --bare --shared "$s" "$d" &&
|
|
|
|
git --git-dir="$d" config http.receivepack true &&
|
|
|
|
git --git-dir="$d" repack -adl &&
|
|
|
|
git push --mirror "$HTTPD_URL"/smart/alternates-mirror.git
|
|
|
|
'
|
|
|
|
|
2012-05-01 08:43:08 +00:00
|
|
|
test_expect_success TTY 'push shows progress when stderr is a tty' '
|
|
|
|
cd "$ROOT_PATH"/test_repo_clone &&
|
|
|
|
test_commit noisy &&
|
|
|
|
test_terminal git push >output 2>&1 &&
|
2023-10-31 05:23:30 +00:00
|
|
|
test_grep "^Writing objects" output
|
2012-05-01 08:43:08 +00:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success TTY 'push --quiet silences status and progress' '
|
2012-01-08 21:06:20 +00:00
|
|
|
cd "$ROOT_PATH"/test_repo_clone &&
|
|
|
|
test_commit quiet &&
|
2012-05-01 08:43:08 +00:00
|
|
|
test_terminal git push --quiet >output 2>&1 &&
|
2018-08-19 21:57:24 +00:00
|
|
|
test_must_be_empty output
|
2012-01-08 21:06:20 +00:00
|
|
|
'
|
|
|
|
|
2012-05-01 08:43:08 +00:00
|
|
|
test_expect_success TTY 'push --no-progress silences progress but not status' '
|
|
|
|
cd "$ROOT_PATH"/test_repo_clone &&
|
|
|
|
test_commit no-progress &&
|
|
|
|
test_terminal git push --no-progress >output 2>&1 &&
|
2023-10-31 05:23:30 +00:00
|
|
|
test_grep "^To http" output &&
|
|
|
|
test_grep ! "^Writing objects" output
|
2012-05-01 08:43:08 +00:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'push --progress shows progress to non-tty' '
|
|
|
|
cd "$ROOT_PATH"/test_repo_clone &&
|
|
|
|
test_commit progress &&
|
|
|
|
git push --progress >output 2>&1 &&
|
2023-10-31 05:23:30 +00:00
|
|
|
test_grep "^To http" output &&
|
|
|
|
test_grep "^Writing objects" output
|
2012-05-01 08:43:08 +00:00
|
|
|
'
|
|
|
|
|
2012-03-30 07:01:30 +00:00
|
|
|
test_expect_success 'http push gives sane defaults to reflog' '
|
|
|
|
cd "$ROOT_PATH"/test_repo_clone &&
|
|
|
|
test_commit reflog-test &&
|
|
|
|
git push "$HTTPD_URL"/smart/test_repo.git &&
|
|
|
|
git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git" \
|
|
|
|
log -g -1 --format="%gn <%ge>" >actual &&
|
|
|
|
echo "anonymous <anonymous@http.127.0.0.1>" >expect &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'http push respects GIT_COMMITTER_* in reflog' '
|
|
|
|
cd "$ROOT_PATH"/test_repo_clone &&
|
|
|
|
test_commit custom-reflog-test &&
|
|
|
|
git push "$HTTPD_URL"/smart_custom_env/test_repo.git &&
|
|
|
|
git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git" \
|
|
|
|
log -g -1 --format="%gn <%ge>" >actual &&
|
|
|
|
echo "Custom User <custom@example.com>" >expect &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
2012-08-27 13:25:36 +00:00
|
|
|
test_expect_success 'push over smart http with auth' '
|
|
|
|
cd "$ROOT_PATH/test_repo_clone" &&
|
|
|
|
echo push-auth-test >expect &&
|
|
|
|
test_commit push-auth-test &&
|
2014-01-02 07:38:35 +00:00
|
|
|
set_askpass user@host pass@host &&
|
2012-08-27 13:25:36 +00:00
|
|
|
git push "$HTTPD_URL"/auth/smart/test_repo.git &&
|
|
|
|
git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git" \
|
|
|
|
log -1 --format=%s >actual &&
|
|
|
|
expect_askpass both user@host &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
http: prompt for credentials on failed POST
All of the smart-http GET requests go through the http_get_*
functions, which will prompt for credentials and retry if we
see an HTTP 401.
POST requests, however, do not go through any central point.
Moreover, it is difficult to retry in the general case; we
cannot assume the request body fits in memory or is even
seekable, and we don't know how much of it was consumed
during the attempt.
Most of the time, this is not a big deal; for both fetching
and pushing, we make a GET request before doing any POSTs,
so typically we figure out the credentials during the first
request, then reuse them during the POST. However, some
servers may allow a client to get the list of refs from
receive-pack without authentication, and then require
authentication when the client actually tries to POST the
pack.
This is not ideal, as the client may do a non-trivial amount
of work to generate the pack (e.g., delta-compressing
objects). However, for a long time it has been the
recommended example configuration in git-http-backend(1) for
setting up a repository with anonymous fetch and
authenticated push. This setup has always been broken
without putting a username into the URL. Prior to commit
986bbc0, it did work with a username in the URL, because git
would prompt for credentials before making any requests at
all. However, post-986bbc0, it is totally broken. Since it
has been advertised in the manpage for some time, we should
make sure it works.
Unfortunately, it is not as easy as simply calling post_rpc
again when it fails, due to the input issue mentioned above.
However, we can still make this specific case work by
retrying in two specific instances:
1. If the request is large (bigger than LARGE_PACKET_MAX),
we will first send a probe request with a single flush
packet. Since this request is static, we can freely
retry it.
2. If the request is small and we are not using gzip, then
we have the whole thing in-core, and we can freely
retry.
That means we will not retry in some instances, including:
1. If we are using gzip. However, we only do so when
calling git-upload-pack, so it does not apply to
pushes.
2. If we have a large request, the probe succeeds, but
then the real POST wants authentication. This is an
extremely unlikely configuration and not worth worrying
about.
While it might be nice to cover those instances, doing so
would be significantly more complex for very little
real-world gain. In the long run, we will be much better off
when curl learns to internally handle authentication as a
callback, and we can cleanly handle all cases that way.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-08-27 13:27:15 +00:00
|
|
|
test_expect_success 'push to auth-only-for-push repo' '
|
2012-08-27 13:25:53 +00:00
|
|
|
cd "$ROOT_PATH/test_repo_clone" &&
|
|
|
|
echo push-half-auth >expect &&
|
|
|
|
test_commit push-half-auth &&
|
2014-01-02 07:38:35 +00:00
|
|
|
set_askpass user@host pass@host &&
|
2012-08-27 13:25:53 +00:00
|
|
|
git push "$HTTPD_URL"/auth-push/smart/test_repo.git &&
|
|
|
|
git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git" \
|
|
|
|
log -1 --format=%s >actual &&
|
|
|
|
expect_askpass both user@host &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
2013-04-13 03:33:36 +00:00
|
|
|
test_expect_success 'create repo without http.receivepack set' '
|
|
|
|
cd "$ROOT_PATH" &&
|
|
|
|
git init half-auth &&
|
|
|
|
(
|
|
|
|
cd half-auth &&
|
|
|
|
test_commit one
|
|
|
|
) &&
|
|
|
|
git clone --bare half-auth "$HTTPD_DOCUMENT_ROOT_PATH/half-auth.git"
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'clone via half-auth-complete does not need password' '
|
|
|
|
cd "$ROOT_PATH" &&
|
|
|
|
set_askpass wrong &&
|
|
|
|
git clone "$HTTPD_URL"/half-auth-complete/smart/half-auth.git \
|
|
|
|
half-auth-clone &&
|
|
|
|
expect_askpass none
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'push into half-auth-complete requires password' '
|
|
|
|
cd "$ROOT_PATH/half-auth-clone" &&
|
|
|
|
echo two >expect &&
|
|
|
|
test_commit two &&
|
2014-01-02 07:38:35 +00:00
|
|
|
set_askpass user@host pass@host &&
|
2013-04-13 03:33:36 +00:00
|
|
|
git push "$HTTPD_URL/half-auth-complete/smart/half-auth.git" &&
|
|
|
|
git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/half-auth.git" \
|
|
|
|
log -1 --format=%s >actual &&
|
|
|
|
expect_askpass both user@host &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
2014-08-21 12:21:20 +00:00
|
|
|
test_expect_success CMDLINE_LIMIT 'push 2000 tags over http' '
|
|
|
|
sha1=$(git rev-parse HEAD) &&
|
|
|
|
test_seq 2000 |
|
|
|
|
sort |
|
|
|
|
sed "s|.*|$sha1 refs/tags/really-long-tag-name-&|" \
|
|
|
|
>.git/packed-refs &&
|
|
|
|
run_with_limited_cmdline git push --mirror
|
|
|
|
'
|
|
|
|
|
2014-09-15 21:59:00 +00:00
|
|
|
test_expect_success GPG 'push with post-receive to inspect certificate' '
|
2022-03-17 10:13:18 +00:00
|
|
|
test_hook -C "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git post-receive <<-\EOF &&
|
2014-09-15 21:59:00 +00:00
|
|
|
# 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}
|
signed push: allow stale nonce in stateless mode
When operating with the stateless RPC mode, we will receive a nonce
issued by another instance of us that advertised our capability and
refs some time ago. Update the logic to check received nonce to
detect this case, compute how much time has passed since the nonce
was issued and report the status with a new environment variable
GIT_PUSH_CERT_NONCE_SLOP to the hooks.
GIT_PUSH_CERT_NONCE_STATUS will report "SLOP" in such a case. The
hooks are free to decide how large a slop it is willing to accept.
Strictly speaking, the "nonce" is not really a "nonce" anymore in
the stateless RPC mode, as it will happily take any "nonce" issued
by it (which is protected by HMAC and its secret key) as long as it
is fresh enough. The degree of this security degradation, relative
to the native protocol, is about the same as the "we make sure that
the 'git push' decided to update our refs with new objects based on
the freshest observation of our refs by making sure the values they
claim the original value of the refs they ask us to update exactly
match the current state" security is loosened to accomodate the
stateless RPC mode in the existing code without this series, so
there is no need for those who are already using smart HTTP to push
to their repositories to be alarmed any more than they already are.
In addition, the server operator can set receive.certnonceslop
configuration variable to specify how stale a nonce can be (in
seconds). When this variable is set, and if the nonce received in
the certificate that passes the HMAC check was less than that many
seconds old, hooks are given "OK" in GIT_PUSH_CERT_NONCE_STATUS
(instead of "SLOP") and the received nonce value is given in
GIT_PUSH_CERT_NONCE, which makes it easier for a simple-minded
hook to check if the certificate we received is recent enough.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-09-05 17:46:04 +00:00
|
|
|
NONCE_STATUS=${GIT_PUSH_CERT_NONCE_STATUS-nononcestatus}
|
|
|
|
NONCE=${GIT_PUSH_CERT_NONCE-nononce}
|
2014-09-15 21:59:00 +00:00
|
|
|
E_O_F
|
2022-03-17 10:13:18 +00:00
|
|
|
EOF
|
|
|
|
(
|
|
|
|
cd "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git &&
|
signed push: allow stale nonce in stateless mode
When operating with the stateless RPC mode, we will receive a nonce
issued by another instance of us that advertised our capability and
refs some time ago. Update the logic to check received nonce to
detect this case, compute how much time has passed since the nonce
was issued and report the status with a new environment variable
GIT_PUSH_CERT_NONCE_SLOP to the hooks.
GIT_PUSH_CERT_NONCE_STATUS will report "SLOP" in such a case. The
hooks are free to decide how large a slop it is willing to accept.
Strictly speaking, the "nonce" is not really a "nonce" anymore in
the stateless RPC mode, as it will happily take any "nonce" issued
by it (which is protected by HMAC and its secret key) as long as it
is fresh enough. The degree of this security degradation, relative
to the native protocol, is about the same as the "we make sure that
the 'git push' decided to update our refs with new objects based on
the freshest observation of our refs by making sure the values they
claim the original value of the refs they ask us to update exactly
match the current state" security is loosened to accomodate the
stateless RPC mode in the existing code without this series, so
there is no need for those who are already using smart HTTP to push
to their repositories to be alarmed any more than they already are.
In addition, the server operator can set receive.certnonceslop
configuration variable to specify how stale a nonce can be (in
seconds). When this variable is set, and if the nonce received in
the certificate that passes the HMAC check was less than that many
seconds old, hooks are given "OK" in GIT_PUSH_CERT_NONCE_STATUS
(instead of "SLOP") and the received nonce value is given in
GIT_PUSH_CERT_NONCE, which makes it easier for a simple-minded
hook to check if the certificate we received is recent enough.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-09-05 17:46:04 +00:00
|
|
|
git config receive.certnonceseed sekrit &&
|
|
|
|
git config receive.certnonceslop 30
|
2014-09-15 21:59:00 +00:00
|
|
|
) &&
|
|
|
|
cd "$ROOT_PATH/test_repo_clone" &&
|
|
|
|
test_commit cert-test &&
|
|
|
|
git push --signed "$HTTPD_URL/smart/test_repo.git" &&
|
|
|
|
(
|
|
|
|
cd "$HTTPD_DOCUMENT_ROOT_PATH" &&
|
signed push: allow stale nonce in stateless mode
When operating with the stateless RPC mode, we will receive a nonce
issued by another instance of us that advertised our capability and
refs some time ago. Update the logic to check received nonce to
detect this case, compute how much time has passed since the nonce
was issued and report the status with a new environment variable
GIT_PUSH_CERT_NONCE_SLOP to the hooks.
GIT_PUSH_CERT_NONCE_STATUS will report "SLOP" in such a case. The
hooks are free to decide how large a slop it is willing to accept.
Strictly speaking, the "nonce" is not really a "nonce" anymore in
the stateless RPC mode, as it will happily take any "nonce" issued
by it (which is protected by HMAC and its secret key) as long as it
is fresh enough. The degree of this security degradation, relative
to the native protocol, is about the same as the "we make sure that
the 'git push' decided to update our refs with new objects based on
the freshest observation of our refs by making sure the values they
claim the original value of the refs they ask us to update exactly
match the current state" security is loosened to accomodate the
stateless RPC mode in the existing code without this series, so
there is no need for those who are already using smart HTTP to push
to their repositories to be alarmed any more than they already are.
In addition, the server operator can set receive.certnonceslop
configuration variable to specify how stale a nonce can be (in
seconds). When this variable is set, and if the nonce received in
the certificate that passes the HMAC check was less than that many
seconds old, hooks are given "OK" in GIT_PUSH_CERT_NONCE_STATUS
(instead of "SLOP") and the received nonce value is given in
GIT_PUSH_CERT_NONCE, which makes it easier for a simple-minded
hook to check if the certificate we received is recent enough.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-09-05 17:46:04 +00:00
|
|
|
cat <<-\EOF &&
|
2014-09-15 21:59:00 +00:00
|
|
|
SIGNER=C O Mitter <committer@example.com>
|
|
|
|
KEY=13B6F51ECDDE430D
|
|
|
|
STATUS=G
|
signed push: allow stale nonce in stateless mode
When operating with the stateless RPC mode, we will receive a nonce
issued by another instance of us that advertised our capability and
refs some time ago. Update the logic to check received nonce to
detect this case, compute how much time has passed since the nonce
was issued and report the status with a new environment variable
GIT_PUSH_CERT_NONCE_SLOP to the hooks.
GIT_PUSH_CERT_NONCE_STATUS will report "SLOP" in such a case. The
hooks are free to decide how large a slop it is willing to accept.
Strictly speaking, the "nonce" is not really a "nonce" anymore in
the stateless RPC mode, as it will happily take any "nonce" issued
by it (which is protected by HMAC and its secret key) as long as it
is fresh enough. The degree of this security degradation, relative
to the native protocol, is about the same as the "we make sure that
the 'git push' decided to update our refs with new objects based on
the freshest observation of our refs by making sure the values they
claim the original value of the refs they ask us to update exactly
match the current state" security is loosened to accomodate the
stateless RPC mode in the existing code without this series, so
there is no need for those who are already using smart HTTP to push
to their repositories to be alarmed any more than they already are.
In addition, the server operator can set receive.certnonceslop
configuration variable to specify how stale a nonce can be (in
seconds). When this variable is set, and if the nonce received in
the certificate that passes the HMAC check was less than that many
seconds old, hooks are given "OK" in GIT_PUSH_CERT_NONCE_STATUS
(instead of "SLOP") and the received nonce value is given in
GIT_PUSH_CERT_NONCE, which makes it easier for a simple-minded
hook to check if the certificate we received is recent enough.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-09-05 17:46:04 +00:00
|
|
|
NONCE_STATUS=OK
|
2014-09-15 21:59:00 +00:00
|
|
|
EOF
|
signed push: allow stale nonce in stateless mode
When operating with the stateless RPC mode, we will receive a nonce
issued by another instance of us that advertised our capability and
refs some time ago. Update the logic to check received nonce to
detect this case, compute how much time has passed since the nonce
was issued and report the status with a new environment variable
GIT_PUSH_CERT_NONCE_SLOP to the hooks.
GIT_PUSH_CERT_NONCE_STATUS will report "SLOP" in such a case. The
hooks are free to decide how large a slop it is willing to accept.
Strictly speaking, the "nonce" is not really a "nonce" anymore in
the stateless RPC mode, as it will happily take any "nonce" issued
by it (which is protected by HMAC and its secret key) as long as it
is fresh enough. The degree of this security degradation, relative
to the native protocol, is about the same as the "we make sure that
the 'git push' decided to update our refs with new objects based on
the freshest observation of our refs by making sure the values they
claim the original value of the refs they ask us to update exactly
match the current state" security is loosened to accomodate the
stateless RPC mode in the existing code without this series, so
there is no need for those who are already using smart HTTP to push
to their repositories to be alarmed any more than they already are.
In addition, the server operator can set receive.certnonceslop
configuration variable to specify how stale a nonce can be (in
seconds). When this variable is set, and if the nonce received in
the certificate that passes the HMAC check was less than that many
seconds old, hooks are given "OK" in GIT_PUSH_CERT_NONCE_STATUS
(instead of "SLOP") and the received nonce value is given in
GIT_PUSH_CERT_NONCE, which makes it easier for a simple-minded
hook to check if the certificate we received is recent enough.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-09-05 17:46:04 +00:00
|
|
|
sed -n -e "s/^nonce /NONCE=/p" -e "/^$/q" push-cert
|
2014-09-15 21:59:00 +00:00
|
|
|
) >expect &&
|
|
|
|
test_cmp expect "$HTTPD_DOCUMENT_ROOT_PATH/push-cert-status"
|
|
|
|
'
|
|
|
|
|
2016-07-13 23:36:53 +00:00
|
|
|
test_expect_success 'push status output scrubs password' '
|
t5541: fix url scrubbing test when GPG is not set
When the GPG prereq is not set, we do not run test 34. That
test changes the directory of the test script as a side
effect (something we usually frown on, but which matches the
style of the rest of this script). When test 35 (the
url-scrubbing test) runs, it expects to be in the directory
from test 34. If it's not, the test fails; we are in a
different sub-repo, our test-commit is built on a different
history, and the push becomes a non-fast-forward.
We can fix this by unconditionally moving to the directory
we expect (again, against our usual style but matching how
the rest of the script operates).
As an additional protection, let's also switch from "make a
new commit and push to master" to just "push to a new
branch". We don't care about the branch name; we just want
_some_ ref update to trigger the status output. Pushing to a
new branch is less likely to run into problems with
force-updates, changing the checked-out branch, etc.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-20 11:32:26 +00:00
|
|
|
cd "$ROOT_PATH/test_repo_clone" &&
|
|
|
|
git push --porcelain \
|
|
|
|
"$HTTPD_URL_USER_PASS/smart/test_repo.git" \
|
|
|
|
+HEAD:scrub >status &&
|
2016-07-13 23:36:53 +00:00
|
|
|
# should have been scrubbed down to vanilla URL
|
|
|
|
grep "^To $HTTPD_URL/smart/test_repo.git" status
|
|
|
|
'
|
|
|
|
|
2020-06-04 20:08:29 +00:00
|
|
|
test_expect_success 'clone/fetch scrubs password from reflogs' '
|
|
|
|
cd "$ROOT_PATH" &&
|
|
|
|
git clone "$HTTPD_URL_USER_PASS/smart/test_repo.git" \
|
|
|
|
reflog-test &&
|
|
|
|
cd reflog-test &&
|
|
|
|
test_commit prepare-for-force-fetch &&
|
|
|
|
git switch -c away &&
|
|
|
|
git fetch "$HTTPD_URL_USER_PASS/smart/test_repo.git" \
|
2020-11-18 23:44:34 +00:00
|
|
|
+main:main &&
|
2020-06-04 20:08:29 +00:00
|
|
|
# should have been scrubbed down to vanilla URL
|
2020-11-18 23:44:34 +00:00
|
|
|
git log -g main >reflog &&
|
2020-06-04 20:08:29 +00:00
|
|
|
grep "$HTTPD_URL" reflog &&
|
|
|
|
! grep "$HTTPD_URL_USER_PASS" reflog
|
|
|
|
'
|
|
|
|
|
remote-curl: make --force-with-lease work with non-ASCII ref names
When we invoke a remote transport helper and pass an option with an
argument, we quote the argument as a C-style string if necessary. This
is the case for the cas option, which implements the --force-with-lease
command-line flag, when we're passing a non-ASCII refname.
However, the remote curl helper isn't designed to parse such an
argument, meaning that if we try to use --force-with-lease with an HTTP
push and a non-ASCII refname, we get an error like this:
error: cannot parse expected object name '0000000000000000000000000000000000000000"'
Note the double quote, which get_oid has reminded us is not valid in an
hex object ID.
Even if we had been able to parse it, we would send the wrong data to
the server: we'd send an escaped ref, which would not behave as the user
wanted and might accidentally result in updating or deleting a ref we
hadn't intended.
Since we need to expect a quoted C-style string here, just check if the
first argument is a double quote, and if so, unquote it. Note that if
the refname contains a double quote, then we will have double-quoted it
already, so there is no ambiguity.
We test for this case only in the smart protocol, since the DAV-based
protocol is not capable of handling this capability. We use UTF-8
because this is nicer in our tests and friendlier to Windows, but the
code should work for all non-ASCII refs.
While we're at it, since the name of the option is now well established
and isn't going to change, let's inline it instead of using the #define
constant.
Reported-by: Frej Bjon <frej.bjon@nemit.fi>
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-07-21 01:15:11 +00:00
|
|
|
test_expect_success 'Non-ASCII branch name can be used with --force-with-lease' '
|
|
|
|
cd "$ROOT_PATH" &&
|
|
|
|
git clone "$HTTPD_URL_USER_PASS/smart/test_repo.git" non-ascii &&
|
|
|
|
cd non-ascii &&
|
|
|
|
git checkout -b rama-de-árbol &&
|
|
|
|
test_commit F &&
|
|
|
|
git push --force-with-lease origin rama-de-árbol &&
|
|
|
|
git ls-remote origin refs/heads/rama-de-árbol >actual &&
|
|
|
|
git ls-remote . refs/heads/rama-de-árbol >expect &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
git push --delete --force-with-lease origin rama-de-árbol &&
|
|
|
|
git ls-remote origin refs/heads/rama-de-árbol >actual &&
|
|
|
|
test_must_be_empty actual
|
|
|
|
'
|
|
|
|
|
2018-04-21 10:10:04 +00:00
|
|
|
test_expect_success 'colorize errors/hints' '
|
|
|
|
cd "$ROOT_PATH"/test_repo_clone &&
|
|
|
|
test_must_fail git -c color.transport=always -c color.advice=always \
|
|
|
|
-c color.push=always \
|
2020-11-18 23:44:34 +00:00
|
|
|
push origin origin/main^:main 2>act &&
|
2018-04-21 10:10:04 +00:00
|
|
|
test_decode_color <act >decoded &&
|
2023-10-31 05:23:30 +00:00
|
|
|
test_grep "<RED>.*rejected.*<RESET>" decoded &&
|
|
|
|
test_grep "<RED>error: failed to push some refs" decoded &&
|
|
|
|
test_grep "<YELLOW>hint: " decoded &&
|
|
|
|
test_grep ! "^hint: " decoded
|
2018-04-21 10:10:04 +00:00
|
|
|
'
|
|
|
|
|
send-pack: complain about "expecting report" with --helper-status
When pushing to a server which erroneously omits the final ref-status
report, the client side should complain about the refs for which we
didn't receive the status (because we can't just assume they were
updated). This works over most transports like ssh, but for http we'll
print a very misleading "Everything up-to-date".
It works for ssh because send-pack internally sets the status of each
ref to REF_STATUS_EXPECTING_REPORT, and then if the server doesn't tell
us about a particular ref, it will stay at that value. When we print the
final status table, we'll see that we're still on EXPECTING_REPORT and
complain then.
But for http, we go through remote-curl, which invokes send-pack with
"--stateless-rpc --helper-status". The latter option causes send-pack to
return a machine-readable list of ref statuses to the remote helper. But
ever since its inception in de1a2fdd38 (Smart push over HTTP: client
side, 2009-10-30), the send-pack code has simply omitted mention of any
ref which ended up in EXPECTING_REPORT.
In the remote helper, we then take the absence of any status report
from send-pack to mean that the ref was not even something we tried to
send, and thus it prints "Everything up-to-date". Fortunately it does
detect the eventual non-zero exit from send-pack, and propagates that in
its own non-zero exit code. So at least a careful script invoking "git
push" would notice the failure. But sending the misleading message on
stderr is certainly confusing for humans (not to mention the
machine-readable "push --porcelain" output, though again, any careful
script should be checking the exit code from push, too).
Nobody seems to have noticed because the server in this instance has to
be misbehaving: it has promised to support the ref-status capability
(otherwise the client will not set EXPECTING_REPORT at all), but didn't
send us any. If the connection were simply cut, then send-pack would
complain about getting EOF while trying to read the status. But if the
server actually sends a flush packet (i.e., saying "now you have all of
the ref statuses" without actually sending any), then the client ends up
in this confused situation.
The fix is simple: we should return an error message from "send-pack
--helper-status", just like we would for any other error per-ref error
condition (in the test I included, the server simply omits all ref
status responses, but a more insidious version of this would skip only
some of them).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-10-18 19:43:47 +00:00
|
|
|
test_expect_success 'report error server does not provide ref status' '
|
|
|
|
git init "$HTTPD_DOCUMENT_ROOT_PATH/no_report" &&
|
|
|
|
git -C "$HTTPD_DOCUMENT_ROOT_PATH/no_report" config http.receivepack true &&
|
|
|
|
test_must_fail git push --porcelain \
|
|
|
|
$HTTPD_URL_USER_PASS/smart/no_report \
|
|
|
|
HEAD:refs/tags/will-fail >actual &&
|
|
|
|
test_must_fail git -C "$HTTPD_DOCUMENT_ROOT_PATH/no_report" \
|
|
|
|
rev-parse --verify refs/tags/will-fail &&
|
|
|
|
cat >expect <<-EOF &&
|
|
|
|
To $HTTPD_URL/smart/no_report
|
2021-10-18 19:45:56 +00:00
|
|
|
! HEAD:refs/tags/will-fail [remote failure] (remote failed to report status)
|
send-pack: complain about "expecting report" with --helper-status
When pushing to a server which erroneously omits the final ref-status
report, the client side should complain about the refs for which we
didn't receive the status (because we can't just assume they were
updated). This works over most transports like ssh, but for http we'll
print a very misleading "Everything up-to-date".
It works for ssh because send-pack internally sets the status of each
ref to REF_STATUS_EXPECTING_REPORT, and then if the server doesn't tell
us about a particular ref, it will stay at that value. When we print the
final status table, we'll see that we're still on EXPECTING_REPORT and
complain then.
But for http, we go through remote-curl, which invokes send-pack with
"--stateless-rpc --helper-status". The latter option causes send-pack to
return a machine-readable list of ref statuses to the remote helper. But
ever since its inception in de1a2fdd38 (Smart push over HTTP: client
side, 2009-10-30), the send-pack code has simply omitted mention of any
ref which ended up in EXPECTING_REPORT.
In the remote helper, we then take the absence of any status report
from send-pack to mean that the ref was not even something we tried to
send, and thus it prints "Everything up-to-date". Fortunately it does
detect the eventual non-zero exit from send-pack, and propagates that in
its own non-zero exit code. So at least a careful script invoking "git
push" would notice the failure. But sending the misleading message on
stderr is certainly confusing for humans (not to mention the
machine-readable "push --porcelain" output, though again, any careful
script should be checking the exit code from push, too).
Nobody seems to have noticed because the server in this instance has to
be misbehaving: it has promised to support the ref-status capability
(otherwise the client will not set EXPECTING_REPORT at all), but didn't
send us any. If the connection were simply cut, then send-pack would
complain about getting EOF while trying to read the status. But if the
server actually sends a flush packet (i.e., saying "now you have all of
the ref statuses" without actually sending any), then the client ends up
in this confused situation.
The fix is simple: we should return an error message from "send-pack
--helper-status", just like we would for any other error per-ref error
condition (in the test I included, the server simply omits all ref
status responses, but a more insidious version of this would skip only
some of them).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-10-18 19:43:47 +00:00
|
|
|
Done
|
|
|
|
EOF
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
2009-10-31 00:47:47 +00:00
|
|
|
test_done
|