diff --git a/app/main.py b/app/main.py index 69c4766..f68470e 100644 --- a/app/main.py +++ b/app/main.py @@ -1,69 +1,96 @@ -import hmac import hashlib +import hmac +import json +import os import subprocess import threading -from fastapi import FastAPI, Request, Header, HTTPException -WEBHOOK_SECRET = "change-me-webhook-secret" -DEPLOY_SCRIPT = "/tools/deploy-app.sh" +from fastapi import FastAPI, Header, HTTPException, Request + +WEBHOOK_SECRET = os.getenv("WEBHOOK_SECRET", "change-me-webhook-secret") + +APP_DEPLOY_SCRIPT = "/tools/deploy-app.sh" +CORE_DEPLOY_SCRIPT = "/tools/deploy-core-service.sh" + +CORE_SERVICES = { + "appfactory-portal", + "appfactory-webhook", +} 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"} + +def verify_signature(body: bytes, signature: str | None): + if not signature: + raise HTTPException(status_code=401, detail="Missing signature") + + valid_signatures = [ + "sha256=" + hmac.new( + WEBHOOK_SECRET.encode("utf-8"), + body, + hashlib.sha256 + ).hexdigest() + ] + + if not any(hmac.compare_digest(s, signature) for s in valid_signatures): + raise HTTPException(status_code=401, detail="Invalid signature") + + +def run_command(command: list[str], repo_name: str): + print(f"Deploy started: {repo_name}", flush=True) + print(f"Command: {' '.join(command)}", flush=True) + + result = subprocess.run( + command, + capture_output=True, + text=True + ) + + print(f"Deploy finished: {repo_name}", flush=True) + print(f"Return code: {result.returncode}", flush=True) + + if result.stdout: + print("STDOUT:", flush=True) + print(result.stdout, flush=True) + + if result.stderr: + print("STDERR:", flush=True) + print(result.stderr, flush=True) + + @app.post("/gitea") async def gitea_webhook( request: Request, - x_gitea_signature: str | None = Header(default=None) + x_gitea_signature: str | None = Header(default=None), ): body = await request.body() verify_signature(body, x_gitea_signature) - payload = await request.json() - + payload = json.loads(body.decode("utf-8")) repo_name = payload.get("repository", {}).get("name") - ref = payload.get("ref", "") if not repo_name: - raise HTTPException(status_code=400, detail="Missing repo name") + raise HTTPException(status_code=400, detail="Missing repository name") - if ref != "refs/heads/main": - return { - "status": "ignored", - "reason": "not main branch", - "ref": ref - } + if repo_name in CORE_SERVICES: + command = [CORE_DEPLOY_SCRIPT, repo_name] + else: + command = [APP_DEPLOY_SCRIPT, repo_name] - threading.Thread(target=run_deploy, args=(repo_name,), daemon=True).start() + thread = threading.Thread( + target=run_command, + args=(command, repo_name), + daemon=True, + ) + thread.start() return { "status": "accepted", - "repo": repo_name + "repo": repo_name, + "core": repo_name in CORE_SERVICES, }