import json from pathlib import Path import pytest from audit_core.senders import SenderRegistry, WILDCARD ROOT = Path(__file__).resolve().parents[1] SCOPE_FILE = ROOT / "deploy" / "senders-scope.json" def test_declared_scope_keeps_user_engine_tenants_wildcard(): scope = json.loads(SCOPE_FILE.read_text()) user_engine = next(entry for entry in scope if entry["name"] == "user-engine") assert user_engine["tenants"] == ["*"] assert user_engine["sources"] == ["user-engine"] assert user_engine["may_write"] is True assert user_engine["may_read"] is False assert "tokens" not in user_engine assert "token" not in user_engine def test_scope_overlay_widens_narrow_secret_tenants(tmp_path): secret = json.dumps( [ { "name": "user-engine", "tokens": ["live-token"], "sources": ["user-engine"], "tenants": ["tenant:friendly:binky"], "may_write": True, "may_read": False, } ] ) env = { "AUDIT_CORE_SENDERS": secret, "AUDIT_CORE_SENDERS_SCOPE_PATH": str(SCOPE_FILE), } registry = SenderRegistry.from_env(env) identity = registry.authenticate("Bearer live-token") assert identity is not None assert WILDCARD in identity.tenants assert identity.permits_tenant("tenant:other:x") assert identity.tokens == ("live-token",) def test_scope_overlay_does_not_take_tokens_from_git(): overlay = json.dumps( [ { "name": "user-engine", "tokens": ["must-not-be-used"], "tenants": ["*"], } ] ) secret = json.dumps( [ { "name": "user-engine", "tokens": ["live-token"], "sources": ["user-engine"], "tenants": ["tenant:friendly:binky"], } ] ) registry = SenderRegistry.from_env( {"AUDIT_CORE_SENDERS": secret, "AUDIT_CORE_SENDERS_SCOPE": overlay} ) assert registry.authenticate("Bearer must-not-be-used") is None assert registry.authenticate("Bearer live-token") is not None def test_missing_overlay_leaves_secret_as_is(): secret = json.dumps( [ { "name": "user-engine", "tokens": ["live-token"], "sources": ["user-engine"], "tenants": ["tenant:friendly:binky"], } ] ) identity = SenderRegistry.from_env({"AUDIT_CORE_SENDERS": secret}).identities[0] assert identity.tenants == frozenset({"tenant:friendly:binky"}) def test_invalid_scope_overlay_is_a_startup_error(): secret = json.dumps( [{"name": "user-engine", "tokens": ["t"], "sources": ["user-engine"]}] ) with pytest.raises(ValueError, match="JSON list"): SenderRegistry.from_env( {"AUDIT_CORE_SENDERS": secret, "AUDIT_CORE_SENDERS_SCOPE": "{}"} )