Merge pull request #1521 from stsewd/block-insecure-options · gitpython-developers/GitPython@678a8fe
@@ -539,6 +539,23 @@ class Remote(LazyMixin, IterableObj):
539539__slots__ = ("repo", "name", "_config_reader")
540540_id_attribute_ = "name"
541541542+unsafe_git_fetch_options = [
543+# This option allows users to execute arbitrary commands.
544+# https://git-scm.com/docs/git-fetch#Documentation/git-fetch.txt---upload-packltupload-packgt
545+"--upload-pack",
546+ ]
547+unsafe_git_pull_options = [
548+# This option allows users to execute arbitrary commands.
549+# https://git-scm.com/docs/git-pull#Documentation/git-pull.txt---upload-packltupload-packgt
550+"--upload-pack"
551+ ]
552+unsafe_git_push_options = [
553+# This option allows users to execute arbitrary commands.
554+# https://git-scm.com/docs/git-push#Documentation/git-push.txt---execltgit-receive-packgt
555+"--receive-pack",
556+"--exec",
557+ ]
558+542559def __init__(self, repo: "Repo", name: str) -> None:
543560"""Initialize a remote instance
544561@@ -615,7 +632,9 @@ def iter_items(cls, repo: "Repo", *args: Any, **kwargs: Any) -> Iterator["Remote
615632yield Remote(repo, section[lbound + 1 : rbound])
616633# END for each configuration section
617634618-def set_url(self, new_url: str, old_url: Optional[str] = None, **kwargs: Any) -> "Remote":
635+def set_url(
636+self, new_url: str, old_url: Optional[str] = None, allow_unsafe_protocols: bool = False, **kwargs: Any
637+ ) -> "Remote":
619638"""Configure URLs on current remote (cf command git remote set_url)
620639621640 This command manages URLs on the remote.
@@ -624,15 +643,17 @@ def set_url(self, new_url: str, old_url: Optional[str] = None, **kwargs: Any) ->
624643 :param old_url: when set, replaces this URL with new_url for the remote
625644 :return: self
626645 """
646+if not allow_unsafe_protocols:
647+Git.check_unsafe_protocols(new_url)
627648scmd = "set-url"
628649kwargs["insert_kwargs_after"] = scmd
629650if old_url:
630-self.repo.git.remote(scmd, self.name, new_url, old_url, **kwargs)
651+self.repo.git.remote(scmd, "--", self.name, new_url, old_url, **kwargs)
631652else:
632-self.repo.git.remote(scmd, self.name, new_url, **kwargs)
653+self.repo.git.remote(scmd, "--", self.name, new_url, **kwargs)
633654return self
634655635-def add_url(self, url: str, **kwargs: Any) -> "Remote":
656+def add_url(self, url: str, allow_unsafe_protocols: bool = False, **kwargs: Any) -> "Remote":
636657"""Adds a new url on current remote (special case of git remote set_url)
637658638659 This command adds new URLs to a given remote, making it possible to have
@@ -641,7 +662,7 @@ def add_url(self, url: str, **kwargs: Any) -> "Remote":
641662 :param url: string being the URL to add as an extra remote URL
642663 :return: self
643664 """
644-return self.set_url(url, add=True)
665+return self.set_url(url, add=True, allow_unsafe_protocols=allow_unsafe_protocols)
645666646667def delete_url(self, url: str, **kwargs: Any) -> "Remote":
647668"""Deletes a new url on current remote (special case of git remote set_url)
@@ -733,7 +754,7 @@ def stale_refs(self) -> IterableList[Reference]:
733754return out_refs
734755735756@classmethod
736-def create(cls, repo: "Repo", name: str, url: str, **kwargs: Any) -> "Remote":
757+def create(cls, repo: "Repo", name: str, url: str, allow_unsafe_protocols: bool = False, **kwargs: Any) -> "Remote":
737758"""Create a new remote to the given repository
738759 :param repo: Repository instance that is to receive the new remote
739760 :param name: Desired name of the remote
@@ -743,7 +764,10 @@ def create(cls, repo: "Repo", name: str, url: str, **kwargs: Any) -> "Remote":
743764 :raise GitCommandError: in case an origin with that name already exists"""
744765scmd = "add"
745766kwargs["insert_kwargs_after"] = scmd
746-repo.git.remote(scmd, name, Git.polish_url(url), **kwargs)
767+url = Git.polish_url(url)
768+if not allow_unsafe_protocols:
769+Git.check_unsafe_protocols(url)
770+repo.git.remote(scmd, "--", name, url, **kwargs)
747771return cls(repo, name)
748772749773# add is an alias
@@ -925,6 +949,8 @@ def fetch(
925949progress: Union[RemoteProgress, None, "UpdateProgress"] = None,
926950verbose: bool = True,
927951kill_after_timeout: Union[None, float] = None,
952+allow_unsafe_protocols: bool = False,
953+allow_unsafe_options: bool = False,
928954**kwargs: Any,
929955 ) -> IterableList[FetchInfo]:
930956"""Fetch the latest changes for this remote
@@ -967,6 +993,14 @@ def fetch(
967993else:
968994args = [refspec]
969995996+if not allow_unsafe_protocols:
997+for ref in args:
998+if ref:
999+Git.check_unsafe_protocols(ref)
1000+1001+if not allow_unsafe_options:
1002+Git.check_unsafe_options(options=list(kwargs.keys()), unsafe_options=self.unsafe_git_fetch_options)
1003+9701004proc = self.repo.git.fetch(
9711005"--", self, *args, as_process=True, with_stdout=False, universal_newlines=True, v=verbose, **kwargs
9721006 )
@@ -980,6 +1014,8 @@ def pull(
9801014refspec: Union[str, List[str], None] = None,
9811015progress: Union[RemoteProgress, "UpdateProgress", None] = None,
9821016kill_after_timeout: Union[None, float] = None,
1017+allow_unsafe_protocols: bool = False,
1018+allow_unsafe_options: bool = False,
9831019**kwargs: Any,
9841020 ) -> IterableList[FetchInfo]:
9851021"""Pull changes from the given branch, being the same as a fetch followed
@@ -994,6 +1030,15 @@ def pull(
9941030# No argument refspec, then ensure the repo's config has a fetch refspec.
9951031self._assert_refspec()
9961032kwargs = add_progress(kwargs, self.repo.git, progress)
1033+1034+refspec = Git._unpack_args(refspec or [])
1035+if not allow_unsafe_protocols:
1036+for ref in refspec:
1037+Git.check_unsafe_protocols(ref)
1038+1039+if not allow_unsafe_options:
1040+Git.check_unsafe_options(options=list(kwargs.keys()), unsafe_options=self.unsafe_git_pull_options)
1041+9971042proc = self.repo.git.pull(
9981043"--", self, refspec, with_stdout=False, as_process=True, universal_newlines=True, v=True, **kwargs
9991044 )
@@ -1007,6 +1052,8 @@ def push(
10071052refspec: Union[str, List[str], None] = None,
10081053progress: Union[RemoteProgress, "UpdateProgress", Callable[..., RemoteProgress], None] = None,
10091054kill_after_timeout: Union[None, float] = None,
1055+allow_unsafe_protocols: bool = False,
1056+allow_unsafe_options: bool = False,
10101057**kwargs: Any,
10111058 ) -> PushInfoList:
10121059"""Push changes from source branch in refspec to target branch in refspec.
@@ -1037,6 +1084,15 @@ def push(
10371084 be 0.
10381085 Call ``.raise_if_error()`` on the returned object to raise on any failure."""
10391086kwargs = add_progress(kwargs, self.repo.git, progress)
1087+1088+refspec = Git._unpack_args(refspec or [])
1089+if not allow_unsafe_protocols:
1090+for ref in refspec:
1091+Git.check_unsafe_protocols(ref)
1092+1093+if not allow_unsafe_options:
1094+Git.check_unsafe_options(options=list(kwargs.keys()), unsafe_options=self.unsafe_git_push_options)
1095+10401096proc = self.repo.git.push(
10411097"--",
10421098self,