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 <jonathantanmy@google.com> Signed-off-by: Kim Altintop <kim@eagain.st> Reviewed-by: Jonathan Tan <jonathantanmy@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Kim Altintop committed
Aug 13, 2021 at 06:23 UTC
39551406539e6ea87f89f619f7f0800e887e9b57
2 files changed
+146
-7
t/t5703-upload-pack-ref-in-want.sh
+135
@@ -299,6 +299,141 @@ test_expect_success 'fetching with wildcard that matches multiple refs' '
299
grep "want-ref refs/heads/o/bar" log
300
'
301
302
+REPO="$(pwd)/repo-ns"
303
+
304
+test_expect_success 'setup namespaced repo' '
305
+ (
306
+ git init -b main "$REPO" &&
307
+ cd "$REPO" &&
308
+ test_commit a &&
309
+ test_commit b &&
310
+ git checkout a &&
311
+ test_commit c &&
312
+ git checkout a &&
313
+ test_commit d &&
314
+ git update-ref refs/heads/ns-no b &&
315
+ git update-ref refs/namespaces/ns/refs/heads/ns-yes c &&
316
+ git update-ref refs/namespaces/ns/refs/heads/hidden d
317
+ ) &&
318
+ git -C "$REPO" config uploadpack.allowRefInWant true
319
+'
320
+
321
+test_expect_success 'with namespace: want-ref is considered relative to namespace' '
322
+ wanted_ref=refs/heads/ns-yes &&
323
+
324
+ oid=$(git -C "$REPO" rev-parse "refs/namespaces/ns/$wanted_ref") &&
325
+ cat >expected_refs <<-EOF &&
326
+ $oid $wanted_ref
327
+ EOF
328
+ cat >expected_commits <<-EOF &&
329
+ $oid
330
+ $(git -C "$REPO" rev-parse a)
331
+ EOF
332
+
333
+ write_fetch_command >pkt <<-EOF &&
334
+ want-ref $wanted_ref
335
+ EOF
336
+ test-tool pkt-line pack <pkt >in &&
337
+
338
+ GIT_NAMESPACE=ns test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in &&
339
+ check_output
340
+'
341
+
342
+test_expect_success 'with namespace: want-ref outside namespace is unknown' '
343
+ wanted_ref=refs/heads/ns-no &&
344
+
345
+ write_fetch_command >pkt <<-EOF &&
346
+ want-ref $wanted_ref
347
+ EOF
348
+ test-tool pkt-line pack <pkt >in &&
349
+
350
+ test_must_fail env GIT_NAMESPACE=ns \
351
+ test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in &&
352
+ grep "unknown ref" out
353
+'
354
+
355
+# Cross-check refs/heads/ns-no indeed exists
356
+test_expect_success 'without namespace: want-ref outside namespace succeeds' '
357
+ wanted_ref=refs/heads/ns-no &&
358
+
359
+ oid=$(git -C "$REPO" rev-parse $wanted_ref) &&
360
+ cat >expected_refs <<-EOF &&
361
+ $oid $wanted_ref
362
+ EOF
363
+ cat >expected_commits <<-EOF &&
364
+ $oid
365
+ $(git -C "$REPO" rev-parse a)
366
+ EOF
367
+
368
+ write_fetch_command >pkt <<-EOF &&
369
+ want-ref $wanted_ref
370
+ EOF
371
+ test-tool pkt-line pack <pkt >in &&
372
+
373
+ test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in &&
374
+ check_output
375
+'
376
+
377
+test_expect_success 'with namespace: hideRefs is matched, relative to namespace' '
378
+ wanted_ref=refs/heads/hidden &&
379
+ git -C "$REPO" config transfer.hideRefs $wanted_ref &&
380
+
381
+ write_fetch_command >pkt <<-EOF &&
382
+ want-ref $wanted_ref
383
+ EOF
384
+ test-tool pkt-line pack <pkt >in &&
385
+
386
+ test_must_fail env GIT_NAMESPACE=ns \
387
+ test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in &&
388
+ grep "unknown ref" out
389
+'
390
+
391
+# Cross-check refs/heads/hidden indeed exists
392
+test_expect_success 'with namespace: want-ref succeeds if hideRefs is removed' '
393
+ wanted_ref=refs/heads/hidden &&
394
+ git -C "$REPO" config --unset transfer.hideRefs $wanted_ref &&
395
+
396
+ oid=$(git -C "$REPO" rev-parse "refs/namespaces/ns/$wanted_ref") &&
397
+ cat >expected_refs <<-EOF &&
398
+ $oid $wanted_ref
399
+ EOF
400
+ cat >expected_commits <<-EOF &&
401
+ $oid
402
+ $(git -C "$REPO" rev-parse a)
403
+ EOF
404
+
405
+ write_fetch_command >pkt <<-EOF &&
406
+ want-ref $wanted_ref
407
+ EOF
408
+ test-tool pkt-line pack <pkt >in &&
409
+
410
+ GIT_NAMESPACE=ns test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in &&
411
+ check_output
412
+'
413
+
414
+test_expect_success 'without namespace: relative hideRefs does not match' '
415
+ wanted_ref=refs/namespaces/ns/refs/heads/hidden &&
416
+ git -C "$REPO" config transfer.hideRefs refs/heads/hidden &&
417
+
418
+ oid=$(git -C "$REPO" rev-parse $wanted_ref) &&
419
+ cat >expected_refs <<-EOF &&
420
+ $oid $wanted_ref
421
+ EOF
422
+ cat >expected_commits <<-EOF &&
423
+ $oid
424
+ $(git -C "$REPO" rev-parse a)
425
+ EOF
426
+
427
+ write_fetch_command >pkt <<-EOF &&
428
+ want-ref $wanted_ref
429
+ EOF
430
+ test-tool pkt-line pack <pkt >in &&
431
+
432
+ test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in &&
433
+ check_output
434
+'
435
+
436
+
437
. "$TEST_DIRECTORY"/lib-httpd.sh
438
start_httpd
439
upload-pack.c
+11
-7
@@ -1417,21 +1417,25 @@ static int parse_want_ref(struct packet_writer *writer, const char *line,
1417
struct string_list *wanted_refs,
1418
struct object_array *want_obj)
1419
{
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)) {
1422
struct object_id oid;
1423
struct string_list_item *item;
1424
struct object *o;
1425
+ struct strbuf refname = STRBUF_INIT;
1426
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);
1432
}
1433
+ strbuf_release(&refname);
1434
1431
- item = string_list_append(wanted_refs, arg);
1435
+ item = string_list_append(wanted_refs, refname_nons);
1436
item->util = oiddup(&oid);
1437
1434
- o = parse_object_or_die(&oid, arg);
1438
+ o = parse_object_or_die(&oid, refname_nons);
1439
if (!(o->flags & WANTED)) {
1440
o->flags |= WANTED;
1441
add_object_array(o, NULL, want_obj);