@@ -535,6 +535,23 @@ class Remote(LazyMixin, IterableObj):
535535 __slots__ = ("repo" , "name" , "_config_reader" )
536536 _id_attribute_ = "name"
537537
538+ unsafe_git_fetch_options = [
539+ # This option allows users to execute arbitrary commands.
540+ # https://git-scm.com/docs/git-fetch#Documentation/git-fetch.txt---upload-packltupload-packgt
541+ "--upload-pack" ,
542+ ]
543+ unsafe_git_pull_options = [
544+ # This option allows users to execute arbitrary commands.
545+ # https://git-scm.com/docs/git-pull#Documentation/git-pull.txt---upload-packltupload-packgt
546+ "--upload-pack"
547+ ]
548+ unsafe_git_push_options = [
549+ # This option allows users to execute arbitrary commands.
550+ # https://git-scm.com/docs/git-push#Documentation/git-push.txt---execltgit-receive-packgt
551+ "--receive-pack" ,
552+ "--exec" ,
553+ ]
554+
538555 def __init__ (self , repo : "Repo" , name : str ) -> None :
539556 """Initialize a remote instance
540557
@@ -611,7 +628,9 @@ def iter_items(cls, repo: "Repo", *args: Any, **kwargs: Any) -> Iterator["Remote
611628 yield Remote (repo , section [lbound + 1 : rbound ])
612629 # END for each configuration section
613630
614- def set_url (self , new_url : str , old_url : Optional [str ] = None , ** kwargs : Any ) -> "Remote" :
631+ def set_url (
632+ self , new_url : str , old_url : Optional [str ] = None , allow_unsafe_protocols : bool = False , ** kwargs : Any
633+ ) -> "Remote" :
615634 """Configure URLs on current remote (cf command git remote set_url)
616635
617636 This command manages URLs on the remote.
@@ -620,15 +639,17 @@ def set_url(self, new_url: str, old_url: Optional[str] = None, **kwargs: Any) ->
620639 :param old_url: when set, replaces this URL with new_url for the remote
621640 :return: self
622641 """
642+ if not allow_unsafe_protocols :
643+ Git .check_unsafe_protocols (new_url )
623644 scmd = "set-url"
624645 kwargs ["insert_kwargs_after" ] = scmd
625646 if old_url :
626- self .repo .git .remote (scmd , self .name , new_url , old_url , ** kwargs )
647+ self .repo .git .remote (scmd , "--" , self .name , new_url , old_url , ** kwargs )
627648 else :
628- self .repo .git .remote (scmd , self .name , new_url , ** kwargs )
649+ self .repo .git .remote (scmd , "--" , self .name , new_url , ** kwargs )
629650 return self
630651
631- def add_url (self , url : str , ** kwargs : Any ) -> "Remote" :
652+ def add_url (self , url : str , allow_unsafe_protocols : bool = False , ** kwargs : Any ) -> "Remote" :
632653 """Adds a new url on current remote (special case of git remote set_url)
633654
634655 This command adds new URLs to a given remote, making it possible to have
@@ -637,6 +658,8 @@ def add_url(self, url: str, **kwargs: Any) -> "Remote":
637658 :param url: string being the URL to add as an extra remote URL
638659 :return: self
639660 """
661+ if not allow_unsafe_protocols :
662+ Git .check_unsafe_protocols (url )
640663 return self .set_url (url , add = True )
641664
642665 def delete_url (self , url : str , ** kwargs : Any ) -> "Remote" :
@@ -729,7 +752,7 @@ def stale_refs(self) -> IterableList[Reference]:
729752 return out_refs
730753
731754 @classmethod
732- def create (cls , repo : "Repo" , name : str , url : str , ** kwargs : Any ) -> "Remote" :
755+ def create (cls , repo : "Repo" , name : str , url : str , allow_unsafe_protocols : bool = False , ** kwargs : Any ) -> "Remote" :
733756 """Create a new remote to the given repository
734757 :param repo: Repository instance that is to receive the new remote
735758 :param name: Desired name of the remote
@@ -739,7 +762,10 @@ def create(cls, repo: "Repo", name: str, url: str, **kwargs: Any) -> "Remote":
739762 :raise GitCommandError: in case an origin with that name already exists"""
740763 scmd = "add"
741764 kwargs ["insert_kwargs_after" ] = scmd
742- repo .git .remote (scmd , name , Git .polish_url (url ), ** kwargs )
765+ url = Git .polish_url (url )
766+ if not allow_unsafe_protocols :
767+ Git .check_unsafe_protocols (url )
768+ repo .git .remote (scmd , "--" , name , url , ** kwargs )
743769 return cls (repo , name )
744770
745771 # add is an alias
@@ -921,6 +947,8 @@ def fetch(
921947 progress : Union [RemoteProgress , None , "UpdateProgress" ] = None ,
922948 verbose : bool = True ,
923949 kill_after_timeout : Union [None , float ] = None ,
950+ allow_unsafe_protocols : bool = False ,
951+ allow_unsafe_options : bool = False ,
924952 ** kwargs : Any ,
925953 ) -> IterableList [FetchInfo ]:
926954 """Fetch the latest changes for this remote
@@ -963,6 +991,14 @@ def fetch(
963991 else :
964992 args = [refspec ]
965993
994+ if not allow_unsafe_protocols :
995+ for ref in args :
996+ if ref :
997+ Git .check_unsafe_protocols (ref )
998+
999+ if not allow_unsafe_options :
1000+ Git .check_unsafe_options (options = list (kwargs .keys ()), unsafe_options = self .unsafe_git_fetch_options )
1001+
9661002 proc = self .repo .git .fetch (
9671003 "--" , self , * args , as_process = True , with_stdout = False , universal_newlines = True , v = verbose , ** kwargs
9681004 )
@@ -976,6 +1012,8 @@ def pull(
9761012 refspec : Union [str , List [str ], None ] = None ,
9771013 progress : Union [RemoteProgress , "UpdateProgress" , None ] = None ,
9781014 kill_after_timeout : Union [None , float ] = None ,
1015+ allow_unsafe_protocols : bool = False ,
1016+ allow_unsafe_options : bool = False ,
9791017 ** kwargs : Any ,
9801018 ) -> IterableList [FetchInfo ]:
9811019 """Pull changes from the given branch, being the same as a fetch followed
@@ -990,6 +1028,16 @@ def pull(
9901028 # No argument refspec, then ensure the repo's config has a fetch refspec.
9911029 self ._assert_refspec ()
9921030 kwargs = add_progress (kwargs , self .repo .git , progress )
1031+
1032+ if not allow_unsafe_protocols and refspec :
1033+ if isinstance (refspec , str ):
1034+ Git .check_unsafe_protocols (refspec )
1035+ else :
1036+ for ref in refspec :
1037+ Git .check_unsafe_protocols (ref )
1038+ if not allow_unsafe_options :
1039+ Git .check_unsafe_options (options = list (kwargs .keys ()), unsafe_options = self .unsafe_git_pull_options )
1040+
9931041 proc = self .repo .git .pull (
9941042 "--" , self , refspec , with_stdout = False , as_process = True , universal_newlines = True , v = True , ** kwargs
9951043 )
@@ -1003,6 +1051,8 @@ def push(
10031051 refspec : Union [str , List [str ], None ] = None ,
10041052 progress : Union [RemoteProgress , "UpdateProgress" , Callable [..., RemoteProgress ], None ] = None ,
10051053 kill_after_timeout : Union [None , float ] = None ,
1054+ allow_unsafe_protocols : bool = False ,
1055+ allow_unsafe_options : bool = False ,
10061056 ** kwargs : Any ,
10071057 ) -> IterableList [PushInfo ]:
10081058 """Push changes from source branch in refspec to target branch in refspec.
@@ -1033,6 +1083,17 @@ def push(
10331083 If the operation fails completely, the length of the returned IterableList will
10341084 be 0."""
10351085 kwargs = add_progress (kwargs , self .repo .git , progress )
1086+
1087+ if not allow_unsafe_protocols and refspec :
1088+ if isinstance (refspec , str ):
1089+ Git .check_unsafe_protocols (refspec )
1090+ else :
1091+ for ref in refspec :
1092+ Git .check_unsafe_protocols (ref )
1093+
1094+ if not allow_unsafe_options :
1095+ Git .check_unsafe_options (options = list (kwargs .keys ()), unsafe_options = self .unsafe_git_push_options )
1096+
10361097 proc = self .repo .git .push (
10371098 "--" ,
10381099 self ,
0 commit comments