mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-08 13:12:08 +00:00
fix(windows): capture is not a no-window boundary; route flashing spawns through chokepoint (#53829)
Follow-up to #53791 addressing review feedback: the footgun checker treated capture_output=/stdout=/stderr=/check_output as proof a subprocess can't pop a Windows console. That invariant is false — stream redirection controls where a child's output goes, not whether a console is allocated. From a console-less parent (Desktop/Electron, pythonw.exe, detached gateway/cron) a console-subsystem child still flashes a window even when fully captured. - check-windows-footguns.py: capture/redirect/check_output is no longer a blanket safe-pass. Added _WINDOWS_FLASHING_PROGRAMS (git/gh/npm/node/python/uv/ffmpeg/ docker/powershell/…); calls to those are flagged even when captured. Non-flashing programs keep the capture exemption (no 271-site noise). _subprocess_compat.run/ popen calls are inherently safe (wrapper injects CREATE_NO_WINDOW). - Routed the 35 genuine flashing git/gh/npm/uv/ffmpeg/docker spawns through the _subprocess_compat.run/popen chokepoint (Brooklyn's wrapper from #53810) — the durable fix, not per-site annotations. cmd.exe /c start stays # ok (intentional). - Updated tests + CONTRIBUTING.md rule #17 to the corrected invariant.
This commit is contained in:
parent
3ac96d3308
commit
2ecca1e7d3
21 changed files with 191 additions and 76 deletions
|
|
@ -24,6 +24,7 @@ from hermes_constants import get_hermes_home
|
|||
from hermes_cli.profiles import _get_default_hermes_home
|
||||
from plugins.plugin_utils import SingletonSlot
|
||||
from typing import Any, TYPE_CHECKING
|
||||
from hermes_cli import _subprocess_compat
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from honcho import Honcho
|
||||
|
|
@ -625,7 +626,7 @@ class HonchoClientConfig:
|
|||
import subprocess
|
||||
|
||||
try:
|
||||
root = subprocess.run(
|
||||
root = _subprocess_compat.run(
|
||||
["git", "rev-parse", "--show-toplevel"],
|
||||
capture_output=True, text=True, cwd=cwd, timeout=5,
|
||||
stdin=subprocess.DEVNULL,
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ from ._oss_providers import (
|
|||
KNOWN_DIMS,
|
||||
validate_oss_config,
|
||||
)
|
||||
from hermes_cli import _subprocess_compat
|
||||
|
||||
|
||||
def _curses_select(title: str, items: list[tuple[str, str]], default: int = 0) -> int:
|
||||
|
|
@ -405,13 +406,13 @@ def _ensure_pgvector(host: str = "localhost", port: int = 5432) -> dict | None:
|
|||
# Check if our container already exists but is stopped
|
||||
if shutil.which("docker"):
|
||||
try:
|
||||
result = subprocess.run(
|
||||
result = _subprocess_compat.run(
|
||||
["docker", "inspect", _PGVECTOR_CONTAINER, "--format", "{{.State.Status}}"],
|
||||
capture_output=True, text=True, timeout=10, stdin=subprocess.DEVNULL,
|
||||
)
|
||||
if result.returncode == 0 and "exited" in result.stdout:
|
||||
print(f" Found stopped container '{_PGVECTOR_CONTAINER}', restarting...")
|
||||
subprocess.run(["docker", "start", _PGVECTOR_CONTAINER],
|
||||
_subprocess_compat.run(["docker", "start", _PGVECTOR_CONTAINER],
|
||||
capture_output=True, timeout=15,
|
||||
stdin=subprocess.DEVNULL)
|
||||
_wait_for_port(host, port, timeout=15)
|
||||
|
|
@ -438,17 +439,17 @@ def _start_pgvector_docker(host: str, port: int) -> dict | None:
|
|||
"""Pull and start pgvector Docker container."""
|
||||
try:
|
||||
print(f" Pulling {_PGVECTOR_IMAGE}...")
|
||||
subprocess.run(["docker", "pull", _PGVECTOR_IMAGE],
|
||||
_subprocess_compat.run(["docker", "pull", _PGVECTOR_IMAGE],
|
||||
capture_output=True, timeout=120,
|
||||
stdin=subprocess.DEVNULL)
|
||||
|
||||
# Remove existing container if present
|
||||
subprocess.run(["docker", "rm", "-f", _PGVECTOR_CONTAINER],
|
||||
_subprocess_compat.run(["docker", "rm", "-f", _PGVECTOR_CONTAINER],
|
||||
capture_output=True, timeout=10,
|
||||
stdin=subprocess.DEVNULL)
|
||||
|
||||
print(f" Starting container '{_PGVECTOR_CONTAINER}' on port {port}...")
|
||||
subprocess.run([
|
||||
_subprocess_compat.run([
|
||||
"docker", "run", "-d",
|
||||
"--name", _PGVECTOR_CONTAINER,
|
||||
"-e", f"POSTGRES_PASSWORD={_PGVECTOR_PASSWORD}",
|
||||
|
|
@ -734,7 +735,7 @@ def _install_provider_deps(llm_id: str, embedder_id: str, vector_id: str) -> Non
|
|||
for dep in sorted(deps):
|
||||
try:
|
||||
print(f" Installing {dep}...")
|
||||
subprocess.run(
|
||||
_subprocess_compat.run(
|
||||
["uv", "pip", "install", "--python", sys.executable, dep],
|
||||
capture_output=True, timeout=60,
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue