| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 9e8c85e commit 428d205
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1778,9 +1778,13 @@ def archive( | |||
| 1778 | 1778 | treeish = self.head.commit | |
| 1779 | 1779 | if prefix and "prefix" not in kwargs: | |
| 1780 | 1780 | kwargs["prefix"] = prefix | |
| 1781 | - remote = kwargs.get("remote") | ||
| 1782 | - if not allow_unsafe_protocols and remote is not None: | ||
| 1783 | - Git.check_unsafe_protocols(str(remote)) | ||
| 1781 | + if not allow_unsafe_protocols: | ||
| 1782 | + # Check the emitted URL, including repeated values and Git's long-option | ||
| 1783 | + # abbreviations, rather than only the untransformed `remote` keyword. | ||
| 1784 | + for arg in self.git.transform_kwargs(**kwargs): | ||
| 1785 | + option, separator, remote = arg.partition("=") | ||
| 1786 | + if separator and option.startswith("--r") and "--remote".startswith(option): | ||
| 1787 | + Git.check_unsafe_protocols(remote) | ||
| 1784 | 1788 | if not allow_unsafe_options: | |
| 1785 | 1789 | Git.check_unsafe_options( | |
| 1786 | 1790 | options=Git._option_candidates([], kwargs), | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -6,16 +6,16 @@ | |||
| 6 | 6 | import gc | |
| 7 | 7 | import glob | |
| 8 | 8 | import io | |
| 9 | - from io import BytesIO | ||
| 10 | 9 | import itertools | |
| 11 | 10 | import os | |
| 12 | 11 | import os.path as osp | |
| 13 | 12 | import pathlib | |
| 14 | 13 | import pickle | |
| 15 | 14 | import sys | |
| 16 | 15 | import tempfile | |
| 17 | - from unittest import mock | ||
| 16 | + from io import BytesIO | ||
| 18 | 17 | from pathlib import Path | |
| 18 | + from unittest import mock | ||
| 19 | 19 | ||
| 20 | 20 | import pytest | |
| 21 | 21 | ||
@@ -37,14 +37,10 @@ | |||
| 37 | 37 | Submodule, | |
| 38 | 38 | Tree, | |
| 39 | 39 | ) | |
| 40 | - from git.exc import UnsafeOptionError | ||
| 41 | - from git.exc import UnsafeProtocolError | ||
| 42 | - from git.exc import BadObject | ||
| 43 | - from git.exc import WorkTreeRepositoryUnsupported | ||
| 40 | + from git.exc import BadObject, UnsafeOptionError, UnsafeProtocolError, WorkTreeRepositoryUnsupported | ||
| 44 | 41 | from git.repo.fun import find_worktree_git_dir, touch | |
| 45 | 42 | from git.util import bin_to_hex, cwd, cygpath, join_path_native, rmfile, rmtree | |
| 46 | - | ||
| 47 | - from test.lib import TestBase, fixture, requires_symlinks, with_rw_directory, with_rw_repo, PathLikeMock | ||
| 43 | + from test.lib import PathLikeMock, TestBase, fixture, requires_symlinks, with_rw_directory, with_rw_repo | ||
| 48 | 44 | ||
| 49 | 45 | ||
| 50 | 46 | def iter_flatten(lol): | |
@@ -1672,3 +1668,57 @@ def test_ignored_raises_error_w_symlink(self): | |||
| 1672 | 1668 | ||
| 1673 | 1669 | with pytest.raises(GitCommandError): | |
| 1674 | 1670 | temp_repo.ignored(tmp_dir / "symlink/file.txt") | |
| 1671 | + | ||
| 1672 | + | ||
| 1673 | + @pytest.mark.parametrize("allow_unsafe_options", (False, True)) | ||
| 1674 | + @pytest.mark.parametrize( | ||
| 1675 | + "kwargs", | ||
| 1676 | + ( | ||
| 1677 | + {"rem": "ext::helper"}, | ||
| 1678 | + {"re": "ext::helper"}, | ||
| 1679 | + {"remo": "ext::helper"}, | ||
| 1680 | + {"remot": "ext::helper"}, # codespell:ignore remot | ||
| 1681 | + {"remote": ["https://example.com/repo", "ext::helper"]}, | ||
| 1682 | + {"remote": (None, False, "ext::helper")}, | ||
| 1683 | + {"remote=ext::helper": True}, | ||
| 1684 | + {"r=ext::helper": True}, | ||
| 1685 | + {"remote": "ext://helper"}, | ||
| 1686 | + ), | ||
| 1687 | + ) | ||
| 1688 | + def test_archive_protocol_guard_checks_emitted_remote_options(tmp_path, kwargs, allow_unsafe_options): | ||
| 1689 | + with Repo.init(tmp_path) as repo, mock.patch.object(Git, "execute") as execute: | ||
| 1690 | + with pytest.raises(UnsafeProtocolError): | ||
| 1691 | + repo.archive(BytesIO(), "HEAD", allow_unsafe_options=allow_unsafe_options, **kwargs) | ||
| 1692 | + execute.assert_not_called() | ||
| 1693 | + | ||
| 1694 | + | ||
| 1695 | + def test_archive_preserves_safe_repeated_remote_options(tmp_path): | ||
| 1696 | + urls = ["https://[::1]/repo.git", "ssh://git@[2001:db8::1]/repo.git"] | ||
| 1697 | + with Repo.init(tmp_path) as repo, mock.patch.object(Git, "execute") as execute: | ||
| 1698 | + output = BytesIO() | ||
| 1699 | + repo.archive(output, "HEAD", rem=urls) | ||
| 1700 | + execute.assert_called_once_with( | ||
| 1701 | + [Git.GIT_PYTHON_GIT_EXECUTABLE, "archive", *(f"--rem={url}" for url in urls), "--", "HEAD"], | ||
| 1702 | + output_stream=output, | ||
| 1703 | + ) | ||
| 1704 | + | ||
| 1705 | + | ||
| 1706 | + def test_archive_protocol_and_option_opt_ins_are_independent(tmp_path): | ||
| 1707 | + with Repo.init(tmp_path) as repo, mock.patch.object(Git, "execute") as execute: | ||
| 1708 | + with pytest.raises(UnsafeOptionError): | ||
| 1709 | + repo.archive(BytesIO(), "HEAD", rem=["ext::helper"], exec="helper", allow_unsafe_protocols=True) | ||
| 1710 | + execute.assert_not_called() | ||
| 1711 | + | ||
| 1712 | + output = BytesIO() | ||
| 1713 | + repo.archive( | ||
| 1714 | + output, | ||
| 1715 | + "HEAD", | ||
| 1716 | + rem=["ext::helper"], | ||
| 1717 | + exec="helper", | ||
| 1718 | + allow_unsafe_options=True, | ||
| 1719 | + allow_unsafe_protocols=True, | ||
| 1720 | + ) | ||
| 1721 | + execute.assert_called_once_with( | ||
| 1722 | + [Git.GIT_PYTHON_GIT_EXECUTABLE, "archive", "--rem=ext::helper", "--exec=helper", "--", "HEAD"], | ||
| 1723 | + output_stream=output, | ||
| 1724 | + ) | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments