fix: bootstrap the compute host only as python -m; pin library imports side-effect free
tui_gateway.compute_host is also imported by tests, so the module-level hermes_bootstrap import exported TMPDIR/TMP/TEMP/HERMES_SCRATCH_DIR into the importer, the same defect as the hermes-tools MCP server. The new test imports agent.auxiliary_client, gateway.relay and tui_gateway.compute_host in a clean interpreter and asserts no bootstrap and no env change (red at b278fb79c61c).
This commit is contained in:
@@ -196,6 +196,26 @@ class TestEntryPointsImportBootstrap:
|
||||
"cli.py", # legacy direct-launch CLI
|
||||
]
|
||||
|
||||
def test_library_imports_of_dual_use_entry_modules_stay_side_effect_free(self, tmp_path):
|
||||
# The codex hermes-tools MCP server and the compute host are ``python -m`` entry points
|
||||
# that agent/gateway code and tests also import; there the bootstrap exported TMPDIR and
|
||||
# HERMES_SCRATCH_DIR into every importer (gateway.relay's read-only routing included).
|
||||
code = textwrap.dedent("""
|
||||
import json, os, sys
|
||||
before = dict(os.environ)
|
||||
import agent.auxiliary_client, gateway.relay, tui_gateway.compute_host # noqa: F401
|
||||
changed = sorted(k for k in before.keys() | os.environ.keys() if before.get(k) != os.environ.get(k))
|
||||
print(json.dumps({"bootstrapped": "hermes_bootstrap" in sys.modules, "changed": changed}))
|
||||
""")
|
||||
repo = Path(__file__).resolve().parents[1]
|
||||
env = {k: os.environ[k] for k in ("PATH", "SYSTEMROOT", "WINDIR") if k in os.environ}
|
||||
env.update({"HOME": str(tmp_path), "USERPROFILE": str(tmp_path), "PYTHONPATH": str(repo),
|
||||
"HERMES_HOME": str(tmp_path / "home"), "PYTHONDONTWRITEBYTECODE": "1"})
|
||||
child = subprocess.run([sys.executable, "-c", code], cwd=str(tmp_path), env=env,
|
||||
capture_output=True, text=True, timeout=120)
|
||||
assert child.returncode == 0, child.stderr
|
||||
assert child.stdout.splitlines()[-1] == '{"bootstrapped": false, "changed": []}'
|
||||
|
||||
@pytest.mark.parametrize("path", ENTRY_POINTS)
|
||||
def test_entry_point_imports_bootstrap(self, path):
|
||||
"""The file must contain 'import hermes_bootstrap' and that
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
from __future__ import annotations
|
||||
|
||||
# First, like every entry point: stdio, import-path and environ-lifetime fixes (hermes_bootstrap).
|
||||
import hermes_bootstrap # noqa: F401
|
||||
# Only as ``python -m``: tests import this module, and the bootstrap's TMPDIR/scratch exports
|
||||
# must not fire in a library importer.
|
||||
if __name__ == "__main__":
|
||||
import hermes_bootstrap # noqa: F401
|
||||
|
||||
import argparse
|
||||
import concurrent.futures
|
||||
|
||||
Reference in New Issue
Block a user