@@ -131,6 +131,9 @@ class Repo:
131131 git_dir: PathLike
132132 """The ``.git`` repository directory."""
133133
134+ safe: None
135+ """Whether this is operating using restricted protocol and execution access."""
136+
134137 _common_dir: PathLike = ""
135138
136139 # Precompiled regex
@@ -175,6 +178,7 @@ def __init__(
175178 odbt: Type[LooseObjectDB] = GitCmdObjectDB,
176179 search_parent_directories: bool = False,
177180 expand_vars: bool = True,
181+ safe: bool = False,
178182 ) -> None:
179183 R"""Create a new :class:`Repo` instance.
180184
@@ -204,6 +208,17 @@ def __init__(
204208 Please note that this was the default behaviour in older versions of
205209 GitPython, which is considered a bug though.
206210
211+ :param safe:
212+ Lock down the configuration to make it as safe as possible
213+ when working with publicly accessible, untrusted
214+ repositories. This disables all known options that can run
215+ an external program and limits networking to the HTTP
216+ protocol via https:// URLs. This might not cover Git config
217+ options that were added since this was implemented, or
218+ options that might have unknown exploit vectors. It is a
219+ best effort defense rather than an exhaustive protection
220+ measure.
221+
207222 :raise git.exc.InvalidGitRepositoryError:
208223
209224 :raise git.exc.NoSuchPathError:
@@ -235,6 +250,8 @@ def __init__(
235250 if not os.path.exists(epath):
236251 raise NoSuchPathError(epath)
237252
253+ self.safe = safe
254+
238255 # Walk up the path to find the `.git` dir.
239256 curpath = epath
240257 git_dir = None
@@ -309,7 +326,7 @@ def __init__(
309326 # END working dir handling
310327
311328 self.working_dir: PathLike = self._working_tree_dir or self.common_dir
312- self .git = self .GitCommandWrapperType (self .working_dir )
329+ self.git = self.GitCommandWrapperType(self.working_dir, safe )
313330
314331 # Special handling, in special times.
315332 rootpath = osp.join(self.common_dir, "objects")
@@ -1305,6 +1322,7 @@ def init(
13051322 mkdir: bool = True,
13061323 odbt: Type[GitCmdObjectDB] = GitCmdObjectDB,
13071324 expand_vars: bool = True,
1325+ safe: bool = False,
13081326 **kwargs: Any,
13091327 ) -> "Repo":
13101328 """Initialize a git repository at the given path if specified.
@@ -1329,6 +1347,8 @@ def init(
13291347 information disclosure, allowing attackers to access the contents of
13301348 environment variables.
13311349
1350+ TODO :param safe:
1351+
13321352 :param kwargs:
13331353 Keyword arguments serving as additional options to the
13341354 :manpage:`git-init(1)` command.
@@ -1342,9 +1362,9 @@ def init(
13421362 os.makedirs(path, 0o755)
13431363
13441364 # git command automatically chdir into the directory
1345- git = cls .GitCommandWrapperType (path )
1365+ git = cls.GitCommandWrapperType(path, safe )
13461366 git.init(**kwargs)
1347- return cls (path , odbt = odbt )
1367+ return cls(path, odbt=odbt, safe=safe )
13481368
13491369 @classmethod
13501370 def _clone(
@@ -1357,6 +1377,7 @@ def _clone(
13571377 multi_options: Optional[List[str]] = None,
13581378 allow_unsafe_protocols: bool = False,
13591379 allow_unsafe_options: bool = False,
1380+ safe: Union[bool, None] = None,
13601381 **kwargs: Any,
13611382 ) -> "Repo":
13621383 odbt = kwargs.pop("odbt", odb_default_type)
@@ -1418,7 +1439,11 @@ def _clone(
14181439 if not osp.isabs(path):
14191440 path = osp.join(git._working_dir, path) if git._working_dir is not None else path
14201441
1421- repo = cls (path , odbt = odbt )
1442+ # if safe is not explicitly defined, then the new Repo instance should inherit the safe value
1443+ if safe is None:
1444+ safe = git._safe
1445+
1446+ repo = cls(path, odbt=odbt, safe=safe)
14221447
14231448 # Retain env values that were passed to _clone().
14241449 repo.git.update_environment(**git.environment())
@@ -1501,6 +1526,7 @@ def clone_from(
15011526 multi_options: Optional[List[str]] = None,
15021527 allow_unsafe_protocols: bool = False,
15031528 allow_unsafe_options: bool = False,
1529+ safe: bool = False,
15041530 **kwargs: Any,
15051531 ) -> "Repo":
15061532 """Create a clone from the given URL.
@@ -1531,13 +1557,16 @@ def clone_from(
15311557 :param allow_unsafe_options:
15321558 Allow unsafe options to be used, like ``--upload-pack``.
15331559
1560+ :param safe:
1561+ TODO
1562+
15341563 :param kwargs:
15351564 See the :meth:`clone` method.
15361565
15371566 :return:
15381567 :class:`Repo` instance pointing to the cloned directory.
15391568 """
1540- git = cls .GitCommandWrapperType (os .getcwd ())
1569+ git = cls.GitCommandWrapperType(os.getcwd(), safe )
15411570 if env is not None:
15421571 git.update_environment(**env)
15431572 return cls._clone(
@@ -1549,6 +1578,7 @@ def clone_from(
15491578 multi_options,
15501579 allow_unsafe_protocols=allow_unsafe_protocols,
15511580 allow_unsafe_options=allow_unsafe_options,
1581+ safe=safe,
15521582 **kwargs,
15531583 )
15541584
0 commit comments