feat(runtime): enforce server request authority

This commit is contained in:
Alexandre Teixeira
2026-10-01 18:35:41 +01:00
parent 05c6cfcfa1
commit 9d0257134f
37 changed files with 1683 additions and 39 deletions
+10
View File
@@ -25,6 +25,7 @@ from src.tool_approval_scopes import (
scope_for_decision,
)
from src.tool_capabilities import ToolCapabilities, capabilities_for_action
from src.agent_runtime.authority import RequestAuthority
DEFAULT_APPROVAL_TTL_SECONDS = 10 * 60
@@ -117,6 +118,7 @@ def _binding_payload(
continuation_query: Any,
effects: tuple[str, ...],
result_integrity: str,
request_authority: RequestAuthority | None = None,
) -> dict[str, Any]:
return {
"owner": _normalized_owner(owner),
@@ -137,6 +139,7 @@ def _binding_payload(
"continuation_query": _normalized_continuation_query(continuation_query),
"effects": list(effects),
"result_integrity": str(result_integrity),
"request_authority": request_authority.to_dict() if request_authority is not None else None,
}
@@ -165,6 +168,7 @@ class PendingToolApproval:
# The originating user request is internal continuation context only; it
# is never displayed or treated as authorization for the sealed action.
request_text: str = ""
request_authority: RequestAuthority | None = None
def public_payload(self, *, reason: str | None = None) -> dict[str, Any]:
return {
@@ -273,6 +277,7 @@ class ExactToolApproval:
continuation_query=self.pending.continuation_query,
effects=effects,
result_integrity=result_integrity,
request_authority=self.pending.request_authority,
)
return _canonical_digest(expected) == self.pending.digest
@@ -356,7 +361,10 @@ class ToolApprovalStore:
external_untrusted_context_seen: bool,
capabilities: ToolCapabilities,
request_text: Any = "",
request_authority: RequestAuthority | None = None,
) -> PendingToolApproval:
if request_authority is not None and not isinstance(request_authority, RequestAuthority):
raise TypeError("Approval authority must be server-owned RequestAuthority")
now = time.time()
effects = tuple(sorted(effect.value for effect in capabilities.effects))
result_integrity = capabilities.result_integrity.value
@@ -375,6 +383,7 @@ class ToolApprovalStore:
continuation_query=continuation_query,
effects=effects,
result_integrity=result_integrity,
request_authority=request_authority,
)
pending = PendingToolApproval(
approval_id=secrets.token_urlsafe(32),
@@ -398,6 +407,7 @@ class ToolApprovalStore:
selected_tools=tuple(payload["selected_tools"]),
continuation_query=payload["continuation_query"],
request_text=str(request_text or ""),
request_authority=request_authority,
)
with self._lock:
self._purge_expired_locked(now)