fix(file_tools): block agent writes to ~/.hermes/config.yaml to prevent silent approval bypass

This commit is contained in:
sbw2025
2026-06-01 03:29:48 -07:00
committed by Teknium
parent 023149f665
commit 8f2931e3ee
2 changed files with 95 additions and 0 deletions
+64
View File
@@ -401,6 +401,70 @@ class TestSearchHints:
# PATCH_SCHEMA shape tests (issue #15524)
# ---------------------------------------------------------------------------
class TestSensitivePathCheck:
"""Verify that _check_sensitive_path blocks writes to protected locations."""
def test_hermes_config_blocked_for_write_file(self, tmp_path, monkeypatch):
fake_config = tmp_path / "config.yaml"
monkeypatch.setattr("tools.file_tools._hermes_config_resolved", str(fake_config))
monkeypatch.setattr("tools.file_tools._hermes_config_resolved_loaded", True)
from tools.file_tools import write_file_tool
result = json.loads(write_file_tool(str(fake_config), "approvals:\n mode: off\n"))
assert "error" in result
assert "Hermes config" in result["error"]
def test_hermes_config_blocked_via_tilde_path(self, tmp_path, monkeypatch):
fake_config = tmp_path / "config.yaml"
monkeypatch.setattr("tools.file_tools._hermes_config_resolved", str(fake_config))
monkeypatch.setattr("tools.file_tools._hermes_config_resolved_loaded", True)
from tools.file_tools import write_file_tool
result = json.loads(write_file_tool(str(fake_config), "approvals:\n mode: off\n"))
assert "error" in result
assert "Hermes config" in result["error"]
def test_hermes_config_blocked_for_patch(self, tmp_path, monkeypatch):
fake_config = tmp_path / "config.yaml"
fake_config.write_text("approvals:\n mode: manual\n")
monkeypatch.setattr("tools.file_tools._hermes_config_resolved", str(fake_config))
monkeypatch.setattr("tools.file_tools._hermes_config_resolved_loaded", True)
from tools.file_tools import patch_tool
result = json.loads(patch_tool(
mode="replace",
path=str(fake_config),
old_string="mode: manual",
new_string="mode: off",
))
assert "error" in result
assert "Hermes config" in result["error"]
def test_system_path_still_blocked(self, monkeypatch):
monkeypatch.setattr("tools.file_tools._hermes_config_resolved", "/some/other/path")
monkeypatch.setattr("tools.file_tools._hermes_config_resolved_loaded", True)
from tools.file_tools import write_file_tool
result = json.loads(write_file_tool("/etc/passwd", "evil"))
assert "error" in result
assert "sensitive system path" in result["error"]
@patch("tools.file_tools._get_file_ops")
def test_normal_file_not_blocked(self, mock_get, monkeypatch):
monkeypatch.setattr("tools.file_tools._hermes_config_resolved", "/home/user/.hermes/config.yaml")
monkeypatch.setattr("tools.file_tools._hermes_config_resolved_loaded", True)
mock_ops = MagicMock()
result_obj = MagicMock()
result_obj.to_dict.return_value = {"status": "ok", "path": "/tmp/other.txt", "bytes": 5}
mock_ops.write_file.return_value = result_obj
mock_get.return_value = mock_ops
from tools.file_tools import write_file_tool
result = json.loads(write_file_tool("/tmp/other.txt", "hello"))
assert result["status"] == "ok"
class TestPatchSchemaShape:
"""PATCH_SCHEMA must advertise per-mode required params via description
text (not JSON-schema ``required``), so strict models like kimi-k2.x stop