chore: merge main

This commit is contained in:
Abdessamad Derraz committed 2026-10-27 23:30:30 +01:00
commit 3ce6911a7a
2 files changed
+71 -12

No files matched your search

+38 -12
View File
@@ -766,27 +766,53 @@ def _bwrap_base(bwrap: str, network: bool) -> list[str]:
return argv
def _python_prefix(path: Path) -> bool:
"""A Python installation or a venv, and nothing wider: it holds
lib/pythonX.Y or a pyvenv.cfg, and it is neither / nor the home folder
nor a folder above it."""
home = Path.home().resolve()
resolved = path.resolve()
if resolved == Path("/") or resolved == home or resolved in home.parents:
return False
version = f"python{sys.version_info.major}.{sys.version_info.minor}"
return (path / "pyvenv.cfg").is_file() or (path / "lib" / version).is_dir()
def interpreter_paths() -> list[Path]:
"""The trees the worker's Python lives in, when the sandbox's system
binds do not hold them: CI's setup-python under /opt/hostedtoolcache, a
venv, pyenv or uv. Each link on the way to the interpreter is a path too:
a venv's python points at uv's unversioned name, itself a link to the
versioned tree. Without them the worker could not start in the sandbox,
and every run crashed."""
"""What the worker's Python needs inside the sandbox when the system
binds do not hold it: CI's setup-python under /opt/hostedtoolcache, a
venv, pyenv or uv. Without it the worker could not start, and every run
crashed.
Only Python installation prefixes are bound whole (sys.prefix,
sys.base_prefix and the prefix of each link's target, each proven by
lib/pythonX.Y or pyvenv.cfg). Every link on the way to the interpreter
is bound as itself, a single file, so ~/.local/bin/python3 never exposes
~/.local."""
system = ("/usr/", "/bin/", "/lib")
found: list[Path] = []
candidates = [Path(sys.prefix), Path(sys.base_prefix)]
def add(path: Path) -> None:
path = Path(os.path.abspath(path))
# Inside a tree already bound, a path is there already: bwrap cannot
# mount over a link in a read-only tree, and the run would not start.
if any(path == bound or bound in path.parents for bound in found):
return
if not str(path).startswith(system) and path.exists():
found.append(path)
for prefix in (Path(sys.prefix), Path(sys.base_prefix)):
if _python_prefix(prefix):
add(prefix)
hop = Path(sys.executable)
for _ in range(16):
candidates.append(hop.parent.parent)
if _python_prefix(hop.parent.parent):
add(hop.parent.parent)
if not hop.is_symlink():
break
add(hop)
target = Path(os.readlink(hop))
hop = target if target.is_absolute() else hop.parent / target
for path in candidates:
path = Path(os.path.abspath(path))
if not str(path).startswith(system) and path not in found and path.exists():
found.append(path)
return found
+33
View File
@@ -672,10 +672,13 @@ class TheInterpreterIsInTheSandbox(unittest.TestCase):
real = root / "uv" / "cpython-3.13.12" / "bin"
real.mkdir(parents=True)
(real / "python3.13").write_text("")
version = f"python{sys.version_info.major}.{sys.version_info.minor}"
(root / "uv" / "cpython-3.13.12" / "lib" / version).mkdir(parents=True)
alias = root / "uv" / "cpython-3.13"
alias.symlink_to(root / "uv" / "cpython-3.13.12")
venv = root / "venv" / "bin"
venv.mkdir(parents=True)
(root / "venv" / "pyvenv.cfg").write_text("home = x\n")
(venv / "python").symlink_to(alias / "bin" / "python3.13")
with mock.patch.object(core_probe.sys, "executable", str(venv / "python")), \
mock.patch.object(core_probe.sys, "prefix", str(root / "venv")), \
@@ -684,6 +687,36 @@ class TheInterpreterIsInTheSandbox(unittest.TestCase):
self.assertIn(root / "venv", paths)
self.assertIn(alias, paths)
self.assertIn(root / "uv" / "cpython-3.13.12", paths)
# The venv's own link sits in the venv, bound already.
self.assertNotIn(venv / "python", paths)
def test_a_link_in_a_shared_folder_binds_only_itself(self):
"""~/.local/bin/python3 must not expose ~/.local: only the link file
and the proven Python prefix behind it are bound."""
from unittest import mock # noqa: PLC0415
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp)
prefix = root / "share" / "cpython"
(prefix / "bin").mkdir(parents=True)
(prefix / "bin" / "python3").write_text("")
version = f"python{sys.version_info.major}.{sys.version_info.minor}"
(prefix / "lib" / version).mkdir(parents=True)
local = root / "dotlocal"
(local / "bin").mkdir(parents=True)
(local / "secrets.txt").write_text("x")
(local / "bin" / "python3").symlink_to(prefix / "bin" / "python3")
with mock.patch.object(core_probe.sys, "executable", str(local / "bin" / "python3")), \
mock.patch.object(core_probe.sys, "prefix", str(prefix)), \
mock.patch.object(core_probe.sys, "base_prefix", str(prefix)):
paths = core_probe.interpreter_paths()
self.assertNotIn(local, paths)
self.assertIn(local / "bin" / "python3", paths)
self.assertIn(prefix, paths)
def test_home_and_root_are_never_a_prefix(self):
self.assertFalse(core_probe._python_prefix(Path("/")))
self.assertFalse(core_probe._python_prefix(Path.home()))
def test_a_link_is_mounted_at_its_own_path(self):
with tempfile.TemporaryDirectory() as tmp: