mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-01 12:02:05 +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
|
|
@ -72,23 +72,44 @@ def test_flags_multiline_call_without_redirection(checker):
|
|||
@pytest.mark.parametrize(
|
||||
"src",
|
||||
[
|
||||
# output captured / redirected -> inherits parent console, no popup
|
||||
'subprocess.run(["git", "x"], capture_output=True)',
|
||||
'subprocess.run(["git", "x"], stdout=subprocess.PIPE)',
|
||||
'subprocess.run(["git", "x"], stderr=subprocess.DEVNULL)',
|
||||
# check_output always captures stdout
|
||||
'subprocess.check_output(["git", "rev-parse", "HEAD"])',
|
||||
# captured/redirected AND not a known Windows-flashing program -> safe.
|
||||
# (espeak-ng / a non-console-exe; capture inherits the parent console.)
|
||||
'subprocess.run(["espeak-ng", "hi"], capture_output=True)',
|
||||
'subprocess.run(["mytool", "x"], stdout=subprocess.PIPE)',
|
||||
'subprocess.check_output(["mytool", "rev-parse"])',
|
||||
# already managing the console
|
||||
'subprocess.run(["x"], creationflags=windows_hide_flags())',
|
||||
'subprocess.run(["git", "x"], creationflags=windows_hide_flags())',
|
||||
# ** spread may carry a helper -> not penalised
|
||||
"subprocess.Popen(argv, **windows_detach_popen_kwargs())",
|
||||
"subprocess.run(cmd, **run_kwargs)",
|
||||
# routed through the chokepoint wrapper -> different prefix, never flagged
|
||||
"_subprocess_compat.run(['git', 'status'])",
|
||||
],
|
||||
)
|
||||
def test_exempts_window_safe_calls(checker, src):
|
||||
assert _flag(checker, src) == [], src
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"src",
|
||||
[
|
||||
# Cross-platform console exes that allocate a Windows console even when
|
||||
# captured — capture is NOT a safety boundary for these (Gille review,
|
||||
# PR #53791 follow-up). They must be flagged despite capture/redirect.
|
||||
'subprocess.run(["git", "status"], capture_output=True)',
|
||||
'subprocess.run(["git", "x"], stdout=subprocess.PIPE)',
|
||||
'subprocess.run(["gh", "pr", "list"], stderr=subprocess.DEVNULL)',
|
||||
'subprocess.check_output(["git", "rev-parse", "HEAD"])',
|
||||
'subprocess.run(["npm", "ci"], capture_output=True)',
|
||||
'subprocess.run(["ffmpeg", "-i", "x"], capture_output=True)',
|
||||
'subprocess.run(["docker", "info"], capture_output=True, timeout=10)',
|
||||
'subprocess.run(["uv", "pip", "install"], capture_output=True)',
|
||||
],
|
||||
)
|
||||
def test_flags_flashing_programs_even_when_captured(checker, src):
|
||||
assert _flag(checker, src) == [1], src
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"src",
|
||||
[
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue