fix(approval): gate perl/ruby -i in-place edits of Hermes config/env

sed -i coverage for ~/.hermes/config.yaml and .env was added in #14639,
but perl -i and ruby -i — which perform the same direct file mutation —
were not covered. The existing perl/ruby pattern only catches -e/-c (code
evaluation), not -i (file mutation), so:

  perl -i -pe 's/approvals.mode: on/approvals.mode: off/' ~/.hermes/config.yaml

bypasses the approval gate entirely, letting the agent flip approvals.mode
off mid-session via the mtime-keyed config cache reload.

Add a single pattern mirroring the sed -i lines: `\b(?:perl|ruby)\s+-[^\s]*i`
against both _HERMES_CONFIG_PATH and _HERMES_ENV_PATH. Three regression
tests pin the new coverage.
This commit is contained in:
AhmetArif0
2026-06-04 05:36:30 -07:00
committed by Teknium
parent 5f199e610b
commit a6a4e6f9d7
2 changed files with 25 additions and 0 deletions
+21
View File
@@ -428,6 +428,27 @@ class TestHermesConfigWriteProtection:
dangerous, key, desc = detect_dangerous_command("echo x | tee $HERMES_HOME/config.yaml")
assert dangerous is True
def test_perl_in_place_config(self):
# perl -i performs the same in-place mutation as sed -i but was not
# caught by the -e/-c pattern (which targets code evaluation).
dangerous, key, desc = detect_dangerous_command(
"perl -i -pe 's/approvals.mode: on/approvals.mode: off/' ~/.hermes/config.yaml"
)
assert dangerous is True
assert "in-place" in desc.lower() or "perl" in desc.lower()
def test_ruby_in_place_config(self):
dangerous, key, desc = detect_dangerous_command(
"ruby -i -pe 'gsub(/manual/, \"off\")' ~/.hermes/config.yaml"
)
assert dangerous is True
def test_perl_in_place_env(self):
dangerous, key, desc = detect_dangerous_command(
"perl -i -pe 's/SECRET=old/SECRET=new/' ~/.hermes/.env"
)
assert dangerous is True
def test_read_is_safe(self):
# Reading config is not a write — must not trip.
dangerous, key, desc = detect_dangerous_command("cat ~/.hermes/config.yaml")