From 3c966c7b4e97a5399662f85ab73af08a6419a303 Mon Sep 17 00:00:00 2001 From: Han-Wen Nienhuys Date: Tue, 7 Dec 2021 13:38:18 +0000 Subject: [PATCH] refs: introduce REF_SKIP_REFNAME_VERIFICATION flag Use this flag with the test-helper in t1430, to avoid direct writes to the ref database. Signed-off-by: Han-Wen Nienhuys Signed-off-by: Junio C Hamano --- refs.c | 7 +++-- refs.h | 10 +++++-- t/helper/test-ref-store.c | 1 + t/t1430-bad-ref-name.sh | 59 +++++++++++++++++++++------------------ 4 files changed, 45 insertions(+), 32 deletions(-) diff --git a/refs.c b/refs.c index 996ac27164..93bfe5b30c 100644 --- a/refs.c +++ b/refs.c @@ -1083,9 +1083,10 @@ int ref_transaction_update(struct ref_transaction *transaction, { assert(err); - if ((new_oid && !is_null_oid(new_oid)) ? - check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) : - !refname_is_safe(refname)) { + if (!(flags & REF_SKIP_REFNAME_VERIFICATION) && + ((new_oid && !is_null_oid(new_oid)) ? + check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) : + !refname_is_safe(refname))) { strbuf_addf(err, _("refusing to update ref with bad name '%s'"), refname); return -1; diff --git a/refs.h b/refs.h index 76efc589cc..65017ceaef 100644 --- a/refs.h +++ b/refs.h @@ -621,12 +621,18 @@ struct ref_transaction *ref_transaction_begin(struct strbuf *err); */ #define REF_SKIP_OID_VERIFICATION (1 << 10) +/* + * Skip verifying refname. This is useful for testing data corruption scenarios. + */ +#define REF_SKIP_REFNAME_VERIFICATION (1 << 11) + /* * Bitmask of all of the flags that are allowed to be passed in to * ref_transaction_update() and friends: */ -#define REF_TRANSACTION_UPDATE_ALLOWED_FLAGS \ - (REF_NO_DEREF | REF_FORCE_CREATE_REFLOG | REF_SKIP_OID_VERIFICATION) +#define REF_TRANSACTION_UPDATE_ALLOWED_FLAGS \ + (REF_NO_DEREF | REF_FORCE_CREATE_REFLOG | REF_SKIP_OID_VERIFICATION | \ + REF_SKIP_REFNAME_VERIFICATION) /* * Add a reference update to transaction. `new_oid` is the value that diff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c index 0f3aa84c9f..8bca4f2af1 100644 --- a/t/helper/test-ref-store.c +++ b/t/helper/test-ref-store.c @@ -131,6 +131,7 @@ static struct flag_definition transaction_flags[] = { FLAG_DEF(REF_NO_DEREF), FLAG_DEF(REF_FORCE_CREATE_REFLOG), FLAG_DEF(REF_SKIP_OID_VERIFICATION), + FLAG_DEF(REF_SKIP_REFNAME_VERIFICATION), { NULL, 0 } }; diff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh index 4c77cf89a6..326e5bd5e8 100755 --- a/t/t1430-bad-ref-name.sh +++ b/t/t1430-bad-ref-name.sh @@ -9,7 +9,8 @@ TEST_PASSES_SANITIZE_LEAK=true test_expect_success setup ' test_commit one && - test_commit two + test_commit two && + main_sha1=$(git rev-parse refs/heads/main) ' test_expect_success 'fast-import: fail on invalid branch name ".badbranchname"' ' @@ -43,16 +44,16 @@ test_expect_success 'fast-import: fail on invalid branch name "bad[branch]name"' ' test_expect_success 'git branch shows badly named ref as warning' ' - cp .git/refs/heads/main .git/refs/heads/broken...ref && - test_when_finished "rm -f .git/refs/heads/broken...ref" && + test-tool ref-store main update-ref msg "refs/heads/broken...ref" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION && + test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" && git branch >output 2>error && test_i18ngrep -e "ignoring ref with broken name refs/heads/broken\.\.\.ref" error && ! grep -e "broken\.\.\.ref" output ' test_expect_success 'branch -d can delete badly named ref' ' - cp .git/refs/heads/main .git/refs/heads/broken...ref && - test_when_finished "rm -f .git/refs/heads/broken...ref" && + test-tool ref-store main update-ref msg "refs/heads/broken...ref" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION && + test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" && git branch -d broken...ref && git branch >output 2>error && ! grep -e "broken\.\.\.ref" error && @@ -60,8 +61,8 @@ test_expect_success 'branch -d can delete badly named ref' ' ' test_expect_success 'branch -D can delete badly named ref' ' - cp .git/refs/heads/main .git/refs/heads/broken...ref && - test_when_finished "rm -f .git/refs/heads/broken...ref" && + test-tool ref-store main update-ref msg "refs/heads/broken...ref" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION && + test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" && git branch -D broken...ref && git branch >output 2>error && ! grep -e "broken\.\.\.ref" error && @@ -90,7 +91,7 @@ test_expect_success 'branch -D cannot delete absolute path' ' ' test_expect_success 'git branch cannot create a badly named ref' ' - test_when_finished "rm -f .git/refs/heads/broken...ref" && + test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" && test_must_fail git branch broken...ref && git branch >output 2>error && ! grep -e "broken\.\.\.ref" error && @@ -98,7 +99,7 @@ test_expect_success 'git branch cannot create a badly named ref' ' ' test_expect_success 'branch -m cannot rename to a bad ref name' ' - test_when_finished "rm -f .git/refs/heads/broken...ref" && + test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" && test_might_fail git branch -D goodref && git branch goodref && test_must_fail git branch -m goodref broken...ref && @@ -109,8 +110,9 @@ test_expect_success 'branch -m cannot rename to a bad ref name' ' ' test_expect_failure 'branch -m can rename from a bad ref name' ' - cp .git/refs/heads/main .git/refs/heads/broken...ref && - test_when_finished "rm -f .git/refs/heads/broken...ref" && + test-tool ref-store main update-ref msg "refs/heads/broken...ref" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION && + + test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" && git branch -m broken...ref renamed && test_cmp_rev main renamed && git branch >output 2>error && @@ -119,7 +121,7 @@ test_expect_failure 'branch -m can rename from a bad ref name' ' ' test_expect_success 'push cannot create a badly named ref' ' - test_when_finished "rm -f .git/refs/heads/broken...ref" && + test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" && test_must_fail git push "file://$(pwd)" HEAD:refs/heads/broken...ref && git branch >output 2>error && ! grep -e "broken\.\.\.ref" error && @@ -139,7 +141,7 @@ test_expect_failure 'push --mirror can delete badly named ref' ' cd dest && test_commit two && git checkout --detach && - cp .git/refs/heads/main .git/refs/heads/broken...ref + test-tool ref-store main update-ref msg "refs/heads/broken...ref" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION ) && git -C src push --mirror "file://$top/dest" && git -C dest branch >output 2>error && @@ -148,9 +150,9 @@ test_expect_failure 'push --mirror can delete badly named ref' ' ' test_expect_success 'rev-parse skips symref pointing to broken name' ' - test_when_finished "rm -f .git/refs/heads/broken...ref" && + test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" && git branch shadow one && - cp .git/refs/heads/main .git/refs/heads/broken...ref && + test-tool ref-store main update-ref msg "refs/heads/broken...ref" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION && printf "ref: refs/heads/broken...ref\n" >.git/refs/tags/shadow && test_when_finished "rm -f .git/refs/tags/shadow" && git rev-parse --verify one >expect && @@ -160,8 +162,8 @@ test_expect_success 'rev-parse skips symref pointing to broken name' ' ' test_expect_success 'for-each-ref emits warnings for broken names' ' - cp .git/refs/heads/main .git/refs/heads/broken...ref && - test_when_finished "rm -f .git/refs/heads/broken...ref" && + test-tool ref-store main update-ref msg "refs/heads/broken...ref" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION && + test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" && printf "ref: refs/heads/broken...ref\n" >.git/refs/heads/badname && test_when_finished "rm -f .git/refs/heads/badname" && printf "ref: refs/heads/main\n" >.git/refs/heads/broken...symref && @@ -176,8 +178,8 @@ test_expect_success 'for-each-ref emits warnings for broken names' ' ' test_expect_success 'update-ref -d can delete broken name' ' - cp .git/refs/heads/main .git/refs/heads/broken...ref && - test_when_finished "rm -f .git/refs/heads/broken...ref" && + test-tool ref-store main update-ref msg "refs/heads/broken...ref" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION && + test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" && git update-ref -d refs/heads/broken...ref >output 2>error && test_must_be_empty output && test_must_be_empty error && @@ -187,8 +189,8 @@ test_expect_success 'update-ref -d can delete broken name' ' ' test_expect_success 'branch -d can delete broken name' ' - cp .git/refs/heads/main .git/refs/heads/broken...ref && - test_when_finished "rm -f .git/refs/heads/broken...ref" && + test-tool ref-store main update-ref msg "refs/heads/broken...ref" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION && + test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" && git branch -d broken...ref >output 2>error && test_i18ngrep "Deleted branch broken...ref (was broken)" output && test_must_be_empty error && @@ -198,8 +200,9 @@ test_expect_success 'branch -d can delete broken name' ' ' test_expect_success 'update-ref --no-deref -d can delete symref to broken name' ' - cp .git/refs/heads/main .git/refs/heads/broken...ref && - test_when_finished "rm -f .git/refs/heads/broken...ref" && + test-tool ref-store main update-ref msg "refs/heads/broken...ref" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION && + + test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" && printf "ref: refs/heads/broken...ref\n" >.git/refs/heads/badname && test_when_finished "rm -f .git/refs/heads/badname" && git update-ref --no-deref -d refs/heads/badname >output 2>error && @@ -209,8 +212,9 @@ test_expect_success 'update-ref --no-deref -d can delete symref to broken name' ' test_expect_success 'branch -d can delete symref to broken name' ' - cp .git/refs/heads/main .git/refs/heads/broken...ref && - test_when_finished "rm -f .git/refs/heads/broken...ref" && + test-tool ref-store main update-ref msg "refs/heads/broken...ref" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION && + + test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" && printf "ref: refs/heads/broken...ref\n" >.git/refs/heads/badname && test_when_finished "rm -f .git/refs/heads/badname" && git branch -d badname >output 2>error && @@ -238,8 +242,9 @@ test_expect_success 'branch -d can delete dangling symref to broken name' ' ' test_expect_success 'update-ref -d can delete broken name through symref' ' - cp .git/refs/heads/main .git/refs/heads/broken...ref && - test_when_finished "rm -f .git/refs/heads/broken...ref" && + test-tool ref-store main update-ref msg "refs/heads/broken...ref" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION && + + test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" && printf "ref: refs/heads/broken...ref\n" >.git/refs/heads/badname && test_when_finished "rm -f .git/refs/heads/badname" && git update-ref -d refs/heads/badname >output 2>error &&