Skip to content

Commit 9bedd82

Browse files
committed
upload-pack.c: treat want-ref relative to namespace
When 'upload-pack' runs within the context of a git namespace, treat any 'want-ref' lines the client sends as relative to that namespace. Also check if the wanted ref is hidden via 'hideRefs'. If it is hidden, respond with an error as if the ref didn't exist. Helped-by: Jonathan Tan <[email protected]> Signed-off-by: Kim Altintop <[email protected]>
1 parent 1adf29e commit 9bedd82

File tree

2 files changed

+140
-7
lines changed

2 files changed

+140
-7
lines changed

t/t5703-upload-pack-ref-in-want.sh

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,135 @@ test_expect_success 'fetching with wildcard that matches multiple refs' '
339339
grep "want-ref refs/heads/o/bar" log
340340
'
341341

342+
REPO="$(pwd)/repo-ns"
343+
344+
test_expect_success 'setup namespaced repo' '
345+
(
346+
git init -b main "$REPO" &&
347+
cd "$REPO" &&
348+
test_commit a &&
349+
test_commit b &&
350+
git checkout a &&
351+
test_commit c &&
352+
git checkout a &&
353+
test_commit d &&
354+
git update-ref refs/heads/ns-no b &&
355+
git update-ref refs/namespaces/ns/refs/heads/ns-yes c &&
356+
git update-ref refs/namespaces/ns/refs/heads/hidden d
357+
) &&
358+
git -C "$REPO" config uploadpack.allowRefInWant true
359+
'
360+
361+
test_expect_success 'with namespace: want-ref is considered relative to namespace' '
362+
wanted_ref=refs/heads/ns-yes &&
363+
364+
oid=$(git -C "$REPO" rev-parse "refs/namespaces/ns/$wanted_ref") &&
365+
cat >expected_refs <<-EOF &&
366+
$oid $wanted_ref
367+
EOF
368+
cat >expected_commits <<-EOF &&
369+
$oid
370+
$(git -C "$REPO" rev-parse a)
371+
EOF
372+
373+
test-tool pkt-line pack >in <<-EOF &&
374+
$(write_fetch_command $wanted_ref)
375+
EOF
376+
377+
GIT_NAMESPACE=ns test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in &&
378+
check_output
379+
'
380+
381+
test_expect_success 'with namespace: want-ref outside namespace is unknown' '
382+
wanted_ref=refs/heads/ns-no &&
383+
384+
test-tool pkt-line pack >in <<-EOF &&
385+
$(write_fetch_command $wanted_ref)
386+
EOF
387+
388+
test_must_fail env GIT_NAMESPACE=ns \
389+
test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in &&
390+
grep "unknown ref" out
391+
'
392+
393+
# Cross-check refs/heads/ns-no indeed exists
394+
test_expect_success 'without namespace: want-ref outside namespace succeeds' '
395+
wanted_ref=refs/heads/ns-no &&
396+
397+
oid=$(git -C "$REPO" rev-parse $wanted_ref) &&
398+
cat >expected_refs <<-EOF &&
399+
$oid $wanted_ref
400+
EOF
401+
cat >expected_commits <<-EOF &&
402+
$oid
403+
$(git -C "$REPO" rev-parse a)
404+
EOF
405+
406+
test-tool pkt-line pack >in <<-EOF &&
407+
$(write_fetch_command $wanted_ref)
408+
EOF
409+
410+
test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in &&
411+
check_output
412+
'
413+
414+
test_expect_success 'with namespace: hideRefs is matched, relative to namespace' '
415+
wanted_ref=refs/heads/hidden &&
416+
git -C "$REPO" config transfer.hideRefs $wanted_ref &&
417+
418+
test-tool pkt-line pack >in <<-EOF &&
419+
$(write_fetch_command $wanted_ref)
420+
EOF
421+
422+
test_must_fail env GIT_NAMESPACE=ns \
423+
test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in &&
424+
grep "unknown ref" out
425+
'
426+
427+
# Cross-check refs/heads/hidden indeed exists
428+
test_expect_success 'with namespace: want-ref succeeds if hideRefs is removed' '
429+
wanted_ref=refs/heads/hidden &&
430+
git -C "$REPO" config --unset transfer.hideRefs $wanted_ref &&
431+
432+
oid=$(git -C "$REPO" rev-parse "refs/namespaces/ns/$wanted_ref") &&
433+
cat >expected_refs <<-EOF &&
434+
$oid $wanted_ref
435+
EOF
436+
cat >expected_commits <<-EOF &&
437+
$oid
438+
$(git -C "$REPO" rev-parse a)
439+
EOF
440+
441+
test-tool pkt-line pack >in <<-EOF &&
442+
$(write_fetch_command $wanted_ref)
443+
EOF
444+
445+
GIT_NAMESPACE=ns test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in &&
446+
check_output
447+
'
448+
449+
test_expect_success 'without namespace: relative hideRefs does not match' '
450+
wanted_ref=refs/namespaces/ns/refs/heads/hidden &&
451+
git -C "$REPO" config transfer.hideRefs refs/heads/hidden &&
452+
453+
oid=$(git -C "$REPO" rev-parse $wanted_ref) &&
454+
cat >expected_refs <<-EOF &&
455+
$oid $wanted_ref
456+
EOF
457+
cat >expected_commits <<-EOF &&
458+
$oid
459+
$(git -C "$REPO" rev-parse a)
460+
EOF
461+
462+
test-tool pkt-line pack >in <<-EOF &&
463+
$(write_fetch_command $wanted_ref)
464+
EOF
465+
466+
test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in &&
467+
check_output
468+
'
469+
470+
342471
. "$TEST_DIRECTORY"/lib-httpd.sh
343472
start_httpd
344473

upload-pack.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1417,21 +1417,25 @@ static int parse_want_ref(struct packet_writer *writer, const char *line,
14171417
struct string_list *wanted_refs,
14181418
struct object_array *want_obj)
14191419
{
1420-
const char *arg;
1421-
if (skip_prefix(line, "want-ref ", &arg)) {
1420+
const char *refname_nons;
1421+
if (skip_prefix(line, "want-ref ", &refname_nons)) {
14221422
struct object_id oid;
14231423
struct string_list_item *item;
14241424
struct object *o;
1425+
struct strbuf refname = STRBUF_INIT;
14251426

1426-
if (read_ref(arg, &oid)) {
1427-
packet_writer_error(writer, "unknown ref %s", arg);
1428-
die("unknown ref %s", arg);
1427+
strbuf_addf(&refname, "%s%s", get_git_namespace(), refname_nons);
1428+
if (ref_is_hidden(refname_nons, refname.buf) ||
1429+
read_ref(refname.buf, &oid)) {
1430+
packet_writer_error(writer, "unknown ref %s", refname_nons);
1431+
die("unknown ref %s", refname_nons);
14291432
}
1433+
strbuf_release(&refname);
14301434

1431-
item = string_list_append(wanted_refs, arg);
1435+
item = string_list_append(wanted_refs, refname_nons);
14321436
item->util = oiddup(&oid);
14331437

1434-
o = parse_object_or_die(&oid, arg);
1438+
o = parse_object_or_die(&oid, refname_nons);
14351439
if (!(o->flags & WANTED)) {
14361440
o->flags |= WANTED;
14371441
add_object_array(o, NULL, want_obj);

0 commit comments

Comments
 (0)