Ctrl K
ComunidadGuías…

scripts/check_no_renderer_api_fetch.py

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env python3
"""Guard against raw renderer fetch('/api/...') calls in gui/src/.

Scans gui/src/**/*.{ts,tsx,js,jsx} for patterns that match
  fetch('/api...   fetch("/api...   fetch(`/api...

Any match whose "relative/path:lineno" is NOT listed in
gui/src/ALLOWED_API_FETCHES.txt causes the script to exit 1.

Usage:
    python scripts/check_no_renderer_api_fetch.py [--repo-root PATH]

Exit codes:
    0  no unapproved raw /api/ fetches found
    1  one or more unapproved raw /api/ fetches found
"""

import argparse
import re
import sys
from pathlib import Path

_PATTERN = re.compile(r"""fetch\(['"` ]/api""".replace(" ", ""))
_GUI_SRC_GLOBS = ("*.ts", "*.tsx", "*.js", "*.jsx")
_ALLOWLIST_RELPATH = Path("gui/src/ALLOWED_API_FETCHES.txt")


def load_allowlist(repo_root: Path) -> set[str]:
    """Return set of 'rel/path:lineno' keys from the allowlist file."""
    path = repo_root / _ALLOWLIST_RELPATH
    if not path.exists():
        return set()
    entries: set[str] = set()
    for line in path.read_text(encoding="utf-8").splitlines():
        stripped = line.split("#")[0].strip()
        if stripped:
            entries.add(stripped)
    return entries


def find_violations(repo_root: Path) -> list[tuple[str, int, str]]:
    """Return (rel_path, lineno, line_content) for each unapproved match."""
    allowlist = load_allowlist(repo_root)
    gui_src = repo_root / "gui" / "src"
    violations: list[tuple[str, int, str]] = []

    if not gui_src.is_dir():
        return violations

    for glob in _GUI_SRC_GLOBS:
        for fpath in sorted(gui_src.rglob(glob)):
            rel = fpath.relative_to(repo_root).as_posix()
            try:
                lines = fpath.read_text(encoding="utf-8").splitlines()
            except (OSError, UnicodeDecodeError):
                continue
            for i, line in enumerate(lines, start=1):
                if _PATTERN.search(line):
                    key = f"{rel}:{i}"
                    if key not in allowlist:
                        violations.append((rel, i, line.strip()))

    return violations


def main(argv: list[str] | None = None) -> int:
    parser = argparse.ArgumentParser(
        description="Check for unapproved raw /api/ fetches in gui/src/."
    )
    parser.add_argument(
        "--repo-root",
        default=".",
        help="Repository root directory (default: current directory)",
    )
    args = parser.parse_args(argv)
    repo_root = Path(args.repo_root).resolve()

    violations = find_violations(repo_root)
    if violations:
        print(f"ERROR: {len(violations)} unapproved raw /api/ fetch(s) in gui/src/:")
        for rel, lineno, content in violations:
            print(f"  {rel}:{lineno}  {content}")
        print()
        print(
            "To allow an existing call site, add a line to "
            "gui/src/ALLOWED_API_FETCHES.txt:\n"
            "  rel/path/to/file.tsx:lineno  # justification\n"
            "To fix permanently, migrate the call to typed IPC."
        )
        return 1

    print("OK: no unapproved raw /api/ fetches in gui/src/")
    return 0


if __name__ == "__main__":
    sys.exit(main())