#!/usr/bin/env python3 """Simple Forgejo push webhook receiver that triggers deploy.sh""" from http.server import HTTPServer, BaseHTTPRequestHandler import hmac, hashlib, subprocess, json, os, datetime SECRET = os.environ.get("WEBHOOK_SECRET", "web-cad-neu-deploy-2026") DEPLOY_SCRIPT = "/data/web-cad-neu/deploy.sh" LOG_FILE = "/var/log/webhook-deploy.log" PORT = int(os.environ.get("WEBHOOK_PORT", "9876")) class WebhookHandler(BaseHTTPRequestHandler): def do_POST(self): if self.path != "/webhook": self.send_response(404) self.end_headers() return content_length = int(self.headers.get("Content-Length", 0)) body = self.rfile.read(content_length) # Verify signature signature = self.headers.get("X-Gitea-Signature", "") computed = hmac.new(SECRET.encode(), body, hashlib.sha256).hexdigest() if not hmac.compare_digest(signature, computed): self.send_response(403) self.end_headers() self.wfile.write(b"Invalid signature") return # Parse event event = self.headers.get("X-Gitea-Event", "") if event != "push": self.send_response(200) self.end_headers() self.wfile.write(b"Ignored: not a push event") return payload = json.loads(body) ref = payload.get("ref", "") if ref != "refs/heads/main": self.send_response(200) self.end_headers() self.wfile.write(b"Ignored: not main branch") return # Trigger deploy in background ts = datetime.datetime.now().isoformat() self.log_msg(f"[{ts}] Push to main detected, triggering deploy...") subprocess.Popen( ["bash", DEPLOY_SCRIPT], stdout=open(LOG_FILE, "a"), stderr=subprocess.STDOUT ) self.send_response(200) self.end_headers() self.wfile.write(b"Deploy triggered") def log_msg(self, msg): with open(LOG_FILE, "a") as f: f.write(msg + "\n") if __name__ == "__main__": server = HTTPServer(("0.0.0.0", PORT), WebhookHandler) print(f"Webhook receiver listening on port {PORT}") server.serve_forever()