Skip to content

Commit c8ae33b

Browse files
committed
More tests
1 parent b92f01a commit c8ae33b

File tree

4 files changed

+247
-7
lines changed

4 files changed

+247
-7
lines changed

Diff for: git/objects/submodule/base.py

+33-3
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,16 @@ def _module_abspath(cls, parent_repo: "Repo", path: PathLike, name: str) -> Path
272272
# end
273273

274274
@classmethod
275-
def _clone_repo(cls, repo: "Repo", url: str, path: PathLike, name: str, **kwargs: Any) -> "Repo":
275+
def _clone_repo(
276+
cls,
277+
repo: "Repo",
278+
url: str,
279+
path: PathLike,
280+
name: str,
281+
allow_unsafe_options: bool = False,
282+
allow_unsafe_protocols: bool = False,
283+
**kwargs: Any,
284+
) -> "Repo":
276285
""":return: Repo instance of newly cloned repository
277286
:param repo: our parent repository
278287
:param url: url to clone from
@@ -289,7 +298,13 @@ def _clone_repo(cls, repo: "Repo", url: str, path: PathLike, name: str, **kwargs
289298
module_checkout_path = osp.join(str(repo.working_tree_dir), path)
290299
# end
291300

292-
clone = git.Repo.clone_from(url, module_checkout_path, **kwargs)
301+
clone = git.Repo.clone_from(
302+
url,
303+
module_checkout_path,
304+
allow_unsafe_options=allow_unsafe_options,
305+
allow_unsafe_protocols=allow_unsafe_protocols,
306+
**kwargs,
307+
)
293308
if cls._need_gitfile_submodules(repo.git):
294309
cls._write_git_file_and_module_config(module_checkout_path, module_abspath)
295310
# end
@@ -359,6 +374,8 @@ def add(
359374
depth: Union[int, None] = None,
360375
env: Union[Mapping[str, str], None] = None,
361376
clone_multi_options: Union[Sequence[TBD], None] = None,
377+
allow_unsafe_options: bool = False,
378+
allow_unsafe_protocols: bool = False,
362379
) -> "Submodule":
363380
"""Add a new submodule to the given repository. This will alter the index
364381
as well as the .gitmodules file, but will not create a new commit.
@@ -475,7 +492,16 @@ def add(
475492
kwargs["multi_options"] = clone_multi_options
476493

477494
# _clone_repo(cls, repo, url, path, name, **kwargs):
478-
mrepo = cls._clone_repo(repo, url, path, name, env=env, **kwargs)
495+
mrepo = cls._clone_repo(
496+
repo,
497+
url,
498+
path,
499+
name,
500+
env=env,
501+
allow_unsafe_options=allow_unsafe_options,
502+
allow_unsafe_protocols=allow_unsafe_protocols,
503+
**kwargs,
504+
)
479505
# END verify url
480506

481507
## See #525 for ensuring git urls in config-files valid under Windows.
@@ -520,6 +546,8 @@ def update(
520546
keep_going: bool = False,
521547
env: Union[Mapping[str, str], None] = None,
522548
clone_multi_options: Union[Sequence[TBD], None] = None,
549+
allow_unsafe_options: bool = False,
550+
allow_unsafe_protocols: bool = False,
523551
) -> "Submodule":
524552
"""Update the repository of this submodule to point to the checkout
525553
we point at with the binsha of this instance.
@@ -643,6 +671,8 @@ def update(
643671
n=True,
644672
env=env,
645673
multi_options=clone_multi_options,
674+
allow_unsafe_options=allow_unsafe_options,
675+
allow_unsafe_protocols=allow_unsafe_protocols,
646676
)
647677
# END handle dry-run
648678
progress.update(

Diff for: git/remote.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -658,9 +658,7 @@ def add_url(self, url: str, allow_unsafe_protocols: bool = False, **kwargs: Any)
658658
:param url: string being the URL to add as an extra remote URL
659659
:return: self
660660
"""
661-
if not allow_unsafe_protocols:
662-
Git.check_unsafe_protocols(url)
663-
return self.set_url(url, add=True)
661+
return self.set_url(url, add=True, allow_unsafe_protocols=allow_unsafe_protocols)
664662

665663
def delete_url(self, url: str, **kwargs: Any) -> "Remote":
666664
"""Deletes a new url on current remote (special case of git remote set_url)

Diff for: test/test_remote.py

+211
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
GitCommandError,
2424
)
2525
from git.cmd import Git
26+
from pathlib import Path
27+
from git.exc import UnsafeOptionError, UnsafeProtocolError
2628
from test.lib import (
2729
TestBase,
2830
with_rw_repo,
@@ -690,6 +692,215 @@ def test_push_error(self, repo):
690692
with self.assertRaisesRegex(GitCommandError, "src refspec __BAD_REF__ does not match any"):
691693
rem.push("__BAD_REF__")
692694

695+
@with_rw_repo("HEAD")
696+
def test_set_unsafe_url(self, rw_repo):
697+
remote = rw_repo.remote("origin")
698+
urls = [
699+
"ext::sh -c touch% /tmp/pwn",
700+
"fd::17/foo",
701+
]
702+
for url in urls:
703+
with self.assertRaises(UnsafeProtocolError):
704+
remote.set_url(url)
705+
706+
@with_rw_repo("HEAD")
707+
def test_set_unsafe_url_allowed(self, rw_repo):
708+
remote = rw_repo.remote("origin")
709+
urls = [
710+
"ext::sh -c touch% /tmp/pwn",
711+
"fd::17/foo",
712+
]
713+
for url in urls:
714+
remote.set_url(url, allow_unsafe_protocols=True)
715+
assert list(remote.urls)[-1] == url
716+
717+
@with_rw_repo("HEAD")
718+
def test_add_unsafe_url(self, rw_repo):
719+
remote = rw_repo.remote("origin")
720+
urls = [
721+
"ext::sh -c touch% /tmp/pwn",
722+
"fd::17/foo",
723+
]
724+
for url in urls:
725+
with self.assertRaises(UnsafeProtocolError):
726+
remote.add_url(url)
727+
728+
@with_rw_repo("HEAD")
729+
def test_add_unsafe_url_allowed(self, rw_repo):
730+
remote = rw_repo.remote("origin")
731+
urls = [
732+
"ext::sh -c touch% /tmp/pwn",
733+
"fd::17/foo",
734+
]
735+
for url in urls:
736+
remote.add_url(url, allow_unsafe_protocols=True)
737+
assert list(remote.urls)[-1] == url
738+
739+
@with_rw_repo("HEAD")
740+
def test_create_remote_unsafe_url(self, rw_repo):
741+
urls = [
742+
"ext::sh -c touch% /tmp/pwn",
743+
"fd::17/foo",
744+
]
745+
for url in urls:
746+
with self.assertRaises(UnsafeProtocolError):
747+
Remote.create(rw_repo, "origin", url)
748+
749+
@with_rw_repo("HEAD")
750+
def test_create_remote_unsafe_url_allowed(self, rw_repo):
751+
urls = [
752+
"ext::sh -c touch% /tmp/pwn",
753+
"fd::17/foo",
754+
]
755+
for i, url in enumerate(urls):
756+
remote = Remote.create(rw_repo, f"origin{i}", url, allow_unsafe_protocols=True)
757+
assert remote.url == url
758+
759+
@with_rw_repo("HEAD")
760+
def test_fetch_unsafe_url(self, rw_repo):
761+
remote = rw_repo.remote("origin")
762+
urls = [
763+
"ext::sh -c touch% /tmp/pwn",
764+
"fd::17/foo",
765+
]
766+
for url in urls:
767+
with self.assertRaises(UnsafeProtocolError):
768+
remote.fetch(url)
769+
770+
@with_rw_repo("HEAD")
771+
def test_fetch_unsafe_url_allowed(self, rw_repo):
772+
remote = rw_repo.remote("origin")
773+
urls = [
774+
"ext::sh -c touch% /tmp/pwn",
775+
"fd::17/foo",
776+
]
777+
for url in urls:
778+
# The URL will be allowed into the command, but the command will
779+
# fail since we don't have that protocol enabled in the Git config file.
780+
with self.assertRaises(GitCommandError):
781+
remote.fetch(url, allow_unsafe_protocols=True)
782+
783+
@with_rw_repo("HEAD")
784+
def test_fetch_unsafe_options(self, rw_repo):
785+
remote = rw_repo.remote("origin")
786+
tmp_dir = Path(tempfile.mkdtemp())
787+
tmp_file = tmp_dir / "pwn"
788+
unsafe_options = [{"upload-pack": f"touch {tmp_file}"}]
789+
for unsafe_option in unsafe_options:
790+
with self.assertRaises(UnsafeOptionError):
791+
remote.fetch(**unsafe_option)
792+
793+
@with_rw_repo("HEAD")
794+
def test_fetch_unsafe_options_allowed(self, rw_repo):
795+
remote = rw_repo.remote("origin")
796+
tmp_dir = Path(tempfile.mkdtemp())
797+
tmp_file = tmp_dir / "pwn"
798+
unsafe_options = [{"upload-pack": f"touch {tmp_file}"}]
799+
for unsafe_option in unsafe_options:
800+
# The options will be allowed, but the command will fail.
801+
with self.assertRaises(GitCommandError):
802+
remote.fetch(**unsafe_option, allow_unsafe_options=True)
803+
804+
@with_rw_repo("HEAD")
805+
def test_pull_unsafe_url(self, rw_repo):
806+
remote = rw_repo.remote("origin")
807+
urls = [
808+
"ext::sh -c touch% /tmp/pwn",
809+
"fd::17/foo",
810+
]
811+
for url in urls:
812+
with self.assertRaises(UnsafeProtocolError):
813+
remote.pull(url)
814+
815+
@with_rw_repo("HEAD")
816+
def test_pull_unsafe_url_allowed(self, rw_repo):
817+
remote = rw_repo.remote("origin")
818+
urls = [
819+
"ext::sh -c touch% /tmp/pwn",
820+
"fd::17/foo",
821+
]
822+
for url in urls:
823+
# The URL will be allowed into the command, but the command will
824+
# fail since we don't have that protocol enabled in the Git config file.
825+
with self.assertRaises(GitCommandError):
826+
remote.pull(url, allow_unsafe_protocols=True)
827+
828+
@with_rw_repo("HEAD")
829+
def test_pull_unsafe_options(self, rw_repo):
830+
remote = rw_repo.remote("origin")
831+
tmp_dir = Path(tempfile.mkdtemp())
832+
tmp_file = tmp_dir / "pwn"
833+
unsafe_options = [{"upload-pack": f"touch {tmp_file}"}]
834+
for unsafe_option in unsafe_options:
835+
with self.assertRaises(UnsafeOptionError):
836+
remote.pull(**unsafe_option)
837+
838+
@with_rw_repo("HEAD")
839+
def test_pull_unsafe_options_allowed(self, rw_repo):
840+
remote = rw_repo.remote("origin")
841+
tmp_dir = Path(tempfile.mkdtemp())
842+
tmp_file = tmp_dir / "pwn"
843+
unsafe_options = [{"upload-pack": f"touch {tmp_file}"}]
844+
for unsafe_option in unsafe_options:
845+
# The options will be allowed, but the command will fail.
846+
with self.assertRaises(GitCommandError):
847+
remote.pull(**unsafe_option, allow_unsafe_options=True)
848+
849+
@with_rw_repo("HEAD")
850+
def test_push_unsafe_url(self, rw_repo):
851+
remote = rw_repo.remote("origin")
852+
urls = [
853+
"ext::sh -c touch% /tmp/pwn",
854+
"fd::17/foo",
855+
]
856+
for url in urls:
857+
with self.assertRaises(UnsafeProtocolError):
858+
remote.push(url)
859+
860+
@with_rw_repo("HEAD")
861+
def test_push_unsafe_url_allowed(self, rw_repo):
862+
remote = rw_repo.remote("origin")
863+
urls = [
864+
"ext::sh -c touch% /tmp/pwn",
865+
"fd::17/foo",
866+
]
867+
for url in urls:
868+
# The URL will be allowed into the command, but the command will
869+
# fail since we don't have that protocol enabled in the Git config file.
870+
with self.assertRaises(GitCommandError):
871+
remote.push(url, allow_unsafe_protocols=True)
872+
873+
@with_rw_repo("HEAD")
874+
def test_push_unsafe_options(self, rw_repo):
875+
remote = rw_repo.remote("origin")
876+
tmp_dir = Path(tempfile.mkdtemp())
877+
tmp_file = tmp_dir / "pwn"
878+
unsafe_options = [
879+
{
880+
"receive-pack": f"touch {tmp_file}",
881+
"exec": f"touch {tmp_file}",
882+
}
883+
]
884+
for unsafe_option in unsafe_options:
885+
with self.assertRaises(UnsafeOptionError):
886+
remote.push(**unsafe_option)
887+
888+
@with_rw_repo("HEAD")
889+
def test_push_unsafe_options_allowed(self, rw_repo):
890+
remote = rw_repo.remote("origin")
891+
tmp_dir = Path(tempfile.mkdtemp())
892+
tmp_file = tmp_dir / "pwn"
893+
unsafe_options = [
894+
{
895+
"receive-pack": f"touch {tmp_file}",
896+
"exec": f"touch {tmp_file}",
897+
}
898+
]
899+
for unsafe_option in unsafe_options:
900+
# The options will be allowed, but the command will fail.
901+
with self.assertRaises(GitCommandError):
902+
remote.push(**unsafe_option, allow_unsafe_options=True)
903+
693904

694905
class TestTimeouts(TestBase):
695906
@with_rw_repo("HEAD", bare=False)

Diff for: test/test_submodule.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1026,7 +1026,7 @@ def test_update_clone_multi_options_argument(self, rwdir):
10261026
)
10271027

10281028
# Act
1029-
sm.update(init=True, clone_multi_options=["--config core.eol=true"])
1029+
sm.update(init=True, clone_multi_options=["--config core.eol=true"], allow_unsafe_options=True)
10301030

10311031
# Assert
10321032
sm_config = GitConfigParser(file_or_files=osp.join(parent.git_dir, "modules", sm_name, "config"))
@@ -1070,6 +1070,7 @@ def test_add_clone_multi_options_argument(self, rwdir):
10701070
sm_name,
10711071
url=self._small_repo_url(),
10721072
clone_multi_options=["--config core.eol=true"],
1073+
allow_unsafe_options=True,
10731074
)
10741075

10751076
# Assert

0 commit comments

Comments
 (0)