#!/usr/bin/env python3 # SPDX-FileCopyrightText: 2026 Team Centurions # SPDX-License-Identifier: AGPL-3.0-or-later import sys from pathlib import Path ROOT_DIR = Path(__file__).resolve().parent.parent EXCLUDED_DIRS = { ".git", ".github", ".gitlab", ".venv", ".pytest_cache", ".mypy_cache", "node_modules", "dist", "build", "tmp", "models", ".specify", } EXCLUDED_FILES = { "pageparse.db", "package-lock.json", ".secrets.baseline", } REQUIRED_KEYWORDS = [ "SPDX-FileCopyrightText", "SPDX-License-Identifier" ] def check_file(file_path: Path) -> bool: # Skip binary or very large files if file_path.suffix in [".png", ".jpg", ".jpeg", ".db", ".onnx", ".gguf", ".zip", ".tar", ".gz"]: return True if file_path.name in EXCLUDED_FILES: return True try: content = file_path.read_text(encoding="utf-8", errors="ignore") # Check if the keywords exist in the file missing = [kw for kw in REQUIRED_KEYWORDS if kw not in content] if missing: print(f"FAIL: Missing license keywords {missing} in {file_path.relative_to(ROOT_DIR)}") return False return True except Exception as e: print(f"ERROR reading {file_path}: {e}") return False def main() -> None: print("Checking license compliance in files...") all_passed = True count = 0 # Check all files under source and configurations for path in ROOT_DIR.rglob("*"): if path.is_file(): # Check if any parent dir is excluded parts = path.relative_to(ROOT_DIR).parts if any(p in EXCLUDED_DIRS for p in parts): continue # Check only code/config/markdown files if path.suffix in [".py", ".ts", ".tsx", ".yml", ".yaml", ".md", ".gbnf"]: count += 1 if not check_file(path): all_passed = False print(f"Checked {count} files.") if all_passed: print("SUCCESS: All checked files have correct license headers.") sys.exit(0) else: print("FAILURE: Some files are missing copyright or license headers.") sys.exit(1) if __name__ == "__main__": main()