up
This commit is contained in:
@@ -1,36 +1,30 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import builtins
|
||||
import contextlib
|
||||
import functools
|
||||
import itertools
|
||||
import operator
|
||||
import os
|
||||
import pickle
|
||||
import re
|
||||
import sys
|
||||
import tempfile
|
||||
import operator
|
||||
import functools
|
||||
import itertools
|
||||
import re
|
||||
import contextlib
|
||||
import pickle
|
||||
import textwrap
|
||||
from types import TracebackType
|
||||
from typing import TYPE_CHECKING, Any, ClassVar
|
||||
import builtins
|
||||
|
||||
import pkg_resources
|
||||
from distutils.errors import DistutilsError
|
||||
from pkg_resources import working_set
|
||||
|
||||
from distutils.errors import DistutilsError
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import os as _os
|
||||
elif sys.platform.startswith('java'):
|
||||
import org.python.modules.posix.PosixModule as _os # pyright: ignore[reportMissingImports]
|
||||
if sys.platform.startswith('java'):
|
||||
import org.python.modules.posix.PosixModule as _os
|
||||
else:
|
||||
_os = sys.modules[os.name]
|
||||
try:
|
||||
_file = file
|
||||
except NameError:
|
||||
_file = None
|
||||
_open = open
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing_extensions import Self
|
||||
|
||||
__all__ = [
|
||||
"AbstractSandbox",
|
||||
"DirectorySandbox",
|
||||
@@ -121,21 +115,16 @@ class UnpickleableException(Exception):
|
||||
|
||||
class ExceptionSaver:
|
||||
"""
|
||||
A Context Manager that will save an exception, serialize, and restore it
|
||||
A Context Manager that will save an exception, serialized, and restore it
|
||||
later.
|
||||
"""
|
||||
|
||||
def __enter__(self) -> Self:
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(
|
||||
self,
|
||||
type: type[BaseException] | None,
|
||||
exc: BaseException | None,
|
||||
tb: TracebackType | None,
|
||||
) -> bool:
|
||||
def __exit__(self, type, exc, tb):
|
||||
if not exc:
|
||||
return False
|
||||
return
|
||||
|
||||
# dump the exception
|
||||
self._saved = UnpickleableException.dump(type, exc)
|
||||
@@ -150,7 +139,7 @@ class ExceptionSaver:
|
||||
if '_saved' not in vars(self):
|
||||
return
|
||||
|
||||
_type, exc = map(pickle.loads, self._saved)
|
||||
type, exc = map(pickle.loads, self._saved)
|
||||
raise exc.with_traceback(self._tb)
|
||||
|
||||
|
||||
@@ -248,7 +237,7 @@ def hide_setuptools():
|
||||
"""
|
||||
_distutils_hack = sys.modules.get('_distutils_hack', None)
|
||||
if _distutils_hack is not None:
|
||||
_distutils_hack._remove_shim()
|
||||
_distutils_hack.remove_shim()
|
||||
|
||||
modules = filter(_needs_hiding, sys.modules)
|
||||
_clear_modules(modules)
|
||||
@@ -279,7 +268,7 @@ class AbstractSandbox:
|
||||
|
||||
_active = False
|
||||
|
||||
def __init__(self) -> None:
|
||||
def __init__(self):
|
||||
self._attrs = [
|
||||
name
|
||||
for name in dir(_os)
|
||||
@@ -290,18 +279,17 @@ class AbstractSandbox:
|
||||
for name in self._attrs:
|
||||
setattr(os, name, getattr(source, name))
|
||||
|
||||
def __enter__(self) -> None:
|
||||
def __enter__(self):
|
||||
self._copy(self)
|
||||
if _file:
|
||||
builtins.file = self._file
|
||||
builtins.open = self._open
|
||||
self._active = True
|
||||
|
||||
def __exit__(
|
||||
self,
|
||||
exc_type: type[BaseException] | None,
|
||||
exc_value: BaseException | None,
|
||||
traceback: TracebackType | None,
|
||||
):
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self._active = False
|
||||
if _file:
|
||||
builtins.file = _file
|
||||
builtins.open = _open
|
||||
self._copy(_os)
|
||||
|
||||
@@ -310,7 +298,7 @@ class AbstractSandbox:
|
||||
with self:
|
||||
return func()
|
||||
|
||||
def _mk_dual_path_wrapper(name: str): # type: ignore[misc] # https://github.com/pypa/setuptools/pull/4099
|
||||
def _mk_dual_path_wrapper(name):
|
||||
original = getattr(_os, name)
|
||||
|
||||
def wrap(self, src, dst, *args, **kw):
|
||||
@@ -320,11 +308,11 @@ class AbstractSandbox:
|
||||
|
||||
return wrap
|
||||
|
||||
for __name in ["rename", "link", "symlink"]:
|
||||
if hasattr(_os, __name):
|
||||
locals()[__name] = _mk_dual_path_wrapper(__name)
|
||||
for name in ["rename", "link", "symlink"]:
|
||||
if hasattr(_os, name):
|
||||
locals()[name] = _mk_dual_path_wrapper(name)
|
||||
|
||||
def _mk_single_path_wrapper(name: str, original=None): # type: ignore[misc] # https://github.com/pypa/setuptools/pull/4099
|
||||
def _mk_single_path_wrapper(name, original=None):
|
||||
original = original or getattr(_os, name)
|
||||
|
||||
def wrap(self, path, *args, **kw):
|
||||
@@ -334,8 +322,10 @@ class AbstractSandbox:
|
||||
|
||||
return wrap
|
||||
|
||||
if _file:
|
||||
_file = _mk_single_path_wrapper('file', _file)
|
||||
_open = _mk_single_path_wrapper('open', _open)
|
||||
for __name in [
|
||||
for name in [
|
||||
"stat",
|
||||
"listdir",
|
||||
"chdir",
|
||||
@@ -356,10 +346,10 @@ class AbstractSandbox:
|
||||
"pathconf",
|
||||
"access",
|
||||
]:
|
||||
if hasattr(_os, __name):
|
||||
locals()[__name] = _mk_single_path_wrapper(__name)
|
||||
if hasattr(_os, name):
|
||||
locals()[name] = _mk_single_path_wrapper(name)
|
||||
|
||||
def _mk_single_with_return(name: str): # type: ignore[misc] # https://github.com/pypa/setuptools/pull/4099
|
||||
def _mk_single_with_return(name):
|
||||
original = getattr(_os, name)
|
||||
|
||||
def wrap(self, path, *args, **kw):
|
||||
@@ -370,11 +360,11 @@ class AbstractSandbox:
|
||||
|
||||
return wrap
|
||||
|
||||
for __name in ['readlink', 'tempnam']:
|
||||
if hasattr(_os, __name):
|
||||
locals()[__name] = _mk_single_with_return(__name)
|
||||
for name in ['readlink', 'tempnam']:
|
||||
if hasattr(_os, name):
|
||||
locals()[name] = _mk_single_with_return(name)
|
||||
|
||||
def _mk_query(name: str): # type: ignore[misc] # https://github.com/pypa/setuptools/pull/4099
|
||||
def _mk_query(name):
|
||||
original = getattr(_os, name)
|
||||
|
||||
def wrap(self, *args, **kw):
|
||||
@@ -385,9 +375,9 @@ class AbstractSandbox:
|
||||
|
||||
return wrap
|
||||
|
||||
for __name in ['getcwd', 'tmpnam']:
|
||||
if hasattr(_os, __name):
|
||||
locals()[__name] = _mk_query(__name)
|
||||
for name in ['getcwd', 'tmpnam']:
|
||||
if hasattr(_os, name):
|
||||
locals()[name] = _mk_query(name)
|
||||
|
||||
def _validate_path(self, path):
|
||||
"""Called to remap or validate any path, whether input or output"""
|
||||
@@ -408,11 +398,6 @@ class AbstractSandbox:
|
||||
self._remap_input(operation + '-to', dst, *args, **kw),
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# This is a catch-all for all the dynamically created attributes.
|
||||
# This isn't public API anyway
|
||||
def __getattribute__(self, name: str) -> Any: ...
|
||||
|
||||
|
||||
if hasattr(os, 'devnull'):
|
||||
_EXCEPTIONS = [os.devnull]
|
||||
@@ -423,26 +408,28 @@ else:
|
||||
class DirectorySandbox(AbstractSandbox):
|
||||
"""Restrict operations to a single subdirectory - pseudo-chroot"""
|
||||
|
||||
write_ops: ClassVar[dict[str, None]] = dict.fromkeys([
|
||||
"open",
|
||||
"chmod",
|
||||
"chown",
|
||||
"mkdir",
|
||||
"remove",
|
||||
"unlink",
|
||||
"rmdir",
|
||||
"utime",
|
||||
"lchown",
|
||||
"chroot",
|
||||
"mkfifo",
|
||||
"mknod",
|
||||
"tempnam",
|
||||
])
|
||||
write_ops = dict.fromkeys(
|
||||
[
|
||||
"open",
|
||||
"chmod",
|
||||
"chown",
|
||||
"mkdir",
|
||||
"remove",
|
||||
"unlink",
|
||||
"rmdir",
|
||||
"utime",
|
||||
"lchown",
|
||||
"chroot",
|
||||
"mkfifo",
|
||||
"mknod",
|
||||
"tempnam",
|
||||
]
|
||||
)
|
||||
|
||||
_exception_patterns: list[str | re.Pattern] = []
|
||||
_exception_patterns = []
|
||||
"exempt writing to paths that match the pattern"
|
||||
|
||||
def __init__(self, sandbox, exceptions=_EXCEPTIONS) -> None:
|
||||
def __init__(self, sandbox, exceptions=_EXCEPTIONS):
|
||||
self._sandbox = os.path.normcase(os.path.realpath(sandbox))
|
||||
self._prefix = os.path.join(self._sandbox, '')
|
||||
self._exceptions = [
|
||||
@@ -455,12 +442,19 @@ class DirectorySandbox(AbstractSandbox):
|
||||
|
||||
raise SandboxViolation(operation, args, kw)
|
||||
|
||||
if _file:
|
||||
|
||||
def _file(self, path, mode='r', *args, **kw):
|
||||
if mode not in ('r', 'rt', 'rb', 'rU', 'U') and not self._ok(path):
|
||||
self._violation("file", path, mode, *args, **kw)
|
||||
return _file(path, mode, *args, **kw)
|
||||
|
||||
def _open(self, path, mode='r', *args, **kw):
|
||||
if mode not in ('r', 'rt', 'rb', 'rU', 'U') and not self._ok(path):
|
||||
self._violation("open", path, mode, *args, **kw)
|
||||
return _open(path, mode, *args, **kw)
|
||||
|
||||
def tmpnam(self) -> None:
|
||||
def tmpnam(self):
|
||||
self._violation("tmpnam")
|
||||
|
||||
def _ok(self, path):
|
||||
@@ -498,7 +492,7 @@ class DirectorySandbox(AbstractSandbox):
|
||||
self._violation(operation, src, dst, *args, **kw)
|
||||
return (src, dst)
|
||||
|
||||
def open(self, file, flags, mode: int = 0o777, *args, **kw) -> int:
|
||||
def open(self, file, flags, mode=0o777, *args, **kw):
|
||||
"""Called for low-level os.open()"""
|
||||
if flags & WRITE_FLAGS and not self._ok(file):
|
||||
self._violation("os.open", file, flags, mode, *args, **kw)
|
||||
@@ -531,6 +525,6 @@ class SandboxViolation(DistutilsError):
|
||||
"""
|
||||
).lstrip()
|
||||
|
||||
def __str__(self) -> str:
|
||||
def __str__(self):
|
||||
cmd, args, kwargs = self.args
|
||||
return self.tmpl.format(**locals())
|
||||
|
||||
Reference in New Issue
Block a user