Files
hermes-agent/tests/scripts/test_footgun_encoding_direction.py
ethernet 2be53ecd7b fix(encoding): read kernel pseudo-files as plain utf-8
utf-8-sig exists to tolerate BOMs that Windows tooling adds to files
users edit. /proc and /sys files are generated by the Linux kernel, never
BOM'd and absent on Windows, so -sig there only muddies the read/write
policy. Switch every literal /proc/ and /sys/ read to utf-8 and teach
the footgun read rule that string literals starting with /proc/ or
/sys/ are exempt (user-edited files keep utf-8-sig).
2026-09-24 11:50:30 -04:00

70 lines
3.5 KiB
Python

"""Encoding-direction diagnostics through the real file scanner, not a cloned loop."""
import importlib.util
from pathlib import Path
import sys
import pytest
READ = "read with encoding='utf-8' (BOM-intolerant — use 'utf-8-sig')"
WRITE = "write with encoding='utf-8-sig' (emits a BOM)"
@pytest.fixture(scope="module")
def linter():
path = Path(__file__).resolve().parents[2] / "scripts/check-windows-footguns.py"
spec = importlib.util.spec_from_file_location("encoding_footguns", path)
assert spec is not None and spec.loader is not None
module = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = module
spec.loader.exec_module(module)
return module
@pytest.mark.parametrize("source,expected", [
('data = path.read_text(encoding="utf-8")', [(1, READ)]),
("with open(path, 'r', encoding='utf-8') as f:", [(1, READ)]),
("with open(path, encoding='utf-8') as f:", [(1, READ)]),
("f = os.fdopen(fd, 'r', encoding='utf-8')", [(1, READ)]),
('data = path.read_text(encoding="utf_8")', [(1, READ)]),
("with open(path, mode='r', encoding='utf-8') as f:", [(1, READ)]),
('path.read_text(encoding="utf-8-sig")', []),
('Path(f"/proc/{pid}/stat").read_text(encoding="utf-8")', []),
("with open('/sys/fs/cgroup/cgroup.procs', encoding='utf-8') as f:", []),
('Path(proc_root, "stat").read_text(encoding="utf-8") # /proc/ in prose only', [(1, READ)]),
('path.write_text(data, encoding="utf-8")', []),
("open(path, 'w', encoding='utf-8')", []),
("open(path, 'a', encoding='utf-8')", []),
("open(path, 'r+', encoding='utf-8')", []),
("subprocess.run(cmd, text=True, encoding='utf-8')", []),
("path.read_text(encoding='utf-8') # windows-footgun: ok — owned file", []),
("# use path.read_text(encoding='utf-8') here", []),
('path.write_text(data, encoding="utf-8-sig")', [(1, WRITE)]),
("open(path, 'w', encoding='utf-8-sig')", [(1, WRITE)]),
("open(path, 'a', encoding='utf-8-sig')", [(1, WRITE)]),
("os.fdopen(fd, 'w', encoding='utf-8-sig')", [(1, WRITE)]),
('path.open("a", encoding="utf-8-sig")', [(1, WRITE)]),
('path.open("a+", encoding="utf-8-sig")', [(1, WRITE)]),
('path.open("r+", encoding="utf-8-sig")', [(1, WRITE)]),
('path.write_text(data, encoding="utf_8_sig")', [(1, WRITE)]),
("open(path, 'r', encoding='utf-8-sig')", []),
("open(path, encoding='utf-8-sig')", []),
("codec = 'utf-8-sig'", []),
('open(os.path.join(root, "install-stamp.json"), encoding="utf-8-sig")', []),
('path.open("r", encoding="utf-8-sig")', []),
('path.open("a", encoding="utf-8")', []),
('something.open(encoding="utf-8")', []),
("path.write_text(data, encoding='utf-8-sig') # windows-footgun: ok — BOM required", []),
("open(p, 'x', encoding='utf-8-sig')", [(1, WRITE)]),
("enc = 'utf-8'", []),
("path.read_text(encoding='utf-8') # merely mentions windows-footgun", [(1, READ)]),
("path.read_text(encoding='utf-8') if hasattr(path, 'read_text') else ''", [(1, READ)]),
("path.read_text(encoding='utf-8') if sys.platform != 'win32' else ''", []),
('"""Example:\npath.read_text(encoding="utf-8")\n"""\npath.read_text(encoding="utf-8")', [(4, READ)]),
])
def test_encoding_diagnostics(linter, tmp_path, source, expected):
path = tmp_path / "input.py"
path.write_text(source + "\n", encoding="utf-8")
rules = [rule for rule in linter.FOOTGUNS if rule.name in {READ, WRITE}]
assert {rule.name for rule in rules} == {READ, WRITE}
assert [(line, rule.name) for line, _, rule in linter.scan_file(path, rules)] == expected