diff --git a/tests/conftest.py b/tests/conftest.py index 4fc15fd1e00a..40feed643768 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -158,6 +158,32 @@ def _looks_like_credential(name: str) -> bool: return any(name.endswith(suf) for suf in _CREDENTIAL_SUFFIXES) +# Kanban env pins are legitimate production/operator controls: the CLI uses +# them for board selection, the dispatcher injects them into worker processes, +# and the gateway honours the dispatcher toggle. They still must be scrubbed +# from pytest's ambient process env because tests that need Kanban context set +# it explicitly and default-board tests rely on no ambient board/path pin. +# +# Scope this set to HERMES_KANBAN_* variables. The dispatcher also injects +# HERMES_PROFILE for worker author attribution, but that is a broader profile +# selector rather than a Kanban-specific pin and is intentionally out of this +# narrow regression fix. +_HERMES_KANBAN_BEHAVIORAL_VARS = frozenset({ + # Board and path resolution pins. + "HERMES_KANBAN_BOARD", + "HERMES_KANBAN_DB", + "HERMES_KANBAN_HOME", + "HERMES_KANBAN_WORKSPACES_ROOT", + # Dispatcher-spawned worker runtime pins. + "HERMES_KANBAN_TASK", + "HERMES_KANBAN_WORKSPACE", + "HERMES_KANBAN_RUN_ID", + "HERMES_KANBAN_CLAIM_LOCK", + # Gateway dispatcher escape hatch. + "HERMES_KANBAN_DISPATCH_IN_GATEWAY", +}) + + # HERMES_* vars that change test behavior by being set. Unset all of these # unconditionally — individual tests that need them set do so explicitly. _HERMES_BEHAVIORAL_VARS = frozenset({ @@ -188,6 +214,7 @@ def _looks_like_credential(name: str) -> bool: "HERMES_BACKGROUND_NOTIFICATIONS", "HERMES_EXEC_ASK", "HERMES_HOME_MODE", + *_HERMES_KANBAN_BEHAVIORAL_VARS, "TERMINAL_CWD", "TERMINAL_ENV", "TERMINAL_VERCEL_RUNTIME", diff --git a/tests/test_hermetic_environment.py b/tests/test_hermetic_environment.py new file mode 100644 index 000000000000..54434bdec2e2 --- /dev/null +++ b/tests/test_hermetic_environment.py @@ -0,0 +1,33 @@ +"""Regression coverage for process-level pytest environment isolation.""" + +from __future__ import annotations + +import os + +import tests.conftest as hermes_conftest + + +def test_kanban_env_pins_do_not_leak_from_pytest_process_env(): + """Ambient Kanban pins must not be visible inside test bodies. + + Hermes sessions and dispatcher workers legitimately export these variables, + so local developer shells can carry them into `pytest`. The global hermetic + fixture owns clearing them; individual Kanban tests opt back in with + `monkeypatch.setenv(...)` when a variable is part of the behavior under test. + """ + + leaked = { + name: os.environ[name] + for name in sorted(hermes_conftest._HERMES_KANBAN_BEHAVIORAL_VARS) + if name in os.environ + } + + assert leaked == {} + + +def test_tests_can_still_set_kanban_env_pins_explicitly(monkeypatch): + """The hermetic fixture clears ambient state, not test-local setup.""" + + monkeypatch.setenv("HERMES_KANBAN_BOARD", "explicit-test-board") + + assert os.environ["HERMES_KANBAN_BOARD"] == "explicit-test-board"