mirror of
https://github.com/git/git.git
synced 2024-11-28 20:44:04 +08:00
Merge branch 'ka/want-ref-in-namespace' into maint
"git upload-pack" which runs on the other side of "git fetch" forgot to take the ref namespaces into account when handling want-ref requests. * ka/want-ref-in-namespace: docs: clarify the interaction of transfer.hideRefs and namespaces upload-pack.c: treat want-ref relative to namespace t5730: introduce fetch command helper
This commit is contained in:
commit
0a5af02acb
@ -52,13 +52,17 @@ If you have multiple hideRefs values, later entries override earlier ones
|
|||||||
(and entries in more-specific config files override less-specific ones).
|
(and entries in more-specific config files override less-specific ones).
|
||||||
+
|
+
|
||||||
If a namespace is in use, the namespace prefix is stripped from each
|
If a namespace is in use, the namespace prefix is stripped from each
|
||||||
reference before it is matched against `transfer.hiderefs` patterns.
|
reference before it is matched against `transfer.hiderefs` patterns. In
|
||||||
|
order to match refs before stripping, add a `^` in front of the ref name. If
|
||||||
|
you combine `!` and `^`, `!` must be specified first.
|
||||||
|
+
|
||||||
For example, if `refs/heads/master` is specified in `transfer.hideRefs` and
|
For example, if `refs/heads/master` is specified in `transfer.hideRefs` and
|
||||||
the current namespace is `foo`, then `refs/namespaces/foo/refs/heads/master`
|
the current namespace is `foo`, then `refs/namespaces/foo/refs/heads/master`
|
||||||
is omitted from the advertisements but `refs/heads/master` and
|
is omitted from the advertisements. If `uploadpack.allowRefInWant` is set,
|
||||||
`refs/namespaces/bar/refs/heads/master` are still advertised as so-called
|
`upload-pack` will treat `want-ref refs/heads/master` in a protocol v2
|
||||||
"have" lines. In order to match refs before stripping, add a `^` in front of
|
`fetch` command as if `refs/namespaces/foo/refs/heads/master` did not exist.
|
||||||
the ref name. If you combine `!` and `^`, `!` must be specified first.
|
`receive-pack`, on the other hand, will still advertise the object id the
|
||||||
|
ref is pointing to without mentioning its name (a so-called ".have" line).
|
||||||
+
|
+
|
||||||
Even if you hide refs, a client may still be able to steal the target
|
Even if you hide refs, a client may still be able to steal the target
|
||||||
objects via the techniques described in the "SECURITY" section of the
|
objects via the techniques described in the "SECURITY" section of the
|
||||||
|
@ -40,6 +40,30 @@ write_command () {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Write a complete fetch command to stdout, suitable for use with `test-tool
|
||||||
|
# pkt-line`. "want-ref", "want", and "have" lines are read from stdin.
|
||||||
|
#
|
||||||
|
# Examples:
|
||||||
|
#
|
||||||
|
# write_fetch_command <<-EOF
|
||||||
|
# want-ref refs/heads/main
|
||||||
|
# have $(git rev-parse a)
|
||||||
|
# EOF
|
||||||
|
#
|
||||||
|
# write_fetch_command <<-EOF
|
||||||
|
# want $(git rev-parse b)
|
||||||
|
# have $(git rev-parse a)
|
||||||
|
# EOF
|
||||||
|
#
|
||||||
|
write_fetch_command () {
|
||||||
|
write_command fetch &&
|
||||||
|
echo "0001" &&
|
||||||
|
echo "no-progress" &&
|
||||||
|
cat &&
|
||||||
|
echo "done" &&
|
||||||
|
echo "0000"
|
||||||
|
}
|
||||||
|
|
||||||
# c(o/foo) d(o/bar)
|
# c(o/foo) d(o/bar)
|
||||||
# \ /
|
# \ /
|
||||||
# b e(baz) f(main)
|
# b e(baz) f(main)
|
||||||
@ -77,15 +101,11 @@ test_expect_success 'config controls ref-in-want advertisement' '
|
|||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'invalid want-ref line' '
|
test_expect_success 'invalid want-ref line' '
|
||||||
test-tool pkt-line pack >in <<-EOF &&
|
write_fetch_command >pkt <<-EOF &&
|
||||||
$(write_command fetch)
|
|
||||||
0001
|
|
||||||
no-progress
|
|
||||||
want-ref refs/heads/non-existent
|
want-ref refs/heads/non-existent
|
||||||
done
|
|
||||||
0000
|
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
test-tool pkt-line pack <pkt >in &&
|
||||||
test_must_fail test-tool serve-v2 --stateless-rpc 2>out <in &&
|
test_must_fail test-tool serve-v2 --stateless-rpc 2>out <in &&
|
||||||
grep "unknown ref" out
|
grep "unknown ref" out
|
||||||
'
|
'
|
||||||
@ -97,16 +117,11 @@ test_expect_success 'basic want-ref' '
|
|||||||
EOF
|
EOF
|
||||||
git rev-parse f >expected_commits &&
|
git rev-parse f >expected_commits &&
|
||||||
|
|
||||||
oid=$(git rev-parse a) &&
|
write_fetch_command >pkt <<-EOF &&
|
||||||
test-tool pkt-line pack >in <<-EOF &&
|
|
||||||
$(write_command fetch)
|
|
||||||
0001
|
|
||||||
no-progress
|
|
||||||
want-ref refs/heads/main
|
want-ref refs/heads/main
|
||||||
have $oid
|
have $(git rev-parse a)
|
||||||
done
|
|
||||||
0000
|
|
||||||
EOF
|
EOF
|
||||||
|
test-tool pkt-line pack <pkt >in &&
|
||||||
|
|
||||||
test-tool serve-v2 --stateless-rpc >out <in &&
|
test-tool serve-v2 --stateless-rpc >out <in &&
|
||||||
check_output
|
check_output
|
||||||
@ -121,17 +136,12 @@ test_expect_success 'multiple want-ref lines' '
|
|||||||
EOF
|
EOF
|
||||||
git rev-parse c d >expected_commits &&
|
git rev-parse c d >expected_commits &&
|
||||||
|
|
||||||
oid=$(git rev-parse b) &&
|
write_fetch_command >pkt <<-EOF &&
|
||||||
test-tool pkt-line pack >in <<-EOF &&
|
|
||||||
$(write_command fetch)
|
|
||||||
0001
|
|
||||||
no-progress
|
|
||||||
want-ref refs/heads/o/foo
|
want-ref refs/heads/o/foo
|
||||||
want-ref refs/heads/o/bar
|
want-ref refs/heads/o/bar
|
||||||
have $oid
|
have $(git rev-parse b)
|
||||||
done
|
|
||||||
0000
|
|
||||||
EOF
|
EOF
|
||||||
|
test-tool pkt-line pack <pkt >in &&
|
||||||
|
|
||||||
test-tool serve-v2 --stateless-rpc >out <in &&
|
test-tool serve-v2 --stateless-rpc >out <in &&
|
||||||
check_output
|
check_output
|
||||||
@ -144,16 +154,12 @@ test_expect_success 'mix want and want-ref' '
|
|||||||
EOF
|
EOF
|
||||||
git rev-parse e f >expected_commits &&
|
git rev-parse e f >expected_commits &&
|
||||||
|
|
||||||
test-tool pkt-line pack >in <<-EOF &&
|
write_fetch_command >pkt <<-EOF &&
|
||||||
$(write_command fetch)
|
|
||||||
0001
|
|
||||||
no-progress
|
|
||||||
want-ref refs/heads/main
|
want-ref refs/heads/main
|
||||||
want $(git rev-parse e)
|
want $(git rev-parse e)
|
||||||
have $(git rev-parse a)
|
have $(git rev-parse a)
|
||||||
done
|
|
||||||
0000
|
|
||||||
EOF
|
EOF
|
||||||
|
test-tool pkt-line pack <pkt >in &&
|
||||||
|
|
||||||
test-tool serve-v2 --stateless-rpc >out <in &&
|
test-tool serve-v2 --stateless-rpc >out <in &&
|
||||||
check_output
|
check_output
|
||||||
@ -166,16 +172,11 @@ test_expect_success 'want-ref with ref we already have commit for' '
|
|||||||
EOF
|
EOF
|
||||||
>expected_commits &&
|
>expected_commits &&
|
||||||
|
|
||||||
oid=$(git rev-parse c) &&
|
write_fetch_command >pkt <<-EOF &&
|
||||||
test-tool pkt-line pack >in <<-EOF &&
|
|
||||||
$(write_command fetch)
|
|
||||||
0001
|
|
||||||
no-progress
|
|
||||||
want-ref refs/heads/o/foo
|
want-ref refs/heads/o/foo
|
||||||
have $oid
|
have $(git rev-parse c)
|
||||||
done
|
|
||||||
0000
|
|
||||||
EOF
|
EOF
|
||||||
|
test-tool pkt-line pack <pkt >in &&
|
||||||
|
|
||||||
test-tool serve-v2 --stateless-rpc >out <in &&
|
test-tool serve-v2 --stateless-rpc >out <in &&
|
||||||
check_output
|
check_output
|
||||||
@ -298,6 +299,141 @@ test_expect_success 'fetching with wildcard that matches multiple refs' '
|
|||||||
grep "want-ref refs/heads/o/bar" log
|
grep "want-ref refs/heads/o/bar" log
|
||||||
'
|
'
|
||||||
|
|
||||||
|
REPO="$(pwd)/repo-ns"
|
||||||
|
|
||||||
|
test_expect_success 'setup namespaced repo' '
|
||||||
|
(
|
||||||
|
git init -b main "$REPO" &&
|
||||||
|
cd "$REPO" &&
|
||||||
|
test_commit a &&
|
||||||
|
test_commit b &&
|
||||||
|
git checkout a &&
|
||||||
|
test_commit c &&
|
||||||
|
git checkout a &&
|
||||||
|
test_commit d &&
|
||||||
|
git update-ref refs/heads/ns-no b &&
|
||||||
|
git update-ref refs/namespaces/ns/refs/heads/ns-yes c &&
|
||||||
|
git update-ref refs/namespaces/ns/refs/heads/hidden d
|
||||||
|
) &&
|
||||||
|
git -C "$REPO" config uploadpack.allowRefInWant true
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'with namespace: want-ref is considered relative to namespace' '
|
||||||
|
wanted_ref=refs/heads/ns-yes &&
|
||||||
|
|
||||||
|
oid=$(git -C "$REPO" rev-parse "refs/namespaces/ns/$wanted_ref") &&
|
||||||
|
cat >expected_refs <<-EOF &&
|
||||||
|
$oid $wanted_ref
|
||||||
|
EOF
|
||||||
|
cat >expected_commits <<-EOF &&
|
||||||
|
$oid
|
||||||
|
$(git -C "$REPO" rev-parse a)
|
||||||
|
EOF
|
||||||
|
|
||||||
|
write_fetch_command >pkt <<-EOF &&
|
||||||
|
want-ref $wanted_ref
|
||||||
|
EOF
|
||||||
|
test-tool pkt-line pack <pkt >in &&
|
||||||
|
|
||||||
|
GIT_NAMESPACE=ns test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in &&
|
||||||
|
check_output
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'with namespace: want-ref outside namespace is unknown' '
|
||||||
|
wanted_ref=refs/heads/ns-no &&
|
||||||
|
|
||||||
|
write_fetch_command >pkt <<-EOF &&
|
||||||
|
want-ref $wanted_ref
|
||||||
|
EOF
|
||||||
|
test-tool pkt-line pack <pkt >in &&
|
||||||
|
|
||||||
|
test_must_fail env GIT_NAMESPACE=ns \
|
||||||
|
test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in &&
|
||||||
|
grep "unknown ref" out
|
||||||
|
'
|
||||||
|
|
||||||
|
# Cross-check refs/heads/ns-no indeed exists
|
||||||
|
test_expect_success 'without namespace: want-ref outside namespace succeeds' '
|
||||||
|
wanted_ref=refs/heads/ns-no &&
|
||||||
|
|
||||||
|
oid=$(git -C "$REPO" rev-parse $wanted_ref) &&
|
||||||
|
cat >expected_refs <<-EOF &&
|
||||||
|
$oid $wanted_ref
|
||||||
|
EOF
|
||||||
|
cat >expected_commits <<-EOF &&
|
||||||
|
$oid
|
||||||
|
$(git -C "$REPO" rev-parse a)
|
||||||
|
EOF
|
||||||
|
|
||||||
|
write_fetch_command >pkt <<-EOF &&
|
||||||
|
want-ref $wanted_ref
|
||||||
|
EOF
|
||||||
|
test-tool pkt-line pack <pkt >in &&
|
||||||
|
|
||||||
|
test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in &&
|
||||||
|
check_output
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'with namespace: hideRefs is matched, relative to namespace' '
|
||||||
|
wanted_ref=refs/heads/hidden &&
|
||||||
|
git -C "$REPO" config transfer.hideRefs $wanted_ref &&
|
||||||
|
|
||||||
|
write_fetch_command >pkt <<-EOF &&
|
||||||
|
want-ref $wanted_ref
|
||||||
|
EOF
|
||||||
|
test-tool pkt-line pack <pkt >in &&
|
||||||
|
|
||||||
|
test_must_fail env GIT_NAMESPACE=ns \
|
||||||
|
test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in &&
|
||||||
|
grep "unknown ref" out
|
||||||
|
'
|
||||||
|
|
||||||
|
# Cross-check refs/heads/hidden indeed exists
|
||||||
|
test_expect_success 'with namespace: want-ref succeeds if hideRefs is removed' '
|
||||||
|
wanted_ref=refs/heads/hidden &&
|
||||||
|
git -C "$REPO" config --unset transfer.hideRefs $wanted_ref &&
|
||||||
|
|
||||||
|
oid=$(git -C "$REPO" rev-parse "refs/namespaces/ns/$wanted_ref") &&
|
||||||
|
cat >expected_refs <<-EOF &&
|
||||||
|
$oid $wanted_ref
|
||||||
|
EOF
|
||||||
|
cat >expected_commits <<-EOF &&
|
||||||
|
$oid
|
||||||
|
$(git -C "$REPO" rev-parse a)
|
||||||
|
EOF
|
||||||
|
|
||||||
|
write_fetch_command >pkt <<-EOF &&
|
||||||
|
want-ref $wanted_ref
|
||||||
|
EOF
|
||||||
|
test-tool pkt-line pack <pkt >in &&
|
||||||
|
|
||||||
|
GIT_NAMESPACE=ns test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in &&
|
||||||
|
check_output
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'without namespace: relative hideRefs does not match' '
|
||||||
|
wanted_ref=refs/namespaces/ns/refs/heads/hidden &&
|
||||||
|
git -C "$REPO" config transfer.hideRefs refs/heads/hidden &&
|
||||||
|
|
||||||
|
oid=$(git -C "$REPO" rev-parse $wanted_ref) &&
|
||||||
|
cat >expected_refs <<-EOF &&
|
||||||
|
$oid $wanted_ref
|
||||||
|
EOF
|
||||||
|
cat >expected_commits <<-EOF &&
|
||||||
|
$oid
|
||||||
|
$(git -C "$REPO" rev-parse a)
|
||||||
|
EOF
|
||||||
|
|
||||||
|
write_fetch_command >pkt <<-EOF &&
|
||||||
|
want-ref $wanted_ref
|
||||||
|
EOF
|
||||||
|
test-tool pkt-line pack <pkt >in &&
|
||||||
|
|
||||||
|
test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in &&
|
||||||
|
check_output
|
||||||
|
'
|
||||||
|
|
||||||
|
|
||||||
. "$TEST_DIRECTORY"/lib-httpd.sh
|
. "$TEST_DIRECTORY"/lib-httpd.sh
|
||||||
start_httpd
|
start_httpd
|
||||||
|
|
||||||
|
@ -1417,21 +1417,25 @@ static int parse_want_ref(struct packet_writer *writer, const char *line,
|
|||||||
struct string_list *wanted_refs,
|
struct string_list *wanted_refs,
|
||||||
struct object_array *want_obj)
|
struct object_array *want_obj)
|
||||||
{
|
{
|
||||||
const char *arg;
|
const char *refname_nons;
|
||||||
if (skip_prefix(line, "want-ref ", &arg)) {
|
if (skip_prefix(line, "want-ref ", &refname_nons)) {
|
||||||
struct object_id oid;
|
struct object_id oid;
|
||||||
struct string_list_item *item;
|
struct string_list_item *item;
|
||||||
struct object *o;
|
struct object *o;
|
||||||
|
struct strbuf refname = STRBUF_INIT;
|
||||||
|
|
||||||
if (read_ref(arg, &oid)) {
|
strbuf_addf(&refname, "%s%s", get_git_namespace(), refname_nons);
|
||||||
packet_writer_error(writer, "unknown ref %s", arg);
|
if (ref_is_hidden(refname_nons, refname.buf) ||
|
||||||
die("unknown ref %s", arg);
|
read_ref(refname.buf, &oid)) {
|
||||||
|
packet_writer_error(writer, "unknown ref %s", refname_nons);
|
||||||
|
die("unknown ref %s", refname_nons);
|
||||||
}
|
}
|
||||||
|
strbuf_release(&refname);
|
||||||
|
|
||||||
item = string_list_append(wanted_refs, arg);
|
item = string_list_append(wanted_refs, refname_nons);
|
||||||
item->util = oiddup(&oid);
|
item->util = oiddup(&oid);
|
||||||
|
|
||||||
o = parse_object_or_die(&oid, arg);
|
o = parse_object_or_die(&oid, refname_nons);
|
||||||
if (!(o->flags & WANTED)) {
|
if (!(o->flags & WANTED)) {
|
||||||
o->flags |= WANTED;
|
o->flags |= WANTED;
|
||||||
add_object_array(o, NULL, want_obj);
|
add_object_array(o, NULL, want_obj);
|
||||||
|
Loading…
Reference in New Issue
Block a user