fix(approval): catch hermes gateway stop/restart behind a profile flag (#55515)

The gateway-lifecycle guard's hermes-CLI pattern required `hermes`
and `gateway` to be adjacent, so a profile flag slipped the agent
past it: `hermes -p ade gateway restart` was not flagged. That is the
exact form from the 2026-04-11 ade-profile self-kill loop. Allow an
optional run of global flags (`-p ade`, `--profile ade`, multiple
flags) between `hermes` and the gateway subcommand.

launchctl self-termination is already covered on main by #33071; this
narrows the only remaining real gap.
This commit is contained in:
Teknium 2026-06-30 02:48:30 -07:00 committed by GitHub
parent 1d495cfbbf
commit b03635daea
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 39 additions and 2 deletions

View file

@ -965,6 +965,41 @@ class TestGatewayProtection:
assert dangerous is True
assert "stop/restart" in desc
def test_hermes_gateway_stop_detected(self):
cmd = "hermes gateway stop"
dangerous, key, desc = detect_dangerous_command(cmd)
assert dangerous is True
assert "gateway" in desc.lower()
def test_hermes_gateway_restart_with_profile_flag_detected(self):
"""A profile flag between `hermes` and `gateway` must not slip past
the guard. See the 2026-04-11 ade-profile self-kill incident."""
cmd = "hermes -p ade gateway restart"
dangerous, key, desc = detect_dangerous_command(cmd)
assert dangerous is True
assert "gateway" in desc.lower()
def test_hermes_gateway_stop_with_long_profile_flag_detected(self):
cmd = "hermes --profile ade gateway stop"
dangerous, key, desc = detect_dangerous_command(cmd)
assert dangerous is True
def test_hermes_gateway_multiple_flags_detected(self):
cmd = "hermes -p cocoa --verbose gateway restart"
dangerous, key, desc = detect_dangerous_command(cmd)
assert dangerous is True
def test_hermes_gateway_status_with_profile_flag_not_flagged(self):
"""Read-only subcommands stay allowed even with a profile flag."""
cmd = "hermes -p ade gateway status"
dangerous, key, desc = detect_dangerous_command(cmd)
assert dangerous is False
def test_hermes_gateway_start_not_flagged(self):
cmd = "hermes gateway start"
dangerous, key, desc = detect_dangerous_command(cmd)
assert dangerous is False
def test_pkill_hermes_detected(self):
"""pkill targeting hermes/gateway processes must be caught."""
cmd = 'pkill -f "cli.py --gateway"'

View file

@ -424,8 +424,10 @@ DANGEROUS_PATTERNS = [
(r'\bfind\b.*-delete\b', "find -delete"),
# Gateway lifecycle protection: prevent the agent from killing its own
# gateway process. These commands trigger a gateway restart/stop that
# terminates all running agents mid-work.
(r'\bhermes\s+gateway\s+(stop|restart)\b', "stop/restart hermes gateway (kills running agents)"),
# terminates all running agents mid-work. Allow global flags between
# `hermes` and `gateway` (e.g. `hermes -p ade gateway restart`) so a
# profile flag can't slip the agent past the guard.
(r'\bhermes\s+(?:-{1,2}\S+(?:\s+\S+)?\s+)*gateway\s+(stop|restart)\b', "stop/restart hermes gateway (kills running agents)"),
(r'\bhermes\s+update\b', "hermes update (restarts gateway, kills running agents)"),
# Docker container lifecycle — any user with docker.sock mounted (a common
# Docker Compose pattern) gives the agent the ability to restart/stop/kill