From 8a08091ba092326abb480fc8403745c8e77ae96a Mon Sep 17 00:00:00 2001 From: Jonah Gray Date: Tue, 5 May 2026 17:32:25 -0400 Subject: [PATCH 1/3] feat(OMN-10559): FakeSecretStore for tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a deterministic in-memory ProtocolSecretStore implementation for the canonical conftest in omnimarket and other downstream consumers. Dict-backed; constructor takes an optional initial: Mapping[str, str] that is copied (not referenced) so callers can mutate the source after construction without affecting the store. All seven protocol methods are fully implemented: - get_secret returns the stored value or None. - set_secret stores or overwrites; returns True. - delete_secret returns True if removed, False if absent. - list_keys returns sorted keys, optionally prefix-filtered. - health_check returns True until close() is called, then False. - close marks the store closed; timeout_seconds accepted for protocol parity (the close is synchronous and immediate). Packaging: lives at omnibase_infra.test_utils.fake_secret_store. The test_utils package is new in this PR; it is intended to ship in the wheel because consumer test suites import it. Heavyweight fixtures that require infrastructure (Postgres, Kafka) belong in the existing omnibase_infra.testing package instead — test_utils is the lightweight fakes layer. 13 unit tests cover protocol conformance, empty-vs-preloaded construction, the no-aliasing copy semantics, set/delete round-trips, delete-missing returns False, sorted prefix listing, and the health-check-after-close lifecycle. Wave 5 / Epic 2 (OMN-10546). Independent of Task 11 / Task 12. --- src/omnibase_infra/test_utils/__init__.py | 18 ++++ .../test_utils/fake_secret_store.py | 59 +++++++++++ tests/unit/test_utils/__init__.py | 3 + .../unit/test_utils/test_fake_secret_store.py | 98 +++++++++++++++++++ 4 files changed, 178 insertions(+) create mode 100644 src/omnibase_infra/test_utils/__init__.py create mode 100644 src/omnibase_infra/test_utils/fake_secret_store.py create mode 100644 tests/unit/test_utils/__init__.py create mode 100644 tests/unit/test_utils/test_fake_secret_store.py diff --git a/src/omnibase_infra/test_utils/__init__.py b/src/omnibase_infra/test_utils/__init__.py new file mode 100644 index 0000000000..038bdc5b10 --- /dev/null +++ b/src/omnibase_infra/test_utils/__init__.py @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT +"""Test utilities ``omnibase_infra`` ships for downstream tests (OMN-10559). + +These helpers are deliberately *not* under ``tests/`` because consumer +repos (omnimarket, etc.) import them from their own conftests. They are +shipped in the wheel — acceptable for an internal platform package. + +Add lightweight fakes / fixtures here. Heavyweight fixtures that depend +on infrastructure (Postgres, Kafka) belong in ``omnibase_infra.testing`` +instead. +""" + +from __future__ import annotations + +from omnibase_infra.test_utils.fake_secret_store import FakeSecretStore + +__all__: list[str] = ["FakeSecretStore"] diff --git a/src/omnibase_infra/test_utils/fake_secret_store.py b/src/omnibase_infra/test_utils/fake_secret_store.py new file mode 100644 index 0000000000..1ff9b6e4a2 --- /dev/null +++ b/src/omnibase_infra/test_utils/fake_secret_store.py @@ -0,0 +1,59 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT +"""Deterministic in-memory ``ProtocolSecretStore`` for tests (OMN-10559). + +Used by the canonical conftest in omnimarket and other consumers to +exercise code that depends on a ``ProtocolSecretStore`` without standing +up a real backend. + +Packaging note: this module ships in the omnibase_infra wheel (under +``omnibase_infra.test_utils``) because downstream test suites import it. +The package is internal-platform-only; shipping test helpers is +deliberate. Heavier fixtures requiring infrastructure (Postgres, Kafka) +belong in ``omnibase_infra.testing`` instead. +""" + +from __future__ import annotations + +from collections.abc import Mapping + + +class FakeSecretStore: + """In-memory ``ProtocolSecretStore`` impl backed by a ``dict``. + + Fully implements every protocol method (gets, sets, deletes, lists, + health, close). Constructor accepts an optional ``initial`` mapping + to preload values. + """ + + def __init__(self, initial: Mapping[str, str] | None = None) -> None: + self._data: dict[str, str] = dict(initial) if initial else {} + self._closed: bool = False + + async def get_secret(self, key: str) -> str | None: + return self._data.get(key) + + async def set_secret(self, key: str, value: str) -> bool: + self._data[key] = value + return True + + async def delete_secret(self, key: str) -> bool: + if key in self._data: + del self._data[key] + return True + return False + + async def list_keys(self, prefix: str | None = None) -> list[str]: + if prefix is None: + return sorted(self._data.keys()) + return sorted(k for k in self._data if k.startswith(prefix)) + + async def health_check(self) -> bool: + return not self._closed + + async def close(self, timeout_seconds: float = 30.0) -> None: + del timeout_seconds + self._closed = True + + +__all__: list[str] = ["FakeSecretStore"] diff --git a/tests/unit/test_utils/__init__.py b/tests/unit/test_utils/__init__.py new file mode 100644 index 0000000000..e2ea15acf9 --- /dev/null +++ b/tests/unit/test_utils/__init__.py @@ -0,0 +1,3 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT +"""Unit tests for ``omnibase_infra.test_utils``.""" diff --git a/tests/unit/test_utils/test_fake_secret_store.py b/tests/unit/test_utils/test_fake_secret_store.py new file mode 100644 index 0000000000..91ff6869c3 --- /dev/null +++ b/tests/unit/test_utils/test_fake_secret_store.py @@ -0,0 +1,98 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT +"""Unit tests for ``FakeSecretStore`` (OMN-10559).""" + +from __future__ import annotations + +import pytest + +from omnibase_infra.test_utils.fake_secret_store import FakeSecretStore +from omnibase_spi.protocols.services.protocol_secret_store import ProtocolSecretStore + + +@pytest.mark.unit +def test_satisfies_protocol_secret_store() -> None: + assert isinstance(FakeSecretStore(), ProtocolSecretStore) + + +@pytest.mark.unit +async def test_empty_constructor_yields_empty_store() -> None: + store = FakeSecretStore() + assert await store.list_keys() == [] + assert await store.get_secret("anything") is None + + +@pytest.mark.unit +async def test_initial_data_preloaded() -> None: + store = FakeSecretStore(initial={"a": "1", "b": "2"}) + assert await store.get_secret("a") == "1" + assert await store.get_secret("b") == "2" + + +@pytest.mark.unit +async def test_initial_data_is_copied_not_referenced() -> None: + source = {"a": "1"} + store = FakeSecretStore(initial=source) + source["a"] = "mutated" + assert await store.get_secret("a") == "1" + + +@pytest.mark.unit +async def test_set_then_get_round_trip() -> None: + store = FakeSecretStore() + assert await store.set_secret("key", "value") is True + assert await store.get_secret("key") == "value" + + +@pytest.mark.unit +async def test_set_overwrites_existing_value() -> None: + store = FakeSecretStore(initial={"key": "original"}) + await store.set_secret("key", "updated") + assert await store.get_secret("key") == "updated" + + +@pytest.mark.unit +async def test_delete_existing_returns_true_and_removes() -> None: + store = FakeSecretStore(initial={"key": "value"}) + assert await store.delete_secret("key") is True + assert await store.get_secret("key") is None + + +@pytest.mark.unit +async def test_delete_missing_returns_false() -> None: + store = FakeSecretStore() + assert await store.delete_secret("absent") is False + + +@pytest.mark.unit +async def test_list_keys_no_prefix_returns_all_sorted() -> None: + store = FakeSecretStore(initial={"b": "2", "a": "1", "c": "3"}) + assert await store.list_keys() == ["a", "b", "c"] + + +@pytest.mark.unit +async def test_list_keys_filters_by_prefix() -> None: + store = FakeSecretStore( + initial={"llm/openai": "k1", "db/pg": "k2", "llm/anthropic": "k3"} + ) + assert await store.list_keys(prefix="llm/") == ["llm/anthropic", "llm/openai"] + + +@pytest.mark.unit +async def test_health_check_true_when_open() -> None: + store = FakeSecretStore() + assert await store.health_check() is True + + +@pytest.mark.unit +async def test_health_check_false_after_close() -> None: + store = FakeSecretStore() + await store.close() + assert await store.health_check() is False + + +@pytest.mark.unit +async def test_close_accepts_default_timeout() -> None: + store = FakeSecretStore() + await store.close() + await store.close(timeout_seconds=5.0) From 6d83cfb6ebced4fc367414630a62678b67547598 Mon Sep 17 00:00:00 2001 From: Jonah Gray Date: Tue, 5 May 2026 17:56:06 -0400 Subject: [PATCH 2/3] ci(OMN-10559): re-trigger CI after Evidence-Source body update From 7a6b8df3aeb24c1f9f2f0c157e83b3055629e657 Mon Sep 17 00:00:00 2001 From: Jonah Gray Date: Wed, 6 May 2026 08:27:36 -0400 Subject: [PATCH 3/3] test(OMN-10559): add fake secret store integration coverage --- .../test_fake_secret_store_integration.py | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 tests/integration/test_fake_secret_store_integration.py diff --git a/tests/integration/test_fake_secret_store_integration.py b/tests/integration/test_fake_secret_store_integration.py new file mode 100644 index 0000000000..d82cab8147 --- /dev/null +++ b/tests/integration/test_fake_secret_store_integration.py @@ -0,0 +1,26 @@ +# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc. +# SPDX-License-Identifier: MIT +"""Integration coverage for the fake secret store test utility (OMN-10559).""" + +from __future__ import annotations + +import pytest + +from omnibase_infra.test_utils.fake_secret_store import FakeSecretStore +from omnibase_spi.protocols.services.protocol_secret_store import ProtocolSecretStore + + +@pytest.mark.integration +async def test_fake_secret_store_protocol_lifecycle() -> None: + store: ProtocolSecretStore = FakeSecretStore(initial={"db/url": "postgres"}) + + assert await store.health_check() is True + assert await store.get_secret("db/url") == "postgres" + assert await store.set_secret("llm/key", "secret") is True + assert await store.get_secret("llm/key") == "secret" + assert await store.list_keys(prefix="llm/") == ["llm/key"] + assert await store.delete_secret("db/url") is True + assert await store.get_secret("db/url") is None + + await store.close() + assert await store.health_check() is False