diff --git a/tests/tools/test_cron_approval_mode.py b/tests/tools/test_cron_approval_mode.py index 838385befe..47ce7997dd 100644 --- a/tests/tools/test_cron_approval_mode.py +++ b/tests/tools/test_cron_approval_mode.py @@ -283,26 +283,6 @@ class TestCronDenyModeAllGuards: assert result["approved"] is True - def test_session_pattern_key_does_not_allow_command_in_cron_deny(self, monkeypatch): - """A session-only approval must not become standing authority for unattended work.""" - monkeypatch.delenv("HERMES_CRON_SESSION", raising=False) - monkeypatch.delenv("HERMES_INTERACTIVE", raising=False) - monkeypatch.delenv("HERMES_GATEWAY_SESSION", raising=False) - monkeypatch.delenv("HERMES_EXEC_ASK", raising=False) - monkeypatch.delenv("HERMES_YOLO_MODE", raising=False) - approval_module.approve_session("test-session", "script execution via heredoc") - - from unittest.mock import patch as mock_patch - tokens = set_session_vars(session_key="test-session", cron_session="1") - try: - with mock_patch("tools.approval_context._get_cron_approval_mode", return_value="deny"): - result = check_all_command_guards("python3 - <<'PY'\nprint('ok')\nPY", "local") - finally: - clear_session_vars(tokens) - - assert result["approved"] is False - assert "BLOCKED" in result["message"] - def test_pattern_key_allowlist_does_not_bypass_tirith_in_cron_deny(self, monkeypatch): """Approving one dangerous pattern must not suppress an independent Tirith finding.""" monkeypatch.setenv("HERMES_CRON_SESSION", "1") diff --git a/website/docs/user-guide/security.md b/website/docs/user-guide/security.md index fea2eb5e2f..d41e495a08 100644 --- a/website/docs/user-guide/security.md +++ b/website/docs/user-guide/security.md @@ -267,6 +267,14 @@ command_allowlist: These patterns are loaded at startup and silently approved in all future sessions. +Entries can be exact command text, a shell-style glob (`podman *`), or a +dangerous-pattern rule key such as `script execution via heredoc` (the key shown +in the approval prompt). Rule keys are honored on every surface, including +unattended ones: a cron job, `hermes chat -q` run or webhook session under +`cron_mode`/`single_query_mode`/`unattended_mode: deny` still runs a command whose +detected rule key is in `command_allowlist`, while Tirith content-security +findings on the same command continue to block it. + The setting must be a list of strings. Legacy installs that stored a list as a quoted YAML/JSON string recover that list at load time and log a warning to re-save it with `hermes config edit`. Other malformed values are ignored with