Skip to content

Commit 2ee5f84

Browse files
authored
Merge pull request #1600 from Lifto/feat/action-responses
feat: add Action.RESPONSES for /responses endpoint authorization
2 parents 2d0c79a + ab30ffb commit 2ee5f84

3 files changed

Lines changed: 39 additions & 2 deletions

File tree

src/app/endpoints/responses.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ def _queue_responses_splunk_event( # pylint: disable=too-many-arguments,too-man
204204
response_model=None,
205205
summary="Responses Endpoint Handler",
206206
)
207-
@authorize(Action.QUERY)
207+
@authorize(Action.RESPONSES)
208208
async def responses_endpoint_handler(
209209
request: Request,
210210
responses_request: ResponsesRequest,

src/models/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -991,6 +991,9 @@ class Action(str, Enum):
991991
# Access the query endpoint
992992
QUERY = "query"
993993

994+
# Access the responses endpoint
995+
RESPONSES = "responses"
996+
994997
# Access the streaming query endpoint
995998
STREAMING_QUERY = "streaming_query"
996999

tests/unit/app/endpoints/test_responses.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ def _patch_handle_non_streaming_common(
164164
def dummy_request_fixture() -> Request:
165165
"""Minimal FastAPI Request with authorized_actions for responses endpoint."""
166166
req = Request(scope={"type": "http", "headers": []})
167-
req.state.authorized_actions = {Action.QUERY, Action.READ_OTHERS_CONVERSATIONS}
167+
req.state.authorized_actions = {Action.RESPONSES, Action.READ_OTHERS_CONVERSATIONS}
168168
return req
169169

170170

@@ -636,6 +636,40 @@ async def test_tool_choice_none_without_tools_does_not_load_server_tools(
636636
assert call_kwargs["request"].tools is None
637637
assert call_kwargs["request"].tool_choice is None
638638

639+
@pytest.mark.asyncio
640+
async def test_responses_endpoint_rejects_without_responses_action(
641+
self,
642+
mocker: MockerFixture,
643+
) -> None:
644+
"""Verify that requests lacking Action.RESPONSES are rejected with 403.
645+
646+
Constructs a request whose authorized_actions includes Action.QUERY and
647+
Action.READ_OTHERS_CONVERSATIONS but NOT Action.RESPONSES, then asserts
648+
the @authorize(Action.RESPONSES) decorator raises HTTPException 403.
649+
"""
650+
req = Request(scope={"type": "http", "headers": []})
651+
req.state.authorized_actions = {Action.QUERY, Action.READ_OTHERS_CONVERSATIONS}
652+
653+
mock_role_resolver = mocker.AsyncMock()
654+
mock_role_resolver.resolve_roles = mocker.AsyncMock(return_value=set())
655+
656+
mock_access_resolver = mocker.Mock()
657+
mock_access_resolver.check_access.return_value = False
658+
659+
mocker.patch(
660+
"authorization.middleware.get_authorization_resolvers",
661+
return_value=(mock_role_resolver, mock_access_resolver),
662+
)
663+
664+
with pytest.raises(HTTPException) as exc_info:
665+
await responses_endpoint_handler(
666+
request=req,
667+
responses_request=ResponsesRequest(input="Hello"),
668+
auth=MOCK_AUTH,
669+
mcp_headers={},
670+
)
671+
assert exc_info.value.status_code == 403
672+
639673

640674
class TestHandleNonStreamingResponse:
641675
"""Unit tests for handle_non_streaming_response."""

0 commit comments

Comments
 (0)