mirror of
https://github.com/jmagar/unraid-mcp.git
synced 2026-03-23 12:39:24 -07:00
fix(safety): add stop_array to DESTRUCTIVE_ACTIONS, add error propagation test
stop_array can cause data loss for running containers/VMs that depend on array shares — requires confirm=True like other destructive mutations. - Add stop_array to DESTRUCTIVE_ACTIONS and desc_map in array.py - Update safety audit KNOWN_DESTRUCTIVE[array] to include stop_array - Add stop_array negative/positive tests (test_array.py, safety tests) - Add test_snapshot_wraps_bare_exception to test_live.py (bare Exception from subscribe_once is wrapped by tool_error_handler into ToolError) 748 tests passing
This commit is contained in:
@@ -47,7 +47,7 @@ KNOWN_DESTRUCTIVE: dict[str, dict[str, set[str] | str]] = {
|
||||
"module": "unraid_mcp.tools.array",
|
||||
"register_fn": "register_array_tool",
|
||||
"tool_name": "unraid_array",
|
||||
"actions": {"remove_disk", "clear_disk_stats"},
|
||||
"actions": {"remove_disk", "clear_disk_stats", "stop_array"},
|
||||
"runtime_set": ARRAY_DESTRUCTIVE,
|
||||
},
|
||||
"vm": {
|
||||
@@ -198,6 +198,7 @@ _DESTRUCTIVE_TEST_CASES: list[tuple[str, str, dict]] = [
|
||||
# Array
|
||||
("array", "remove_disk", {"disk_id": "abc123:local"}),
|
||||
("array", "clear_disk_stats", {"disk_id": "abc123:local"}),
|
||||
("array", "stop_array", {}),
|
||||
# VM
|
||||
("vm", "force_stop", {"vm_id": "test-vm-uuid"}),
|
||||
("vm", "reset", {"vm_id": "test-vm-uuid"}),
|
||||
@@ -468,6 +469,12 @@ class TestConfirmAllowsExecution:
|
||||
result = await tool_fn(action="clear_disk_stats", disk_id="abc:local", confirm=True)
|
||||
assert result["success"] is True
|
||||
|
||||
async def test_array_stop_array_with_confirm(self, _mock_array_graphql: AsyncMock) -> None:
|
||||
_mock_array_graphql.return_value = {"array": {"setState": {"state": "STOPPED"}}}
|
||||
tool_fn = make_tool_fn("unraid_mcp.tools.array", "register_array_tool", "unraid_array")
|
||||
result = await tool_fn(action="stop_array", confirm=True)
|
||||
assert result["success"] is True
|
||||
|
||||
async def test_plugins_remove_with_confirm(self, _mock_plugins_graphql: AsyncMock) -> None:
|
||||
_mock_plugins_graphql.return_value = {"removePlugin": True}
|
||||
tool_fn = make_tool_fn(
|
||||
|
||||
Reference in New Issue
Block a user