Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions git/cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -967,11 +967,20 @@ def check_unsafe_options(cls, options: List[str], unsafe_options: List[str]) ->
arbitrary commands. These are blocked by default.
"""
# Options can be of the form `foo`, `--foo`, `--foo bar`, or `--foo=bar`.
# Git accepts any unambiguous prefix of a long option, so an abbreviated
# spelling such as `--upl` for `--upload-pack` must be rejected too. An
# option is unsafe if its canonical name is a prefix of any blocked
# option's canonical name.
canonical_unsafe_options = {cls._canonicalize_option_name(option): option for option in unsafe_options}
for option in options:
unsafe_option = canonical_unsafe_options.get(cls._canonicalize_option_name(option))
if unsafe_option is not None:
raise UnsafeOptionError(f"{unsafe_option} is not allowed, use `allow_unsafe_options=True` to allow it.")
candidate = cls._canonicalize_option_name(option)
if not candidate:
continue
for canonical, unsafe_option in canonical_unsafe_options.items():
if canonical.startswith(candidate):
Comment thread
Byron marked this conversation as resolved.
raise UnsafeOptionError(
f"{unsafe_option} is not allowed, use `allow_unsafe_options=True` to allow it."
)
Comment thread
Byron marked this conversation as resolved.

AutoInterrupt: TypeAlias = _AutoInterrupt

Expand Down
15 changes: 15 additions & 0 deletions test/test_clone.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,21 @@ def test_clone_unsafe_options(self, rw_repo):
rw_repo.clone(tmp_dir, **unsafe_option)
assert not tmp_file.exists()

@with_rw_repo("HEAD")
def test_clone_unsafe_options_abbreviated(self, rw_repo):
with tempfile.TemporaryDirectory() as tdir:
tmp_dir = pathlib.Path(tdir)
tmp_file = tmp_dir / "pwn"
unsafe_options = [
f"--upl='touch {tmp_file}'",
f"--upload-pac='touch {tmp_file}'",
"--conf=protocol.ext.allow=always",
]
for unsafe_option in unsafe_options:
with self.assertRaises(UnsafeOptionError):
rw_repo.clone(tmp_dir, multi_options=[unsafe_option])
assert not tmp_file.exists()
Comment thread
Byron marked this conversation as resolved.

@with_rw_repo("HEAD")
def test_clone_unsafe_options_are_checked_after_splitting_multi_options(self, rw_repo):
with tempfile.TemporaryDirectory() as tdir:
Expand Down
Loading