#!/usr/bin/env python3 """Service d'écoute du webhook Gitea pour presentations.alpinux.org. N'écoute que sur la boucle locale : c'est Apache qui lui transmet les requêtes reçues sur https://presentations.alpinux.org/deploy. La signature HMAC envoyée par Gitea est vérifiée avant de lancer quoi que ce soit, et seuls les push sur main déclenchent un déploiement. Calqué sur les services du wiki et de www (/opt/wiki-mkdocs/webhook.py, /opt/www-alpinux/webhook.py), à trois différences près : le port, le script appelé, et un secret qui lui est propre, lu dans un fichier d'environnement — ce dépôt est public. """ import hashlib import hmac import http.server import json import os import subprocess import threading SECRET = os.environ.get("PRESENTATIONS_WEBHOOK_SECRET", "") DEPLOY_SCRIPT = "/opt/presentations-alpinux/deploy-presentations.sh" LOG = "/var/log/presentations-deploy.log" PORT = 9878 class Handler(http.server.BaseHTTPRequestHandler): def do_POST(self): if self.path != "/deploy": self.send_response(404); self.end_headers(); return length = int(self.headers.get("Content-Length", 0)) body = self.rfile.read(length) signature = self.headers.get("X-Gitea-Signature", "") attendue = hmac.new(SECRET.encode(), body, hashlib.sha256).hexdigest() if not SECRET or not hmac.compare_digest(attendue, signature): self.send_response(403); self.end_headers() self.wfile.write(b"Forbidden"); return try: ref = json.loads(body).get("ref", "") except (ValueError, AttributeError): self.send_response(400); self.end_headers() self.wfile.write(b"Bad request"); return if ref != "refs/heads/main": self.send_response(200); self.end_headers() self.wfile.write(b"Skipped: not main"); return # Déploiement en tâche de fond : Gitea a sa réponse tout de suite. threading.Thread( target=subprocess.run, args=([DEPLOY_SCRIPT],), kwargs={"capture_output": True}, daemon=True, ).start() self.send_response(200); self.end_headers() self.wfile.write(b"Deploy triggered") def log_message(self, fmt, *args): with open(LOG, "a") as journal: journal.write(self.log_date_time_string() + " " + fmt % args + "\n") if __name__ == "__main__": http.server.HTTPServer(("127.0.0.1", PORT), Handler).serve_forever()