#!/usr/bin/env python3 """Verify repository packaging, documentation references, and safe templates.""" from __future__ import annotations import re import sys from pathlib import Path ROOT = Path(__file__).resolve().parents[1] REQUIRED = ( ".env.example", ".gitignore", ".gitattributes", ".python-version", "VERSION", "BUILD_MANIFEST.md", "requirements.lock", "requirements-ci.lock", "package.json", "package-lock.json", "README.md", "scripts/check_migrations.py", "scripts/validate_startup_configuration.py", "scripts/generate_dependency_inventory.py", "docs/dependency_inventory.json", "docs/dependency_licenses.json", ) SECRET_TEMPLATE_KEYS = { "HF_TOKEN", "HERMES_ADMIN_PASSWORD", "HERMES_SESSION_SECRET", "FUTURES_API_KEY", "FUTURES_API_SECRET", "FUTURES_API_PASSPHRASE", "OPENROUTER_API_KEY", "GOOGLE_API_KEY", "TELEGRAM_BOT_TOKEN", "TELEGRAM_WEBHOOK_SECRET", "TELEGRAM_BOOTSTRAP_SECRET", } def verify(root: Path = ROOT) -> list[str]: errors: list[str] = [] for rel in REQUIRED: if not (root / rel).is_file(): errors.append(f"required repository file missing: {rel}") readme_path = root / "README.md" if readme_path.is_file(): readme = readme_path.read_text(encoding="utf-8") for target in re.findall(r"\[[^]]+\]\(([^)]+)\)", readme): if "://" in target or target.startswith("#"): continue if not (root / target).exists(): errors.append(f"README link target missing: {target}") for required_command in ( "python scripts/validate_startup_configuration.py", "python scripts/check_migrations.py", "python -m pytest hermes_overlay/tests -q", "docker build", ): if required_command not in readme: errors.append(f"README command missing: {required_command}") package_path = root / "package.json" lock_path = root / "package-lock.json" if package_path.is_file() and lock_path.is_file(): import json try: package = json.loads(package_path.read_text(encoding="utf-8")) lock = json.loads(lock_path.read_text(encoding="utf-8")) except (OSError, ValueError) as exc: errors.append(f"invalid Node metadata: {exc.__class__.__name__}") else: if package.get("engines", {}).get("node") != "22.16.0": errors.append("package.json must pin Node 22.16.0") if not lock.get("lockfileVersion"): errors.append("package-lock.json must declare lockfileVersion") root_package = lock.get("packages", {}).get("", {}) if root_package.get("engines", {}).get("node") != "22.16.0": errors.append("package-lock.json must preserve the Node engine pin") env_path = root / ".env.example" if env_path.is_file(): entries: dict[str, str] = {} for raw in env_path.read_text(encoding="utf-8").splitlines(): line = raw.strip() if not line or line.startswith("#") or "=" not in line: continue key, value = line.split("=", 1) entries[key.strip()] = value.strip() for key in SECRET_TEMPLATE_KEYS: if entries.get(key): errors.append(f"secret template key must be blank: {key}") if entries.get("TRADING_MODE") != "paper": errors.append("TRADING_MODE template must default to paper") if entries.get("HERMES_EXECUTION_ENABLED", "").lower() != "false": errors.append("HERMES_EXECUTION_ENABLED template must default false") return errors def main() -> int: errors = verify() for error in errors: print(f"ERROR: {error}") print(f"repository_metadata={'PASS' if not errors else 'FAIL'}") return 1 if errors else 0 if __name__ == "__main__": raise SystemExit(main())