fix(tests): forward Windows location vars through the hermetic runner; patch Path.home() in hindsight _clean_env
Combines the Windows-hermeticity cluster (#67512 by @webtecnica, earliest; #71112 by @Sanjays2402; #67196 by @anatolijlaptev1991-ctrl) into one fix: - scripts/run_tests.sh: env -i forwarded only HOME, but native Windows CPython resolves Path.home() from USERPROFILE (or HOMEDRIVE+HOMEPATH), stdlib paths from LOCALAPPDATA/APPDATA, ssl/sockets need SYSTEMROOT, tempfile needs TEMP/TMP — the strip broke collection tree-wide on native Windows (issues #67385, #70813). Location vars (never credentials) are now forwarded, each only when actually set, so POSIX runs are byte-for-byte unchanged (probe-verified both ways). PYTHONUTF8=1 added for legacy-codepage consoles printing the runner's glyphs. - tests/plugins/memory/test_hindsight_provider.py: _clean_env patched HOME only; on Windows Path.home() ignores HOME. Now patches Path.home directly into tmp_path (from #67196). Not ported: #71112's guard test — it regex-reads run_tests.sh source, which the test policy bans (never read source code in tests). Fixes #67385. Fixes #70813.
This commit is contained in:
1
contributors/emails/anatolij.laptev.1991@gmail.com
Normal file
1
contributors/emails/anatolij.laptev.1991@gmail.com
Normal file
@@ -0,0 +1 @@
|
||||
anatolijlaptev1991-ctrl
|
||||
@@ -94,6 +94,21 @@ if [ -f "$HOME/.hermes/pytest_live_guard.py" ]; then
|
||||
fi
|
||||
|
||||
|
||||
# ── Windows location variables (computed before we drop env) ───────────────
|
||||
# `env -i` forwards HOME, which is enough on POSIX. Native Windows CPython
|
||||
# resolves Path.home() from USERPROFILE (or HOMEDRIVE+HOMEPATH), stdlib
|
||||
# platform paths come from LOCALAPPDATA/APPDATA, ssl/sockets need SYSTEMROOT,
|
||||
# and tempfile needs TEMP/TMP. Dropping them breaks collection on native
|
||||
# Windows (issues #67385, #70813). These are location variables, not
|
||||
# credentials, so forwarding them keeps the isolation intent intact. Each is
|
||||
# only forwarded when actually set, so POSIX runs are byte-for-byte unchanged.
|
||||
WIN_ENV=()
|
||||
for _win_var in USERPROFILE HOMEDRIVE HOMEPATH LOCALAPPDATA APPDATA SYSTEMROOT TEMP TMP; do
|
||||
if [ -n "${!_win_var:-}" ]; then
|
||||
WIN_ENV+=("$_win_var=${!_win_var}")
|
||||
fi
|
||||
done
|
||||
|
||||
# ── Run in hermetic env ──────────────────────────────────────────────────────
|
||||
# env -i: start with empty environment, opt-in only what we need.
|
||||
# No credential var can leak — you'd have to explicitly add it here.
|
||||
@@ -114,10 +129,12 @@ echo "▶ launching test runner"
|
||||
exec env -i \
|
||||
PATH="$PATH" \
|
||||
HOME="$HOME" \
|
||||
${WIN_ENV[@]+"${WIN_ENV[@]}"} \
|
||||
TZ=UTC \
|
||||
LANG=C.UTF-8 \
|
||||
LC_ALL=C.UTF-8 \
|
||||
PYTHONHASHSEED=0 \
|
||||
PYTHONUTF8=1 \
|
||||
${HERMES_RUN_SLOW_PET_TESTS:+HERMES_RUN_SLOW_PET_TESTS="$HERMES_RUN_SLOW_PET_TESTS"} \
|
||||
${HERMES_E2E_BROWSER:+HERMES_E2E_BROWSER="$HERMES_E2E_BROWSER"} \
|
||||
${EXTRA_PYTHONPATH:+PYTHONPATH="$EXTRA_PYTHONPATH"} \
|
||||
|
||||
@@ -10,6 +10,7 @@ import os
|
||||
import re
|
||||
import stat
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
|
||||
@@ -37,8 +38,8 @@ from plugins.memory.hindsight import (
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _clean_env(monkeypatch):
|
||||
"""Ensure no stale env vars leak between tests."""
|
||||
def _clean_env(tmp_path, monkeypatch):
|
||||
"""Ensure no stale env vars or Windows home state leak between tests."""
|
||||
for key in (
|
||||
"HINDSIGHT_API_KEY", "HINDSIGHT_API_URL", "HINDSIGHT_BANK_ID",
|
||||
"HINDSIGHT_BUDGET", "HINDSIGHT_MODE", "HINDSIGHT_TIMEOUT",
|
||||
@@ -49,6 +50,12 @@ def _clean_env(monkeypatch):
|
||||
):
|
||||
monkeypatch.delenv(key, raising=False)
|
||||
|
||||
# On Windows pathlib.Path.home() resolves USERPROFILE/HOMEDRIVE+HOMEPATH,
|
||||
# not the POSIX HOME alias that these tests historically monkeypatched.
|
||||
# Patch the actual API and keep all legacy profile writes in tmp_path.
|
||||
isolated_home = tmp_path / "user-home"
|
||||
monkeypatch.setattr(Path, "home", classmethod(lambda cls: isolated_home))
|
||||
|
||||
|
||||
def _make_mock_client():
|
||||
"""Create a mock Hindsight client with async methods."""
|
||||
|
||||
Reference in New Issue
Block a user