"""Regla permanente (2026-10-31): ningún fichero versionado contiene patrones de credenciales. Placeholders de .env.example están permitidos. Fallará si alguien mete un DSN con contraseña real, un token en claro, o cualquier valor que deba vivir solo en .env / tokens.json. """ from __future__ import annotations import re from pathlib import Path REPO = Path(__file__).resolve().parent.parent SCAN_DIRS = ["runtime", "deploy", "docs", "scripts", "prompts"] SCAN_GLOBS = ["*.py", "*.mjs", "*.js", "*.ts", "*.md", "*.yml", "*.yaml", "*.sh", "*.sql"] # DSN con credencial literal (user:pass@host) — excluye placeholders conocidos DSN = re.compile(r"(postgres|postgresql|mysql|mongodb)(\+[a-z]+)?://[A-Za-z0-9_]+:(?!password\b|change-me\b|<[^>]+>)[^@\s/]{8,}@", re.I) # tokens hex largos fuera de tests (los fixtures de tests están allowlistados por diseño) HEXTOKEN = re.compile(r"\b[0-9a-f]{64}\b") # nsec bech32 NSEC = re.compile(r"nsec1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{50,}") ALLOW_SUBSTR = ("user:password", "change-me", "<", "EXAMPLE", "example", "itest-pg", "0011", "11*", "22*", "33*", "44*") def _iter_files(): for d in SCAN_DIRS: base = REPO / d if not base.exists(): continue for pat in SCAN_GLOBS: for f in base.rglob(pat): if ".git" in f.parts or "node_modules" in f.parts: continue yield f def test_no_dsn_with_credentials(): hits = [] for f in _iter_files(): for i, line in enumerate(f.read_text(errors="ignore").splitlines(), 1): if DSN.search(line) and not any(a in line for a in ALLOW_SUBSTR): hits.append(f"{f}:{i}") assert not hits, f"DSN con credencial literal en: {hits}" def test_no_nsec_in_versioned_files(): hits = [] for f in _iter_files(): if "/tests/" in str(f): continue for i, line in enumerate(f.read_text(errors="ignore").splitlines(), 1): if NSEC.search(line): hits.append(f"{f}:{i}") assert not hits, f"nsec en fichero versionado: {hits}" def test_no_raw_hex_tokens_outside_tests(): """Tokens hex de 64 chars fuera de tests/ y del conftest (las claves de test viven solo en tests/). El outbox no debe contener secretos.""" hits = [] for f in _iter_files(): if "/tests/" in str(f) or f.name == "cayce-identity.md": continue for i, line in enumerate(f.read_text(errors="ignore").splitlines(), 1): if HEXTOKEN.search(line): hits.append(f"{f}:{i}") assert not hits, f"posible token hex versionado: {hits}"