#!/usr/bin/env python3 """Webhook receiver — listens for Forgejo push events and runs the auto-pipeline.""" import json, os, subprocess, hmac, hashlib, logging from http.server import HTTPServer, BaseHTTPRequestHandler from pathlib import Path ROOT = Path(__file__).resolve().parent.parent.parent PIPELINE = ROOT / "scripts/auto/auto_pipeline.py" SECRET = os.environ.get("WEBHOOK_SECRET", "") PORT = int(os.environ.get("WEBHOOK_PORT", "8080")) logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s") class WebhookHandler(BaseHTTPRequestHandler): def do_POST(self): length = int(self.headers.get("Content-Length", 0)) body = self.rfile.read(length) sig = self.headers.get("X-Forgejo-Signature", "") # Validate signature if SECRET: expected = hmac.new(SECRET.encode(), body, hashlib.sha256).hexdigest() if not hmac.compare_digest(f"sha256={expected}", sig): self.send_error(401, "Invalid signature") return event = json.loads(body) ref = event.get("ref", "") repo = event.get("repository", {}).get("full_name", "unknown") logging.info(f"Push to {repo} {ref}") # Run the auto-pipeline try: r = subprocess.run( ["python3", str(PIPELINE), "--ci"], capture_output=True, text=True, timeout=600 ) logging.info(f"Pipeline exit={r.returncode}: {r.stdout[-200:]}") except subprocess.TimeoutExpired: logging.warning("Pipeline timed out") self.send_response(200) self.end_headers() self.wfile.write(b'{"status":"ok"}') def log_message(self, fmt, *args): logging.info(fmt % args) if __name__ == "__main__": server = HTTPServer(("0.0.0.0", PORT), WebhookHandler) logging.info(f"Webhook receiver on :{PORT}") server.serve_forever()