From b576bd1ef1873f86402258451b96a744e038ac30 Mon Sep 17 00:00:00 2001 From: Amanbig Date: Sat, 31 Oct 2026 16:02:01 +0530 Subject: [PATCH] test: isolate the test suite from the real ~/.devorch tests/test_integration.py calls Permissions().set_tool_permission(...), which saves to the real ~/.devorch/permissions.yaml, so every pytest run replaced the developer's saved permissions with 'edit: allow' and 'filesystem: allow'. Point HOME and USERPROFILE at a throwaway directory before the application modules are imported, use the null keyring backend, and clear API key variables. Add tests that fail if the suite ever resolves to the real home. --- tests/conftest.py | 43 +++++++++++++++++++++++++++++++++++++++++ tests/test_isolation.py | 41 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 tests/conftest.py create mode 100644 tests/test_isolation.py diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..5f7da2b --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,43 @@ +"""Keep the test suite away from the developer's real DevOrch data. + +Several modules compute ``Path.home() / ".devorch"`` at import time, and some tests (for example +``Permissions().set_tool_permission(...)``) save through those paths. Without isolation, running +``pytest`` overwrote the developer's real ``~/.devorch/permissions.yaml`` (replacing their saved rules +with ``edit: allow`` / ``filesystem: allow``) and wrote to their real sessions folder. + +This must run before the application modules are imported, hence environment variables set at import +time of this conftest rather than a fixture. +""" + +import os +import shutil +import tempfile + +_TEST_HOME = tempfile.mkdtemp(prefix="devorch-test-home-") + +# Path.home() reads HOME on POSIX and USERPROFILE on Windows +os.environ["HOME"] = _TEST_HOME +os.environ["USERPROFILE"] = _TEST_HOME +os.environ.pop("HOMEDRIVE", None) +os.environ.pop("HOMEPATH", None) +# never read from or write to the developer's real keychain +os.environ["PYTHON_KEYRING_BACKEND"] = "keyring.backends.null.Keyring" +# and no real API keys leak into tests +for _var in ( + "OPENAI_API_KEY", + "ANTHROPIC_API_KEY", + "GOOGLE_API_KEY", + "GROQ_API_KEY", + "MISTRAL_API_KEY", + "OPENROUTER_API_KEY", + "TOGETHER_API_KEY", + "GITHUB_TOKEN", + "DEEPSEEK_API_KEY", + "MOONSHOT_API_KEY", + "CUSTOM_API_KEY", +): + os.environ.pop(_var, None) + + +def pytest_sessionfinish(session, exitstatus): + shutil.rmtree(_TEST_HOME, ignore_errors=True) diff --git a/tests/test_isolation.py b/tests/test_isolation.py new file mode 100644 index 0000000..48b65f7 --- /dev/null +++ b/tests/test_isolation.py @@ -0,0 +1,41 @@ +"""The suite must never read or write the developer's real ~/.devorch.""" + +import os +from pathlib import Path + +from config import permissions as perm_mod +from config import settings as settings_mod +from core import sessions as sessions_mod +from core.memory import MEMORY_DIR + + +def test_home_is_a_throwaway_directory(): + home = Path.home() + assert "devorch-test-home-" in home.name + assert home == Path(os.environ["HOME"]) + + +def test_application_paths_resolve_under_the_test_home(): + home = Path.home() + for path in ( + perm_mod.PERMISSIONS_FILE, + settings_mod.CONFIG_FILE, + sessions_mod.DB_PATH, + MEMORY_DIR, + ): + assert home in path.parents, f"{path} is outside the test HOME" + + +def test_saving_permissions_does_not_touch_the_real_file(): + from config.permissions import PermissionLevel, Permissions + + Permissions().set_tool_permission("edit", PermissionLevel.ALLOW) # saves to PERMISSIONS_FILE + assert perm_mod.PERMISSIONS_FILE.exists() + assert Path.home() in perm_mod.PERMISSIONS_FILE.parents + + +def test_keyring_is_the_null_backend(): + import keyring + + assert keyring.get_password("devorch", "openai") is None + assert type(keyring.get_keyring()).__module__ == "keyring.backends.null"