fb556586e3
Vuong-directed. gitea webhook (push→main) → HMAC listener on corviduo-dev:9010 → clone (read-only deploy key) → uv sync + pytest → redeploy soong-lab-studio.service ONLY on green (running studio untouched on red). Validated end-to-end 2026-07-13. Canonical copies of the deploy script + listener + unit; runbook in docs/runbooks.
28 lines
1.6 KiB
Python
28 lines
1.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Gitea push-webhook listener for soong-lab: on a verified push to main, run
|
|
~/soong-lab-deploy.sh. HMAC-SHA256 (X-Gitea-Signature) vs ~/.config/soong/webhook-secret."""
|
|
import hashlib, hmac, json, os, subprocess, threading
|
|
from http.server import BaseHTTPRequestHandler, HTTPServer
|
|
SECRET = open(os.path.expanduser("~/.config/soong/webhook-secret"), "rb").read().strip()
|
|
DEPLOY = os.path.expanduser("~/soong-lab-deploy.sh")
|
|
STATUS = os.path.expanduser("~/.config/soong/last-deploy.json")
|
|
class H(BaseHTTPRequestHandler):
|
|
def do_POST(self):
|
|
body = self.rfile.read(int(self.headers.get("Content-Length", 0)))
|
|
mac = hmac.new(SECRET, body, hashlib.sha256).hexdigest()
|
|
if not hmac.compare_digest(mac, self.headers.get("X-Gitea-Signature", "")):
|
|
self.send_response(401); self.end_headers(); self.wfile.write(b"bad signature\n"); return
|
|
try: ref = json.loads(body).get("ref", "")
|
|
except Exception: self.send_response(400); self.end_headers(); return
|
|
if ref != "refs/heads/main":
|
|
self.send_response(200); self.end_headers(); self.wfile.write(b"ignored " + ref.encode() + b"\n"); return
|
|
self.send_response(202); self.end_headers(); self.wfile.write(b"deploying\n")
|
|
threading.Thread(target=lambda: subprocess.run(["bash", DEPLOY]), daemon=True).start()
|
|
def do_GET(self):
|
|
self.send_response(200); self.end_headers()
|
|
try: st = open(STATUS).read().strip()
|
|
except Exception: st = "no deploy yet"
|
|
self.wfile.write(b"soong-webhook ok | last: " + st.encode())
|
|
def log_message(self, *a): pass
|
|
HTTPServer(("0.0.0.0", 9010), H).serve_forever()
|