Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license

This commit is contained in:
2026-09-05 13:26:46 +03:00
commit 03634b1ca3
11340 changed files with 3442369 additions and 0 deletions
@@ -0,0 +1,99 @@
"""Invariants for scripts/build_skills_index.py's health-check guard.
Regression context (June 2026): a GitHub API rate limit zeroed every
api.github.com-backed source (github / well-known) at
once during the docs deploy crawl. The build's health check fired and exited
non-zero — but it had ALREADY written the degenerate index to disk, and
deploy-site.yml swallowed the exit code with ``|| echo non-fatal``. The
partial index (missing the OpenAI/Anthropic/HuggingFace/NVIDIA tabs) shipped
to the live Skills Hub.
These tests pin the two contracts that prevent a recurrence:
1. A degenerate crawl exits non-zero AND does NOT write the output file
(so extract-skills.py falls back instead of reading a broken index).
2. A healthy crawl exits zero AND writes the file with every source present.
"""
import os
import sys
import types
import pytest
import scripts.build_skills_index as build_mod
def _meta(name, src):
return build_mod.SkillMeta(
name=name, description="d", source=src,
identifier=f"{src}/{name}", trust_level="community",
)
class _FakeSource:
def __init__(self, src, n, rate_limited=False):
self._src = src
self._n = n
self.is_rate_limited = rate_limited
def search(self, query, limit=10):
return [_meta(f"{self._src}-{i}", self._src) for i in range(self._n)]
def enrich_owners(self, skills, max_workers=30):
# No-op: fake source doesn't need owner enrichment.
return 0
def _install_fake_sources(monkeypatch, *, github_count,
well_known_count=10, github_rate_limited=False):
monkeypatch.setattr(build_mod, "SkillsShSource", lambda auth: _FakeSource("skills.sh", 15000))
monkeypatch.setattr(build_mod, "OptionalSkillSource", lambda: _FakeSource("official", 95))
monkeypatch.setattr(build_mod, "WellKnownSkillSource", lambda: _FakeSource("well-known", well_known_count))
monkeypatch.setattr(
build_mod, "GitHubSource",
lambda auth: _FakeSource("github", github_count, rate_limited=github_rate_limited),
)
monkeypatch.setattr(build_mod, "ClawHubSource", lambda: _FakeSource("clawhub", 69000))
monkeypatch.setattr(build_mod, "LobeHubSource", lambda: _FakeSource("lobehub", 500))
monkeypatch.setattr(build_mod, "BrowseShSource", lambda: _FakeSource("browse-sh", 380))
monkeypatch.setattr(
build_mod, "crawl_skills_sh",
lambda source: [build_mod._meta_to_dict(m) for m in source.search("", 0)],
)
monkeypatch.setattr(build_mod, "batch_resolve_paths", lambda skills, auth: skills)
monkeypatch.setattr(
build_mod, "GitHubAuth",
lambda: types.SimpleNamespace(auth_method=lambda: "token"),
)
def test_degenerate_crawl_exits_nonzero_and_writes_no_file(tmp_path, monkeypatch):
"""A collapsed GitHub crawl must fail loud and leave OUTPUT_PATH unwritten."""
out = tmp_path / "skills-index.json"
monkeypatch.setattr(build_mod, "OUTPUT_PATH", str(out))
_install_fake_sources(monkeypatch, github_count=0,
well_known_count=0, github_rate_limited=True)
with pytest.raises(SystemExit) as exc:
build_mod.main()
assert exc.value.code != 0
# The degenerate index must NOT have been written — extract-skills.py
# relies on the file's absence to fall back instead of reading garbage.
assert not out.exists()
def test_healthy_crawl_writes_index_with_all_sources(tmp_path, monkeypatch):
out = tmp_path / "skills-index.json"
monkeypatch.setattr(build_mod, "OUTPUT_PATH", str(out))
_install_fake_sources(monkeypatch, github_count=200)
build_mod.main() # exit 0 (no SystemExit)
assert out.exists()
import json
data = json.loads(out.read_text())
sources = {s["source"] for s in data["skills"]}
# Every GitHub-API-backed source that vanished in the regression is present.
assert {"github", "well-known"} <= sources
assert data["skill_count"] == len(data["skills"])
+118
View File
@@ -0,0 +1,118 @@
"""Wrappers for scripts/check-case-collisions.py.
Same pattern as tests/scripts/test_windows_footguns_full_repo_scan.py: run
the real checker and assert its outcomes, so a normal pytest run catches a
regression — someone committing a case-colliding pair — without anyone
having to remember to run the script by hand.
The collision cases are built with ``git update-index --cacheinfo`` (index
only, never touching the working tree), so they exercise the same index the
checker reads and work even on a case-insensitive filesystem, where the two
spellings cannot coexist on disk.
"""
from __future__ import annotations
import hashlib
import subprocess
import sys
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[2]
SCRIPT = REPO_ROOT / "scripts" / "check-case-collisions.py"
def _git_blob_sha(data: bytes) -> str:
"""The git object hash for a blob with ``data`` as its content."""
header = f"blob {len(data)}\0".encode("ascii")
return hashlib.sha1(header + data).hexdigest()
def _run_check(*args, root=None):
cmd = [sys.executable, str(SCRIPT)] + list(args)
if root is not None:
cmd.append(str(root))
return subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=60,
stdin=subprocess.DEVNULL,
cwd=REPO_ROOT,
)
def _git_init(tmp_path) -> Path:
repo = tmp_path / "repo"
repo.mkdir()
subprocess.run(["git", "init", "-q"], cwd=repo, check=True)
return repo
def test_full_repo_has_no_case_colliding_paths():
"""The real checker against the whole tracked tree must exit clean."""
result = _run_check()
assert result.returncode == 0, (
f"Case-collision check failed:\n{result.stdout}\n{result.stderr}"
)
def test_detects_case_colliding_paths(tmp_path):
"""Same-directory Foo.txt + foo.txt must fail, naming both paths."""
repo = _git_init(tmp_path)
subprocess.run(
[
"git", "update-index", "--add", "--cacheinfo",
f"100644,{_git_blob_sha(b'a')},Foo.txt",
],
cwd=repo, check=True,
)
subprocess.run(
[
"git", "update-index", "--add", "--cacheinfo",
f"100644,{_git_blob_sha(b'b')},foo.txt",
],
cwd=repo, check=True,
)
result = _run_check(root=repo)
assert result.returncode == 1, f"expected failure, got:\n{result.stdout}"
assert "Foo.txt" in result.stdout
assert "foo.txt" in result.stdout
def test_detects_directory_case_collisions(tmp_path):
"""The comparison is on the FULL path — dir/Foo.txt vs DIR/foo.txt too."""
repo = _git_init(tmp_path)
subprocess.run(
[
"git", "update-index", "--add", "--cacheinfo",
f"100644,{_git_blob_sha(b'a')},src/Helper.py",
],
cwd=repo, check=True,
)
subprocess.run(
[
"git", "update-index", "--add", "--cacheinfo",
f"100644,{_git_blob_sha(b'b')},SRC/helper.py",
],
cwd=repo, check=True,
)
result = _run_check(root=repo)
assert result.returncode == 1, f"expected failure, got:\n{result.stdout}"
assert "src/Helper.py" in result.stdout
assert "SRC/helper.py" in result.stdout
def test_same_name_in_different_dirs_is_not_a_collision(tmp_path):
"""a/Readme.txt and b/readme.txt share a basename but not a path."""
repo = _git_init(tmp_path)
(repo / "a").mkdir()
(repo / "b").mkdir()
(repo / "a" / "Readme.txt").write_text("a", encoding="utf-8")
(repo / "b" / "readme.txt").write_text("b", encoding="utf-8")
subprocess.run(["git", "add", "-A"], cwd=repo, check=True)
result = _run_check(root=repo)
assert result.returncode == 0, f"expected clean, got:\n{result.stdout}"
@@ -0,0 +1,57 @@
"""Behavioral tests for the profile archive CI guard."""
from __future__ import annotations
import subprocess
import sys
from pathlib import Path
SCRIPT = (
Path(__file__).resolve().parents[2]
/ "scripts"
/ "ci"
/ "check_profile_archive_boundary.py"
)
def _run(root: Path) -> subprocess.CompletedProcess[str]:
return subprocess.run(
[sys.executable, str(SCRIPT), "--root", str(root)],
capture_output=True,
text=True,
check=False,
)
def test_clean_root_passes(tmp_path):
result = _run(tmp_path)
assert result.returncode == 0
assert "No profile export archives" in result.stdout
def test_root_profile_archive_fails_without_printing_contents(tmp_path):
default_archive = tmp_path / "default.tar.gz"
alternate_archive = tmp_path / "backup.TGZ"
default_archive.write_bytes(b"profile webhook secret must never be printed")
alternate_archive.write_bytes(b"another archive")
result = _run(tmp_path)
assert result.returncode == 1
assert "default.tar.gz" in result.stdout
assert "backup.TGZ" in result.stdout
assert "profile webhook secret" not in result.stdout
assert "another archive" not in result.stdout
def test_nested_profile_archive_is_also_rejected(tmp_path):
nested = tmp_path / "fixtures"
nested.mkdir()
(nested / "fixture.tar.gz").write_bytes(b"test fixture")
result = _run(tmp_path)
assert result.returncode == 1
assert "fixtures/fixture.tar.gz" in result.stdout
+181
View File
@@ -0,0 +1,181 @@
"""Tests for the conflict-free contributor mapping system.
New contributor email → GitHub login mappings live as one file per email
under contributors/emails/ (additions never merge-conflict). The legacy
AUTHOR_MAP dict in scripts/release.py is frozen; release.py merges both at
import time with the directory winning on duplicates.
"""
import subprocess
import sys
from pathlib import Path
import pytest
REPO_ROOT = Path(__file__).resolve().parents[2]
SCRIPTS_DIR = REPO_ROOT / "scripts"
sys.path.insert(0, str(SCRIPTS_DIR))
import release # noqa: E402
from add_contributor import add_contributor, read_mapping_file # noqa: E402
# ── directory loader behavior ─────────────────────────────────────────
def test_loader_reads_login_from_first_noncomment_line(tmp_path):
d = tmp_path / "emails"
d.mkdir()
(d / "jane@example.com").write_text("# salvage PR #1\njanedoe\n# trailing note\n")
mapping = release._load_contributor_dir(d)
assert mapping == {"jane@example.com": "janedoe"}
def test_effective_map_merges_legacy_and_directory():
# Invariant: every legacy entry survives into the effective map unless
# shadowed by a directory entry, and the directory contributes on top.
assert set(release.LEGACY_AUTHOR_MAP) <= (
set(release.AUTHOR_MAP) | set(release._load_contributor_dir())
)
for email, login in release._load_contributor_dir().items():
assert release.AUTHOR_MAP[email] == login
# ── add_contributor.py CLI behavior ───────────────────────────────────
@pytest.fixture()
def emails_dir(tmp_path, monkeypatch):
import add_contributor
d = tmp_path / "contributors" / "emails"
monkeypatch.setattr(add_contributor, "EMAILS_DIR", d)
return d
def test_add_creates_mapping_file(emails_dir):
rc = add_contributor("new@example.com", "newperson", "PR #999 salvage")
assert rc == 0
path = emails_dir / "new@example.com"
assert path.is_file()
assert read_mapping_file(path) == "newperson"
assert "# PR #999 salvage" in path.read_text()
def test_add_refuses_login_conflicting_with_legacy_map(emails_dir):
email, login = next(iter(release.LEGACY_AUTHOR_MAP.items()))
assert add_contributor(email, login + "x") == 1
assert not (emails_dir / email).exists()
def test_add_accepts_legacy_consecutive_hyphen_login(emails_dir):
# Legacy GitHub accounts with consecutive hyphens are real (Roger--Han);
# current signup rules forbid them but existing logins remain valid.
assert add_contributor("roger.hanhong@gmail.com", "Roger--Han") == 0
assert (emails_dir / "roger.hanhong@gmail.com").read_text(
encoding="utf-8"
).strip().endswith("Roger--Han")
def test_add_strips_at_prefix(emails_dir):
assert add_contributor("z@z.com", "@zeta") == 0
assert read_mapping_file(emails_dir / "z@z.com") == "zeta"
def test_cli_entrypoint_end_to_end(tmp_path):
# Run the real script in a subprocess against a temp repo layout.
scripts = tmp_path / "scripts"
scripts.mkdir()
for name in ("add_contributor.py",):
# Explicit encoding: add_contributor.py contains UTF-8 multi-byte
# characters (an em dash), so the locale-default read_text() raises
# UnicodeDecodeError on non-UTF-8 Windows locales (e.g. cp950).
(scripts / name).write_text(
(SCRIPTS_DIR / name).read_text(encoding="utf-8"), encoding="utf-8"
)
# Minimal stub release.py so the legacy lookup import works
(scripts / "release.py").write_text("LEGACY_AUTHOR_MAP = {}\n")
proc = subprocess.run(
[sys.executable, str(scripts / "add_contributor.py"),
"cli@example.com", "cliperson", "via subprocess"],
cwd=tmp_path, capture_output=True, text=True,
)
assert proc.returncode == 0, proc.stderr
out = (tmp_path / "contributors" / "emails" / "cli@example.com").read_text(encoding="utf-8")
assert out.splitlines()[0] == "cliperson"
# ── case-insensitive filename collisions ──────────────────────────────
#
# The mapping key IS the filename, so two emails differing only in case are the
# same file on Windows and on default macOS. When both exist, git writes one and
# then reports the other as modified in a FRESH clone, permanently: the repo can
# never be checked out clean on those platforms.
#
# The historical agent@Agents-Mac-mini.local / agent@agents-Mac-mini.local pair
# was removed from the tree (fcdae2cf0b), so there is no allowlist: any pair
# is a regression. scripts/check-case-collisions.py enforces the same
# invariant repo-wide in CI; this test keeps it visible next to the writer.
EMAILS_DIR = REPO_ROOT / "contributors" / "emails"
def test_no_case_insensitive_mapping_collisions():
groups: dict[str, set[str]] = {}
for entry in EMAILS_DIR.iterdir():
if entry.is_file():
groups.setdefault(entry.name.casefold(), set()).add(entry.name)
collisions = {frozenset(names) for names in groups.values() if len(names) > 1}
assert not collisions, (
"contributor mappings differing only in case cannot coexist on "
"case-insensitive filesystems (Windows, default macOS) — a fresh clone "
f"there is permanently dirty: {sorted(sorted(c) for c in collisions)}"
)
def test_add_contributor_refuses_a_case_collision(tmp_path, monkeypatch):
d = tmp_path / "emails"
d.mkdir()
(d / "agent@Example-Host.local").write_text("someone\n")
import add_contributor as mod
monkeypatch.setattr(mod, "EMAILS_DIR", d)
assert mod.add_contributor("agent@example-host.local", "otherperson") == 1
assert not (d / "agent@example-host.local").exists()
def test_add_contributor_refuses_case_collision_even_for_same_login(emails_dir, capsys):
# Same login, different spelling: still refused — the problem is the
# filename pair, not the login. The exact spelling is what's "present".
emails_dir.mkdir(parents=True)
(emails_dir / "Foo@Example.com").write_text("foouser\n")
assert add_contributor("foo@example.com", "foouser") == 1
assert "Foo@Example.com" in capsys.readouterr().err
assert sorted(p.name for p in emails_dir.iterdir()) == ["Foo@Example.com"]
# Exact-case re-add is the ordinary idempotent path.
assert add_contributor("Foo@Example.com", "foouser") == 0
def test_case_collision_uses_casefold(emails_dir):
# casefold, not lower: matches how macOS/Windows fold non-ASCII (ß ~ ss).
emails_dir.mkdir(parents=True)
(emails_dir / "strasse@example.com").write_text("someone\n")
assert add_contributor("STRASSE@example.com", "someone") == 1
assert add_contributor("straße@example.com", "someone") == 1
@@ -0,0 +1,234 @@
"""Tests for the ``subprocess text=True without explicit encoding=`` footgun
rule in ``scripts/check-windows-footguns.py``.
This rule (added alongside PR #60741) catches ``subprocess.run/Popen/call/
check_output/check_call(..., text=True, ...)`` calls that don't pass an
explicit ``encoding=``. On Chinese Windows (cp936/GBK) and other non-UTF-8
default codepages, ``text=True`` without ``encoding=`` decodes child output
with ``locale.getpreferredencoding(False)`` and crashes ``_readerthread``
with ``UnicodeDecodeError`` on non-default-codepage bytes.
See issues #47939, #53428, #57238.
"""
from __future__ import annotations
import importlib.util
import sys
from pathlib import Path
import pytest
REPO_ROOT = Path(__file__).resolve().parents[2]
LINTER_PATH = REPO_ROOT / "scripts" / "check-windows-footguns.py"
def _load_linter_module():
"""Import the linter script as a module (it's not a package).
Register the module in sys.modules BEFORE exec_module so that
``@dataclass`` can resolve ``cls.__module__`` via
``sys.modules.get(cls.__module__).__dict__`` (CPython 3.11+ dataclass
internals require this).
"""
spec = importlib.util.spec_from_file_location("check_windows_footguns", LINTER_PATH)
mod = importlib.util.module_from_spec(spec)
sys.modules["check_windows_footguns"] = mod
spec.loader.exec_module(mod)
return mod
@pytest.fixture(scope="module")
def linter():
return _load_linter_module()
def _find_footgun(linter, name: str):
"""Locate a Footgun by name in the FOOTGUNS list."""
for fg in linter.FOOTGUNS:
if fg.name == name:
return fg
pytest.fail(f"Footgun rule '{name}' not found in FOOTGUNS")
def _scan_line(linter, line: str, footgun_name: str) -> bool:
"""Return True if the given line triggers the named footgun rule.
Uses the linter's own pattern + post_filter logic so the test exercises
the real detection path (including guard-hint and suppression checks).
"""
fg = _find_footgun(linter, footgun_name)
# Replicate the relevant checks from scan_file(): suppression marker,
# guard hints, then pattern + post_filter.
if linter.SUPPRESS_MARKER.search(line):
return False
if any(hint in line for hint in linter.GUARD_HINTS):
return False
code = linter._strip_code(line)
if not code.strip():
return False
match = fg.pattern.search(code)
if not match:
return False
if fg.post_filter is not None:
try:
if not fg.post_filter(match, line):
return False
except (IndexError, AttributeError):
return False
return True
RULE_NAME = "subprocess text=True without explicit encoding="
# ---------------------------------------------------------------------------
# Detection — these SHOULD be flagged
# ---------------------------------------------------------------------------
class TestDetection:
def test_flags_subprocess_check_output_text_true(self, linter):
line = ' out = subprocess.check_output(["git", "status"], text=True)'
assert _scan_line(linter, line, RULE_NAME)
def test_flags_text_with_spaces_around_equals(self, linter):
line = ' subprocess.run(cmd, text = True, timeout=10)'
assert _scan_line(linter, line, RULE_NAME)
def test_flags_bare_run_call(self, linter):
# .run( without explicit subprocess. prefix — still a subprocess call
line = ' result = obj.run(cmd, text=True)'
assert _scan_line(linter, line, RULE_NAME)
# ---------------------------------------------------------------------------
# Suppression — these should NOT be flagged
# ---------------------------------------------------------------------------
class TestSuppression:
def test_does_not_flag_comment_only_line(self, linter):
line = ' # subprocess.run(cmd, text=True) — example'
assert not _scan_line(linter, line, RULE_NAME)
# ---------------------------------------------------------------------------
# Helper functions — unit tests for _is_likely_subprocess_call and
# _looks_like_string_literal
# ---------------------------------------------------------------------------
class TestHelpers:
def test_is_likely_subprocess_call_matches_subprocess_run(self, linter):
assert linter._is_likely_subprocess_call("subprocess.run(cmd, text=True)")
def test_is_likely_subprocess_call_rejects_plain_assignment(self, linter):
assert not linter._is_likely_subprocess_call("config.text = True")
def test_looks_like_string_literal_double_quotes(self, linter):
import re
line = ' msg = "use text=True carefully"'
match = re.search(r"\btext\s*=\s*True\b", line)
assert match is not None
assert linter._looks_like_string_literal(line, match)
def test_looks_like_string_literal_false_for_real_code(self, linter):
import re
line = ' subprocess.run(cmd, text=True)'
match = re.search(r"\btext\s*=\s*True\b", line)
assert match is not None
assert not linter._looks_like_string_literal(line, match)
# ---------------------------------------------------------------------------
# Full-repo scan — after PR #60741 merges, the new rule should find ZERO
# unsuppressed violations in the whole tree (excluding the linter itself
# and CONTRIBUTING docs). This test will FAIL until PR #60741 is merged;
# mark it xfail when run on a branch that doesn't include PR #60741's fixes.
# ---------------------------------------------------------------------------
class TestFullRepoScan:
def test_new_rule_find_only_known_violations(self, linter, monkeypatch):
"""Scan the full repo and assert the new rule's matches are exactly
the set of call sites that PR #60741 fixes (or zero, if PR #60741
is already merged into this branch).
This is a regression guard: if someone adds a new
``subprocess.run(text=True)`` without ``encoding=``, this test
catches it.
"""
# The 7 call sites that PR #60741 fixes. If PR #60741 is merged
# into this branch, this set should be empty. If not, these are
# the expected matches.
pr_60741_sites = {
"hermes_cli/main.py",
"hermes_cli/onepassword_secrets_cli.py",
"hermes_cli/setup.py",
"tools/transcription_tools.py",
"tools/tts_tool.py",
}
# Run the full scan
roots = [
REPO_ROOT / "hermes_cli",
REPO_ROOT / "gateway",
REPO_ROOT / "tools",
REPO_ROOT / "cron",
REPO_ROOT / "agent",
REPO_ROOT / "plugins",
REPO_ROOT / "scripts",
REPO_ROOT / "acp_adapter",
REPO_ROOT / "acp_registry",
]
roots = [r for r in roots if r.exists()]
fg = _find_footgun(linter, RULE_NAME)
new_rule_matches: dict[str, list[int]] = {}
for path in linter.iter_files(roots):
matches = linter.scan_file(path, [fg]) # scan with ONLY the new rule
if matches:
rel = path.relative_to(REPO_ROOT).as_posix()
new_rule_matches[rel] = [m[0] for m in matches]
# Determine which sites remain. PR #60741's fixes are on a separate
# branch; if this branch doesn't include them, the 7 call sites
# will still be flagged — that's expected, not a failure.
if new_rule_matches:
# Filter out the linter itself (it mentions text=True in its
# own pattern/message, but EXCLUDED_FILES handles that for the
# CLI entry point; the helper functions could trip it).
new_rule_matches = {
k: v for k, v in new_rule_matches.items()
if k != "scripts/check-windows-footguns.py"
}
if not new_rule_matches:
# PR #60741 already merged — clean tree. This is the goal state.
return
# Matches remain — they must be exactly the PR #60741 sites.
matched_files = set(new_rule_matches.keys())
unexpected = matched_files - pr_60741_sites
if unexpected:
pytest.fail(
f"New footgun rule found UNEXPECTED matches in files not "
f"covered by PR #60741: {sorted(unexpected)}.\n"
f"These are either new regressions or call sites that need "
f"a `# windows-footgun: ok` suppression."
)
# All matches are the expected PR #60741 sites — OK on this branch.
@@ -0,0 +1,41 @@
"""Tests for the shared-metrics smoke artifact."""
from pathlib import Path
import pytest
from scripts import smoke_nemo_relay_shared_metrics as smoke
@pytest.mark.parametrize(
"relative_path",
[
Path(".venv") / "bin" / "hermes",
Path(".venv") / "Scripts" / "hermes.exe",
],
)
def test_resolve_hermes_executable_from_repository_venv(
tmp_path,
monkeypatch,
relative_path,
):
executable = tmp_path / relative_path
executable.parent.mkdir(parents=True)
executable.touch()
monkeypatch.setattr(smoke.shutil, "which", lambda _name: None)
assert smoke._resolve_hermes_executable(tmp_path) == executable
def test_resolve_hermes_executable_falls_back_to_path(tmp_path, monkeypatch):
executable = tmp_path / "bin" / "hermes"
monkeypatch.setattr(smoke.shutil, "which", lambda _name: str(executable))
assert smoke._resolve_hermes_executable(tmp_path / "repo") == executable
def test_resolve_hermes_executable_reports_missing_binary(tmp_path, monkeypatch):
monkeypatch.setattr(smoke.shutil, "which", lambda _name: None)
with pytest.raises(SystemExit, match="or on PATH"):
smoke._resolve_hermes_executable(tmp_path)
@@ -0,0 +1,41 @@
"""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}"
)