mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-26 17:38:36 +00:00
fix(windows): widen utf-8 subprocess decode guard to sibling desktop-backend sites
The salvaged #61978 covers tui_gateway/server.py. The crash reported on
Jul 24 came from a sibling site it doesn't touch: the desktop update
panel's _recent_upstream_commits() in hermes_cli/web_server.py runs
git log with text=True and no encoding. Commit 84db32484f put a bug
emoji (UTF-8 f0 9f 90 9b) in a subject on main; byte 0x90 is undefined
in cp1252, so every Windows desktop install behind that commit crashed
in subprocess._readerthread during the update check (#52649).
Guard every text=True capture site in the desktop-backend process with
encoding='utf-8', errors='replace':
- hermes_cli/web_server.py: git log update panel, memory-provider setup
runner, WhatsApp bridge npm install, docker probe
- hermes_cli/banner.py: all 5 git sites (update check runs at startup)
- tui_gateway/host_supervisor.py: build-sha probe, ps probe, compute-host
Popen drain threads
- tui_gateway/compute_host.py: build-sha probe, ps rss probe
This commit is contained in:
parent
a214f3026d
commit
ead23aadb9
4 changed files with 43 additions and 3 deletions
|
|
@ -160,6 +160,11 @@ def _git_stdout(args: list[str], *, cwd: Path, timeout: int = 5) -> Optional[str
|
|||
["git", *args],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
# git output is UTF-8; on Windows text=True defaults to the ANSI
|
||||
# code page and bytes like 0x90 (3rd byte of 🐛 in a commit
|
||||
# subject) crash the stdlib reader thread (#52649).
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
timeout=timeout,
|
||||
cwd=str(cwd),
|
||||
)
|
||||
|
|
@ -179,7 +184,8 @@ def _check_via_rev(local_rev: str) -> Optional[int]:
|
|||
try:
|
||||
result = subprocess.run(
|
||||
["git", "ls-remote", _UPSTREAM_REPO_URL, "refs/heads/main"],
|
||||
capture_output=True, text=True, timeout=10,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace",
|
||||
timeout=10,
|
||||
)
|
||||
except Exception:
|
||||
return None
|
||||
|
|
@ -241,7 +247,8 @@ def _check_via_local_git(repo_dir: Path) -> Optional[int]:
|
|||
try:
|
||||
result = subprocess.run(
|
||||
["git", "rev-list", "--count", "HEAD..origin/main"],
|
||||
capture_output=True, text=True, timeout=5,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace",
|
||||
timeout=5,
|
||||
cwd=str(repo_dir),
|
||||
)
|
||||
if result.returncode == 0:
|
||||
|
|
@ -343,6 +350,8 @@ def _git_short_hash(repo_dir: Path, rev: str) -> Optional[str]:
|
|||
["git", "rev-parse", "--short=8", rev],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
timeout=5,
|
||||
cwd=str(repo_dir),
|
||||
)
|
||||
|
|
@ -399,6 +408,8 @@ def get_git_banner_state(repo_dir: Optional[Path] = None) -> Optional[dict]:
|
|||
["git", "rev-list", "--count", "origin/main..HEAD"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
timeout=5,
|
||||
cwd=str(repo_dir),
|
||||
)
|
||||
|
|
@ -435,6 +446,8 @@ def get_latest_release_tag(repo_dir: Optional[Path] = None) -> Optional[tuple]:
|
|||
["git", "describe", "--tags", "--abbrev=0"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
timeout=3,
|
||||
cwd=str(repo_dir),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -4158,6 +4158,12 @@ def _recent_upstream_commits(n: int = 20) -> List[Dict[str, Any]]:
|
|||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
# git log emits UTF-8 (commit subjects can carry emoji/CJK). On
|
||||
# Windows text=True defaults to the ANSI code page — a byte like
|
||||
# 0x90 (3rd byte of 🐛) is undefined in cp1252 and crashed the
|
||||
# stdlib _readerthread, killing the desktop backend (#52649).
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
timeout=5,
|
||||
)
|
||||
if out.returncode != 0:
|
||||
|
|
@ -5780,6 +5786,10 @@ def _run_setup_command(
|
|||
env=_memory_provider_setup_env(),
|
||||
capture_output=True,
|
||||
text=True,
|
||||
# Lossy UTF-8 decode — setup tools emit UTF-8; never let a
|
||||
# locale-mismatched byte raise in the reader thread (#52649).
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
timeout=timeout,
|
||||
check=False,
|
||||
)
|
||||
|
|
@ -8711,6 +8721,10 @@ def _ensure_whatsapp_bridge_dependencies(bridge_dir: Path) -> None:
|
|||
cwd=str(bridge_dir),
|
||||
capture_output=True,
|
||||
text=True,
|
||||
# npm output is UTF-8; guard the Windows ANSI-code-page default
|
||||
# against undefined bytes crashing the reader thread (#52649).
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
timeout=timeout,
|
||||
env=with_hermes_node_path(),
|
||||
creationflags=windows_hide_flags(),
|
||||
|
|
@ -16199,6 +16213,8 @@ def _probe_docker_backend() -> tuple:
|
|||
["docker", "info", "--format", "{{.ServerVersion}}"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
timeout=2,
|
||||
)
|
||||
if proc.returncode == 0:
|
||||
|
|
|
|||
|
|
@ -113,6 +113,8 @@ def _build_sha() -> str:
|
|||
["git", "rev-parse", "HEAD"],
|
||||
cwd=str(_repo_root()),
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
stderr=subprocess.DEVNULL,
|
||||
timeout=2,
|
||||
).strip()
|
||||
|
|
@ -686,7 +688,7 @@ class ComputeHost:
|
|||
|
||||
def _rss_mb(pid: int) -> float:
|
||||
try:
|
||||
out = subprocess.check_output(["ps", "-o", "rss=", "-p", str(pid)], text=True, stdin=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=2).strip()
|
||||
out = subprocess.check_output(["ps", "-o", "rss=", "-p", str(pid)], text=True, encoding="utf-8", errors="replace", stdin=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=2).strip()
|
||||
return int(out.splitlines()[-1].strip()) / 1024.0 if out else 0.0
|
||||
except Exception:
|
||||
return 0.0
|
||||
|
|
|
|||
|
|
@ -72,6 +72,8 @@ def _build_sha() -> str:
|
|||
["git", "rev-parse", "HEAD"],
|
||||
cwd=str(_repo_root()),
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
stderr=subprocess.DEVNULL,
|
||||
timeout=2,
|
||||
).strip()
|
||||
|
|
@ -112,6 +114,8 @@ def _pid_command(pid: int) -> str:
|
|||
return subprocess.check_output(
|
||||
["ps", "-p", str(pid), "-o", "command="],
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
stderr=subprocess.DEVNULL,
|
||||
timeout=2,
|
||||
).strip()
|
||||
|
|
@ -327,6 +331,11 @@ class HostSupervisor:
|
|||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
# Lossy UTF-8 decode — the compute host emits UTF-8; a
|
||||
# locale-mismatched byte must not raise inside the drain
|
||||
# threads and kill the supervisor (#52649).
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
bufsize=1,
|
||||
start_new_session=True,
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue