Skip to content

Commit 4045245

Browse files
committed
fix(authz): register build agents as resources
1 parent b46c34a commit 4045245

2 files changed

Lines changed: 71 additions & 2 deletions

File tree

agentex/src/api/routes/agents.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ async def register_build(
236236
agents_use_case: DAgentsUseCase,
237237
authorization_service: DAuthorizationService,
238238
) -> Agent:
239-
"""Create a build-only agent row and grant the caller access to it."""
239+
"""Create a build-only agent row and register its authz resource."""
240240
await authorization_service.check(
241241
AgentexResource.agent("*"),
242242
AuthorizedOperationType.create,
@@ -252,7 +252,7 @@ async def register_build(
252252
)
253253
except ValueError as e:
254254
raise HTTPException(status_code=400, detail=str(e)) from e
255-
await authorization_service.grant(
255+
await authorization_service.register_resource(
256256
AgentexResource.agent(agent_entity.id),
257257
principal_context=request.principal_context,
258258
)
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
"""Route-level authz tests for agent build registration."""
2+
3+
from datetime import UTC, datetime
4+
from unittest.mock import AsyncMock, MagicMock
5+
6+
import pytest
7+
from src.api.routes.agents import register_build
8+
from src.api.schemas.agents import RegisterBuildRequest
9+
from src.api.schemas.authorization_types import AgentexResource, AuthorizedOperationType
10+
from src.domain.entities.agents import AgentEntity, AgentStatus
11+
12+
13+
def _agent() -> AgentEntity:
14+
now = datetime.now(tz=UTC)
15+
return AgentEntity(
16+
id="agent-123",
17+
name="build-agent",
18+
description="Created from build",
19+
status=AgentStatus.BUILD_ONLY,
20+
status_reason="Agent build registered; not yet deployed.",
21+
acp_url=None,
22+
created_at=now,
23+
updated_at=now,
24+
)
25+
26+
27+
@pytest.mark.unit
28+
@pytest.mark.asyncio
29+
async def test_register_build_registers_agent_resource() -> None:
30+
"""Build-time agent creation must call register_resource, not grant-only."""
31+
agents_use_case = MagicMock()
32+
agents_use_case.register_build = AsyncMock(return_value=_agent())
33+
authorization_service = MagicMock()
34+
authorization_service.check = AsyncMock(return_value=True)
35+
authorization_service.register_resource = AsyncMock(return_value=None)
36+
authorization_service.grant = AsyncMock(return_value=None)
37+
principal_context = {
38+
"account_id": "account-123",
39+
"user_id": "user-123",
40+
"api_key": "test-key",
41+
}
42+
43+
result = await register_build(
44+
request=RegisterBuildRequest(
45+
name="build-agent",
46+
description="Created from build",
47+
principal_context=principal_context,
48+
),
49+
agents_use_case=agents_use_case,
50+
authorization_service=authorization_service,
51+
)
52+
53+
assert result.id == "agent-123"
54+
authorization_service.check.assert_awaited_once_with(
55+
AgentexResource.agent("*"),
56+
AuthorizedOperationType.create,
57+
principal_context=principal_context,
58+
)
59+
agents_use_case.register_build.assert_awaited_once_with(
60+
name="build-agent",
61+
description="Created from build",
62+
registration_metadata=None,
63+
agent_input_type=None,
64+
)
65+
authorization_service.register_resource.assert_awaited_once_with(
66+
AgentexResource.agent("agent-123"),
67+
principal_context=principal_context,
68+
)
69+
authorization_service.grant.assert_not_awaited()

0 commit comments

Comments
 (0)