Skip to content

Commit 25c684b

Browse files
codexByron
authored andcommitted
Address review feedback about unsafe option abbreviations
The prefix check could reject otherwise allowed one-letter short options when an unrelated blocked long option began with the same character. Keep exact matches for every spelling, but restrict prefix matching to explicit long options and multi-character kwargs. This addresses the review comment: single-letter short options and kwargs must not be treated as long-option abbreviations. It also adds coverage for abbreviated unsafe kwargs so both clone validation paths remain protected.
1 parent 2ab0516 commit 25c684b

3 files changed

Lines changed: 29 additions & 1 deletion

File tree

git/cmd.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -970,12 +970,20 @@ def check_unsafe_options(cls, options: List[str], unsafe_options: List[str]) ->
970970
# Git accepts any unambiguous prefix of a long option, so an abbreviated
971971
# spelling such as `--upl` for `--upload-pack` must be rejected too. An
972972
# option is unsafe if its canonical name is a prefix of any blocked
973-
# option's canonical name.
973+
# option's canonical name. Only long options and multi-character kwargs
974+
# can be abbreviations; single-character short options remain exact-match
975+
# only.
974976
canonical_unsafe_options = {cls._canonicalize_option_name(option): option for option in unsafe_options}
977+
options_are_kwargs = all(not option.startswith("-") for option in options)
975978
for option in options:
976979
candidate = cls._canonicalize_option_name(option)
977980
if not candidate:
978981
continue
982+
unsafe_option = canonical_unsafe_options.get(candidate)
983+
if unsafe_option is not None:
984+
raise UnsafeOptionError(f"{unsafe_option} is not allowed, use `allow_unsafe_options=True` to allow it.")
985+
if not (option.startswith("--") or (options_are_kwargs and len(candidate) > 1)):
986+
continue
979987
for canonical, unsafe_option in canonical_unsafe_options.items():
980988
if canonical.startswith(candidate):
981989
raise UnsafeOptionError(

test/test_clone.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,16 @@ def test_clone_unsafe_options_abbreviated(self, rw_repo):
153153
rw_repo.clone(tmp_dir, multi_options=[unsafe_option])
154154
assert not tmp_file.exists()
155155

156+
unsafe_kwargs = [
157+
{"upl": f"touch {tmp_file}"},
158+
{"upload_pac": f"touch {tmp_file}"},
159+
{"conf": "protocol.ext.allow=always"},
160+
]
161+
for unsafe_option in unsafe_kwargs:
162+
with self.assertRaises(UnsafeOptionError):
163+
rw_repo.clone(tmp_dir, **unsafe_option)
164+
assert not tmp_file.exists()
165+
156166
@with_rw_repo("HEAD")
157167
def test_clone_unsafe_options_are_checked_after_splitting_multi_options(self, rw_repo):
158168
with tempfile.TemporaryDirectory() as tdir:

test/test_git.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,16 @@ def test_check_unsafe_options_normalizes_kwargs(self):
170170
with self.assertRaises(UnsafeOptionError):
171171
Git.check_unsafe_options(options=options, unsafe_options=unsafe_options)
172172

173+
def test_check_unsafe_options_does_not_treat_short_options_as_abbreviations(self):
174+
unsafe_options = ["--upload-pack"]
175+
176+
Git.check_unsafe_options(options=["-u", "u", "-upl"], unsafe_options=unsafe_options)
177+
with self.assertRaises(UnsafeOptionError):
178+
Git.check_unsafe_options(options=["--u"], unsafe_options=unsafe_options)
179+
180+
def test_check_unsafe_options_does_not_treat_option_values_as_abbreviations(self):
181+
Git.check_unsafe_options(options=["--branch", "conf"], unsafe_options=["--config"])
182+
173183
_shell_cases = (
174184
# value_in_call, value_from_class, expected_popen_arg
175185
(None, False, False),

0 commit comments

Comments
 (0)