Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 46d3d05

Browse files
Add more checks for the validity of refnames
This change adds checks based on the rules described in [0] in order to more robustly check a refname's validity. [0]: https://git-scm.com/docs/git-check-ref-format
1 parent a5a6464 commit 46d3d05

File tree

2 files changed

+84
-2
lines changed

2 files changed

+84
-2
lines changed

‎git/refs/symbolic.py

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,15 +161,61 @@ def dereference_recursive(cls, repo: "Repo", ref_path: Union[PathLike, None]) ->
161161
return hexsha
162162
# END recursive dereferencing
163163

164+
@staticmethod
165+
def _check_ref_name_valid(ref_path: PathLike) -> None:
166+
# Based on the rules described in https://git-scm.com/docs/git-check-ref-format/#_description
167+
previous: Union[str, None] = None
168+
one_before_previous: Union[str, None] = None
169+
for c in str(ref_path):
170+
if c in " ~^:?*[\\":
171+
raise ValueError(
172+
f"Invalid reference '{ref_path}': references cannot contain spaces, tildes (~), carets (^),"
173+
f" colons (:), question marks (?), asterisks (*), open brackets ([) or backslashes (\\)"
174+
)
175+
elif c == ".":
176+
if previous is None or previous == "/":
177+
raise ValueError(
178+
f"Invalid reference '{ref_path}': references cannot start with a period (.) or contain '/.'"
179+
)
180+
elif previous == ".":
181+
raise ValueError(f"Invalid reference '{ref_path}': references cannot contain '..'")
182+
elif c == "/":
183+
if previous == "/":
184+
raise ValueError(f"Invalid reference '{ref_path}': references cannot contain '//'")
185+
elif previous is None:
186+
raise ValueError(
187+
f"Invalid reference '{ref_path}': references cannot start with forward slashes '/'"
188+
)
189+
elif c == "{" and previous == "@":
190+
raise ValueError(f"Invalid reference '{ref_path}': references cannot contain '@{{'")
191+
elif ord(c) < 32 or ord(c) == 127:
192+
raise ValueError(f"Invalid reference '{ref_path}': references cannot contain ASCII control characters")
193+
194+
one_before_previous = previous
195+
previous = c
196+
197+
if previous == ".":
198+
raise ValueError(f"Invalid reference '{ref_path}': references cannot end with a period (.)")
199+
elif previous == "/":
200+
raise ValueError(f"Invalid reference '{ref_path}': references cannot end with a forward slash (/)")
201+
elif previous == "@" and one_before_previous is None:
202+
raise ValueError(f"Invalid reference '{ref_path}': references cannot be '@'")
203+
elif any([component.endswith(".lock") for component in str(ref_path).split("/")]):
204+
raise ValueError(
205+
f"Invalid reference '{ref_path}': references cannot have slash-separated components that end with"
206+
f" '.lock'"
207+
)
208+
164209
@classmethod
165210
def _get_ref_info_helper(
166211
cls, repo: "Repo", ref_path: Union[PathLike, None]
167212
) -> Union[Tuple[str, None], Tuple[None, str]]:
168213
"""Return: (str(sha), str(target_ref_path)) if available, the sha the file at
169214
rela_path points to, or None. target_ref_path is the reference we
170215
point to, or None"""
171-
if ".." in str(ref_path):
172-
raise ValueError(f"Invalid reference '{ref_path}'")
216+
if ref_path:
217+
cls._check_ref_name_valid(ref_path)
218+
173219
tokens: Union[None, List[str], Tuple[str, str]] = None
174220
repodir = _git_dir(repo, ref_path)
175221
try:

‎test/test_refs.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,3 +631,39 @@ def test_refs_outside_repo(self):
631631
ref_file.flush()
632632
ref_file_name = Path(ref_file.name).name
633633
self.assertRaises(BadName, self.rorepo.commit, f"../../{ref_file_name}")
634+
635+
def test_validity_ref_names(self):
636+
check_ref = SymbolicReference._check_ref_name_valid
637+
# Based on the rules specified in https://git-scm.com/docs/git-check-ref-format/#_description
638+
# Rule 1
639+
self.assertRaises(ValueError, check_ref, ".ref/begins/with/dot")
640+
self.assertRaises(ValueError, check_ref, "ref/component/.begins/with/dot")
641+
self.assertRaises(ValueError, check_ref, "ref/ends/with/a.lock")
642+
self.assertRaises(ValueError, check_ref, "ref/component/ends.lock/with/period_lock")
643+
# Rule 2
644+
check_ref("valid_one_level_refname")
645+
# Rule 3
646+
self.assertRaises(ValueError, check_ref, "ref/contains/../double/period")
647+
# Rule 4
648+
for c in " ~^:":
649+
self.assertRaises(ValueError, check_ref, f"ref/contains/invalid{c}/character")
650+
for code in range(0, 32):
651+
self.assertRaises(ValueError, check_ref, f"ref/contains/invalid{chr(code)}/ASCII/control_character")
652+
self.assertRaises(ValueError, check_ref, f"ref/contains/invalid{chr(127)}/ASCII/control_character")
653+
# Rule 5
654+
for c in "*?[":
655+
self.assertRaises(ValueError, check_ref, f"ref/contains/invalid{c}/character")
656+
# Rule 6
657+
self.assertRaises(ValueError, check_ref, "/ref/begins/with/slash")
658+
self.assertRaises(ValueError, check_ref, "ref/ends/with/slash/")
659+
self.assertRaises(ValueError, check_ref, "ref/contains//double/slash/")
660+
# Rule 7
661+
self.assertRaises(ValueError, check_ref, "ref/ends/with/dot.")
662+
# Rule 8
663+
self.assertRaises(ValueError, check_ref, "ref/contains@{/at_brace")
664+
# Rule 9
665+
self.assertRaises(ValueError, check_ref, "@")
666+
# Rule 10
667+
self.assertRaises(ValueError, check_ref, "ref/contain\\s/backslash")
668+
# Valid reference name should not raise
669+
check_ref("valid/ref/name")

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /