Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4660,6 +4660,8 @@ def process_command(self, command: str) -> bool:
exec_cmd = qcmd.get("command", "")
if exec_cmd:
try:
# shell=True is intentional: quick_commands are user-defined
# shell snippets from config.yaml β€” not agent/LLM controlled.
result = subprocess.run(
exec_cmd, shell=True, capture_output=True,
text=True, timeout=30
Expand Down
3 changes: 2 additions & 1 deletion hermes_cli/memory_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import getpass
import os
import sys
import shlex
from pathlib import Path

from hermes_constants import get_hermes_home
Expand Down Expand Up @@ -204,7 +205,7 @@ def _install_dependencies(provider_name: str) -> None:
if check_cmd:
try:
subprocess.run(
check_cmd, shell=True, capture_output=True, timeout=5
shlex.split(check_cmd), check=True, capture_output=True, timeout=5
)
except Exception:
if install_cmd:
Expand Down
41 changes: 41 additions & 0 deletions tests/tools/test_transcription_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -858,3 +858,44 @@ def test_returns_none_when_model_key_missing(self, tmp_path, monkeypatch):

from tools.transcription_tools import get_stt_model_from_config
assert get_stt_model_from_config() is None

# ============================================================================
# Shell safety β€” shlex.split on auto-detected templates
# ============================================================================
class TestShellSafety:
def test_auto_detected_template_is_shlex_safe(self, monkeypatch):
"""Auto-detected whisper command should be safely splittable."""
import shlex
monkeypatch.delenv("HERMES_LOCAL_STT_COMMAND", raising=False)
monkeypatch.setattr(
"tools.transcription_tools._find_whisper_binary",
lambda: "/usr/bin/whisper",
)
from tools.transcription_tools import _get_local_command_template
template = _get_local_command_template()
assert template is not None
cmd = template.format(
input_path=shlex.quote("/tmp/test.wav"),
output_dir=shlex.quote("/tmp/out"),
language=shlex.quote("en"),
model=shlex.quote("base"),
)
parts = shlex.split(cmd)
assert parts[0] == "/usr/bin/whisper"
assert "/tmp/test.wav" in parts

def test_env_var_template_uses_shell_path(self, monkeypatch):
"""When HERMES_LOCAL_STT_COMMAND is set, use_shell should be True."""
import os
from tools.transcription_tools import LOCAL_STT_COMMAND_ENV
monkeypatch.setenv(LOCAL_STT_COMMAND_ENV, "whisper {input_path} | tee log.txt")
use_shell = bool(os.getenv(LOCAL_STT_COMMAND_ENV, "").strip())
assert use_shell is True

def test_no_env_var_uses_list_mode(self, monkeypatch):
"""When no env var is set, use_shell should be False."""
import os
from tools.transcription_tools import LOCAL_STT_COMMAND_ENV
monkeypatch.delenv(LOCAL_STT_COMMAND_ENV, raising=False)
use_shell = bool(os.getenv(LOCAL_STT_COMMAND_ENV, "").strip())
assert use_shell is False
8 changes: 7 additions & 1 deletion tools/transcription_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,13 @@ def _transcribe_local_command(file_path: str, model_name: str) -> Dict[str, Any]
language=shlex.quote(language),
model=shlex.quote(normalized_model),
)
subprocess.run(command, shell=True, check=True, capture_output=True, text=True)
# User-provided templates (env var) may contain shell syntax; auto-detected commands are safe for list mode.
use_shell = bool(os.getenv(LOCAL_STT_COMMAND_ENV, "").strip())
if use_shell:
subprocess.run(command, shell=True, check=True, capture_output=True, text=True)
else:
subprocess.run(shlex.split(command), check=True, capture_output=True, text=True)


txt_files = sorted(Path(output_dir).glob("*.txt"))
if not txt_files:
Expand Down