fix(cli): fail closed without bang shell sanitizer
This commit is contained in:
@@ -90,13 +90,11 @@ def _bang_env() -> dict:
|
||||
"""Environment for a bang command with Hermes-managed secrets filtered.
|
||||
|
||||
The CLI process holds every provider API key; a user-typed command may still run a third-party
|
||||
script, so reuse the sanitizer ``quick_commands`` and the local terminal backend use.
|
||||
script, so reuse the sanitizer ``quick_commands`` and the local terminal backend use. If that
|
||||
boundary is unavailable, let the launch fail rather than passing the CLI's full environment.
|
||||
"""
|
||||
try:
|
||||
from tools.environments.local import build_subprocess_env
|
||||
return build_subprocess_env() # == _sanitize_subprocess_env(os.environ.copy())
|
||||
except Exception:
|
||||
return os.environ.copy() # tools package unimportable: run the user's command anyway
|
||||
from tools.environments.local import build_subprocess_env
|
||||
return build_subprocess_env()
|
||||
|
||||
|
||||
def run_bang_command(command: str, *, cwd: Optional[str] = None, timeout: int = DEFAULT_TIMEOUT, writer=None) -> int:
|
||||
|
||||
@@ -5,6 +5,7 @@ invoked for a dangerous command, that non-zero exit codes surface, and the
|
||||
load-bearing invariant: a bang command leaves conversation_history
|
||||
byte-identical because it never becomes a turn.
|
||||
"""
|
||||
import builtins
|
||||
import copy
|
||||
import json
|
||||
import os
|
||||
@@ -121,6 +122,23 @@ class TestBangExecution:
|
||||
assert code == 0
|
||||
assert "ok" in lines
|
||||
|
||||
def test_unavailable_environment_sanitizer_prevents_launch(self):
|
||||
lines = []
|
||||
real_import = builtins.__import__
|
||||
|
||||
def block_sanitizer(name, *args, **kwargs):
|
||||
if name == "tools.environments.local":
|
||||
raise ImportError("environment sanitizer unavailable")
|
||||
return real_import(name, *args, **kwargs)
|
||||
|
||||
with patch("builtins.__import__", block_sanitizer), \
|
||||
patch("hermes_cli.bang_shell.subprocess.Popen") as popen:
|
||||
code = run_bang_command("echo must-not-run", writer=lines.append)
|
||||
|
||||
assert code == 127
|
||||
popen.assert_not_called()
|
||||
assert any("failed to run command" in line for line in lines)
|
||||
|
||||
|
||||
# ── CLI handler: approval gate, usage hint, exit codes ─────────────────────
|
||||
|
||||
|
||||
Reference in New Issue
Block a user