mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-09-02 14:28:46 +02:00
* authz fix for custom auth * add back resource param * auth on multiple resources
133 lines
3.4 KiB
Python
133 lines
3.4 KiB
Python
import pytest
|
|
|
|
from langgraph_sdk import Auth
|
|
|
|
|
|
def test_handler_multiple_resources_and_actions() -> None:
|
|
auth = Auth()
|
|
|
|
@auth.on(resources=["threads", "assistants"], actions=["read", "search"])
|
|
async def allow_reads(ctx, value):
|
|
del value
|
|
return {"owner": ctx.user.identity}
|
|
|
|
assert auth._handlers == {
|
|
("threads", "read"): [allow_reads],
|
|
("threads", "search"): [allow_reads],
|
|
("assistants", "read"): [allow_reads],
|
|
("assistants", "search"): [allow_reads],
|
|
}
|
|
|
|
|
|
def test_resource_handler_actions_are_scoped() -> None:
|
|
auth = Auth()
|
|
|
|
@auth.on
|
|
async def deny_all(ctx, value):
|
|
del ctx, value
|
|
return False
|
|
|
|
@auth.on.threads(actions=["create", "search"])
|
|
async def handler(ctx, value):
|
|
del ctx, value
|
|
return None
|
|
|
|
@auth.on.threads(actions="create_run")
|
|
async def run_handler(ctx, value):
|
|
del ctx, value
|
|
return None
|
|
|
|
assert auth._handlers == {
|
|
("threads", "create"): [handler],
|
|
("threads", "search"): [handler],
|
|
("threads", "create_run"): [run_handler],
|
|
}
|
|
assert auth._global_handlers == [deny_all]
|
|
|
|
|
|
def test_resource_handler_preserves_wildcard() -> None:
|
|
auth = Auth()
|
|
|
|
@auth.on.threads
|
|
async def handler(ctx, value):
|
|
del ctx, value
|
|
return None
|
|
|
|
assert auth._handlers == {("threads", "*"): [handler]}
|
|
|
|
|
|
def test_resource_handler_preserves_wildcard_with_parentheses() -> None:
|
|
auth = Auth()
|
|
|
|
@auth.on.threads()
|
|
async def handler(ctx, value):
|
|
del ctx, value
|
|
return None
|
|
|
|
assert auth._handlers == {("threads", "*"): [handler]}
|
|
|
|
|
|
def test_resource_handler_accepts_matching_resource() -> None:
|
|
auth = Auth()
|
|
|
|
@auth.on.threads(resources=["threads"], actions="read")
|
|
async def handler(ctx, value):
|
|
del ctx, value
|
|
return None
|
|
|
|
assert auth._handlers == {("threads", "read"): [handler]}
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"resources", [["assistants"], ["threads", "assistants"], [], [1]]
|
|
)
|
|
def test_resource_handler_rejects_nonmatching_resources(resources) -> None:
|
|
auth = Auth()
|
|
|
|
async def handler(ctx, value):
|
|
del ctx, value
|
|
return None
|
|
|
|
with pytest.raises(ValueError, match=r"Use @auth\.on"):
|
|
auth.on.threads(resources=resources)(handler)
|
|
assert auth._handlers == {}
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("resource", "actions", "error"),
|
|
[
|
|
("threads", [], ValueError),
|
|
("threads", ["reed"], ValueError),
|
|
("threads", ["create", "create"], ValueError),
|
|
("threads", {"create": True}, TypeError),
|
|
("crons", ["create_run"], ValueError),
|
|
],
|
|
)
|
|
def test_resource_handler_rejects_invalid_actions(resource, actions, error) -> None:
|
|
auth = Auth()
|
|
|
|
async def handler(ctx, value):
|
|
del ctx, value
|
|
return None
|
|
|
|
with pytest.raises(error):
|
|
getattr(auth.on, resource)(actions=actions)(handler)
|
|
assert auth._handlers == {}
|
|
|
|
|
|
def test_resource_handler_registration_is_atomic() -> None:
|
|
auth = Auth()
|
|
|
|
@auth.on.threads.read
|
|
async def read_handler(ctx, value):
|
|
del ctx, value
|
|
return None
|
|
|
|
async def handler(ctx, value):
|
|
del ctx, value
|
|
return None
|
|
|
|
with pytest.raises(ValueError, match="already set"):
|
|
auth.on.threads(actions=["create", "read"])(handler)
|
|
assert auth._handlers == {("threads", "read"): [read_handler]}
|