Restore approved state (tree of 4effcc7 "Added LICENSE")
Roll the working tree back to the last approved shape, before the post-LICENSE span that false-greened the AFI parity matrix with symbol-presence probes and smuggled an unauthorized SQLAlchemy dependency into FastAPI's Shapes binding.
Forward commit, not a history rewrite — the six commits since 4effcc7 stay in the log as the record of what happened.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,147 +0,0 @@
|
||||
"""Unit tests for the adapter-agnostic dispatch core."""
|
||||
|
||||
import asyncio
|
||||
|
||||
import pytest
|
||||
from pydantic import BaseModel
|
||||
|
||||
from mizan_core.auth import AuthConfig, JWTConfig, INVALID, authenticate, create_access_token
|
||||
from mizan_core.authguard import enforce_auth
|
||||
from mizan_core.client.function import client
|
||||
from mizan_core.dispatch import CacheOrchestrator, DispatchRequest, dispatch_call
|
||||
from mizan_core.errors import Forbidden, Unauthorized
|
||||
from mizan_core.invalidation import format_invalidate_header, resolve_invalidation
|
||||
from mizan_core.registry import clear_registry, register
|
||||
|
||||
|
||||
class Ident:
|
||||
def __init__(self, authed=True, staff=False, su=False, pk=1):
|
||||
self.is_authenticated = authed
|
||||
self.is_staff = staff
|
||||
self.is_superuser = su
|
||||
self.pk = pk
|
||||
|
||||
|
||||
# ─── authguard ──────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
def test_auth_required_anonymous():
|
||||
with pytest.raises(Unauthorized):
|
||||
enforce_auth(None, True)
|
||||
|
||||
|
||||
def test_auth_required_authenticated():
|
||||
enforce_auth(Ident(), True) # no raise
|
||||
|
||||
|
||||
def test_auth_staff_denied_then_allowed():
|
||||
with pytest.raises(Forbidden):
|
||||
enforce_auth(Ident(staff=False), "staff")
|
||||
enforce_auth(Ident(staff=True), "staff")
|
||||
|
||||
|
||||
def test_auth_superuser():
|
||||
with pytest.raises(Forbidden):
|
||||
enforce_auth(Ident(su=False), "superuser")
|
||||
enforce_auth(Ident(su=True), "superuser")
|
||||
|
||||
|
||||
def test_auth_callable_false_and_raise():
|
||||
with pytest.raises(Forbidden):
|
||||
enforce_auth(Ident(), lambda r: False)
|
||||
with pytest.raises(Forbidden, match="custom"):
|
||||
enforce_auth(Ident(), lambda r: (_ for _ in ()).throw(PermissionError("custom")))
|
||||
|
||||
|
||||
# ─── authenticate / INVALID sentinel ────────────────────────────────────────
|
||||
|
||||
|
||||
def _cfg():
|
||||
return AuthConfig(jwt=JWTConfig(private_key="k" * 32, public_key="k" * 32))
|
||||
|
||||
|
||||
def test_authenticate_jwt_ok():
|
||||
cfg = _cfg()
|
||||
tok = create_access_token("7", "sess", cfg.jwt, is_staff=True)
|
||||
ident = authenticate({"Authorization": f"Bearer {tok}"}, cfg)
|
||||
assert ident.pk == 7 and ident.is_staff and ident.is_authenticated
|
||||
|
||||
|
||||
def test_authenticate_bad_token_is_invalid_sentinel():
|
||||
assert authenticate({"Authorization": "Bearer garbage"}, _cfg()) is INVALID
|
||||
|
||||
|
||||
def test_authenticate_no_token_is_none():
|
||||
assert authenticate({}, _cfg()) is None
|
||||
|
||||
|
||||
# ─── invalidation + header ──────────────────────────────────────────────────
|
||||
|
||||
|
||||
def test_invalidation_three_tier_and_header():
|
||||
clear_registry()
|
||||
UserCtx = "user"
|
||||
|
||||
class Out(BaseModel):
|
||||
ok: bool
|
||||
|
||||
@client(context=UserCtx)
|
||||
def user_profile(request, user_id: int) -> Out:
|
||||
return Out(ok=True)
|
||||
|
||||
@client(affects=UserCtx)
|
||||
def update_profile(request, user_id: int, name: str) -> Out:
|
||||
return Out(ok=True)
|
||||
|
||||
register(user_profile, "user_profile")
|
||||
register(update_profile, "update_profile")
|
||||
|
||||
# Tier 1: user_id matches context param → scoped
|
||||
inv = resolve_invalidation(update_profile, {"user_id": 5, "name": "x"})
|
||||
assert inv == [{"context": "user", "params": {"user_id": 5}}]
|
||||
assert format_invalidate_header(inv) == "user;user_id=5"
|
||||
|
||||
# Tier 3: no matching param → broad
|
||||
inv2 = resolve_invalidation(update_profile, {"name": "x"})
|
||||
assert inv2 == ["user"]
|
||||
clear_registry()
|
||||
|
||||
|
||||
# ─── dispatch_call end to end ───────────────────────────────────────────────
|
||||
|
||||
|
||||
def test_dispatch_call_auth_and_invalidation():
|
||||
clear_registry()
|
||||
|
||||
class Out(BaseModel):
|
||||
ok: bool
|
||||
|
||||
@client(context="user")
|
||||
def user_profile(request, user_id: int) -> Out:
|
||||
return Out(ok=True)
|
||||
|
||||
@client(affects="user", auth="staff")
|
||||
def secure_update(request, user_id: int) -> Out:
|
||||
return Out(ok=True)
|
||||
|
||||
register(user_profile, "user_profile")
|
||||
register(secure_update, "secure_update")
|
||||
|
||||
cache = CacheOrchestrator(None, None)
|
||||
|
||||
# non-staff rejected
|
||||
with pytest.raises(Forbidden):
|
||||
asyncio.run(dispatch_call(
|
||||
DispatchRequest(identity=Ident(staff=False), args={"user_id": 1}),
|
||||
"secure_update", cache,
|
||||
))
|
||||
|
||||
# staff passes, invalidation resolved
|
||||
res = asyncio.run(dispatch_call(
|
||||
DispatchRequest(identity=Ident(staff=True), args={"user_id": 1}),
|
||||
"secure_update", cache,
|
||||
))
|
||||
assert res.kind == "rpc" and res.data == {"ok": True}
|
||||
assert res.invalidate == [{"context": "user", "params": {"user_id": 1}}]
|
||||
assert res.invalidate_header == "user;user_id=1"
|
||||
clear_registry()
|
||||
Reference in New Issue
Block a user