fix(tests): isolate the platform-default Hermes root
The shared fixture isolates HERMES_HOME, but profile-root resolution also
resolves the native default. This trips the real-home guard even for tests
that use a temporary custom home. Base 75a646e5b3 has the same failures.
Isolate the native default in the shared fixture. Capture its parent before
test fixtures run so explicit home overrides keep their own layout. Leave
HOME, Path.home(), production resolver behavior, and the I/O guard intact.
On the original base, this fixture fixes all 24 PM authority failures and
92 update failures/setup errors. The same four unrelated /proc DB-holder
probe failures remain on both base and current code. Current targeted
profile, path, PM, and guard checks pass: 214 passed, 4 skipped.
This commit is contained in:
@@ -5,11 +5,10 @@ Hermetic-test invariants enforced here (see AGENTS.md for rationale):
|
||||
1. **No credential env vars.** All provider/credential-shaped env vars
|
||||
(ending in _API_KEY, _TOKEN, _SECRET, _PASSWORD, _CREDENTIALS, etc.)
|
||||
are unset before every test. Local developer keys cannot leak in.
|
||||
2. **Isolated HERMES_HOME.** HERMES_HOME points to a per-test tempdir so
|
||||
code reading ``~/.hermes/*`` via ``get_hermes_home()`` can't see the
|
||||
real one. (We do NOT also redirect HOME — that broke subprocesses in
|
||||
CI. Code using ``Path.home() / ".hermes"`` instead of the canonical
|
||||
``get_hermes_home()`` is a bug to fix at the callsite.)
|
||||
2. **Isolated Hermes homes.** HERMES_HOME and the platform-default root
|
||||
resolve inside a per-test tempdir. Profile/root resolution can inspect
|
||||
both without probing production state. HOME and Path.home() stay intact
|
||||
for subprocesses and non-Hermes paths. Explicit test overrides still win.
|
||||
3. **Deterministic runtime.** TZ=UTC, LANG=C.UTF-8, PYTHONHASHSEED=0.
|
||||
4. **No HERMES_SESSION_* inheritance** — the agent's current gateway
|
||||
session must not leak into tests.
|
||||
@@ -60,6 +59,11 @@ if str(PROJECT_ROOT) not in sys.path:
|
||||
_PRE_SANDBOX_KANBAN_OVERRIDE = os.environ.get("HERMES_KANBAN_HOME", "").strip()
|
||||
_PRE_SANDBOX_HERMES_HOME = os.environ.get("HERMES_HOME", "")
|
||||
|
||||
# Capture before any test fixture can override Path.home()/LOCALAPPDATA.
|
||||
from hermes_constants import _get_platform_default_hermes_home
|
||||
|
||||
_NATIVE_HERMES_PARENT = _get_platform_default_hermes_home().parent
|
||||
|
||||
|
||||
def _hermes_home_points_at_production(value: str) -> bool:
|
||||
"""True when a pre-set HERMES_HOME resolves to the real production root.
|
||||
@@ -489,16 +493,24 @@ def _hermetic_environment(tmp_path, monkeypatch):
|
||||
# custom host resolution override/delete this explicitly.
|
||||
monkeypatch.setenv("HERMES_HONCHO_HOST", "hermes")
|
||||
|
||||
# 3. Redirect HERMES_HOME to a per-test tempdir. Code that reads
|
||||
# ``~/.hermes/*`` via ``get_hermes_home()`` now gets the tempdir.
|
||||
#
|
||||
# NOTE: We do NOT also redirect HOME. Doing so broke CI because
|
||||
# some tests (and their transitive deps) spawn subprocesses that
|
||||
# inherit HOME and expect it to be stable. If a test genuinely
|
||||
# needs HOME isolated, it should set it explicitly in its own
|
||||
# fixture. Any code in the codebase reading ``~/.hermes/*`` via
|
||||
# ``Path.home() / ".hermes"`` instead of ``get_hermes_home()``
|
||||
# is a bug to fix at the callsite.
|
||||
# 3. Isolate both inputs to profile/root resolution. HERMES_HOME alone
|
||||
# is insufficient: get_default_hermes_root() resolves the native root
|
||||
# too, to distinguish standard profiles from custom deployments.
|
||||
# Patch only the Hermes default, not HOME/Path.home(). Subprocesses need
|
||||
# a stable HOME. Hardcoded real-home I/O must still trip the guard.
|
||||
import hermes_constants
|
||||
|
||||
platform_default = hermes_constants._get_platform_default_hermes_home
|
||||
|
||||
def isolated_platform_default() -> Path:
|
||||
root = platform_default()
|
||||
# Explicit Path.home()/LOCALAPPDATA overrides in individual tests
|
||||
# still select their own layout. Suffix changes retain their name.
|
||||
return tmp_path / root.name if root.parent == _NATIVE_HERMES_PARENT else root
|
||||
|
||||
monkeypatch.setattr(
|
||||
hermes_constants, "_get_platform_default_hermes_home", isolated_platform_default
|
||||
)
|
||||
fake_hermes_home = tmp_path / "hermes_test"
|
||||
fake_hermes_home.mkdir()
|
||||
(fake_hermes_home / "sessions").mkdir()
|
||||
|
||||
Reference in New Issue
Block a user