| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -398,6 +398,7 @@ class Git(metaclass=_GitMeta): | |||
| 398 | 398 | ||
| 399 | 399 | __slots__ = ( | |
| 400 | 400 | "_working_dir", | |
| 401 | + "_safe", | ||
| 401 | 402 | "cat_file_all", | |
| 402 | 403 | "cat_file_header", | |
| 403 | 404 | "_version_info", | |
@@ -944,17 +945,20 @@ def __del__(self) -> None: | |||
| 944 | 945 | self._stream.read(bytes_left + 1) | |
| 945 | 946 | # END handle incomplete read | |
| 946 | 947 | ||
| 947 | - def __init__(self, working_dir: Union[None, PathLike] = None) -> None: | ||
| 948 | + def __init__(self, working_dir: Union[None, PathLike] = None, safe: bool = False) -> None: | ||
| 948 | 949 | """Initialize this instance with: | |
| 949 | 950 | ||
| 950 | 951 | :param working_dir: | |
| 951 | 952 | Git directory we should work in. If ``None``, we always work in the current | |
| 952 | 953 | directory as returned by :func:`os.getcwd`. | |
| 953 | 954 | This is meant to be the working tree directory if available, or the | |
| 954 | 955 | ``.git`` directory in case of bare repositories. | |
| 956 | + | ||
| 957 | + TODO :param safe: | ||
| 955 | 958 | """ | |
| 956 | 959 | super().__init__() | |
| 957 | 960 | self._working_dir = expand_path(working_dir) | |
| 961 | + self._safe = safe | ||
| 958 | 962 | self._git_options: Union[List[str], Tuple[str, ...]] = () | |
| 959 | 963 | self._persistent_git_options: List[str] = [] | |
| 960 | 964 | ||
@@ -1205,6 +1209,21 @@ def execute( | |||
| 1205 | 1209 | If you add additional keyword arguments to the signature of this method, you | |
| 1206 | 1210 | must update the ``execute_kwargs`` variable housed in this module. | |
| 1207 | 1211 | """ | |
| 1212 | + if self._safe: | ||
| 1213 | + if isinstance(command, str): | ||
| 1214 | + command = [command] | ||
| 1215 | + config_args = [ | ||
| 1216 | + '-c', 'core.askpass=/bin/true', | ||
| 1217 | + '-c', 'core.hooksPath=/dev/null', | ||
| 1218 | + '-c', 'core.sshCommand=/bin/true', | ||
| 1219 | + '-c', 'credential.helper=/bin/true', | ||
| 1220 | + '-c', 'http.emptyAuth=true', | ||
| 1221 | + '-c', 'protocol.allow=never', | ||
| 1222 | + '-c', 'protocol.https.allow=always', | ||
| 1223 | + '-c', 'url.https://.insteadOf=ssh://', | ||
| 1224 | + ] | ||
| 1225 | + command = [command.pop(0)] + config_args + command | ||
| 1226 | + | ||
| 1208 | 1227 | # Remove password for the command if present. | |
| 1209 | 1228 | redacted_command = remove_password_if_present(command) | |
| 1210 | 1229 | if self.GIT_PYTHON_TRACE and (self.GIT_PYTHON_TRACE != "full" or as_process): | |
@@ -1227,6 +1246,12 @@ def execute( | |||
| 1227 | 1246 | # just to be sure. | |
| 1228 | 1247 | env["LANGUAGE"] = "C" | |
| 1229 | 1248 | env["LC_ALL"] = "C" | |
| 1249 | + # Globally disable things that can execute commands, including password prompts. | ||
| 1250 | + if self._safe: | ||
| 1251 | + env['GIT_TERMINAL_PROMPT'] = 'false' | ||
| 1252 | + env['GIT_ASKPASS'] = '/bin/true' | ||
| 1253 | + env['SSH_ASKPASS'] = '/bin/true' | ||
| 1254 | + env['GIT_SSH'] = '/bin/true' | ||
| 1230 | 1255 | env.update(self._environment) | |
| 1231 | 1256 | if inline_env is not None: | |
| 1232 | 1257 | env.update(inline_env) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -131,6 +131,9 @@ class Repo: | |||
| 131 | 131 | git_dir: PathLike | |
| 132 | 132 | """The ``.git`` repository directory.""" | |
| 133 | 133 | ||
| 134 | + safe: None | ||
| 135 | + """Whether this is operating using restricted protocol and execution access.""" | ||
| 136 | + | ||
| 134 | 137 | _common_dir: PathLike = "" | |
| 135 | 138 | ||
| 136 | 139 | # Precompiled regex | |
@@ -175,6 +178,7 @@ def __init__( | |||
| 175 | 178 | odbt: Type[LooseObjectDB] = GitCmdObjectDB, | |
| 176 | 179 | search_parent_directories: bool = False, | |
| 177 | 180 | expand_vars: bool = True, | |
| 181 | + safe: bool = False, | ||
| 178 | 182 | ) -> None: | |
| 179 | 183 | R"""Create a new :class:`Repo` instance. | |
| 180 | 184 | ||
@@ -204,6 +208,11 @@ def __init__( | |||
| 204 | 208 | Please note that this was the default behaviour in older versions of | |
| 205 | 209 | GitPython, which is considered a bug though. | |
| 206 | 210 | ||
| 211 | + :param safe: | ||
| 212 | + Lock down the configuration to make it as safe as possible | ||
| 213 | + when working with publicly accessible, untrusted | ||
| 214 | + repositories. | ||
| 215 | + | ||
| 207 | 216 | :raise git.exc.InvalidGitRepositoryError: | |
| 208 | 217 | ||
| 209 | 218 | :raise git.exc.NoSuchPathError: | |
@@ -235,6 +244,8 @@ def __init__( | |||
| 235 | 244 | if not os.path.exists(epath): | |
| 236 | 245 | raise NoSuchPathError(epath) | |
| 237 | 246 | ||
| 247 | + self.safe = safe | ||
| 248 | + | ||
| 238 | 249 | # Walk up the path to find the `.git` dir. | |
| 239 | 250 | curpath = epath | |
| 240 | 251 | git_dir = None | |
@@ -289,6 +300,8 @@ def __init__( | |||
| 289 | 300 | raise InvalidGitRepositoryError(epath) | |
| 290 | 301 | self.git_dir = git_dir | |
| 291 | 302 | ||
| 303 | + self.safe = safe | ||
| 304 | + | ||
| 292 | 305 | self._bare = False | |
| 293 | 306 | try: | |
| 294 | 307 | self._bare = self.config_reader("repository").getboolean("core", "bare") | |
@@ -309,7 +322,7 @@ def __init__( | |||
| 309 | 322 | # END working dir handling | |
| 310 | 323 | ||
| 311 | 324 | self.working_dir: PathLike = self._working_tree_dir or self.common_dir | |
| 312 | - self.git = self.GitCommandWrapperType(self.working_dir) | ||
| 325 | + self.git = self.GitCommandWrapperType(self.working_dir, safe) | ||
| 313 | 326 | ||
| 314 | 327 | # Special handling, in special times. | |
| 315 | 328 | rootpath = osp.join(self.common_dir, "objects") | |
@@ -1305,6 +1318,7 @@ def init( | |||
| 1305 | 1318 | mkdir: bool = True, | |
| 1306 | 1319 | odbt: Type[GitCmdObjectDB] = GitCmdObjectDB, | |
| 1307 | 1320 | expand_vars: bool = True, | |
| 1321 | + safe: bool = False, | ||
| 1308 | 1322 | **kwargs: Any, | |
| 1309 | 1323 | ) -> "Repo": | |
| 1310 | 1324 | """Initialize a git repository at the given path if specified. | |
@@ -1329,6 +1343,8 @@ def init( | |||
| 1329 | 1343 | information disclosure, allowing attackers to access the contents of | |
| 1330 | 1344 | environment variables. | |
| 1331 | 1345 | ||
| 1346 | + TODO :param safe: | ||
| 1347 | + | ||
| 1332 | 1348 | :param kwargs: | |
| 1333 | 1349 | Keyword arguments serving as additional options to the | |
| 1334 | 1350 | :manpage:`git-init(1)` command. | |
@@ -1342,9 +1358,9 @@ def init( | |||
| 1342 | 1358 | os.makedirs(path, 0o755) | |
| 1343 | 1359 | ||
| 1344 | 1360 | # git command automatically chdir into the directory | |
| 1345 | - git = cls.GitCommandWrapperType(path) | ||
| 1361 | + git = cls.GitCommandWrapperType(path, safe) | ||
| 1346 | 1362 | git.init(**kwargs) | |
| 1347 | - return cls(path, odbt=odbt) | ||
| 1363 | + return cls(path, odbt=odbt, safe=safe) | ||
| 1348 | 1364 | ||
| 1349 | 1365 | @classmethod | |
| 1350 | 1366 | def _clone( | |
@@ -1357,6 +1373,7 @@ def _clone( | |||
| 1357 | 1373 | multi_options: Optional[List[str]] = None, | |
| 1358 | 1374 | allow_unsafe_protocols: bool = False, | |
| 1359 | 1375 | allow_unsafe_options: bool = False, | |
| 1376 | + safe: bool = False, | ||
| 1360 | 1377 | **kwargs: Any, | |
| 1361 | 1378 | ) -> "Repo": | |
| 1362 | 1379 | odbt = kwargs.pop("odbt", odb_default_type) | |
@@ -1418,7 +1435,7 @@ def _clone( | |||
| 1418 | 1435 | if not osp.isabs(path): | |
| 1419 | 1436 | path = osp.join(git._working_dir, path) if git._working_dir is not None else path | |
| 1420 | 1437 | ||
| 1421 | - repo = cls(path, odbt=odbt) | ||
| 1438 | + repo = cls(path, odbt=odbt, safe=safe) | ||
| 1422 | 1439 | ||
| 1423 | 1440 | # Retain env values that were passed to _clone(). | |
| 1424 | 1441 | repo.git.update_environment(**git.environment()) | |
@@ -1501,6 +1518,7 @@ def clone_from( | |||
| 1501 | 1518 | multi_options: Optional[List[str]] = None, | |
| 1502 | 1519 | allow_unsafe_protocols: bool = False, | |
| 1503 | 1520 | allow_unsafe_options: bool = False, | |
| 1521 | + safe: bool = False, | ||
| 1504 | 1522 | **kwargs: Any, | |
| 1505 | 1523 | ) -> "Repo": | |
| 1506 | 1524 | """Create a clone from the given URL. | |
@@ -1537,7 +1555,7 @@ def clone_from( | |||
| 1537 | 1555 | :return: | |
| 1538 | 1556 | :class:`Repo` instance pointing to the cloned directory. | |
| 1539 | 1557 | """ | |
| 1540 | - git = cls.GitCommandWrapperType(os.getcwd()) | ||
| 1558 | + git = cls.GitCommandWrapperType(os.getcwd(), safe) | ||
| 1541 | 1559 | if env is not None: | |
| 1542 | 1560 | git.update_environment(**env) | |
| 1543 | 1561 | return cls._clone( | |
@@ -1549,6 +1567,7 @@ def clone_from( | |||
| 1549 | 1567 | multi_options, | |
| 1550 | 1568 | allow_unsafe_protocols=allow_unsafe_protocols, | |
| 1551 | 1569 | allow_unsafe_options=allow_unsafe_options, | |
| 1570 | + safe=safe, | ||
| 1552 | 1571 | **kwargs, | |
| 1553 | 1572 | ) | |
| 1554 | 1573 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments