Hermes-agent
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
"""Tests for `hermes chat --safe-mode` — pristine troubleshooting runs.
|
||||
|
||||
Inspired by Claude Code v2.1.169's ``--safe-mode`` flag (June 2026), which
|
||||
disables all customizations (CLAUDE.md, plugins, skills, hooks, MCP) for
|
||||
troubleshooting. The Hermes equivalent:
|
||||
|
||||
* implies ``--ignore-user-config`` (built-in config defaults)
|
||||
* implies ``--ignore-rules`` (no AGENTS.md/memory/preloaded-skill injection)
|
||||
* skips plugin discovery entirely (``hermes_cli.plugins``)
|
||||
* loads zero MCP servers (``tools.mcp_tool._load_mcp_config``)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
_VARS = ("HERMES_SAFE_MODE", "HERMES_IGNORE_USER_CONFIG", "HERMES_IGNORE_RULES")
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _clean_env(monkeypatch):
|
||||
for var in _VARS:
|
||||
monkeypatch.delenv(var, raising=False)
|
||||
yield
|
||||
for var in _VARS:
|
||||
os.environ.pop(var, None)
|
||||
|
||||
|
||||
class TestSafeModeEnvWiring:
|
||||
"""cmd_chat must translate --safe-mode into the three env gates."""
|
||||
|
||||
def test_safe_mode_sets_all_gates(self):
|
||||
# Mirrors the cmd_chat logic in hermes_cli/main.py.
|
||||
class Args:
|
||||
safe_mode = True
|
||||
|
||||
args = Args()
|
||||
if getattr(args, "safe_mode", False):
|
||||
os.environ["HERMES_SAFE_MODE"] = "1"
|
||||
os.environ["HERMES_IGNORE_USER_CONFIG"] = "1"
|
||||
os.environ["HERMES_IGNORE_RULES"] = "1"
|
||||
|
||||
assert os.environ.get("HERMES_SAFE_MODE") == "1"
|
||||
assert os.environ.get("HERMES_IGNORE_USER_CONFIG") == "1"
|
||||
assert os.environ.get("HERMES_IGNORE_RULES") == "1"
|
||||
|
||||
|
||||
class TestSafeModePluginDiscovery:
|
||||
"""Plugin discovery must be a no-op under HERMES_SAFE_MODE=1."""
|
||||
|
||||
def test_discovery_skipped(self, monkeypatch):
|
||||
monkeypatch.setenv("HERMES_SAFE_MODE", "1")
|
||||
from hermes_cli.plugins import PluginManager
|
||||
|
||||
mgr = PluginManager()
|
||||
called = []
|
||||
monkeypatch.setattr(
|
||||
mgr, "_discover_and_load_inner", lambda: called.append(True)
|
||||
)
|
||||
mgr.discover_and_load()
|
||||
assert called == [] # inner sweep never ran
|
||||
assert mgr._discovered is True # registry settled as clean-empty
|
||||
assert mgr._plugins == {}
|
||||
|
||||
def test_discovery_runs_without_safe_mode(self, monkeypatch):
|
||||
monkeypatch.delenv("HERMES_SAFE_MODE", raising=False)
|
||||
from hermes_cli.plugins import PluginManager
|
||||
|
||||
mgr = PluginManager()
|
||||
called = []
|
||||
monkeypatch.setattr(
|
||||
mgr, "_discover_and_load_inner", lambda: called.append(True)
|
||||
)
|
||||
mgr.discover_and_load()
|
||||
assert called == [True]
|
||||
|
||||
|
||||
class TestSafeModeMCP:
|
||||
"""_load_mcp_config must return no servers under HERMES_SAFE_MODE=1."""
|
||||
|
||||
def test_mcp_servers_empty(self, monkeypatch):
|
||||
monkeypatch.setenv("HERMES_SAFE_MODE", "1")
|
||||
from tools.mcp_tool import _load_mcp_config
|
||||
|
||||
with pytest.MonkeyPatch.context() as mp:
|
||||
mp.setattr(
|
||||
"hermes_cli.config.load_config",
|
||||
lambda: {"mcp_servers": {"github": {"url": "https://example.com/mcp"}}},
|
||||
)
|
||||
assert _load_mcp_config() == {}
|
||||
|
||||
def test_mcp_servers_load_without_safe_mode(self, monkeypatch):
|
||||
monkeypatch.delenv("HERMES_SAFE_MODE", raising=False)
|
||||
from tools.mcp_tool import _load_mcp_config
|
||||
|
||||
with pytest.MonkeyPatch.context() as mp:
|
||||
mp.setattr(
|
||||
"hermes_cli.config.load_config",
|
||||
lambda: {"mcp_servers": {"github": {"url": "https://example.com/mcp"}}},
|
||||
)
|
||||
servers = _load_mcp_config()
|
||||
assert "github" in servers
|
||||
|
||||
|
||||
class TestSafeModeParser:
|
||||
"""--safe-mode must parse on both the root parser and `hermes chat`."""
|
||||
|
||||
def test_chat_subcommand_accepts_flag(self):
|
||||
from hermes_cli._parser import build_top_level_parser
|
||||
|
||||
parser, _subparsers, _chat = build_top_level_parser()
|
||||
args = parser.parse_args(["chat", "--safe-mode"])
|
||||
assert getattr(args, "safe_mode", False) is True
|
||||
|
||||
def test_root_parser_accepts_flag(self):
|
||||
from hermes_cli._parser import build_top_level_parser
|
||||
|
||||
parser, _subparsers, _chat = build_top_level_parser()
|
||||
args = parser.parse_args(["--safe-mode"])
|
||||
assert getattr(args, "safe_mode", False) is True
|
||||
|
||||
def test_default_is_off(self):
|
||||
from hermes_cli._parser import build_top_level_parser
|
||||
|
||||
parser, _subparsers, _chat = build_top_level_parser()
|
||||
args = parser.parse_args(["chat"])
|
||||
assert getattr(args, "safe_mode", False) is False
|
||||
Reference in New Issue
Block a user