diff --git a/tests/conftest.py b/tests/conftest.py index fca89f0..97a4f5d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -13,25 +13,6 @@ from unittest.mock import AsyncMock, MagicMock, patch from central.bootstrap_config import Settings -@pytest.fixture(autouse=True) -def isolate_enrichment_cache(tmp_path, monkeypatch): - """Redirect the supervisor's enrichment cache off the production path. - - `central.supervisor.ENRICHMENT_CACHE_DB_PATH` defaults to - /var/lib/central/enrichment_cache.db. Constructing a Supervisor opens it, - so without this fixture the suite writes to (or, for any user without write - access to /var/lib/central, fails on) the live cache. Point it at a - per-test temp dir so no test ever touches the production path. - """ - import central.supervisor as supervisor_mod - - monkeypatch.setattr( - supervisor_mod, - "ENRICHMENT_CACHE_DB_PATH", - tmp_path / "enrichment_cache.db", - ) - - @pytest.fixture(scope="session") def event_loop(): """Create an event loop for the test session.""" diff --git a/tests/test_config_source.py b/tests/test_config_source.py index a26a12a..bc944c1 100644 --- a/tests/test_config_source.py +++ b/tests/test_config_source.py @@ -12,7 +12,6 @@ from central.config_source import ( ConfigSource, DbConfigSource, ) -from central.bootstrap_config import get_settings from central.crypto import KEY_SIZE, clear_key_cache # Test database DSN @@ -32,20 +31,11 @@ def master_key_path(tmp_path_factory: pytest.TempPathFactory) -> Path: @pytest.fixture(autouse=True) -def setup_master_key(master_key_path: Path, monkeypatch: pytest.MonkeyPatch): - """Configure master key path for all tests. - - Clear get_settings (and the crypto key cache) AFTER setting the env so - crypto rebuilds from the test key regardless of suite order, and again on - teardown so the test key never leaks into a later test. See PR M-b. - """ +def setup_master_key(master_key_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: + """Configure master key path for all tests.""" + clear_key_cache() monkeypatch.setenv("CENTRAL_DB_DSN", TEST_DB_DSN) monkeypatch.setenv("CENTRAL_MASTER_KEY_PATH", str(master_key_path)) - clear_key_cache() - get_settings.cache_clear() - yield - clear_key_cache() - get_settings.cache_clear() @pytest_asyncio.fixture diff --git a/tests/test_config_store.py b/tests/test_config_store.py index e80d515..4653e32 100644 --- a/tests/test_config_store.py +++ b/tests/test_config_store.py @@ -13,7 +13,6 @@ import asyncpg import pytest import pytest_asyncio -from central.bootstrap_config import get_settings from central.config_store import ConfigStore from central.crypto import KEY_SIZE, clear_key_cache @@ -35,24 +34,12 @@ def master_key_path(tmp_path_factory: pytest.TempPathFactory) -> Path: @pytest.fixture(autouse=True) -def setup_master_key(master_key_path: Path, monkeypatch: pytest.MonkeyPatch): - """Configure master key path for all tests. - - CENTRAL_MASTER_KEY_PATH feeds Settings, which get_settings() lru-caches. An - earlier test can warm that cache with the default /etc/central/master.key - before this fixture runs, so the env change alone is not enough — clear - get_settings (and the crypto key cache) AFTER setting the env so crypto - rebuilds from the test key regardless of suite order, and again on teardown - so the test key never leaks into a later test. - """ +def setup_master_key(master_key_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: + """Configure master key path for all tests.""" + clear_key_cache() monkeypatch.setenv("CENTRAL_DB_DSN", TEST_DB_DSN) monkeypatch.setenv("CENTRAL_MASTER_KEY_PATH", str(master_key_path)) monkeypatch.setenv("CENTRAL_CSRF_SECRET", "test-csrf-secret-for-testing-only-32chars") - clear_key_cache() - get_settings.cache_clear() - yield - clear_key_cache() - get_settings.cache_clear() @pytest_asyncio.fixture @@ -351,13 +338,3 @@ class TestListenerReconnect: pytest.fail("Listener did not stop after cancellation") assert listen_task.cancelled() or listen_task.done() - - -def test_master_key_path_is_isolated(master_key_path: Path) -> None: - """Contract: after setup_master_key runs, get_settings() resolves the master - key to the per-session test key — never the production /etc/central path — - regardless of suite order. Fails on the pre-fix code in a full-suite run - where get_settings was warmed with the default path by an earlier test. - """ - assert get_settings().master_key_path == master_key_path - assert get_settings().master_key_path != Path("/etc/central/master.key") diff --git a/tests/test_supervisor_hotreload.py b/tests/test_supervisor_hotreload.py index 10343b8..54db782 100644 --- a/tests/test_supervisor_hotreload.py +++ b/tests/test_supervisor_hotreload.py @@ -14,7 +14,6 @@ import pytest_asyncio from central.config_models import AdapterConfig from central.config_source import DbConfigSource from central.config_store import ConfigStore -from central.bootstrap_config import get_settings from central.crypto import KEY_SIZE, clear_key_cache # Test database DSN @@ -34,20 +33,11 @@ def master_key_path(tmp_path_factory: pytest.TempPathFactory) -> Path: @pytest.fixture(autouse=True) -def setup_master_key(master_key_path: Path, monkeypatch: pytest.MonkeyPatch): - """Configure master key path for all tests. - - Clear get_settings (and the crypto key cache) AFTER setting the env so - crypto rebuilds from the test key regardless of suite order, and again on - teardown so the test key never leaks into a later test. See PR M-b. - """ +def setup_master_key(master_key_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: + """Configure master key path for all tests.""" + clear_key_cache() monkeypatch.setenv("CENTRAL_DB_DSN", TEST_DB_DSN) monkeypatch.setenv("CENTRAL_MASTER_KEY_PATH", str(master_key_path)) - clear_key_cache() - get_settings.cache_clear() - yield - clear_key_cache() - get_settings.cache_clear() @pytest_asyncio.fixture diff --git a/tests/test_supervisor_integration.py b/tests/test_supervisor_integration.py index 517dbe5..20360fe 100644 --- a/tests/test_supervisor_integration.py +++ b/tests/test_supervisor_integration.py @@ -20,7 +20,6 @@ import pytest import pytest_asyncio from central.config_models import AdapterConfig -from central.bootstrap_config import get_settings from central.crypto import KEY_SIZE, clear_key_cache @@ -57,20 +56,11 @@ def master_key_path(tmp_path_factory: pytest.TempPathFactory) -> Path: @pytest.fixture(autouse=True) -def setup_master_key(master_key_path: Path, monkeypatch: pytest.MonkeyPatch): - """Configure master key path for all tests. - - Clear get_settings (and the crypto key cache) AFTER setting the env so - crypto rebuilds from the test key regardless of suite order, and again on - teardown so the test key never leaks into a later test. See PR M-b. - """ +def setup_master_key(master_key_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: + """Configure master key path for all tests.""" + clear_key_cache() monkeypatch.setenv("CENTRAL_DB_DSN", TEST_DB_DSN) monkeypatch.setenv("CENTRAL_MASTER_KEY_PATH", str(master_key_path)) - clear_key_cache() - get_settings.cache_clear() - yield - clear_key_cache() - get_settings.cache_clear() class MockConfigSource: @@ -149,18 +139,12 @@ class MockNWSAdapter: @pytest.fixture def mock_nats(): - """Mock NATS connection. - - nats-py's `nc.jetstream()` is synchronous, so model it with a sync - MagicMock. (As an AsyncMock attribute, `supervisor._js = nc.jetstream()` - would assign an unawaited coroutine — the "coroutine ... was never awaited" - warning — rather than the JetStream mock.) - """ + """Mock NATS connection.""" mock_nc = AsyncMock() mock_nc.publish = AsyncMock() mock_js = AsyncMock() mock_js.publish = AsyncMock() - mock_nc.jetstream = MagicMock(return_value=mock_js) + mock_nc.jetstream.return_value = mock_js return mock_nc @@ -590,27 +574,3 @@ class TestEnableDisableEnableIntegration: # State should be gone assert "nws" not in supervisor._adapter_states - - -def test_enrichment_cache_path_is_hermetic(mock_config_store, tmp_path: Path) -> None: - """No test may touch the production enrichment cache. - - The autouse `isolate_enrichment_cache` fixture (conftest) must redirect - ENRICHMENT_CACHE_DB_PATH off /var/lib/central onto a per-test temp dir, and - constructing a Supervisor must open the cache there — not in production. - """ - import central.supervisor as supervisor_mod - - patched = supervisor_mod.ENRICHMENT_CACHE_DB_PATH - assert tmp_path in patched.parents - assert "/var/lib/central" not in str(patched) - - supervisor = supervisor_mod.Supervisor( - config_source=MockConfigSource(), - config_store=mock_config_store, - nats_url="nats://localhost:4222", - cloudevents_config=None, - ) - # __init__ opened the cache at the temp path, leaving the db file behind. - assert patched.exists() - assert supervisor._enrichment_cache is not None