feat(runtime): bind remote and owned resources to authority

This commit is contained in:
Alexandre Teixeira
2026-10-02 03:00:46 +01:00
parent ba3e631d58
commit 571f685ad5
23 changed files with 2491 additions and 74 deletions
+397
View File
@@ -0,0 +1,397 @@
"""Backend selection is resolution, never an operation or resource grant."""
import asyncio
from dataclasses import replace
import json
from types import SimpleNamespace
from unittest.mock import AsyncMock
import pytest
from src.agent_runtime.authority import ExactOperation, OperationGrant, RequestAuthority, bind_request_authority
from src.agent_runtime.remote_resources import (
active_backend_operation, bind_backend_operation, bind_backend_for_operation,
configuration_incarnation, endpoint_identity, integration_resource, seal_backends,
)
from src.agent_runtime.resources import ExternalResource, NativeBackendResource, ResourceIdentityError
from src.mcp_manager import McpManager
from src.tool_approvals import ToolApprovalStore
from src.tool_capabilities import ToolRunSecurityContext, capabilities_for_action
from src.tool_types import ToolBlock
def grant(*tools, resources=None):
return RequestAuthority("remote-request", "alice", "s", "",
tuple(OperationGrant(t) for t in tools), backend_resources=resources)
async def dispatch(authority, tool, content="{}", **kwargs):
from src import tool_execution as execution
return await execution.execute_tool_block(ToolBlock(tool, content), owner=authority.owner,
session_id=authority.session_id, request_authority=authority,
security_context=kwargs.pop("security_context", execution.NO_TOOL_SECURITY_CONTEXT), **kwargs)
def approval(authority, tool, content="{}", **kwargs):
store = ToolApprovalStore()
pending = store.create(owner=authority.owner, session_id=authority.session_id, origin_run_id="run",
tool_name=tool, content=content, workspace=None, request_authority=authority,
external_untrusted_context_seen=True, capabilities=capabilities_for_action(tool, content), **kwargs)
return store.consume(pending.approval_id, decision="approve", owner=authority.owner, session_id=authority.session_id)
@pytest.fixture
def manager(monkeypatch):
from src import tool_execution as execution
value = McpManager()
monkeypatch.setattr(execution, "get_mcp_manager", lambda: value)
monkeypatch.setattr(execution, "_owner_is_admin", lambda owner: True)
return value
def connect(manager, server="alpha", tools=("read", "write"), url="https://example.test/mcp?token=SECRET"):
session = SimpleNamespace(call_tool=AsyncMock(return_value=SimpleNamespace(
content=[SimpleNamespace(text="remote result")], isError=False)))
manager._sessions[server] = session
manager._tools[server] = [{"name": tool} for tool in tools]
manager._resource_endpoints[server] = (endpoint_identity(url), configuration_incarnation(url))
manager._register_resource_connection(server, session)
return session
@pytest.mark.parametrize("kind", ["availability", "selection", "model_name", "legacy"])
async def test_remote_availability_does_not_create_resource_authority(manager, kind):
session = connect(manager)
authority = grant("mcp__alpha__read", resources=()) if kind != "model_name" else grant()
if kind == "legacy":
snapshot = grant("mcp__alpha__read").to_dict()
snapshot["version"] = 2
authority = RequestAuthority.from_dict(snapshot)
_, result = await dispatch(authority, "mcp__alpha__read")
assert result["exit_code"] == 1
session.call_tool.assert_not_awaited()
async def test_qualified_mcp_binds_exact_tool_and_backend(manager):
session = connect(manager)
authority = grant("mcp__alpha__read")
_, allowed = await dispatch(authority, "mcp__alpha__read", '{"record":"one"}')
assert allowed["exit_code"] == 0
session.call_tool.assert_awaited_once_with("read", {"record": "one"})
_, denied = await dispatch(replace(authority, grants=(OperationGrant("mcp__alpha__write"),)), "mcp__alpha__write")
assert denied["failure_kind"] == "resource_identity_denied"
assert active_backend_operation() is None
@pytest.mark.parametrize("change", ["session", "endpoint", "path", "query", "discovery"])
async def test_remote_identity_changes_invalidate_admission_and_exact_approval(manager, change):
old = connect(manager)
authority = grant("mcp__alpha__read")
exact = approval(authority, "mcp__alpha__read", '{"resource":"one"}')
assert exact.pending.backend_operation is not None
if change == "session":
new = connect(manager)
elif change == "discovery":
manager._tools["alpha"] = [{"name": "write"}]
else:
url = {"endpoint": "https://other.test/mcp", "path": "https://example.test/other",
"query": "https://example.test/mcp?token=OTHER"}[change]
manager._resource_endpoints["alpha"] = (endpoint_identity(url), configuration_incarnation(url))
for extra in ({}, {"exact_approval": exact, "security_context": ToolRunSecurityContext(external_untrusted_context_seen=True)}):
_, result = await dispatch(authority, "mcp__alpha__read", '{"resource":"one"}', **extra)
assert result["failure_kind"] == "resource_identity_denied"
old.call_tool.assert_not_awaited()
if change == "session":
new.call_tool.assert_not_awaited()
assert not exact._claimed
@pytest.mark.parametrize("change", ["tool", "selector", "request", "owner", "session"])
async def test_remote_approval_is_bound_to_operation_and_request(manager, change):
session = connect(manager)
authority = grant("mcp__alpha__read", "mcp__alpha__write")
exact = approval(authority, "mcp__alpha__read", '{"record":"one"}')
tool, content = "mcp__alpha__read", '{"record":"one"}'
if change == "tool":
tool = "mcp__alpha__write"
elif change == "selector":
content = '{"record":"two"}'
else:
authority = replace(authority, **{"request": {"request_id": "other"}, "owner": {"owner": "bob"},
"session": {"session_id": "other"}}[change])
_, result = await dispatch(authority, tool, content, exact_approval=exact,
security_context=ToolRunSecurityContext(external_untrusted_context_seen=True))
assert result["exit_code"] == 1
session.call_tool.assert_not_awaited()
assert not exact._claimed
async def test_legacy_exact_remote_approval_is_one_use_and_does_not_mint_backend_scope(manager):
session = connect(manager)
authority = grant(resources=())
exact = approval(authority, "mcp__alpha__read")
security = ToolRunSecurityContext(external_untrusted_context_seen=True)
_, result = await dispatch(authority, "mcp__alpha__read", exact_approval=exact, security_context=security)
assert result["exit_code"] == 0
_, replay = await dispatch(authority, "mcp__alpha__read", exact_approval=exact, security_context=security)
assert replay["exit_code"] == 1
assert session.call_tool.await_count == 1 and authority.backend_resources == ()
assert "backend_operation" not in exact.pending.public_payload()
async def test_child_cannot_use_parent_ungranted_backend_or_exact_approval(manager):
session = connect(manager)
parent = grant("mcp__alpha__read", resources=())
child = grant("mcp__alpha__read")
exact = approval(child, "mcp__alpha__read")
with bind_request_authority(parent):
_, denied = await dispatch(child, "mcp__alpha__read", exact_approval=exact,
security_context=ToolRunSecurityContext(external_untrusted_context_seen=True))
assert denied["failure_kind"] == "resource_identity_denied"
session.call_tool.assert_not_awaited()
def test_remote_snapshots_exclude_credentials_and_cannot_claim_containment(manager):
connect(manager, url="https://user:PASSWORD@example.test/SECRET_PATH?token=TOKEN")
authority = grant("mcp__alpha__read")
snapshot = json.dumps(authority.to_dict())
assert all(secret not in snapshot for secret in ("PASSWORD", "SECRET_PATH", "TOKEN", "user:"))
resource = authority.backend_resources[0]
assert resource.endpoint_id == "https://example.test"
assert resource.external is True and resource.contained is False
assert RequestAuthority.from_dict(json.loads(snapshot)) == authority
with pytest.raises(ValueError):
replace(resource, contained=True)
async def test_mcp_revalidates_at_transport_and_never_retries_bound_calls(manager):
manager._resource_owners["memory"] = "alice"
session = connect(manager, server="memory")
authority = grant("mcp__memory__read")
operation = ExactOperation.normalize("mcp__memory__read", "{}")
bound = bind_backend_for_operation(authority, operation)
reconnect = AsyncMock()
manager._reconnect_builtin = reconnect
session.call_tool.side_effect = RuntimeError("disconnected")
with bind_backend_operation(bound):
result = await manager.call_tool(operation.tool, {})
assert result["exit_code"] == 1
replacement = connect(manager, server="memory")
result = await manager.call_tool(operation.tool, {})
assert result["failure_kind"] == "resource_identity_denied"
replacement.call_tool.assert_not_awaited()
reconnect.assert_not_awaited()
@pytest.mark.parametrize("owner", ["", "bob"])
async def test_builtin_memory_backend_requires_its_configured_owner(manager, owner):
manager._resource_owners["memory"] = owner
session = connect(manager, server="memory")
_, result = await dispatch(grant("mcp__memory__read"), "mcp__memory__read")
assert result["failure_kind"] == "resource_identity_denied"
session.call_tool.assert_not_awaited()
async def test_native_filesystem_cannot_be_redirected_through_mcp(manager, tmp_path):
session = connect(manager, server="filesystem", tools=("read_file",))
(tmp_path / "a").write_text("native contents")
authority = RequestAuthority("request", "alice", "s", str(tmp_path), (OperationGrant("read_file"),))
from src import tool_execution as execution
_, result = await execution.execute_tool_block(ToolBlock("read_file", "a"), owner="alice", session_id="s",
workspace=str(tmp_path), request_authority=authority, security_context=execution.NO_TOOL_SECURITY_CONTEXT)
assert result["output"] == "native contents"
assert isinstance(authority.backend_resources[0], NativeBackendResource)
session.call_tool.assert_not_awaited()
@pytest.mark.parametrize("change", ["alias", "endpoint", "secret_path"])
async def test_integration_alias_and_configuration_cannot_retarget_approval(monkeypatch, change):
from src import integrations
rows = [{"id": "one", "name": "service", "base_url": "https://service.test/SECRET", "enabled": True}]
monkeypatch.setattr(integrations, "load_integrations", lambda: rows)
authority = grant("api_call", resources=(integration_resource(rows[0]),))
exact = approval(authority, "api_call", '{"integration":"service","path":"/record/one"}')
assert exact.pending.backend_operation.resource.server_id == "one"
assert "SECRET" not in json.dumps(authority.to_dict())
if change == "alias":
rows[:] = [{**rows[0], "id": "two"}]
else:
rows[0]["base_url"] = "https://other.test/SECRET" if change == "endpoint" else "https://service.test/OTHER"
from src import tool_execution as execution
handler = AsyncMock()
monkeypatch.setattr(execution, "_execute_tool_block_impl", handler)
_, result = await dispatch(authority, "api_call", exact.pending.content, exact_approval=exact,
security_context=ToolRunSecurityContext(external_untrusted_context_seen=True))
assert result["failure_kind"] == "resource_identity_denied"
handler.assert_not_awaited()
@pytest.mark.parametrize("error", [None, RuntimeError, asyncio.CancelledError])
async def test_scoped_bridge_context_restores_and_replacement_is_ungranted(monkeypatch, error):
from src import tool_execution as execution
seen = []
async def route(*args):
seen.append(active_backend_operation().resource)
if error:
raise error("stop")
return "bridge", {"exit_code": 0}
bridge = execution.AgentExecutionBridge(route, frozenset({"host_shell"}), name="test")
monkeypatch.setattr(execution, "_owner_is_admin", lambda owner: True)
with execution.bind_execution_bridge(bridge):
authority = grant("host_shell")
parent_bound = bind_backend_for_operation(authority, ExactOperation.normalize("host_shell", "parent"))
with bind_backend_operation(parent_bound):
if error is asyncio.CancelledError:
with pytest.raises(error):
await dispatch(authority, "host_shell", "pwd")
else:
await dispatch(authority, "host_shell", "pwd")
assert active_backend_operation() is parent_bound
assert active_backend_operation() is None
assert seen[0].external and not seen[0].contained
with execution.bind_execution_bridge(replace(bridge)):
_, denied = await dispatch(authority, "host_shell", "pwd")
assert denied["failure_kind"] == "resource_identity_denied"
async def test_tui_endpoint_is_registered_only_at_trusted_admission(monkeypatch):
from src import tool_execution as execution
context = {"surface": "odysseus-tui", "host_shell_bridge": {"url": "http://127.0.0.1:17654/run", "token": "TOKEN"}}
authority = grant("bash", resources=(NativeBackendResource("bash"),))
_, denied = await dispatch(authority, "bash", "pwd", client_runtime_context=context)
assert denied["failure_kind"] == "resource_identity_denied"
authority = replace(authority, backend_resources=seal_backends(["bash"], context=context, owner="alice"))
monkeypatch.setattr(execution, "_bridge_post", AsyncMock(return_value={"exit_code": 0, "stdout": "external", "stderr": ""}))
monkeypatch.setattr(execution, "_owner_is_admin", lambda owner: True)
_, allowed = await dispatch(authority, "bash", "pwd", client_runtime_context=context)
assert allowed["exit_code"] == 0
context["host_shell_bridge"]["url"] = "http://127.0.0.1:17655/run"
_, denied = await dispatch(authority, "bash", "pwd", client_runtime_context=context)
assert denied["failure_kind"] == "resource_identity_denied"
@pytest.mark.parametrize("change", [None, "url", "token"])
async def test_http_bridge_factory_and_admission_share_config_identity(monkeypatch, change):
from src import tool_execution as execution
from routes.chat_routes import _external_execution_bridge
context = {"external_execution_bridge": {"url": "http://127.0.0.1:17654/execute",
"token": "SECRET_TOKEN", "supported_tools": ["host_shell"]}}
authority = grant("host_shell", resources=seal_backends(["host_shell"], context=context, owner="alice"))
if change:
context["external_execution_bridge"][change] = "http://127.0.0.1:17655/execute" if change == "url" else "OTHER_TOKEN"
bridge = _external_execution_bridge(context)
route = AsyncMock(return_value=("bridge", {"exit_code": 0}))
bridge = replace(bridge, route_tool=route)
monkeypatch.setattr(execution, "_owner_is_admin", lambda owner: True)
with execution.bind_execution_bridge(bridge):
_, result = await dispatch(authority, "host_shell", "pwd", client_runtime_context=context)
if change:
assert result["failure_kind"] == "resource_identity_denied"
route.assert_not_awaited()
else:
assert result["exit_code"] == 0
route.assert_awaited_once()
assert "SECRET_TOKEN" not in json.dumps(authority.to_dict())
async def test_backend_alias_cannot_retarget_a_legacy_tool_after_approval(manager, monkeypatch):
from src import tool_execution as execution
first = connect(manager, server="web_fetch", tools=("web_fetch",))
second = connect(manager, server="other", tools=("fetch",))
authority = grant("web_fetch")
exact = approval(authority, "web_fetch", "https://page.test/one")
monkeypatch.setitem(execution._MCP_TOOL_MAP, "web_fetch", ("other", "fetch"))
_, result = await dispatch(authority, "web_fetch", exact.pending.content, exact_approval=exact,
security_context=ToolRunSecurityContext(external_untrusted_context_seen=True))
assert result["failure_kind"] == "resource_identity_denied"
first.call_tool.assert_not_awaited()
second.call_tool.assert_not_awaited()
async def test_native_backend_is_pinned_when_mcp_becomes_available(manager, monkeypatch):
from src import tool_execution as execution
authority = grant("web_fetch")
session = connect(manager, server="web_fetch", tools=("web_fetch",))
fallback = AsyncMock(return_value={"output": "native", "exit_code": 0})
monkeypatch.setattr(execution, "_direct_fallback", fallback)
_, result = await dispatch(authority, "web_fetch", "https://page.test/one")
assert result["output"] == "native"
session.call_tool.assert_not_awaited()
async def test_integration_inventory_does_not_supply_backend_scope(monkeypatch):
from src import integrations
rows = [{"id": "one", "name": "service", "base_url": "https://service.test", "enabled": True}]
monkeypatch.setattr(integrations, "load_integrations", lambda: rows)
authority = grant("api_call")
assert authority.backend_resources == ()
_, denied = await dispatch(authority, "api_call", '{"integration":"service"}')
assert denied["failure_kind"] == "resource_identity_denied"
async def test_external_bash_marker_cannot_switch_to_local_background_execution(manager, monkeypatch):
from src import bg_jobs
session = connect(manager, server="bash", tools=("bash",))
launch = AsyncMock()
monkeypatch.setattr(bg_jobs, "launch", launch)
_, result = await dispatch(grant("bash"), "bash", "#!bg\npwd")
assert result["exit_code"] == 0
assert session.call_tool.await_count == 1
launch.assert_not_called()
@pytest.mark.parametrize("alias", ["host_shell_bridge", "hostShellBridge"])
def test_host_shell_bridge_aliases_resolve_to_one_external_identity(alias):
context = {"surface": "odysseus-tui", alias: {"url": "http://127.0.0.1:17654/run", "token": "TOKEN"}}
resources = seal_backends(["host_shell"], context=context, owner="alice")
assert len(resources) == 1 and isinstance(resources[0], ExternalResource)
assert resources[0].external and not resources[0].contained
async def test_host_shell_cannot_reconstruct_an_unsealed_external_backend(monkeypatch):
from src import tool_execution as execution
handler = AsyncMock()
monkeypatch.setattr(execution, "_execute_tool_block_impl", handler)
_, result = await dispatch(grant("host_shell"), "host_shell", "pwd")
assert result["failure_kind"] == "resource_identity_denied"
handler.assert_not_awaited()
async def test_http_backend_without_bound_producer_cannot_fall_back_to_native(monkeypatch):
from src import tool_execution as execution
context = {"external_execution_bridge": {"url": "http://127.0.0.1:17654/execute",
"token": "TOKEN", "supported_tools": ["bash"]}}
authority = grant("bash", resources=seal_backends(["bash"], context=context, owner="alice"))
fallback = AsyncMock()
monkeypatch.setattr(execution, "_direct_fallback", fallback)
_, denied = await dispatch(authority, "bash", "pwd", client_runtime_context=context)
assert denied["failure_kind"] == "resource_identity_denied"
fallback.assert_not_awaited()
async def test_resumed_child_approval_cannot_restore_excluded_backend(manager):
session = connect(manager)
child = grant("mcp__alpha__read", resources=()).intersect(grant("mcp__alpha__read"))
exact = approval(child, "mcp__alpha__read")
assert exact.pending.backend_operation is None
_, result = await dispatch(replace(child, inherited=False), "mcp__alpha__read", exact_approval=exact,
security_context=ToolRunSecurityContext(external_untrusted_context_seen=True))
assert result["failure_kind"] == "resource_identity_denied"
session.call_tool.assert_not_awaited()
async def test_integration_executes_server_resolved_id_and_revalidates_loaded_configuration(monkeypatch):
from src import integrations, tool_execution as execution
row = {"id": "one", "name": "service", "base_url": "https://service.test", "enabled": True}
monkeypatch.setattr(integrations, "load_integrations", lambda: [dict(row)])
monkeypatch.setattr(execution, "_owner_is_admin", lambda owner: True)
authority = grant("api_call", resources=(integration_resource(row),))
producer = AsyncMock(return_value={"output": "remote", "exit_code": 0})
original = integrations.execute_api_call
monkeypatch.setattr(integrations, "execute_api_call", producer)
_, allowed = await dispatch(authority, "api_call", '{"integration":"service","method":"GET","path":"/record/one"}')
assert allowed["exit_code"] == 0
assert producer.await_args.args == ("one", "GET", "/record/one")
monkeypatch.setattr(integrations, "execute_api_call", original)
monkeypatch.setattr(integrations, "_find_integration", lambda identifier: {**row, "base_url": "https://other.test"})
_, denied = await dispatch(authority, "api_call", '{"integration":"service","path":"/record/one"}')
assert denied["failure_kind"] == "resource_identity_denied"