#!/usr/bin/env python3 """Small publication gate, not a comprehensive security or licensing audit.""" import os from pathlib import Path import re import subprocess ROOT = Path(__file__).resolve().parents[1] ALLOWED = { ".gitattributes", ".gitignore", "README.md", "RIGHTS.md", "LICENSE", "SECURITY.md", "docs/ARCHITECTURE_KO.md", "docs/FEATURES_KO.md", "docs/RESEARCH_KO.md", "docs/PUBLICATION_KO.md", "telemetry/java/com/chaegeon/niro/HscanRpmDecoder.java", "weather/java/com/chaegeon/niro/WeatherRefreshGate.java", "weather/java/com/chaegeon/niro/WeatherRefreshCounters.java", "backend/php/NiroMqttKeepalive.php", "backend/php/NiroRawSnappy.php", "navigation/archived/v038/patch_nav_vehicle_speed_source.py", "tests/java/HscanRpmDecoderTest.java", "tests/java/WeatherRefreshGateTest.java", "tests/java/WeatherRefreshCountersTest.java", "tests/php/NiroMqttKeepaliveTest.php", "tests/php/NiroRawSnappyTest.php", "tests/python/test_archived_speed_patch.py", "tools/run_tests.py", "tools/check_publication.py", } PATTERNS = { "private-key material": re.compile(rb"-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----"), "GitHub credential candidate": re.compile(rb"\b(?:ghp_[A-Za-z0-9]{30,}|github_pat_[A-Za-z0-9_]{50,})\b"), "literal bearer candidate": re.compile(rb"Bearer [A-Za-z0-9_./+~-]{24,}"), "phone-number candidate": re.compile(rb"(? 128 * 1024 or b"\0" in content: errors.append("binary or unexpectedly large file: " + relative) continue try: content.decode("utf-8") except UnicodeDecodeError: errors.append("non-UTF-8 file: " + relative) for description, pattern in PATTERNS.items(): if pattern.search(content): # Do not reveal a matched secret or personal value in output. errors.append(description + ": " + relative) if (ROOT / ".git").exists(): for relative in git("ls-files").splitlines(): if relative not in ALLOWED: errors.append("unapproved tracked file: " + relative) for email in set(git("log", "--all", "--format=%ae%n%ce").splitlines()): if email and not email.endswith("@users.noreply.git.chaegeon.com"): errors.append("commit author/committer email needs privacy review") if errors: raise SystemExit("Publication checks failed:\n" + "\n".join(sorted(set(errors)))) print("PASS: publication allowlist and basic privacy checks (" + str(len(files)) + " files)") if __name__ == "__main__": main()