mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-11-05 12:42:20 +01:00
fix(agent): close untrusted-context gate bypasses
This commit is contained in:
@@ -12,6 +12,13 @@ import pytest
|
||||
from src.preset_manager import PresetManager
|
||||
|
||||
|
||||
async def _execute_without_run_context(execute_tool_block, *args, **kwargs):
|
||||
from src.tool_execution import NO_TOOL_SECURITY_CONTEXT
|
||||
|
||||
kwargs.setdefault("security_context", NO_TOOL_SECURITY_CONTEXT)
|
||||
return await execute_tool_block(*args, **kwargs)
|
||||
|
||||
|
||||
class _FakeColumn:
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
@@ -494,7 +501,8 @@ async def test_admin_agent_tools_require_admin(monkeypatch):
|
||||
monkeypatch.setattr(auth_mod, "AuthManager", lambda: FakeAuth())
|
||||
|
||||
for tool_name in ("manage_tokens", "app_api", "serve_preset"):
|
||||
desc, result = await execute_tool_block(
|
||||
desc, result = await _execute_without_run_context(
|
||||
execute_tool_block,
|
||||
SimpleNamespace(tool_type=tool_name, content='{"action":"create","name":"bad"}'),
|
||||
owner="regular-user",
|
||||
)
|
||||
@@ -717,7 +725,8 @@ async def test_public_agent_policy_blocks_sensitive_tools(monkeypatch):
|
||||
"mark_email_read", "bulk_email", "download_attachment",
|
||||
)
|
||||
for tool_name in bare_email_tools + ("read_file", "mcp__email__send_email"):
|
||||
desc, result = await execute_tool_block(
|
||||
desc, result = await _execute_without_run_context(
|
||||
execute_tool_block,
|
||||
SimpleNamespace(tool_type=tool_name, content="{}"),
|
||||
owner="regular-user",
|
||||
)
|
||||
@@ -747,7 +756,8 @@ async def test_disabled_qualified_email_tool_blocks_bare_alias(monkeypatch):
|
||||
# …and a bare denylist entry blocks the qualified spelling.
|
||||
("mcp__email__delete_email", {"delete_email"}),
|
||||
):
|
||||
desc, result = await execute_tool_block(
|
||||
desc, result = await _execute_without_run_context(
|
||||
execute_tool_block,
|
||||
SimpleNamespace(tool_type=bare, content="{}"),
|
||||
owner="admin-user",
|
||||
disabled_tools=disabled,
|
||||
@@ -770,7 +780,8 @@ async def test_tool_policy_qualified_email_block_covers_bare_alias(monkeypatch):
|
||||
monkeypatch.setattr(tool_execution, "get_mcp_manager", fail_get_mcp_manager)
|
||||
|
||||
policy = ToolPolicy(disabled_tools=frozenset({"mcp__email__send_email"}))
|
||||
desc, result = await execute_tool_block(
|
||||
desc, result = await _execute_without_run_context(
|
||||
execute_tool_block,
|
||||
SimpleNamespace(tool_type="send_email", content="{}"),
|
||||
owner="admin-user",
|
||||
tool_policy=policy,
|
||||
@@ -872,7 +883,8 @@ async def test_bare_email_dispatch_rejects_non_object_json_args(monkeypatch):
|
||||
mcp = _FakeMcpManager()
|
||||
monkeypatch.setattr(tool_execution, "get_mcp_manager", lambda: mcp)
|
||||
|
||||
desc, result = await execute_tool_block(
|
||||
desc, result = await _execute_without_run_context(
|
||||
execute_tool_block,
|
||||
SimpleNamespace(tool_type="bulk_email", content='["10", "11"]'),
|
||||
owner="admin-user",
|
||||
)
|
||||
@@ -895,7 +907,8 @@ async def test_bare_email_dispatch_rejects_invalid_json_body(monkeypatch):
|
||||
for bad_body in ('{account: "work"}', "account: work"):
|
||||
mcp = _FakeMcpManager()
|
||||
monkeypatch.setattr(tool_execution, "get_mcp_manager", lambda: mcp)
|
||||
desc, result = await execute_tool_block(
|
||||
desc, result = await _execute_without_run_context(
|
||||
execute_tool_block,
|
||||
SimpleNamespace(tool_type="list_emails", content=bad_body),
|
||||
owner="admin-user",
|
||||
)
|
||||
@@ -972,7 +985,7 @@ async def test_write_file_inline_json_args(monkeypatch):
|
||||
from src.tool_parsing import parse_tool_blocks
|
||||
blocks = parse_tool_blocks('```write_file {"path": "/tmp/wf.txt", "content": "hi"}\n```')
|
||||
for b in blocks:
|
||||
await execute_tool_block(b, owner="admin")
|
||||
await _execute_without_run_context(execute_tool_block, b, owner="admin")
|
||||
|
||||
assert captured.get("path") == "/tmp/wf.txt", (
|
||||
f"write_file did not decode inline JSON args; got path {captured.get('path')!r}"
|
||||
@@ -996,7 +1009,8 @@ async def test_plan_mode_blocks_mutating_email_aliases_without_mcp_inventory(mon
|
||||
|
||||
for tool_name in ("draft_email", "draft_email_reply", "ai_draft_email_reply",
|
||||
"download_attachment", "send_email", "delete_email", "unsubscribe_email"):
|
||||
desc, result = await execute_tool_block(
|
||||
desc, result = await _execute_without_run_context(
|
||||
execute_tool_block,
|
||||
SimpleNamespace(tool_type=tool_name, content="{}"),
|
||||
owner="admin-user",
|
||||
disabled_tools=denied,
|
||||
@@ -1004,7 +1018,8 @@ async def test_plan_mode_blocks_mutating_email_aliases_without_mcp_inventory(mon
|
||||
assert result["exit_code"] == 1, tool_name
|
||||
assert mcp.calls == [], f"{tool_name} reached the MCP server in plan mode"
|
||||
|
||||
desc, result = await execute_tool_block(
|
||||
desc, result = await _execute_without_run_context(
|
||||
execute_tool_block,
|
||||
SimpleNamespace(tool_type="search_emails", content='{"query": "x"}'),
|
||||
owner="admin-user",
|
||||
disabled_tools=denied,
|
||||
@@ -1015,7 +1030,8 @@ async def test_plan_mode_blocks_mutating_email_aliases_without_mcp_inventory(mon
|
||||
]
|
||||
|
||||
mcp.calls.clear()
|
||||
desc, result = await execute_tool_block(
|
||||
desc, result = await _execute_without_run_context(
|
||||
execute_tool_block,
|
||||
SimpleNamespace(tool_type="scan_email_unsubscribes", content='{"limit": 1}'),
|
||||
owner="admin-user",
|
||||
disabled_tools=denied,
|
||||
@@ -1037,7 +1053,8 @@ async def test_bare_email_dispatch_empty_content_calls_with_empty_args(monkeypat
|
||||
mcp = _FakeMcpManager()
|
||||
monkeypatch.setattr(tool_execution, "get_mcp_manager", lambda: mcp)
|
||||
|
||||
desc, result = await execute_tool_block(
|
||||
desc, result = await _execute_without_run_context(
|
||||
execute_tool_block,
|
||||
SimpleNamespace(tool_type="list_email_accounts", content=""),
|
||||
owner="admin-user",
|
||||
)
|
||||
@@ -1064,7 +1081,8 @@ async def test_email_mcp_non_object_args_fail_before_dispatch(monkeypatch):
|
||||
monkeypatch.setattr(tool_execution, "_owner_is_admin", lambda owner: True)
|
||||
monkeypatch.setattr(tool_execution, "get_mcp_manager", lambda: fake)
|
||||
|
||||
desc, result = await execute_tool_block(
|
||||
desc, result = await _execute_without_run_context(
|
||||
execute_tool_block,
|
||||
SimpleNamespace(tool_type="mcp__email__list_emails", content='["INBOX"]'),
|
||||
owner="alice",
|
||||
)
|
||||
@@ -1092,7 +1110,8 @@ async def test_email_mcp_dispatch_includes_hidden_owner(monkeypatch):
|
||||
monkeypatch.setattr(tool_execution, "_owner_is_admin", lambda owner: True)
|
||||
monkeypatch.setattr(tool_execution, "get_mcp_manager", lambda: fake)
|
||||
|
||||
desc, result = await execute_tool_block(
|
||||
desc, result = await _execute_without_run_context(
|
||||
execute_tool_block,
|
||||
SimpleNamespace(tool_type="mcp__email__list_emails", content='{"folder":"INBOX"}'),
|
||||
owner="alice",
|
||||
)
|
||||
@@ -1113,7 +1132,8 @@ async def test_bare_email_mcp_dispatch_includes_hidden_owner(monkeypatch):
|
||||
monkeypatch.setattr(tool_execution, "_owner_is_admin", lambda owner: True)
|
||||
monkeypatch.setattr(tool_execution, "get_mcp_manager", lambda: fake)
|
||||
|
||||
desc, result = await execute_tool_block(
|
||||
desc, result = await _execute_without_run_context(
|
||||
execute_tool_block,
|
||||
SimpleNamespace(tool_type="list_emails", content='{"folder":"INBOX"}'),
|
||||
owner="alice",
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user