mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-18 04:41:56 +00:00
fix(terminal): prevent safety filter false positives on keywords inside quoted strings
The _foreground_background_guidance() function matched background-wrapper keywords (nohup/disown/setsid) anywhere in the command text, including inside quoted strings, Python -c code, commit messages, and PR body text. Two-layer fix: 1. Strip single-quoted, double-quoted, and backtick-quoted content before pattern matching via _strip_quotes() helper. 2. Tighten the regex to only match keywords at command-start positions (after ^, ;, &, &&, ||, or $() — not mid-argument. Both layers are needed: quote stripping handles the common case of keywords in string literals, and the position-aware regex handles unquoted cases like 'export FOO=setsid' (word boundary match, wrong position). Fixes #20064
This commit is contained in:
parent
3adde245b7
commit
364ddd45e8
1 changed files with 28 additions and 4 deletions
|
|
@ -1544,9 +1544,29 @@ def _command_requires_pipe_stdin(command: str) -> bool:
|
|||
)
|
||||
|
||||
|
||||
_SHELL_LEVEL_BACKGROUND_RE = re.compile(r"\b(?:nohup|disown|setsid)\b", re.IGNORECASE)
|
||||
_SHELL_LEVEL_BACKGROUND_RE = re.compile(
|
||||
r"(?:^|[;&|]\s*|&&\s*|\|\|\s*|\$\(\s*)(?:nohup|disown|setsid)\b", re.IGNORECASE | re.MULTILINE
|
||||
)
|
||||
_INLINE_BACKGROUND_AMP_RE = re.compile(r"\s&\s")
|
||||
_TRAILING_BACKGROUND_AMP_RE = re.compile(r"\s&\s*(?:#.*)?$")
|
||||
|
||||
|
||||
def _strip_quotes(command: str) -> str:
|
||||
"""Remove single- and double-quoted content so regex checks don't match inside strings.
|
||||
|
||||
This prevents false positives when keywords like 'nohup' or 'setsid' appear
|
||||
in commit messages, Python -c code, echo arguments, or PR body text.
|
||||
Also strips backtick-quoted content and heredoc-style inline text.
|
||||
"""
|
||||
# Remove single-quoted strings (no escaping inside single quotes in shell)
|
||||
result = re.sub(r"'[^']*'", "''", command)
|
||||
# Remove double-quoted strings (handle escaped quotes)
|
||||
result = re.sub(r'"(?:[^"\\]|\\.)*"', '""', result)
|
||||
# Remove backtick-quoted strings
|
||||
result = re.sub(r"`[^`]*`", "``", result)
|
||||
return result
|
||||
|
||||
|
||||
_LONG_LIVED_FOREGROUND_PATTERNS = (
|
||||
re.compile(r"\b(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?(?:dev|start|serve|watch)\b", re.IGNORECASE),
|
||||
re.compile(r"\bdocker\s+compose\s+up\b", re.IGNORECASE),
|
||||
|
|
@ -1579,21 +1599,25 @@ def _foreground_background_guidance(command: str) -> str | None:
|
|||
if _looks_like_help_or_version_command(command):
|
||||
return None
|
||||
|
||||
if _SHELL_LEVEL_BACKGROUND_RE.search(command):
|
||||
# Strip quoted content so keywords inside strings/arguments don't trigger
|
||||
# false positives (e.g., git commit -m "... setsid ...", python3 -c "os.setsid").
|
||||
unquoted = _strip_quotes(command)
|
||||
|
||||
if _SHELL_LEVEL_BACKGROUND_RE.search(unquoted):
|
||||
return (
|
||||
"Foreground command uses shell-level background wrappers (nohup/disown/setsid). "
|
||||
"Use terminal(background=true) so Hermes can track the process, then run "
|
||||
"readiness checks and tests in separate commands."
|
||||
)
|
||||
|
||||
if _INLINE_BACKGROUND_AMP_RE.search(command) or _TRAILING_BACKGROUND_AMP_RE.search(command):
|
||||
if _INLINE_BACKGROUND_AMP_RE.search(unquoted) or _TRAILING_BACKGROUND_AMP_RE.search(unquoted):
|
||||
return (
|
||||
"Foreground command uses '&' backgrounding. Use terminal(background=true) for long-lived "
|
||||
"processes, then run health checks and tests in follow-up terminal calls."
|
||||
)
|
||||
|
||||
for pattern in _LONG_LIVED_FOREGROUND_PATTERNS:
|
||||
if pattern.search(command):
|
||||
if pattern.search(unquoted):
|
||||
return (
|
||||
"This foreground command appears to start a long-lived server/watch process. "
|
||||
"Run it with background=true, verify readiness (health endpoint/log signal), "
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue