#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" main() { cd "$ROOT_DIR" python - <<'PY' import re import subprocess from pathlib import Path root = Path.cwd() failures: list[str] = [] def fail(message: str) -> None: failures.append(message) tracked = subprocess.check_output(["git", "ls-files"], text=True).splitlines() for path in tracked: name = Path(path).name if name == ".env" or (name.startswith(".env.") and name not in {".env.example"}): fail(f"{path}: environment files must not be tracked") if re.search(r"\.(pem|key|p12|pfx)$", name): fail(f"{path}: private key/certificate material must not be tracked") secret_patterns = [ ("private key block", re.compile(r"BEGIN [A-Z ]*PRIVATE KEY")), ("AWS access key", re.compile(r"AKIA[0-9A-Z]{16}")), ("Google API key", re.compile(r"AIza[0-9A-Za-z_-]{35}")), ("OpenAI-style secret key", re.compile(r"sk-[A-Za-z0-9]{32,}")), ("Slack token", re.compile(r"xox[baprs]-[A-Za-z0-9-]{10,}")), ("GitHub token", re.compile(r"gh[pousr]_[A-Za-z0-9_]{30,}")), ] skip_parts = { ".git", ".venv", "node_modules", "dist", "build", ".pytest_cache", ".mypy_cache", "__pycache__", } for path in root.rglob("*"): if not path.is_file(): continue if skip_parts.intersection(path.relative_to(root).parts): continue try: text = path.read_text(encoding="utf-8") except UnicodeDecodeError: continue rel = path.relative_to(root) for label, pattern in secret_patterns: for match in pattern.finditer(text): line_no = text.count("\n", 0, match.start()) + 1 fail(f"{rel}:{line_no}: possible {label} committed to repository") if failures: for message in failures: print(f"fail: {message}") raise SystemExit(f"security check failed: {len(failures)} failure(s)") print("security check passed") PY } main "$@"