-
Notifications
You must be signed in to change notification settings - Fork 6.9k
fix: honor resource auth action filters #8311
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| from __future__ import annotations | ||
|
|
||
| import inspect | ||
|
|
@@ -392,7 +392,7 @@ | |
| def __call__( | ||
| self, | ||
| *, | ||
| resources: str | Sequence[str], | ||
| resources: str | Sequence[str] | None = None, | ||
| actions: str | Sequence[str] | None = None, | ||
| ) -> Callable[ | ||
| [_ActionHandler[VCreate | VUpdate | VRead | VDelete | VSearch]], | ||
|
|
@@ -416,25 +416,38 @@ | |
| _ActionHandler[VCreate | VUpdate | VRead | VDelete | VSearch], | ||
| ] | ||
| ): | ||
| if fn is not None: | ||
| _validate_handler(fn) | ||
| return typing.cast( | ||
| "_ActionHandler[VCreate | VUpdate | VRead | VDelete | VSearch]", | ||
| _register_handler(self.auth, self.resource, "*", fn), | ||
| ) | ||
|
|
||
| def decorator( | ||
| def register( | ||
| handler: _ActionHandler[VCreate | VUpdate | VRead | VDelete | VSearch], | ||
| ) -> _ActionHandler[VCreate | VUpdate | VRead | VDelete | VSearch]: | ||
| _validate_handler(handler) | ||
| return typing.cast( | ||
| "_ActionHandler[VCreate | VUpdate | VRead | VDelete | VSearch]", | ||
| _register_handler(self.auth, self.resource, "*", handler), | ||
| ) | ||
| if isinstance(resources, str): | ||
| resource_list = [resources] | ||
| else: | ||
| resource_list = ( | ||
| list(resources) if resources is not None else [self.resource] | ||
| ) | ||
| if resource_list != [self.resource]: | ||
| raise ValueError( | ||
| f"Resource-specific decorator for {self.resource!r} cannot " | ||
| f"register handlers for {resource_list!r}. Use @auth.on(...) " | ||
| "for multiple resources." | ||
| ) | ||
| if isinstance(actions, str): | ||
| action_list = [actions] | ||
| else: | ||
| action_list = list(actions) if actions is not None else ["*"] | ||
| for action in action_list: | ||
| _register_handler(self.auth, self.resource, action, handler) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If |
||
| return handler | ||
|
|
||
| # Accept keyword-only parameters for future filtering behavior; referenced to satisfy linters. | ||
| _ = resources, actions | ||
| return decorator | ||
| if fn is not None: | ||
| return register( | ||
| typing.cast( | ||
| "_ActionHandler[VCreate | VUpdate | VRead | VDelete | VSearch]", | ||
| fn, | ||
| ) | ||
| ) | ||
| return register | ||
|
|
||
|
|
||
| class _AssistantsOn( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| import pytest | ||
|
|
||
| from langgraph_sdk import Auth | ||
|
|
||
|
|
||
| def _handler(): | ||
| async def handler(ctx, value): | ||
| return ctx is not None and value is not None | ||
|
|
||
| return handler | ||
|
|
||
|
|
||
| def test_resource_decorator_registers_specific_actions(): | ||
| auth = Auth() | ||
|
|
||
| handler = auth.on.threads(actions=["read", "search"])(_handler()) | ||
|
|
||
| assert auth._handlers == { | ||
| ("threads", "read"): [handler], | ||
| ("threads", "search"): [handler], | ||
| } | ||
|
|
||
|
|
||
| def test_resource_decorator_registers_single_action(): | ||
| auth = Auth() | ||
|
|
||
| handler = auth.on.threads(actions="read")(_handler()) | ||
|
|
||
| assert auth._handlers == {("threads", "read"): [handler]} | ||
|
|
||
|
|
||
| def test_resource_decorator_without_actions_registers_resource_wildcard(): | ||
| auth = Auth() | ||
|
|
||
| handler = auth.on.threads(_handler()) | ||
|
|
||
| assert auth._handlers == {("threads", "*"): [handler]} | ||
|
|
||
|
|
||
| def test_resource_decorator_rejects_mismatched_resources(): | ||
| auth = Auth() | ||
|
|
||
| with pytest.raises(ValueError, match=r"Use @auth\.on"): | ||
| auth.on.threads(resources="assistants", actions="read")(_handler()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nothing validates the action strings here, so
auth.on.threads(actions="raed")registers a("threads", "raed")key that never gets looked up and the handler silently never runs. before this change a typo still landed on the"*"key so the handler at least fired; the attribute form (auth.on.threads.read) also fails loudly with AttributeError. worth checkingactionagainst the resource's known actions and raising, since the failure mode is a permissive one.