Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
"""Conformance kit for :class:`agent.secret_sources.base.SecretSource`.
|
||||
|
||||
Any secret-source backend — bundled or external plugin — can validate
|
||||
itself against the contract by subclassing :class:`SecretSourceConformance`
|
||||
and providing a ``source`` fixture (plus optional per-source config
|
||||
fixtures). Example::
|
||||
|
||||
from tests.secret_sources.conformance import SecretSourceConformance
|
||||
|
||||
class TestMySourceConformance(SecretSourceConformance):
|
||||
@pytest.fixture
|
||||
def source(self):
|
||||
return MySource()
|
||||
|
||||
The checks encode the parts of the contract that break OTHER people
|
||||
when violated: never raising, never prompting (stdin closed), respecting
|
||||
disabled config, valid identity attributes, and orchestrator
|
||||
compatibility.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from agent.secret_sources.base import (
|
||||
SECRET_SOURCE_API_VERSION,
|
||||
FetchResult,
|
||||
SecretSource,
|
||||
)
|
||||
from agent.secret_sources.registry import (
|
||||
_reset_registry_for_tests,
|
||||
apply_all,
|
||||
register_source,
|
||||
)
|
||||
|
||||
|
||||
class SecretSourceConformance:
|
||||
"""Base class of contract checks; subclass and provide ``source``."""
|
||||
|
||||
@pytest.fixture
|
||||
def source(self) -> SecretSource: # pragma: no cover — must override
|
||||
raise NotImplementedError("conformance subclasses must provide a source fixture")
|
||||
|
||||
@pytest.fixture
|
||||
def minimal_cfg(self) -> dict:
|
||||
"""An enabled-but-unconfigured section — the common misconfig case."""
|
||||
return {"enabled": True}
|
||||
|
||||
# -- identity ----------------------------------------------------------
|
||||
|
||||
def test_name_is_lowercase_identifier(self, source):
|
||||
assert source.name, "source.name must be non-empty"
|
||||
assert source.name == source.name.lower()
|
||||
assert source.name.replace("_", "").isalnum()
|
||||
|
||||
def test_label_present(self, source):
|
||||
assert source.label, "source.label must be a human-readable name"
|
||||
|
||||
def test_shape_valid(self, source):
|
||||
assert source.shape in ("mapped", "bulk")
|
||||
|
||||
def test_api_version_current(self, source):
|
||||
assert source.api_version == SECRET_SOURCE_API_VERSION
|
||||
|
||||
# -- contract behavior --------------------------------------------------
|
||||
|
||||
def test_fetch_never_raises_on_malformed_config(self, source, tmp_path):
|
||||
"""Every degenerate config shape must produce a FetchResult, not a raise."""
|
||||
for cfg in ({}, {"enabled": True}, {"enabled": True, "env": "not-a-dict"},
|
||||
{"enabled": True, "cache_ttl_seconds": "bogus"}, None):
|
||||
result = source.fetch(cfg if isinstance(cfg, dict) else {}, tmp_path)
|
||||
assert isinstance(result, FetchResult), (
|
||||
f"fetch() returned {type(result).__name__} for cfg={cfg!r}"
|
||||
)
|
||||
|
||||
def test_fetch_unconfigured_reports_error_not_secrets(self, source, tmp_path,
|
||||
minimal_cfg, monkeypatch):
|
||||
"""enabled=true with nothing else set must fail cleanly with a kind."""
|
||||
result = source.fetch(minimal_cfg, tmp_path)
|
||||
assert isinstance(result, FetchResult)
|
||||
if not result.ok:
|
||||
assert result.error_kind is not None, (
|
||||
"errors must carry a machine-readable ErrorKind"
|
||||
)
|
||||
assert not result.secrets
|
||||
|
||||
def test_disabled_by_default(self, source):
|
||||
assert source.is_enabled({}) is False
|
||||
assert source.is_enabled({"enabled": False}) is False
|
||||
|
||||
def test_timeout_is_positive(self, source, minimal_cfg):
|
||||
assert source.fetch_timeout_seconds(minimal_cfg) > 0
|
||||
# Garbage config must not break the timeout accessor either.
|
||||
assert source.fetch_timeout_seconds({"timeout_seconds": "junk"}) > 0
|
||||
|
||||
def test_protected_vars_are_valid_names(self, source, minimal_cfg):
|
||||
from agent.secret_sources.base import is_valid_env_name
|
||||
|
||||
for var in source.protected_env_vars(minimal_cfg):
|
||||
assert is_valid_env_name(var)
|
||||
|
||||
# -- orchestrator compatibility ------------------------------------------
|
||||
|
||||
def test_registers_and_applies_via_orchestrator(self, source, tmp_path,
|
||||
monkeypatch):
|
||||
"""The source must survive a full apply_all() pass without breaking it."""
|
||||
_reset_registry_for_tests()
|
||||
# Prevent the bundled sources from interfering.
|
||||
monkeypatch.setattr(
|
||||
"agent.secret_sources.registry._ensure_builtin_sources", lambda: None
|
||||
)
|
||||
try:
|
||||
assert register_source(source), "register_source() rejected the source"
|
||||
env: dict = {}
|
||||
report = apply_all(
|
||||
{source.name: {"enabled": True}}, tmp_path, environ=env
|
||||
)
|
||||
names = [sr.name for sr in report.sources]
|
||||
assert source.name in names
|
||||
finally:
|
||||
_reset_registry_for_tests()
|
||||
Reference in New Issue
Block a user