#!/usr/bin/env python3 """Fail when tracked content is unsafe for a public showcase.""" from __future__ import annotations import math import re import subprocess import sys from collections import Counter from pathlib import Path ROOT = Path(__file__).resolve().parents[1] SELF = "scripts/check-public-safety.py" PLACEHOLDER_WORDS = ( "change_me", "redacted", "placeholder", "example", "your_token", "your_key", "***", ) ANY_IPV4 = re.compile(r"(? list[Path]: result = subprocess.run( ["git", "-C", str(ROOT), "ls-files", "-z"], check=True, capture_output=True, ) return [ROOT / value.decode() for value in result.stdout.split(b"\0") if value] def is_placeholder(value: str) -> bool: lowered = value.lower() return value.startswith("${") or any(word in lowered for word in PLACEHOLDER_WORDS) def entropy(value: str) -> float: counts = Counter(value) total = len(value) return -sum((count / total) * math.log2(count / total) for count in counts.values()) def main() -> int: findings: set[str] = set() files = tracked_files() for path in files: relative = path.relative_to(ROOT).as_posix() if relative == SELF: continue name = path.name.lower() if name.startswith(".env") and name != ".env.example": findings.add(f"{relative}: prohibited environment filename") if name in RISKY_NAMES or re.fullmatch(r"id_[a-z0-9_-]+", name): findings.add(f"{relative}: prohibited credential filename") if path.suffix.lower() in RISKY_SUFFIXES: findings.add(f"{relative}: prohibited key/config suffix") if re.fullmatch(r"wg\d+\.conf", name): findings.add(f"{relative}: prohibited VPN configuration filename") if RAW_EXPORT_NAME.search(name): findings.add(f"{relative}: raw export/backup-style filename requires review") try: data = path.read_bytes() except OSError as exc: findings.add(f"{relative}: unreadable: {exc}") continue if b"\0" in data[:4096]: findings.add(f"{relative}: binary tracked file requires manual review") continue for line_number, line in enumerate(data.decode("utf-8", errors="ignore").splitlines(), 1): prefix = f"{relative}:{line_number}" if ANY_IPV4.search(line): findings.add(f"{prefix}: literal IPv4 address") if ANY_IPV6.search(line): findings.add(f"{prefix}: literal IPv6 address") if MAC.search(line): findings.add(f"{prefix}: MAC address") if UUID.search(line): findings.add(f"{prefix}: UUID/device identifier") if INTERNAL_DOMAIN.search(line): findings.add(f"{prefix}: internal domain") if PRIVATE_HOME.search(line): findings.add(f"{prefix}: private home path") if PRIVATE_MOUNT.search(line): findings.add(f"{prefix}: private mount path") if PRIVATE_OPT.search(line): findings.add(f"{prefix}: private application path") if PRIVATE_KEY.search(line): findings.add(f"{prefix}: private-key block") for match in EMAIL.finditer(line): domain = match.group(1).lower() if not domain.endswith(("example.com", "example.net", "example.org")): findings.add(f"{prefix}: non-example email address") for match in URL_HOST.finditer(line): host = match.group(1).lower() if host not in ALLOWED_URL_HOSTS and not host.endswith( (".example.com", ".example.net", ".example.org") ): findings.add(f"{prefix}: non-approved URL host") for match in SECRET_ASSIGNMENT.finditer(line): value = match.group(1) if not is_placeholder(value): findings.add(f"{prefix}: non-placeholder secret assignment") for match in AUTHORIZATION.finditer(line): value = match.group(1) if not is_placeholder(value): findings.add(f"{prefix}: authorization material") line_without_urls = re.sub(r"https?://\S+", "", line) for candidate in OPAQUE.findall(line_without_urls): if is_placeholder(candidate): continue # Commit hashes and content digests are still identifiers; require a label. labelled_hash = re.search( r"(?i)(?:\b(?:sha(?:1|256|512)|digest|commit|checksum|example[_-]?hash)\b|\buses\s*:)", line, ) if labelled_hash and re.fullmatch(r"[0-9a-fA-F]{32,128}", candidate): continue if entropy(candidate) >= 3.5: findings.add(f"{prefix}: opaque high-entropy value") break if findings: print("Public-safety scan failed:") for finding in sorted(findings): print(f"- {finding}") return 1 content_count = len(files) - int(any(path.relative_to(ROOT).as_posix() == SELF for path in files)) print( "Public-safety scan passed: " f"{content_count} tracked files content-scanned; detector source executed separately" ) return 0 if __name__ == "__main__": sys.exit(main())