#!/usr/bin/env python3 """Fail-closed Forgejo pre-receive gate for Lake Lamp repo-push grants.""" import json import os import re import sys import time GRANT_DIR = os.environ.get("REPO_AUTHORIZATION_DIR", "/var/lib/guanghu/repo-authorizations") def normalize_repo(value): value = value.strip().lower().removesuffix(".git") match = re.search(r"(?:gitea-repositories|repositories)/([^/]+/[^/]+)$", value) if match: return match.group(1) # Forgejo's hook environment may expose only the repository name. # This instance is single-owner and the allowlist below remains authoritative. if re.fullmatch(r"[a-z0-9._-]+", value): return f"bingshuo/{value}" return value def check(repo, now=None): now = time.time() if now is None else now repo = normalize_repo(repo) if not re.fullmatch(r"bingshuo/[a-z0-9._-]+", repo): return False, "repository_not_allowlisted" filename = os.path.join(GRANT_DIR, repo.replace("/", "__") + ".json") try: with open(filename, encoding="utf-8") as handle: grant = json.load(handle) except (OSError, ValueError): return False, "repo_push_approval_required" if grant.get("repo") != repo or grant.get("target") != "JD-FD-PRIMARY": return False, "repo_push_grant_binding_mismatch" if now > float(grant.get("expires_at", 0)): return False, "repo_push_grant_expired" return True, "ok" if __name__ == "__main__": repo = os.environ.get("FORGEJO_REPO") or os.environ.get("GIT_DIR") or os.getcwd() ok, reason = check(repo) if not ok: print(f"小湖灯推送门已锁定: {reason}。请提交 repo-push 邮件工单。", file=sys.stderr) sys.exit(1)