fix(terminal): block gateway lifecycle commands from inside the gateway process#37475
Open
AhmetArif0 wants to merge 1 commit into
Open
fix(terminal): block gateway lifecycle commands from inside the gateway process#37475AhmetArif0 wants to merge 1 commit into
AhmetArif0 wants to merge 1 commit into
Conversation
…ay process systemctl --user restart hermes-gateway run via the terminal tool is a child of the gateway itself. When systemd delivers SIGTERM the gateway kills this subprocess before it can complete, so the service may never restart — reproducing issue NousResearch#37453. The hermes gateway restart/stop guard (hermes_cli/gateway.py) and the cron-path guard (hermes_cli/cron.py) already block equivalent commands in their respective paths but the terminal tool had no such defense. Add a hard-block before command execution in terminal_tool: when _HERMES_GATEWAY=1 and the command matches _contains_gateway_lifecycle_command, return an error immediately. force=True cannot bypass it — unlike the normal dangerous-command approval flow, here even a user-approved restart would fail because the SIGTERM propagates to child processes. Also extend _GATEWAY_LIFECYCLE_PATTERNS to match systemctl with flags (e.g. systemctl --user restart) — the previous regex required the action word immediately after systemctl with no flags in between. Adds 9 regression tests: 6 blocked variants (parametrized), force bypass attempt, safe systemctl passthrough, and guard-inactive-outside-gateway.
tonydwb
approved these changes
Jun 2, 2026
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Approved
Important safety fix: adds a hard block in terminal_tool against gateway lifecycle commands (systemctl restart hermes-gateway, hermes gateway restart, launchctl kickstart ..., pkill ...) when executed from inside the gateway process itself. Without this guard, restarting the gateway from within kills the child process mid-execution before the restart can complete.
✅ Looks Good
- Comprehensive regex update in
cron.pyto also matchsystemctl --user ...variants - 4 carefully designed tests: block lifecycle commands, force bypass test, safe commands pass through, guard inactive outside gateway
- Clean inline comment explaining the issue
- No security concerns — blocking gateway restarts from within the gateway is the correct behavior
Reviewed by Hermes Agent
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #37453.
systemctl --user restart hermes-gatewayrun from the terminal tool is a child process of the gateway. When systemd delivers SIGTERM, the gateway kills this subprocess before it can complete — the service may never restart (deadlock).The
hermes gateway restart/stopguard (hermes_cli/gateway.py) and the cron-path guard (hermes_cli/cron.py) already block equivalent commands in their respective paths, but the terminal tool had no such defense.Changes
tools/terminal_tool.py— hard-block before execution: when_HERMES_GATEWAY=1and the command matches_contains_gateway_lifecycle_command, return an error immediately.force=Truecannot bypass it — unlike the normal dangerous-command approval flow, a user-approved restart would still fail because SIGTERM propagates to child processes.hermes_cli/cron.py— extend_GATEWAY_LIFECYCLE_PATTERNSto matchsystemctlwith flags (e.g.systemctl --user restart). The previous regex required the action word immediately aftersystemctlwith no flags in between, sosystemctl --user restart hermes-gateway(the exact command from the issue) was not caught.Test plan
test_blocks_lifecycle_commands_inside_gateway— 6 variants:systemctl restart/stop,systemctl --user restart,hermes gateway restart,launchctl kickstart,pkilltest_force_true_cannot_bypass_block—force=Truedoes not helptest_safe_systemctl_commands_pass_through—systemctl status nginxis not blocked inside gatewaytest_guard_inactive_outside_gateway— guard only fires when_HERMES_GATEWAY=1test_gateway_restart_loop.pytests still pass