fix(tools): tighten Hermes PYTHONPATH ownership semantics

Adversarial review of the previous two commits (and #78917 itself)
found three ownership-boundary issues; this commit addresses them:

1. Repo direct-child over-strip (Finding A)
   No launcher injects <repo>/tools or another direct child as an
   independent PYTHONPATH entry - audited all four producers (Electron
   electron-main.mjs, gateway/run.py::_ensure_windows_gateway_venv_imports,
   cron/scheduler.py::_windows_cron_python_invocation,
   tui_gateway/host_supervisor.py).  The depth<=1 rule deleted user paths
   that merely live under the repo directory; only the EXACT repo root is
   now stripped.

2. Windows junction/symlink alias (Finding B)
   The gateway launcher renders Hermes-owned paths under the configured
   HERMES_HOME spelling (gateway_windows.py::_preserve_hermes_home_path),
   which may be a junction to another drive, so it differs lexically from
   the resolved repo root.  _hermes_repo_root_aliases now carries both the
   resolved and unresolved spellings; both are recognized as Hermes-owned.

3. Stale abstraction rename (Phase 4)
   _strip_mismatched_site_packages -> _strip_hermes_owned_pythonpath:
   the cross-version heuristic is gone, so the old name misdescribes the
   behavior (ownership-based, not version-based).

Tests: direct-child now preserved; junction alias stripped (lexical pair
monkeypatched); Windows-only real-semantics test added (POSIX test remains
a safety test); mixed-ordering, duplicate-Hermes, and no-scrub PYTHONHOME
contract tests added.  Full file: 52 passed / 16 failed (identical failure
set to base, all isolation-venv environment issues).
This commit is contained in:
Xinyu Du
2026-08-09 22:14:07 +08:00
committed by Teknium
parent 850686a515
commit 73b49f473a
3 changed files with 232 additions and 66 deletions

View File

@@ -1483,16 +1483,15 @@ def execute_code(
# external venv; exposing Hermes's site-packages to that interpreter
# can mix incompatible compiled extensions (for example, Python 3.12
# NumPy with a Python 3.9 project interpreter).
# Before re-injecting PYTHONPATH, strip any mismatched site-packages
# entries that leaked through _scrub_child_env (PYTHONPATH is in
# _SAFE_ENV_PREFIXES so it passes the scrub). Cross-version entries
# (e.g. python3.11 site-packages injected by systemd/Electron) would
# poison the sandbox's sys.path with ABI-incompatible C extensions
# (#74817); Hermes venv/repo-root entries are redundant because the
# correct ones are re-added below, gated on the child interpreter
# actually being the Hermes environment.
from tools.environments.local import _strip_mismatched_site_packages
_strip_mismatched_site_packages(child_env)
#
# Before re-injecting PYTHONPATH, strip Hermes-owned entries that
# leaked through _scrub_child_env (PYTHONPATH is in _SAFE_ENV_PREFIXES
# so it passes the scrub). The sandbox runs the SAME Python as
# Hermes, so the Hermes venv entries are redundant — and if they
# came from a different Hermes venv they would poison the sandbox's
# sys.path with ABI-incompatible C extensions (#74817).
from tools.environments.local import _strip_hermes_owned_pythonpath
_strip_hermes_owned_pythonpath(child_env)
_hermes_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
_existing_pp = child_env.get("PYTHONPATH", "")
_pp_parts = [tmpdir]