fix(terminal): strip VIRTUAL_ENV/CONDA_PREFIX from terminal subprocess env

The Hermes gateway runs inside its own venv, so its process environment
carries VIRTUAL_ENV (and possibly CONDA_PREFIX). The terminal tool spawned
subprocesses inheriting those markers. When the agent ran `uv sync`,
`uv pip install`, `poetry install`, etc. in ANY other project directory,
those tools honored the inherited VIRTUAL_ENV and rebuilt/synced that
project's dependencies into the Hermes venv path — wiping Hermes' own runtime
deps (and, when the other project pinned a different Python, replacing the
interpreter), bricking the gateway on the next restart (#23473).

Strip VIRTUAL_ENV/CONDA_PREFIX in both subprocess-env construction points in
tools/environments/local.py — `_sanitize_subprocess_env` and `_make_run_env`
— via a shared `_ACTIVE_VENV_MARKER_VARS` constant. The Hermes venv stays
reachable because its bin dir is already first on PATH, so removing the
active-environment markers is safe and only prevents the cross-project clobber.

Adds TestActiveVenvMarkerStripping: end-to-end (markers in os.environ don't
reach the spawned subprocess) and unit coverage for both functions, plus a
guard on the marker constant.

Also adds the AUTHOR_MAP entry for the salvaged contributor.

Closes #23473
This commit is contained in:
Dale Nguyen 2026-06-28 00:54:22 +05:30 committed by kshitij
parent d470ed0c4c
commit dbbf102b8e
3 changed files with 67 additions and 0 deletions

View file

@ -192,6 +192,18 @@ def _build_provider_env_blocklist() -> frozenset:
_HERMES_PROVIDER_ENV_BLOCKLIST = _build_provider_env_blocklist()
# Active-virtualenv markers that must NOT leak into terminal subprocesses.
# The gateway runs inside its own venv, so its process environment carries
# VIRTUAL_ENV (and possibly CONDA_PREFIX). If those leak into commands the
# agent runs against OTHER Python projects, tools like ``uv``/``poetry`` treat
# the inherited value as the active environment and build/sync that other
# project's dependencies into the Hermes venv path instead of the project's own
# ``.venv`` — silently clobbering the Hermes environment (e.g. a project pinned
# to a different Python version overwrites it and breaks the gateway). The
# Hermes venv stays reachable via PATH (its bin dir is first), so stripping
# these markers is safe and only prevents the cross-project clobber (#23473).
_ACTIVE_VENV_MARKER_VARS = ("VIRTUAL_ENV", "CONDA_PREFIX")
def _inject_context_hermes_home(env: dict) -> None:
"""Bridge the context-local Hermes home override into subprocess env."""
@ -232,6 +244,9 @@ def _sanitize_subprocess_env(base_env: dict | None, extra_env: dict | None = Non
from hermes_constants import apply_subprocess_home_env
apply_subprocess_home_env(sanitized)
for _marker in _ACTIVE_VENV_MARKER_VARS:
sanitized.pop(_marker, None)
return sanitized
@ -528,6 +543,9 @@ def _make_run_env(env: dict) -> dict:
except Exception:
pass
for _marker in _ACTIVE_VENV_MARKER_VARS:
run_env.pop(_marker, None)
return run_env