mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-01 02:02:20 +00:00
fix(agents): isolate human subject reads and reject inactive authentication writes
This commit is contained in:
parent
dd2cfa2643
commit
c8e1fc003d
2 changed files with 27 additions and 4 deletions
|
|
@ -98,9 +98,6 @@ class AgentIdentityStore:
|
|||
row: Final = await self.identities.table.find_unique(where=where)
|
||||
except Exception:
|
||||
return AgentIdentityFailure(code="policy_unavailable", message="Agent identity could not be loaded")
|
||||
proven: Final = await self.subject(issuer, tenant, claims.get("oid"))
|
||||
if isinstance(proven, AgentIdentityFailure):
|
||||
return proven
|
||||
if row is None:
|
||||
return await self.unbound_client(where)
|
||||
agent: Final = await self.agent(row.agent_id)
|
||||
|
|
@ -124,6 +121,9 @@ class AgentIdentityStore:
|
|||
mode=subject.mode,
|
||||
subject_oid=subject.oid,
|
||||
)
|
||||
proven: Final = await self.subject(issuer, tenant, claims.get("oid"))
|
||||
if isinstance(proven, AgentIdentityFailure):
|
||||
return proven
|
||||
human: Final = (
|
||||
VerifiedHumanSubject.model_validate(proven.model_dump())
|
||||
if proven is not None
|
||||
|
|
@ -170,6 +170,8 @@ class AgentIdentityStore:
|
|||
where: Final[LiteLLM_AgentIdentityWhereInput] = {
|
||||
"agent_id": context.agent_id,
|
||||
"revision": context.binding_revision,
|
||||
"active": True,
|
||||
"agent": {"is": {"enabled": True, "identity_managed": True}},
|
||||
}
|
||||
data: Final[LiteLLM_AgentIdentityUpdateManyMutationInput] = {
|
||||
"last_authenticated_at": datetime.now(timezone.utc)
|
||||
|
|
|
|||
|
|
@ -158,7 +158,12 @@ async def test_rebinding_during_authentication_does_not_mark_new_identity_verifi
|
|||
result: Final = await store.record_authentication(context)
|
||||
assert isinstance(result, AgentIdentityFailure)
|
||||
assert "changed" in result.message
|
||||
assert identities.update_many.call_args.kwargs["where"] == {"agent_id": "agent-one", "revision": "old-revision"}
|
||||
assert identities.update_many.call_args.kwargs["where"] == {
|
||||
"agent_id": "agent-one",
|
||||
"revision": "old-revision",
|
||||
"active": True,
|
||||
"agent": {"is": {"enabled": True, "identity_managed": True}},
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -379,3 +384,19 @@ async def test_resolver_preserves_unconfigured_and_unrelated_authentication() ->
|
|||
store, _, identities, _ = setup_store()
|
||||
identities.find_unique.return_value = None
|
||||
assert await store.resolve_verified_claims(CLAIMS) is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize("registered", [True, False])
|
||||
async def test_application_and_unregistered_clients_do_not_depend_on_human_subject_storage(registered: bool) -> None:
|
||||
store, _, identities, humans = setup_store()
|
||||
identities.find_unique.return_value = BINDING if registered else None
|
||||
humans.find_unique.side_effect = RuntimeError("subject database unavailable")
|
||||
result: Final = await store.resolve_verified_claims(CLAIMS)
|
||||
if registered:
|
||||
assert isinstance(result, ManagedAgentContext)
|
||||
assert result.mode == "autonomous"
|
||||
assert result.user_id is None
|
||||
else:
|
||||
assert result is None
|
||||
humans.find_unique.assert_not_awaited()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue