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 <hanwen@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Han-Wen Nienhuys committed Dec 7, 2021 at 13:38 UTC 3c966c7b4e97a5399662f85ab73af08a6419a303
4 files changed +45 -32
refs.c
+4 -3
@@ -1083,9 +1083,10 @@ int ref_transaction_update(struct ref_transaction *transaction,
1083 {
1084 assert(err);
1085
1086 - if ((new_oid && !is_null_oid(new_oid)) ?
1087 - check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) :
1088 - !refname_is_safe(refname)) {
1086 + if (!(flags & REF_SKIP_REFNAME_VERIFICATION) &&
1087 + ((new_oid && !is_null_oid(new_oid)) ?
1088 + check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) :
1089 + !refname_is_safe(refname))) {
1090 strbuf_addf(err, _("refusing to update ref with bad name '%s'"),
1091 refname);
1092 return -1;
refs.h
+8 -2
@@ -621,12 +621,18 @@ struct ref_transaction *ref_transaction_begin(struct strbuf *err);
621 */
622 #define REF_SKIP_OID_VERIFICATION (1 << 10)
623
624 +/*
625 + * Skip verifying refname. This is useful for testing data corruption scenarios.
626 + */
627 +#define REF_SKIP_REFNAME_VERIFICATION (1 << 11)
628 +
629 /*
630 * Bitmask of all of the flags that are allowed to be passed in to
631 * ref_transaction_update() and friends:
632 */
628 -#define REF_TRANSACTION_UPDATE_ALLOWED_FLAGS \
629 - (REF_NO_DEREF | REF_FORCE_CREATE_REFLOG | REF_SKIP_OID_VERIFICATION)
633 +#define REF_TRANSACTION_UPDATE_ALLOWED_FLAGS \
634 + (REF_NO_DEREF | REF_FORCE_CREATE_REFLOG | REF_SKIP_OID_VERIFICATION | \
635 + REF_SKIP_REFNAME_VERIFICATION)
636
637 /*
638 * Add a reference update to transaction. `new_oid` is the value that
t/helper/test-ref-store.c
+1
@@ -131,6 +131,7 @@ static struct flag_definition transaction_flags[] = {
131 FLAG_DEF(REF_NO_DEREF),
132 FLAG_DEF(REF_FORCE_CREATE_REFLOG),
133 FLAG_DEF(REF_SKIP_OID_VERIFICATION),
134 + FLAG_DEF(REF_SKIP_REFNAME_VERIFICATION),
135 { NULL, 0 }
136 };
137
t/t1430-bad-ref-name.sh
+32 -27
@@ -9,7 +9,8 @@ TEST_PASSES_SANITIZE_LEAK=true
9
10 test_expect_success setup '
11 test_commit one &&
12 - test_commit two
12 + test_commit two &&
13 + main_sha1=$(git rev-parse refs/heads/main)
14 '
15
16 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"'
44 '
45
46 test_expect_success 'git branch shows badly named ref as warning' '
46 - cp .git/refs/heads/main .git/refs/heads/broken...ref &&
47 - test_when_finished "rm -f .git/refs/heads/broken...ref" &&
47 + test-tool ref-store main update-ref msg "refs/heads/broken...ref" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&
48 + test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" &&
49 git branch >output 2>error &&
50 test_i18ngrep -e "ignoring ref with broken name refs/heads/broken\.\.\.ref" error &&
51 ! grep -e "broken\.\.\.ref" output
52 '
53
54 test_expect_success 'branch -d can delete badly named ref' '
54 - cp .git/refs/heads/main .git/refs/heads/broken...ref &&
55 - test_when_finished "rm -f .git/refs/heads/broken...ref" &&
55 + test-tool ref-store main update-ref msg "refs/heads/broken...ref" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&
56 + test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" &&
57 git branch -d broken...ref &&
58 git branch >output 2>error &&
59 ! grep -e "broken\.\.\.ref" error &&
@@ -60,8 +61,8 @@ test_expect_success 'branch -d can delete badly named ref' '
61 '
62
63 test_expect_success 'branch -D can delete badly named ref' '
63 - cp .git/refs/heads/main .git/refs/heads/broken...ref &&
64 - test_when_finished "rm -f .git/refs/heads/broken...ref" &&
64 + test-tool ref-store main update-ref msg "refs/heads/broken...ref" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&
65 + test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" &&
66 git branch -D broken...ref &&
67 git branch >output 2>error &&
68 ! grep -e "broken\.\.\.ref" error &&
@@ -90,7 +91,7 @@ test_expect_success 'branch -D cannot delete absolute path' '
91 '
92
93 test_expect_success 'git branch cannot create a badly named ref' '
93 - test_when_finished "rm -f .git/refs/heads/broken...ref" &&
94 + test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" &&
95 test_must_fail git branch broken...ref &&
96 git branch >output 2>error &&
97 ! grep -e "broken\.\.\.ref" error &&
@@ -98,7 +99,7 @@ test_expect_success 'git branch cannot create a badly named ref' '
99 '
100
101 test_expect_success 'branch -m cannot rename to a bad ref name' '
101 - test_when_finished "rm -f .git/refs/heads/broken...ref" &&
102 + test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" &&
103 test_might_fail git branch -D goodref &&
104 git branch goodref &&
105 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' '
110 '
111
112 test_expect_failure 'branch -m can rename from a bad ref name' '
112 - cp .git/refs/heads/main .git/refs/heads/broken...ref &&
113 - test_when_finished "rm -f .git/refs/heads/broken...ref" &&
113 + test-tool ref-store main update-ref msg "refs/heads/broken...ref" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&
114 +
115 + test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" &&
116 git branch -m broken...ref renamed &&
117 test_cmp_rev main renamed &&
118 git branch >output 2>error &&
@@ -119,7 +121,7 @@ test_expect_failure 'branch -m can rename from a bad ref name' '
121 '
122
123 test_expect_success 'push cannot create a badly named ref' '
122 - test_when_finished "rm -f .git/refs/heads/broken...ref" &&
124 + test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" &&
125 test_must_fail git push "file://$(pwd)" HEAD:refs/heads/broken...ref &&
126 git branch >output 2>error &&
127 ! grep -e "broken\.\.\.ref" error &&
@@ -139,7 +141,7 @@ test_expect_failure 'push --mirror can delete badly named ref' '
141 cd dest &&
142 test_commit two &&
143 git checkout --detach &&
142 - cp .git/refs/heads/main .git/refs/heads/broken...ref
144 + test-tool ref-store main update-ref msg "refs/heads/broken...ref" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION
145 ) &&
146 git -C src push --mirror "file://$top/dest" &&
147 git -C dest branch >output 2>error &&
@@ -148,9 +150,9 @@ test_expect_failure 'push --mirror can delete badly named ref' '
150 '
151
152 test_expect_success 'rev-parse skips symref pointing to broken name' '
151 - test_when_finished "rm -f .git/refs/heads/broken...ref" &&
153 + test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" &&
154 git branch shadow one &&
153 - cp .git/refs/heads/main .git/refs/heads/broken...ref &&
155 + test-tool ref-store main update-ref msg "refs/heads/broken...ref" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&
156 printf "ref: refs/heads/broken...ref\n" >.git/refs/tags/shadow &&
157 test_when_finished "rm -f .git/refs/tags/shadow" &&
158 git rev-parse --verify one >expect &&
@@ -160,8 +162,8 @@ test_expect_success 'rev-parse skips symref pointing to broken name' '
162 '
163
164 test_expect_success 'for-each-ref emits warnings for broken names' '
163 - cp .git/refs/heads/main .git/refs/heads/broken...ref &&
164 - test_when_finished "rm -f .git/refs/heads/broken...ref" &&
165 + test-tool ref-store main update-ref msg "refs/heads/broken...ref" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&
166 + test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" &&
167 printf "ref: refs/heads/broken...ref\n" >.git/refs/heads/badname &&
168 test_when_finished "rm -f .git/refs/heads/badname" &&
169 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' '
178 '
179
180 test_expect_success 'update-ref -d can delete broken name' '
179 - cp .git/refs/heads/main .git/refs/heads/broken...ref &&
180 - test_when_finished "rm -f .git/refs/heads/broken...ref" &&
181 + test-tool ref-store main update-ref msg "refs/heads/broken...ref" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&
182 + test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" &&
183 git update-ref -d refs/heads/broken...ref >output 2>error &&
184 test_must_be_empty output &&
185 test_must_be_empty error &&
@@ -187,8 +189,8 @@ test_expect_success 'update-ref -d can delete broken name' '
189 '
190
191 test_expect_success 'branch -d can delete broken name' '
190 - cp .git/refs/heads/main .git/refs/heads/broken...ref &&
191 - test_when_finished "rm -f .git/refs/heads/broken...ref" &&
192 + test-tool ref-store main update-ref msg "refs/heads/broken...ref" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&
193 + test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" &&
194 git branch -d broken...ref >output 2>error &&
195 test_i18ngrep "Deleted branch broken...ref (was broken)" output &&
196 test_must_be_empty error &&
@@ -198,8 +200,9 @@ test_expect_success 'branch -d can delete broken name' '
200 '
201
202 test_expect_success 'update-ref --no-deref -d can delete symref to broken name' '
201 - cp .git/refs/heads/main .git/refs/heads/broken...ref &&
202 - test_when_finished "rm -f .git/refs/heads/broken...ref" &&
203 + test-tool ref-store main update-ref msg "refs/heads/broken...ref" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&
204 +
205 + test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" &&
206 printf "ref: refs/heads/broken...ref\n" >.git/refs/heads/badname &&
207 test_when_finished "rm -f .git/refs/heads/badname" &&
208 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'
212 '
213
214 test_expect_success 'branch -d can delete symref to broken name' '
212 - cp .git/refs/heads/main .git/refs/heads/broken...ref &&
213 - test_when_finished "rm -f .git/refs/heads/broken...ref" &&
215 + test-tool ref-store main update-ref msg "refs/heads/broken...ref" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&
216 +
217 + test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" &&
218 printf "ref: refs/heads/broken...ref\n" >.git/refs/heads/badname &&
219 test_when_finished "rm -f .git/refs/heads/badname" &&
220 git branch -d badname >output 2>error &&
@@ -238,8 +242,9 @@ test_expect_success 'branch -d can delete dangling symref to broken name' '
242 '
243
244 test_expect_success 'update-ref -d can delete broken name through symref' '
241 - cp .git/refs/heads/main .git/refs/heads/broken...ref &&
242 - test_when_finished "rm -f .git/refs/heads/broken...ref" &&
245 + test-tool ref-store main update-ref msg "refs/heads/broken...ref" $main_sha1 $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&
246 +
247 + test_when_finished "test-tool ref-store main delete-refs REF_NO_DEREF msg refs/heads/broken...ref" &&
248 printf "ref: refs/heads/broken...ref\n" >.git/refs/heads/badname &&
249 test_when_finished "rm -f .git/refs/heads/badname" &&
250 git update-ref -d refs/heads/badname >output 2>error &&