2121)
2222from git .config import GitConfigParser
2323from git .db import GitCmdObjectDB
24- from git .exc import InvalidGitRepositoryError , NoSuchPathError , GitCommandError
24+ from git .exc import (
25+ GitCommandError ,
26+ InvalidGitRepositoryError ,
27+ NoSuchPathError ,
28+ UnsafeOptionsUsedError ,
29+ )
2530from git .index import IndexFile
2631from git .objects import Submodule , RootModule , Commit
2732from git .refs import HEAD , Head , Reference , TagReference
@@ -128,6 +133,7 @@ class Repo(object):
128133 re_envvars = re .compile (r"(\$(\{\s?)?[a-zA-Z_]\w*(\}\s?)?|%\s?[a-zA-Z_]\w*\s?%)" )
129134 re_author_committer_start = re .compile (r"^(author|committer)" )
130135 re_tab_full_line = re .compile (r"^\t(.*)$" )
136+ re_config_protocol_option = re .compile (r"-[-]?c(|onfig)\s+protocol\." , re .I )
131137
132138 # invariants
133139 # represents the configuration level of a configuration file
@@ -1214,11 +1220,27 @@ def _clone(
12141220 # END handle remote repo
12151221 return repo
12161222
1223+ @classmethod
1224+ def unsafe_options (
1225+ cls ,
1226+ url : str ,
1227+ multi_options : Optional [List [str ]] = None ,
1228+ ) -> bool :
1229+ if "ext::" in url :
1230+ return True
1231+ if multi_options is not None :
1232+ if any (["--upload-pack" in m for m in multi_options ]):
1233+ return True
1234+ if any ([re .match (cls .re_config_protocol_option , m ) for m in multi_options ]):
1235+ return True
1236+ return False
1237+
12171238 def clone (
12181239 self ,
12191240 path : PathLike ,
12201241 progress : Optional [Callable ] = None ,
12211242 multi_options : Optional [List [str ]] = None ,
1243+ unsafe_protocols : bool = False ,
12221244 ** kwargs : Any ,
12231245 ) -> "Repo" :
12241246 """Create a clone from this repository.
@@ -1229,12 +1251,15 @@ def clone(
12291251 option per list item which is passed exactly as specified to clone.
12301252 For example ['--config core.filemode=false', '--config core.ignorecase',
12311253 '--recurse-submodule=repo1_path', '--recurse-submodule=repo2_path']
1254+ :param unsafe_protocols: Allow unsafe protocols to be used, like ext
12321255 :param kwargs:
12331256 * odbt = ObjectDatabase Type, allowing to determine the object database
12341257 implementation used by the returned Repo instance
12351258 * All remaining keyword arguments are given to the git-clone command
12361259
12371260 :return: ``git.Repo`` (the newly cloned repo)"""
1261+ if not unsafe_protocols and self .unsafe_options (url , multi_options ):
1262+ raise UnsafeOptionsUsedError (f"{ url } requires unsafe_protocols flag" )
12381263 return self ._clone (
12391264 self .git ,
12401265 self .common_dir ,
@@ -1253,6 +1278,7 @@ def clone_from(
12531278 progress : Optional [Callable ] = None ,
12541279 env : Optional [Mapping [str , str ]] = None ,
12551280 multi_options : Optional [List [str ]] = None ,
1281+ unsafe_protocols : bool = False ,
12561282 ** kwargs : Any ,
12571283 ) -> "Repo" :
12581284 """Create a clone from the given URL
@@ -1267,11 +1293,14 @@ def clone_from(
12671293 If you want to unset some variable, consider providing empty string
12681294 as its value.
12691295 :param multi_options: See ``clone`` method
1296+ :param unsafe_protocols: Allow unsafe protocols to be used, like ext
12701297 :param kwargs: see the ``clone`` method
12711298 :return: Repo instance pointing to the cloned directory"""
12721299 git = cls .GitCommandWrapperType (os .getcwd ())
12731300 if env is not None :
12741301 git .update_environment (** env )
1302+ if not unsafe_protocols and cls .unsafe_options (url , multi_options ):
1303+ raise UnsafeOptionsUsedError (f"{ url } requires unsafe_protocols flag" )
12751304 return cls ._clone (git , url , to_path , GitCmdObjectDB , progress , multi_options , ** kwargs )
12761305
12771306 def archive (
0 commit comments