64 lines
1.9 KiB
Python
64 lines
1.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Detect tests that read/write real TOML files. Used as a CI gate.
|
|
|
|
Run from repo root: python scripts/check_test_toml_paths.py
|
|
Exits 0 if all tests use sandboxed paths, 1 otherwise.
|
|
"""
|
|
from __future__ import annotations
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
TOML_BASENAMES = {
|
|
"manual_slop", "config", "credentials",
|
|
"presets", "personas", "tool_presets",
|
|
"workspace_profiles", "tool_presets",
|
|
}
|
|
|
|
PATTERNS = [
|
|
re.compile(rf'Path\(["\'](?:{"|".join(TOML_BASENAMES)})\.toml["\']'),
|
|
re.compile(rf'open\(["\'](?:{"|".join(TOML_BASENAMES)})\.toml["\']'),
|
|
re.compile(rf'["\']\.{{1,2}}/(?:{"|".join(TOML_BASENAMES)})\.toml["\']'),
|
|
re.compile(rf'Path\(["\']\.\./(?:{"|".join(TOML_BASENAMES)})\.toml["\']'),
|
|
]
|
|
|
|
EXCLUDE_DIRS = {"artifacts", "logs", "__pycache__", "snapshots"}
|
|
|
|
|
|
def find_violations(tests_dir: Path) -> list[tuple[Path, int, str]]:
|
|
violations = []
|
|
for test_file in tests_dir.rglob("test_*.py"):
|
|
if any(excluded in test_file.parts for excluded in EXCLUDE_DIRS):
|
|
continue
|
|
try:
|
|
content = test_file.read_text(encoding="utf-8")
|
|
except (OSError, UnicodeDecodeError):
|
|
continue
|
|
for lineno, line in enumerate(content.splitlines(), start=1):
|
|
for pattern in PATTERNS:
|
|
if pattern.search(line):
|
|
violations.append((test_file, lineno, line.strip()))
|
|
break
|
|
return violations
|
|
|
|
|
|
def main() -> int:
|
|
repo_root = Path(__file__).resolve().parent.parent
|
|
tests_dir = repo_root / "tests"
|
|
if not tests_dir.exists():
|
|
print(f"Tests dir not found: {tests_dir}", file=sys.stderr)
|
|
return 1
|
|
violations = find_violations(tests_dir)
|
|
if not violations:
|
|
print("OK: No tests reference real TOML files.")
|
|
return 0
|
|
print(f"FAIL: {len(violations)} test(s) reference real TOML files:")
|
|
for path, lineno, line in violations:
|
|
rel = path.relative_to(repo_root)
|
|
print(f" {rel}:{lineno}: {line}")
|
|
return 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|