Initial AppFactory webhook service

This commit is contained in:
AppFactory Bot
2026-05-27 12:39:08 +02:00
commit ccde0a02cb
3 changed files with 87 additions and 0 deletions
+69
View File
@@ -0,0 +1,69 @@
import hmac
import hashlib
import subprocess
import threading
from fastapi import FastAPI, Request, Header, HTTPException
WEBHOOK_SECRET = "change-me-webhook-secret"
DEPLOY_SCRIPT = "/tools/deploy-app.sh"
app = FastAPI(title="AppFactory Webhook")
def verify_signature(body: bytes, signature: str | None):
if not signature:
raise HTTPException(status_code=401, detail="Missing signature")
expected = hmac.new(
WEBHOOK_SECRET.encode("utf-8"),
body,
hashlib.sha256
).hexdigest()
valid_signatures = [
expected,
f"sha256={expected}",
]
if not any(hmac.compare_digest(s, signature) for s in valid_signatures):
raise HTTPException(status_code=401, detail="Invalid signature")
def run_deploy(app_id: str):
subprocess.run(
[DEPLOY_SCRIPT, app_id],
capture_output=True,
text=True
)
@app.get("/health")
def health():
return {"status": "ok"}
@app.post("/gitea")
async def gitea_webhook(
request: Request,
x_gitea_signature: str | None = Header(default=None)
):
body = await request.body()
verify_signature(body, x_gitea_signature)
payload = await request.json()
repo_name = payload.get("repository", {}).get("name")
ref = payload.get("ref", "")
if not repo_name:
raise HTTPException(status_code=400, detail="Missing repo name")
if ref != "refs/heads/main":
return {
"status": "ignored",
"reason": "not main branch",
"ref": ref
}
threading.Thread(target=run_deploy, args=(repo_name,), daemon=True).start()
return {
"status": "accepted",
"repo": repo_name
}