hermes-agent/tests/gateway/test_matrix_exec_approval.py
alt-glitch 2bd9c9b881 opentui(phase3): launcher integration — HERMES_TUI_ENGINE dual-engine
hermes --tui launches the native OpenTUI engine (Bun) when
HERMES_TUI_ENGINE=opentui (env) or display.tui_engine=opentui (config);
Ink stays the default and the shipping path is untouched.

- _resolve_tui_engine() (env > config > ink); refuses opentui on
  Windows/Termux (no Bun) -> falls back to ink with a notice.
- _make_opentui_argv() -> [bun, src/entry.real.tsx] (no build step).
- _bun_bin() with HERMES_BUN override.
- Branch at top of _make_tui_argv BEFORE _ensure_tui_node (Bun-only host
  must not bootstrap Node).
- Gate _launch_tui NODE_OPTIONS/--max-old-space-size on engine==ink (Bun
  is JSC; the V8 flag errors/ignores).

Verified end-to-end via tmux: real hermes --tui -> Bun -> OpenTUI ->
real Python gateway streamed a real reply. No-flag default still ink.
2026-06-08 11:11:54 +00:00

60 lines
2.6 KiB
Python

import types
import pytest
from unittest.mock import AsyncMock, patch
from gateway.config import PlatformConfig
class TestMatrixExecApprovalReactions:
@pytest.mark.asyncio
async def test_send_exec_approval_registers_prompt_and_seeds_reactions(self, monkeypatch):
monkeypatch.setenv("MATRIX_ALLOWED_USERS", "@liizfq:liizfq.top")
from gateway.platforms.matrix import MatrixAdapter
adapter = MatrixAdapter(PlatformConfig(enabled=True, token="tok", extra={"homeserver": "https://matrix.example.org"}))
adapter._client = types.SimpleNamespace()
adapter.send = AsyncMock(return_value=types.SimpleNamespace(success=True, message_id="$evt1"))
adapter._send_reaction = AsyncMock(return_value="$r")
result = await adapter.send_exec_approval(
chat_id="!room:example.org",
command="rm -rf /tmp/test",
session_key="sess-1",
description="dangerous",
)
assert result.success is True
assert adapter._approval_prompt_by_session["sess-1"] == "$evt1"
assert adapter._approval_prompts_by_event["$evt1"].session_key == "sess-1"
assert adapter._send_reaction.await_count == 2
emojis = [call.args[2] for call in adapter._send_reaction.await_args_list]
assert emojis == ["", ""]
@pytest.mark.asyncio
async def test_reaction_resolves_pending_approval(self, monkeypatch):
monkeypatch.setenv("MATRIX_ALLOWED_USERS", "@liizfq:liizfq.top")
from gateway.platforms.matrix import MatrixAdapter, _MatrixApprovalPrompt
adapter = MatrixAdapter(PlatformConfig(enabled=True, token="tok", extra={"homeserver": "https://matrix.example.org"}))
# Resolve user_id so _is_self_sender doesn't defensively drop all traffic (#15763).
adapter._user_id = "@bot:example.org"
adapter._approval_prompts_by_event["$target"] = _MatrixApprovalPrompt(
session_key="sess-1", chat_id="!room:example.org", message_id="$target"
)
adapter._approval_prompt_by_session["sess-1"] = "$target"
content = {"m.relates_to": {"event_id": "$target", "key": ""}}
event = types.SimpleNamespace(
sender="@liizfq:liizfq.top",
event_id="$react1",
room_id="!room:example.org",
content=content,
)
with patch("tools.approval.resolve_gateway_approval", return_value=1) as mock_resolve:
await adapter._on_reaction(event)
mock_resolve.assert_called_once_with("sess-1", "once")
assert "$target" not in adapter._approval_prompts_by_event
assert "sess-1" not in adapter._approval_prompt_by_session