mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-28 08:42:24 +01:00
- Enforce vision probe SSRF safe local host validation, SafeProbeBackend TOCTOU elimination, and session owner authorization - Authorize session titling endpoints against registered owner configuration - Sanitize sensitive metadata logging from agent loop debug logs - Add async non-blocking execution for spec router tools and thinking decisions - Harden email cache invalidation fencing and thread-safe mutation - Add regression test suites for legacy browser authority, spec contracts, spec router request scoping, and task MCP delivery
74 lines
3.5 KiB
Python
74 lines
3.5 KiB
Python
"""Scheduled MCP delivery must use the task owner's mailbox and report failure."""
|
|
from types import SimpleNamespace
|
|
from unittest.mock import AsyncMock
|
|
|
|
import pytest
|
|
|
|
from src.task_scheduler import TaskScheduler
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_mcp_delivery_uses_task_owner_mailbox(monkeypatch):
|
|
calls = []
|
|
monkeypatch.setattr('routes.email_helpers._get_email_config',
|
|
lambda **kwargs: calls.append(kwargs) or {'from_address': 'alice@example.test'})
|
|
manager = SimpleNamespace(call_tool=AsyncMock(return_value={'exit_code': 0, 'stdout': 'Sent email to alice@example.test'}))
|
|
monkeypatch.setattr('src.tool_utils.get_mcp_manager', lambda: manager)
|
|
task = SimpleNamespace(id='task', name='Digest', owner='alice')
|
|
await TaskScheduler(None)._deliver_via_mcp('mcp__email__send_email', task, 'content')
|
|
assert calls == [{'owner': 'alice'}]
|
|
assert manager.call_tool.await_args.args[1]['to'] == 'alice@example.test'
|
|
assert manager.call_tool.await_args.args[1]['_odysseus_owner'] == 'alice'
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
@pytest.mark.parametrize('output', [
|
|
{'exit_code': 1, 'stderr': 'failed'},
|
|
{'error': 'not connected', 'exit_code': 1},
|
|
{'exit_code': 0, 'stdout': 'Error: SMTP failed'},
|
|
{'exit_code': 0, 'stdout': 'Draft staged for approval. Nothing has been sent yet.'},
|
|
{},
|
|
None,
|
|
])
|
|
async def test_mcp_delivery_failure_is_reported(monkeypatch, output):
|
|
monkeypatch.setattr('routes.email_helpers._get_email_config', lambda **kwargs: {})
|
|
manager = SimpleNamespace(call_tool=AsyncMock(return_value=output))
|
|
monkeypatch.setattr('src.tool_utils.get_mcp_manager', lambda: manager)
|
|
task = SimpleNamespace(id='task', name='Digest', owner='alice@example.test')
|
|
with pytest.raises(RuntimeError):
|
|
await TaskScheduler(None)._deliver_via_mcp('mcp__email__send_email', task, 'content')
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_generic_mcp_delivery_reports_text_errors(monkeypatch):
|
|
monkeypatch.setattr('routes.email_helpers._get_email_config', lambda **kwargs: {})
|
|
manager = SimpleNamespace(call_tool=AsyncMock(return_value={'exit_code': 0, 'stdout': 'Error: delivery failed'}))
|
|
monkeypatch.setattr('src.tool_utils.get_mcp_manager', lambda: manager)
|
|
task = SimpleNamespace(id='task', name='Digest', owner='alice@example.test')
|
|
with pytest.raises(RuntimeError):
|
|
await TaskScheduler(None)._deliver_via_mcp('mcp__custom__send', task, 'content')
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_authenticated_ownerless_action_is_not_executed(monkeypatch):
|
|
from src import builtin_actions
|
|
monkeypatch.setenv('AUTH_ENABLED', 'true')
|
|
action = AsyncMock(return_value=('done', True))
|
|
monkeypatch.setitem(builtin_actions.BUILTIN_ACTIONS, 'test_action', action)
|
|
task = SimpleNamespace(id='task', name='job', owner=None, action='test_action',
|
|
prompt='', task_type='action')
|
|
with pytest.raises(RuntimeError):
|
|
await TaskScheduler(None)._execute_action(task)
|
|
action.assert_not_awaited()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_authenticated_ownerless_mcp_delivery_is_not_executed(monkeypatch):
|
|
monkeypatch.setenv('AUTH_ENABLED', 'true')
|
|
manager = SimpleNamespace(call_tool=AsyncMock())
|
|
monkeypatch.setattr('src.tool_utils.get_mcp_manager', lambda: manager)
|
|
task = SimpleNamespace(id='task', name='job', owner=None)
|
|
with pytest.raises(RuntimeError):
|
|
await TaskScheduler(None)._deliver_via_mcp('mcp__email__send_email', task, 'content')
|
|
manager.call_tool.assert_not_awaited()
|