Files
diario_coversazioni/webhook_receiver.py
automationkriz 006bb24215 CI/CD: webhook receiver + deploy automatico su push
- deploy.sh: git pull, pip install, migrate, collectstatic, restart gunicorn
- webhook_receiver.py: HTTP server con verifica HMAC-SHA256 Gitea
- olimpic-nastri-webhook.service: systemd unit per il receiver
- Nginx: aggiunto proxy /webhook/deploy → porta 9000
- sudoers: restart gunicorn senza password per deploy automatico
2026-04-05 15:02:25 +00:00

86 lines
2.3 KiB
Python

#!/usr/bin/env python3
"""
Webhook receiver per Gitea — Diario Conversazioni Olimpic Nastri.
Ascolta su porta 9000, verifica la firma HMAC del payload Gitea,
e lancia deploy.sh quando riceve un push sul branch main.
"""
import hashlib
import hmac
import json
import subprocess
import sys
from http.server import HTTPServer, BaseHTTPRequestHandler
WEBHOOK_SECRET = "c91dca86b9a87d9f25e07a63354da9f2469998f9"
DEPLOY_SCRIPT = "/home/marco/olimpic_nastri/deploy.sh"
LISTEN_PORT = 9000
class WebhookHandler(BaseHTTPRequestHandler):
def do_POST(self):
if self.path != "/deploy":
self.send_response(404)
self.end_headers()
return
content_length = int(self.headers.get("Content-Length", 0))
if content_length > 1_000_000: # max 1 MB payload
self.send_response(413)
self.end_headers()
return
body = self.rfile.read(content_length)
# Verifica firma HMAC-SHA256 di Gitea
signature = self.headers.get("X-Gitea-Signature", "")
expected = hmac.new(
WEBHOOK_SECRET.encode(), body, hashlib.sha256
).hexdigest()
if not hmac.compare_digest(signature, expected):
self.send_response(403)
self.end_headers()
self.wfile.write(b"Firma non valida")
return
# Controlla che sia un push su main
try:
payload = json.loads(body)
except json.JSONDecodeError:
self.send_response(400)
self.end_headers()
return
ref = payload.get("ref", "")
if ref != "refs/heads/main":
self.send_response(200)
self.end_headers()
self.wfile.write(b"Push ignorato (non main)")
return
# Lancia il deploy in background
subprocess.Popen([DEPLOY_SCRIPT], close_fds=True)
self.send_response(200)
self.end_headers()
self.wfile.write(b"Deploy avviato")
def log_message(self, format, *args):
print(f"[webhook] {args[0]}", flush=True)
def main():
server = HTTPServer(("127.0.0.1", LISTEN_PORT), WebhookHandler)
print(f"Webhook receiver in ascolto su 127.0.0.1:{LISTEN_PORT}", flush=True)
try:
server.serve_forever()
except KeyboardInterrupt:
pass
server.server_close()
if __name__ == "__main__":
main()