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
@@ -1215,11 +1221,27 @@ def _clone(
12151221 # END handle remote repo
12161222 return repo
12171223
1224+ @classmethod
1225+ def unsafe_options (
1226+ cls ,
1227+ url : str ,
1228+ multi_options : Optional [List [str ]] = None ,
1229+ ) -> bool :
1230+ if "ext::" in url :
1231+ return True
1232+ if multi_options is not None :
1233+ if any (["--upload-pack" in m for m in multi_options ]):
1234+ return True
1235+ if any ([re .match (cls .re_config_protocol_option , m ) for m in multi_options ]):
1236+ return True
1237+ return False
1238+
12181239 def clone (
12191240 self ,
12201241 path : PathLike ,
12211242 progress : Optional [Callable ] = None ,
12221243 multi_options : Optional [List [str ]] = None ,
1244+ unsafe_protocols : bool = False ,
12231245 ** kwargs : Any ,
12241246 ) -> "Repo" :
12251247 """Create a clone from this repository.
@@ -1230,12 +1252,15 @@ def clone(
12301252 option per list item which is passed exactly as specified to clone.
12311253 For example ['--config core.filemode=false', '--config core.ignorecase',
12321254 '--recurse-submodule=repo1_path', '--recurse-submodule=repo2_path']
1255+ :param unsafe_protocols: Allow unsafe protocols to be used, like ext
12331256 :param kwargs:
12341257 * odbt = ObjectDatabase Type, allowing to determine the object database
12351258 implementation used by the returned Repo instance
12361259 * All remaining keyword arguments are given to the git-clone command
12371260
12381261 :return: ``git.Repo`` (the newly cloned repo)"""
1262+ if not unsafe_protocols and self .unsafe_options (path , multi_options ):
1263+ raise UnsafeOptionsUsedError (f"{ path } requires unsafe_protocols flag" )
12391264 return self ._clone (
12401265 self .git ,
12411266 self .common_dir ,
@@ -1254,6 +1279,7 @@ def clone_from(
12541279 progress : Optional [Callable ] = None ,
12551280 env : Optional [Mapping [str , str ]] = None ,
12561281 multi_options : Optional [List [str ]] = None ,
1282+ unsafe_protocols : bool = False ,
12571283 ** kwargs : Any ,
12581284 ) -> "Repo" :
12591285 """Create a clone from the given URL
@@ -1268,11 +1294,14 @@ def clone_from(
12681294 If you want to unset some variable, consider providing empty string
12691295 as its value.
12701296 :param multi_options: See ``clone`` method
1297+ :param unsafe_protocols: Allow unsafe protocols to be used, like ext
12711298 :param kwargs: see the ``clone`` method
12721299 :return: Repo instance pointing to the cloned directory"""
12731300 git = cls .GitCommandWrapperType (os .getcwd ())
12741301 if env is not None :
12751302 git .update_environment (** env )
1303+ if not unsafe_protocols and cls .unsafe_options (url , multi_options ):
1304+ raise UnsafeOptionsUsedError (f"{ url } requires unsafe_protocols flag" )
12761305 return cls ._clone (git , url , to_path , GitCmdObjectDB , progress , multi_options , ** kwargs )
12771306
12781307 def archive (
0 commit comments