mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-28 00:32:22 +01:00
feat(security): apply audited PR #6738 remediations and test hardening
- 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
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
"""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()
|
||||
Reference in New Issue
Block a user