SilverSight/scripts/auto/webhook_receiver.py
allaun 85141a4b94 feat(nuvmap,braid): NUVMAP port + Rossby/Kelvin braid correspondence
- Port NUVMAP projection engine from Research Stack to SilverSight
  with Q16_16 fixed-point (zero Float) and CBOR serialization
- Add Rotational Wave — Braid Correspondence formalization at boundary
  (ChiralLabel, RossbyDrift, rossby_convergence_bound stubbed,
   kelvin_wave_eigensolid proven)
- Add auto-pipeline CI workflow, webhook receiver, Forgejo MCP server
- Add SOPS/Age encryption config
- Add stack compose for portable deployment
- Add rotational wave design doc
2026-06-30 16:38:11 -05:00

52 lines
1.9 KiB
Python

#!/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()