@@ -121,7 +121,20 @@ async def _authorize_target_read_if_present(
121121 request : Request ,
122122 context : dict [str , str ] | None ,
123123) -> Principal | None :
124- """Require target read authorization before returning target-merged controls."""
124+ """Require target read authorization before returning target-merged controls.
125+
126+ Agent endpoints that accept optional target context have two separate
127+ authorization decisions:
128+
129+ - the endpoint operation itself (for example, ``agents.create``), whose
130+ result is exposed to the route as ``principal``;
131+ - the target binding read (``control_bindings.read``), whose result is
132+ exposed as ``target_principal``.
133+
134+ Keeping the results separate lets the route verify that the caller's
135+ namespace and the target's resolved namespace agree before merging
136+ target-bound controls into the response.
137+ """
125138 if context is None :
126139 return None
127140 return await get_authorizer (Operation .CONTROL_BINDINGS_READ ).authorize (
@@ -545,7 +558,8 @@ async def init_agent(
545558 Args:
546559 request: Agent metadata and step schemas
547560 db: Database session (injected)
548- principal: Authorized request principal
561+ principal: Authorized request principal for the agent create operation
562+ target_principal: Optional principal from the target binding read check
549563
550564 Returns:
551565 InitAgentResponse with created flag and the effective controls
@@ -1596,7 +1610,8 @@ async def list_agent_controls(
15961610 target_type: Optional opaque target kind (paired with target_id)
15971611 target_id: Optional opaque target identifier (paired with target_type)
15981612 db: Database session (injected)
1599- principal: Authorized request principal
1613+ principal: Authorized request principal for the agent read operation
1614+ target_principal: Optional principal from the target binding read check
16001615
16011616 Returns:
16021617 AgentControlsResponse with controls matching the requested state filters
0 commit comments