diff --git a/tests/gateway/test_matrix_exec_approval.py b/tests/gateway/test_matrix_exec_approval.py index 99cf2df793a2..a0bad688924b 100644 --- a/tests/gateway/test_matrix_exec_approval.py +++ b/tests/gateway/test_matrix_exec_approval.py @@ -27,9 +27,56 @@ class TestMatrixExecApprovalReactions: 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 == 3 + assert adapter._send_reaction.await_count == 4 emojis = [call.args[2] for call in adapter._send_reaction.await_args_list] - assert emojis == ["✅", "♾️", "❌"] + assert emojis == ["✅", "🌀", "♾️", "❌"] + + @pytest.mark.asyncio + async def test_send_exec_approval_tirith_seeds_session_but_not_always(self, monkeypatch): + """allow_permanent=False (tirith-only prompt) keeps the session tier + but drops the permanent reaction.""" + monkeypatch.setenv("MATRIX_ALLOWED_USERS", "@liizfq:liizfq.top") + from plugins.platforms.matrix.adapter 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="$evt2")) + adapter._send_reaction = AsyncMock(return_value="$r") + + result = await adapter.send_exec_approval( + chat_id="!room:example.org", + command="curl https://bit.ly/abc", + session_key="sess-2", + description="shortened URL", + allow_permanent=False, + ) + + assert result.success is True + emojis = [call.args[2] for call in adapter._send_reaction.await_args_list] + assert emojis == ["✅", "🌀", "❌"] + + @pytest.mark.asyncio + async def test_send_exec_approval_no_session_seeds_once_deny_only(self, monkeypatch): + """allow_session=False (Smart-DENY-style) collapses to once/deny.""" + monkeypatch.setenv("MATRIX_ALLOWED_USERS", "@liizfq:liizfq.top") + from plugins.platforms.matrix.adapter 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="$evt3")) + adapter._send_reaction = AsyncMock(return_value="$r") + + result = await adapter.send_exec_approval( + chat_id="!room:example.org", + command="rm -rf /tmp/x", + session_key="sess-3", + description="dangerous", + allow_session=False, + ) + + assert result.success is True + 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): diff --git a/tests/tools/test_command_guards.py b/tests/tools/test_command_guards.py index 48f0f8e272c4..1ce20f14e783 100644 --- a/tests/tools/test_command_guards.py +++ b/tests/tools/test_command_guards.py @@ -440,6 +440,9 @@ class TestGatewayApprovalAllowPermanent: renderer hides "Always allow".""" payload = self._capture_gateway_payload("curl https://bit.ly/abc", "gw-no-perm") assert payload["allow_permanent"] is False + # Session scope stays available — pure-tirith prompts are session-max, + # not once-max (salvaged from PR #67312). + assert payload["allow_session"] is True @patch(_TIRITH_PATCH, return_value=_tirith_result("warn",