From 1ffa01f35fb8bc0bf8825117788092ff0e08421f Mon Sep 17 00:00:00 2001 From: teknium1 <127238744+teknium1@users.noreply.github.com> Date: Sun, 28 Jun 2026 05:14:20 -0700 Subject: [PATCH] test(windows): cover no-window backend subprocess flags --- ...test_windows_subprocess_no_window_flags.py | 263 ++++++++++++++++++ tui_gateway/server.py | 5 + 2 files changed, 268 insertions(+) create mode 100644 tests/test_windows_subprocess_no_window_flags.py diff --git a/tests/test_windows_subprocess_no_window_flags.py b/tests/test_windows_subprocess_no_window_flags.py new file mode 100644 index 00000000000..dacf4c985f6 --- /dev/null +++ b/tests/test_windows_subprocess_no_window_flags.py @@ -0,0 +1,263 @@ +from __future__ import annotations + +import subprocess +from pathlib import Path +from types import SimpleNamespace + + +_CREATE_NO_WINDOW = 0x08000000 + + +class _Completed: + def __init__(self, stdout: str | bytes = "ok\n", returncode: int = 0): + self.stdout = stdout + self.stderr = "" + self.returncode = returncode + + +def test_tui_gateway_git_probe_hides_git_windows(monkeypatch): + from tui_gateway import git_probe + + captured = [] + + def fake_run(cmd, **kwargs): + captured.append((cmd, kwargs)) + return _Completed(stdout="main\n") + + monkeypatch.setattr(git_probe, "IS_WINDOWS", True) + monkeypatch.setattr(git_probe, "windows_hide_flags", lambda: _CREATE_NO_WINDOW) + monkeypatch.setattr(git_probe.subprocess, "run", fake_run) + + assert git_probe.run_git("C:/repo", "branch", "--show-current") == "main" + + assert captured == [ + ( + ["git", "-C", "C:/repo", "branch", "--show-current"], + { + "capture_output": True, + "text": True, + "encoding": "utf-8", + "errors": "replace", + "timeout": git_probe._GIT_TIMEOUT, + "check": False, + "stdin": subprocess.DEVNULL, + "creationflags": _CREATE_NO_WINDOW, + }, + ) + ] + + +def test_tui_gateway_fuzzy_file_listing_hides_git_windows(monkeypatch): + from hermes_cli import _subprocess_compat + from tui_gateway import server + + captured = [] + + def fake_run(cmd, **kwargs): + captured.append((cmd, kwargs)) + if cmd[-1] == "--show-toplevel": + return _Completed(stdout=b"C:/repo\n") + return _Completed(stdout=b"src/main.py\0README.md\0") + + monkeypatch.setattr(_subprocess_compat, "IS_WINDOWS", True) + monkeypatch.setattr(_subprocess_compat, "windows_hide_flags", lambda: _CREATE_NO_WINDOW) + monkeypatch.setattr(server.subprocess, "run", fake_run) + server._fuzzy_cache.clear() + + assert server._list_repo_files("C:/repo") == ["src/main.py", "README.md"] + + assert [kwargs["creationflags"] for _, kwargs in captured] == [ + _CREATE_NO_WINDOW, + _CREATE_NO_WINDOW, + ] + + +def test_coding_context_git_hides_git_windows(monkeypatch): + from agent import coding_context + + captured = [] + + def fake_run(cmd, **kwargs): + captured.append((cmd, kwargs)) + return _Completed(stdout="clean\n") + + monkeypatch.setattr(coding_context, "IS_WINDOWS", True) + monkeypatch.setattr(coding_context, "windows_hide_flags", lambda: _CREATE_NO_WINDOW) + monkeypatch.setattr(coding_context.subprocess, "run", fake_run) + + assert coding_context._git(Path("C:/repo"), "status", "--short") == "clean" + assert captured[0][1]["creationflags"] == _CREATE_NO_WINDOW + + +def test_context_reference_git_and_rg_hide_windows(monkeypatch): + from agent import context_references + + captured = [] + + def fake_run(cmd, **kwargs): + captured.append((cmd, kwargs)) + if cmd[0] == "rg": + return _Completed(stdout="src/main.py\n") + return _Completed(stdout="diff --git a/src/main.py b/src/main.py\n") + + monkeypatch.setattr(context_references, "IS_WINDOWS", True) + monkeypatch.setattr(context_references, "windows_hide_flags", lambda: _CREATE_NO_WINDOW) + monkeypatch.setattr(context_references.subprocess, "run", fake_run) + + ref = context_references.ContextReference( + raw="@diff", + kind="diff", + target="", + start=0, + end=5, + ) + warning, block = context_references._expand_git_reference( + ref, + Path("C:/repo"), + ["diff"], + "git diff", + ) + assert warning is None + assert block is not None + assert "git diff" in block + assert context_references._rg_files(Path("C:/repo/src"), Path("C:/repo"), 10) == [ + Path("src/main.py") + ] + + assert [kwargs["creationflags"] for _, kwargs in captured] == [ + _CREATE_NO_WINDOW, + _CREATE_NO_WINDOW, + ] + + +def test_copilot_gh_cli_probe_hides_gh_windows(monkeypatch): + from hermes_cli import copilot_auth + + captured = [] + + def fake_run(cmd, **kwargs): + captured.append((cmd, kwargs)) + return _Completed(stdout="gho_from_cli\n") + + monkeypatch.setattr(copilot_auth, "IS_WINDOWS", True) + monkeypatch.setattr(copilot_auth, "windows_hide_flags", lambda: _CREATE_NO_WINDOW) + monkeypatch.setattr(copilot_auth, "_gh_cli_candidates", lambda: ["gh"]) + monkeypatch.setattr(copilot_auth.subprocess, "run", fake_run) + + assert copilot_auth._try_gh_cli_token() == "gho_from_cli" + assert captured[0][0] == ["gh", "auth", "token"] + assert captured[0][1]["creationflags"] == _CREATE_NO_WINDOW + + +def test_gateway_pid_scan_hides_wmic_and_powershell_windows(monkeypatch): + from hermes_cli import gateway + from hermes_cli import _subprocess_compat + + captured = [] + + def fake_run(cmd, **kwargs): + captured.append((cmd, kwargs)) + if cmd[0] == "wmic": + return _Completed(stdout="", returncode=1) + return _Completed(stdout="CommandLine=hermes gateway\nProcessId=123\n") + + monkeypatch.setattr(gateway, "is_windows", lambda: True) + monkeypatch.setattr(gateway.shutil, "which", lambda name: name) + monkeypatch.setattr(_subprocess_compat, "IS_WINDOWS", True) + monkeypatch.setattr(_subprocess_compat, "windows_hide_flags", lambda: _CREATE_NO_WINDOW) + monkeypatch.setattr(gateway.subprocess, "run", fake_run) + + assert gateway._scan_gateway_pids(set()) == [123] + assert [kwargs["creationflags"] for _, kwargs in captured] == [ + _CREATE_NO_WINDOW, + _CREATE_NO_WINDOW, + ] + + +def test_stale_dashboard_windows_scan_hides_wmic(monkeypatch): + from hermes_cli import main + from hermes_cli import _subprocess_compat + + captured = [] + + def fake_run(cmd, **kwargs): + captured.append((cmd, kwargs)) + return _Completed(stdout="CommandLine=hermes dashboard\nProcessId=123\n") + + monkeypatch.setattr(main.sys, "platform", "win32") + monkeypatch.setattr(_subprocess_compat, "IS_WINDOWS", True) + monkeypatch.setattr(_subprocess_compat, "windows_hide_flags", lambda: _CREATE_NO_WINDOW) + monkeypatch.setattr(main.subprocess, "run", fake_run) + + assert main._find_stale_dashboard_pids() == [123] + assert captured[0][1]["creationflags"] == _CREATE_NO_WINDOW + + +def test_gateway_force_kill_hides_taskkill_window(monkeypatch): + from gateway import status + from hermes_cli import _subprocess_compat + + captured = [] + + def fake_run(cmd, **kwargs): + captured.append((cmd, kwargs)) + return _Completed(stdout="") + + monkeypatch.setattr(status, "_IS_WINDOWS", True) + monkeypatch.setattr(_subprocess_compat, "IS_WINDOWS", True) + monkeypatch.setattr(_subprocess_compat, "windows_hide_flags", lambda: _CREATE_NO_WINDOW) + monkeypatch.setattr(status.subprocess, "run", fake_run) + + status.terminate_pid(123, force=True) + + assert captured == [ + ( + ["taskkill", "/PID", "123", "/T", "/F"], + { + "capture_output": True, + "text": True, + "timeout": 10, + "creationflags": _CREATE_NO_WINDOW, + }, + ) + ] + + +def test_shell_hooks_hide_hook_command_windows(monkeypatch): + from agent import shell_hooks + + captured = [] + + def fake_run(cmd, **kwargs): + captured.append((cmd, kwargs)) + return SimpleNamespace(returncode=0, stdout="{}", stderr="") + + monkeypatch.setattr(shell_hooks, "IS_WINDOWS", True) + monkeypatch.setattr(shell_hooks, "windows_hide_flags", lambda: _CREATE_NO_WINDOW) + monkeypatch.setattr(shell_hooks.subprocess, "run", fake_run) + + result = shell_hooks._spawn( + shell_hooks.ShellHookSpec(event="post_tool_call", command="hook-bin --flag"), + "{}", + ) + + assert result["returncode"] == 0 + assert captured[0][1]["creationflags"] == _CREATE_NO_WINDOW + + +def test_inline_skill_shell_hides_bash_window(monkeypatch): + from agent import skill_preprocessing + + captured = [] + + def fake_run(cmd, **kwargs): + captured.append((cmd, kwargs)) + return SimpleNamespace(returncode=0, stdout="ok\n", stderr="") + + monkeypatch.setattr(skill_preprocessing, "IS_WINDOWS", True) + monkeypatch.setattr(skill_preprocessing, "windows_hide_flags", lambda: _CREATE_NO_WINDOW) + monkeypatch.setattr(skill_preprocessing.subprocess, "run", fake_run) + + assert skill_preprocessing.run_inline_shell("echo ok", cwd=None, timeout=5) == "ok" + assert captured[0][0] == ["bash", "-c", "echo ok"] + assert captured[0][1]["creationflags"] == _CREATE_NO_WINDOW diff --git a/tui_gateway/server.py b/tui_gateway/server.py index 21590a51582..ea4ae4fbbf9 100644 --- a/tui_gateway/server.py +++ b/tui_gateway/server.py @@ -11668,6 +11668,9 @@ def _list_repo_files(root: str) -> list[str]: return cached[1] files: list[str] = [] + from hermes_cli._subprocess_compat import windows_hide_flags + + _creationflags = windows_hide_flags() try: top_result = subprocess.run( ["git", "-C", root, "rev-parse", "--show-toplevel"], @@ -11675,6 +11678,7 @@ def _list_repo_files(root: str) -> list[str]: timeout=2.0, check=False, stdin=subprocess.DEVNULL, + creationflags=_creationflags, ) if top_result.returncode == 0: top = top_result.stdout.decode("utf-8", "replace").strip() @@ -11693,6 +11697,7 @@ def _list_repo_files(root: str) -> list[str]: timeout=2.0, check=False, stdin=subprocess.DEVNULL, + creationflags=_creationflags, ) if list_result.returncode == 0: for p in list_result.stdout.decode("utf-8", "replace").split("\0"):