From dd3320d1cea44938eae44e856e76e2d8b7649619 Mon Sep 17 00:00:00 2001 From: ekko <152005280+EKKOLearnAI@users.noreply.github.com> Date: Thu, 21 May 2026 12:25:38 +0800 Subject: [PATCH] Fix Windows netstat encoding in agent bridge (#894) --- .../hermes/agent-bridge/hermes_bridge.py | 13 ++++- .../services/hermes/agent-bridge/manager.ts | 2 +- tests/server/agent-bridge-profile-env.test.ts | 51 +++++++++++++++++++ 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/packages/server/src/services/hermes/agent-bridge/hermes_bridge.py b/packages/server/src/services/hermes/agent-bridge/hermes_bridge.py index 36bdda59..98c615cf 100755 --- a/packages/server/src/services/hermes/agent-bridge/hermes_bridge.py +++ b/packages/server/src/services/hermes/agent-bridge/hermes_bridge.py @@ -14,6 +14,7 @@ import copy import hashlib import importlib.util import json +import locale import os import queue import shutil @@ -1649,6 +1650,13 @@ def _tcp_endpoint_port(endpoint: str) -> int | None: return None +def _platform_text_encoding() -> str: + getencoding = getattr(locale, "getencoding", None) + if callable(getencoding): + return getencoding() or "utf-8" + return locale.getpreferredencoding(False) or "utf-8" + + def _windows_listening_pids_on_port(port: int) -> list[int]: if os.name != "nt": return [] @@ -1658,12 +1666,15 @@ def _windows_listening_pids_on_port(port: int) -> list[int]: check=False, capture_output=True, text=True, + encoding=_platform_text_encoding(), + errors="ignore", timeout=5, ) except Exception: return [] + stdout = result.stdout or "" pids: set[int] = set() - for line in result.stdout.splitlines(): + for line in stdout.splitlines(): parts = line.strip().split() if len(parts) < 5: continue diff --git a/packages/server/src/services/hermes/agent-bridge/manager.ts b/packages/server/src/services/hermes/agent-bridge/manager.ts index a534f67e..a6d49c41 100644 --- a/packages/server/src/services/hermes/agent-bridge/manager.ts +++ b/packages/server/src/services/hermes/agent-bridge/manager.ts @@ -245,7 +245,7 @@ function tcpEndpointPort(endpoint: string): number | undefined { function windowsListeningPidsOnPort(port: number): number[] { try { - const output = execFileSync('netstat.exe', ['-ano', '-p', 'tcp'], { encoding: 'utf-8', windowsHide: true }) + const output = execFileSync('netstat.exe', ['-ano', '-p', 'tcp'], { windowsHide: true }).toString('utf8') const pids = new Set() for (const line of output.split(/\r?\n/)) { const parts = line.trim().split(/\s+/) diff --git a/tests/server/agent-bridge-profile-env.test.ts b/tests/server/agent-bridge-profile-env.test.ts index f6194806..c1536bf7 100644 --- a/tests/server/agent-bridge-profile-env.test.ts +++ b/tests/server/agent-bridge-profile-env.test.ts @@ -234,4 +234,55 @@ print(json.dumps({ restored_glm: 'shell-glm', }) }) + + it('handles Windows netstat output decode failures without crashing', async () => { + const result = await runBridgeProbe(` +import importlib.util +import json +import os +import sys + +spec = importlib.util.spec_from_file_location("hermes_bridge", os.environ["BRIDGE_PATH"]) +bridge = importlib.util.module_from_spec(spec) +sys.modules["hermes_bridge"] = bridge +spec.loader.exec_module(bridge) + +class EmptyStdoutResult: + stdout = None + +def fake_run_empty(*args, **kwargs): + return EmptyStdoutResult() + +class NetstatResult: + stdout = " TCP 127.0.0.1:18765 0.0.0.0:0 LISTENING 4321\\r\\n" + +def fake_run_listener(*args, **kwargs): + return NetstatResult() + +original_name = bridge.os.name +original_pid = bridge.os.getpid +original_run = bridge.subprocess.run +try: + bridge.os.name = "nt" + bridge.os.getpid = lambda: 1234 + bridge.subprocess.run = fake_run_empty + empty = bridge._windows_listening_pids_on_port(18765) + bridge.subprocess.run = fake_run_listener + listener = bridge._windows_listening_pids_on_port(18765) +finally: + bridge.os.name = original_name + bridge.os.getpid = original_pid + bridge.subprocess.run = original_run + +print(json.dumps({ + "empty": empty, + "listener": listener, +})) +`) + + expect(result).toEqual({ + empty: [], + listener: [4321], + }) + }) })