94f095e8b7
check_subprocess_stdin.py already had a full-repo-scan pytest wrapper (test_subprocess_stdin_guard.py), so a plain pytest run catches a regression there without anyone remembering to run the script by hand. check-windows-footguns.py had no equivalent (only a narrow single-rule test existed), which is why the bare os.killpg/ signal.SIGKILL regression in the npx-agent-browser hardening commit shipped past local testing and was only caught by CI running the script directly. New test_windows_footguns_full_repo_scan.py mirrors the stdin guard's exact pattern to close that asymmetry. Also adds direct coverage for _kill_process_tree's getattr fallback when os.killpg is missing, and asserts warm_agent_browser_npx_cache's Popen call passes stdin=subprocess.DEVNULL as a literal argument.
42 lines
1.7 KiB
Python
42 lines
1.7 KiB
Python
"""Full-repo self-scan wrapper for scripts/check-windows-footguns.py.
|
|
|
|
scripts/check_subprocess_stdin.py has had a pytest wrapper (see
|
|
tests/tools/test_subprocess_stdin_guard.py's test_all_tui_subprocess_calls_
|
|
have_stdin) that runs the checker with its default full-scan behavior and
|
|
asserts a clean exit — so a normal pytest run of that file catches
|
|
regressions even when no one remembers to run the standalone script by hand.
|
|
check-windows-footguns.py had no equivalent: only a narrow rule-level test
|
|
(tests/scripts/test_footgun_subprocess_encoding.py, scoped to the
|
|
text=True/encoding= rule) existed, so a bare ``os.killpg``/``signal.SIGKILL``
|
|
regression (caught by CI running the real script with --all, not by any
|
|
local pytest run) shipped in the T1-T3 npx-agent-browser hardening commit
|
|
before anyone ran the script directly. This closes that gap the same way
|
|
the stdin guard already closes its equivalent one.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[2]
|
|
SCRIPT = REPO_ROOT / "scripts" / "check-windows-footguns.py"
|
|
|
|
|
|
def test_full_repo_scan_has_no_unsuppressed_windows_footguns():
|
|
"""Mirrors check_subprocess_stdin.py's wrapper: run the real checker
|
|
against the whole repo (--all) and require a clean exit, so this test
|
|
file — not just institutional memory — is what catches the next
|
|
bare os.killpg/signal.SIGKILL-style regression."""
|
|
result = subprocess.run(
|
|
[sys.executable, str(SCRIPT), "--all"],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=60,
|
|
stdin=subprocess.DEVNULL,
|
|
)
|
|
assert result.returncode == 0, (
|
|
f"Windows footgun check failed:\n{result.stdout}\n{result.stderr}"
|
|
)
|