Subject: Re: [PATCH v6 2/9] ref: check the full refname instead of basename

From: Patrick Steinhardt <[email-masked]>
Date: Tue, 5 Nov 2024 08:11:42 +0100

On Mon, Oct 21, 2024 at 09:34:22PM +0800, shejialuo wrote:
> In "files-backend.c::files_fsck_refs_name", we validate the refname
> format by using "check_refname_format" to check the basename of the
> iterator with "REFNAME_ALLOW_ONELEVEL" flag.
> 
> However, this is a bad implementation. Although we doesn't allow a
> single "@" in ".git" directory, we do allow "refs/heads/@". So, we will
> report an error wrongly when there is a "refs/heads/@" ref by using one
> level refname "@".
> 
> Because we just check one level refname, we either cannot check the
> other parts of the full refname. And we will ignore the following
> errors:
> 
>   "refs/heads/ new-feature/test"
>   "refs/heads/~new-feature/test"
> 
> In order to fix the above problem, enhance "files_fsck_refs_name" to use
> the full name for "check_refname_format". Then, replace the tests which
> are related to "@" and add tests to exercise the above situations.

Okay, makes sense.

> diff --git a/refs/files-backend.c b/refs/files-backend.c
> index 03d2503276..f246c92684 100644
> --- a/refs/files-backend.c
> +++ b/refs/files-backend.c
> @@ -3519,10 +3519,10 @@ static int files_fsck_refs_name(struct ref_store *ref_store UNUSED,
>  	if (iter->basename[0] != '.' && ends_with(iter->basename, ".lock"))
>  		goto cleanup;
>  
> -	if (check_refname_format(iter->basename, REFNAME_ALLOW_ONELEVEL)) {
> +	strbuf_addf(&sb, "%s/%s", refs_check_dir, iter->relative_path);
> +	if (check_refname_format(sb.buf, 0)) {
>  		struct fsck_ref_report report = { 0 };
>  
> -		strbuf_addf(&sb, "%s/%s", refs_check_dir, iter->relative_path);
>  		report.path = sb.buf;
>  		ret = fsck_report_ref(o, &report,
>  				      FSCK_MSG_BAD_REF_NAME,

So this only works right now because we never check root refs in the
first place? Maybe that is worth a comment.

> diff --git a/t/t0602-reffiles-fsck.sh b/t/t0602-reffiles-fsck.sh
> index 71a4d1a5ae..0aee377439 100755
> --- a/t/t0602-reffiles-fsck.sh
> +++ b/t/t0602-reffiles-fsck.sh
> @@ -25,6 +25,13 @@ test_expect_success 'ref name should be checked' '
>  	git tag tag-2 &&
>  	git tag multi_hierarchy/tag-2 &&
>  
> +	cp $branch_dir_prefix/branch-1 $branch_dir_prefix/@ &&
> +	git refs verify 2>err &&
> +	cat >expect <<-EOF &&
> +	EOF
> +	test_must_be_empty err &&
> +	rm $branch_dir_prefix/@ &&

`expect` isn't used here as you use `test_must_be_empty`.

>  	cp $branch_dir_prefix/branch-1 $branch_dir_prefix/.branch-1 &&
>  	test_must_fail git refs verify 2>err &&
>  	cat >expect <<-EOF &&
> @@ -33,20 +40,20 @@ test_expect_success 'ref name should be checked' '
>  	rm $branch_dir_prefix/.branch-1 &&
>  	test_cmp expect err &&
>  
> -	cp $branch_dir_prefix/branch-1 $branch_dir_prefix/@ &&
> +	cp $branch_dir_prefix/branch-1 $branch_dir_prefix/'\'' branch-1'\'' &&
>  	test_must_fail git refs verify 2>err &&
>  	cat >expect <<-EOF &&
> -	error: refs/heads/@: badRefName: invalid refname format
> +	error: refs/heads/ branch-1: badRefName: invalid refname format
>  	EOF
> -	rm $branch_dir_prefix/@ &&
> +	rm $branch_dir_prefix/'\'' branch-1'\'' &&
>  	test_cmp expect err &&

Okay, we now allow `refs/heads/@`, but still don't allow other bad
formatting like spaces in the refname.

Patrick