feat(guards): wire elicitation into notifications/vm/rclone/settings/storage

Replace hard ToolError guard with gate_destructive_action() in 5 tools so
destructive actions prompt for interactive confirmation via MCP elicitation
when ctx is available, and still accept confirm=True as a bypass. Update
all test match strings from "destructive" to "not confirmed" accordingly.
This commit is contained in:
Jacob Magar
2026-03-15 23:38:20 -04:00
parent cdab970c12
commit d7545869e2
10 changed files with 66 additions and 24 deletions

View File

@@ -576,7 +576,7 @@ class TestVMToolRequests:
@respx.mock
async def test_force_stop_requires_confirm(self) -> None:
tool = self._get_tool()
with pytest.raises(ToolError, match="destructive"):
with pytest.raises(ToolError, match="not confirmed"):
await tool(action="force_stop", vm_id="vm-789")
@respx.mock
@@ -593,7 +593,7 @@ class TestVMToolRequests:
@respx.mock
async def test_reset_requires_confirm(self) -> None:
tool = self._get_tool()
with pytest.raises(ToolError, match="destructive"):
with pytest.raises(ToolError, match="not confirmed"):
await tool(action="reset", vm_id="vm-abc")
@respx.mock
@@ -880,7 +880,7 @@ class TestNotificationsToolRequests:
@respx.mock
async def test_delete_requires_confirm(self) -> None:
tool = self._get_tool()
with pytest.raises(ToolError, match="destructive"):
with pytest.raises(ToolError, match="not confirmed"):
await tool(action="delete", notification_id="n1", notification_type="UNREAD")
@respx.mock
@@ -990,7 +990,7 @@ class TestRCloneToolRequests:
@respx.mock
async def test_delete_remote_requires_confirm(self) -> None:
tool = self._get_tool()
with pytest.raises(ToolError, match="destructive"):
with pytest.raises(ToolError, match="not confirmed"):
await tool(action="delete_remote", name="old-remote")
@respx.mock