test(approval): patch _YOLO_MODE_FROZEN directly in test_yolo_overrides_cron_deny

The test set HERMES_YOLO_MODE=1 via monkeypatch.setenv, expecting
check_dangerous_command() to honor yolo and bypass cron_mode=deny. But
tools.approval._YOLO_MODE_FROZEN is intentionally frozen at module
import time (security: prevents prompt-injection runtime escalation).
When CI imports the module BEFORE the test sets the env, the frozen
value stays False and the yolo bypass never activates.

Local runs missed this because the conftest leaked a non-empty
HERMES_YOLO_MODE into the import-time env. CI's clean-env path exposed
the bug deterministically on test (3) / test (4) shards.

Fix: patch the module attribute directly via mock.patch.object so the
test simulates process-startup-with-yolo regardless of import order.
The behavior under test (yolo bypasses cron_mode=deny for non-hardline
commands) is unchanged; the security invariant (_YOLO_MODE_FROZEN can't
be set at runtime by skills) is preserved.

Reproduced locally with: env -i HOME=$HOME PATH=$PATH python3 -m pytest
  tests/tools/test_cron_approval_mode.py -o 'addopts=' -v
Without the fix: 1 failed, 23 passed. With the fix: 24 passed.
This commit is contained in:
Teknium 2026-05-25 04:06:43 -07:00
parent 95848b1cbc
commit 79799c80f5

View file

@ -240,8 +240,18 @@ class TestCronModeInteractions:
monkeypatch.delenv("HERMES_INTERACTIVE", raising=False)
monkeypatch.delenv("HERMES_GATEWAY_SESSION", raising=False)
# _YOLO_MODE_FROZEN is frozen at module import time (security: prevents
# prompt injection from runtime-setting HERMES_YOLO_MODE). When the
# test process imports tools.approval BEFORE this test sets the env,
# the frozen value is False and yolo-bypass paths don't activate.
# Patch the module attribute directly to simulate process-startup
# with HERMES_YOLO_MODE=1.
from unittest.mock import patch as mock_patch
with mock_patch("tools.approval._get_cron_approval_mode", return_value="deny"):
import tools.approval
with (
mock_patch.object(tools.approval, "_YOLO_MODE_FROZEN", True),
mock_patch("tools.approval._get_cron_approval_mode", return_value="deny"),
):
# Use a dangerous-but-not-hardline command — `rm -rf /` is now
# hardline-blocked regardless of yolo (see test_hardline_blocklist.py).
result = check_dangerous_command("rm -rf /tmp/stuff", "local")