Pass webhook attribution to deploy scripts
This commit is contained in:
Regular → Executable
+74
-21
@@ -21,10 +21,7 @@ def read_env_file_value(key: str, default: str = "") -> str:
|
||||
return default
|
||||
|
||||
|
||||
WEBHOOK_SECRET = os.getenv(
|
||||
"WEBHOOK_SECRET",
|
||||
read_env_file_value("WEBHOOK_SECRET", "")
|
||||
)
|
||||
WEBHOOK_SECRET = os.getenv("WEBHOOK_SECRET", read_env_file_value("WEBHOOK_SECRET", ""))
|
||||
|
||||
APP_DEPLOY_SCRIPT = "/tools/deploy-app.sh"
|
||||
CORE_DEPLOY_SCRIPT = "/tools/deploy-core-service.sh"
|
||||
@@ -49,31 +46,75 @@ def verify_signature(body: bytes, signature: str | None):
|
||||
if not signature:
|
||||
raise HTTPException(status_code=401, detail="Missing signature")
|
||||
|
||||
digest = hmac.new(
|
||||
WEBHOOK_SECRET.encode("utf-8"),
|
||||
body,
|
||||
hashlib.sha256
|
||||
).hexdigest()
|
||||
|
||||
accepted = {
|
||||
digest,
|
||||
f"sha256={digest}",
|
||||
}
|
||||
digest = hmac.new(WEBHOOK_SECRET.encode("utf-8"), body, hashlib.sha256).hexdigest()
|
||||
accepted = {digest, f"sha256={digest}"}
|
||||
|
||||
signature = signature.strip()
|
||||
|
||||
if not any(hmac.compare_digest(signature, item) for item in accepted):
|
||||
print("Invalid signature", flush=True)
|
||||
print(f"Received prefix: {signature[:16]}", flush=True)
|
||||
print(f"Expected prefix: {digest[:16]}", flush=True)
|
||||
raise HTTPException(status_code=401, detail="Invalid signature")
|
||||
|
||||
|
||||
def run_command(command: list[str], repo_name: str):
|
||||
def first_commit(payload: dict) -> dict:
|
||||
commits = payload.get("commits") or []
|
||||
if commits:
|
||||
return commits[-1] or {}
|
||||
return payload.get("head_commit") or {}
|
||||
|
||||
|
||||
def extract_attribution(payload: dict) -> dict:
|
||||
pusher = payload.get("pusher") or {}
|
||||
sender = payload.get("sender") or {}
|
||||
commit = first_commit(payload)
|
||||
author = commit.get("author") or {}
|
||||
|
||||
pusher_name = (
|
||||
pusher.get("full_name")
|
||||
or pusher.get("username")
|
||||
or pusher.get("name")
|
||||
or sender.get("full_name")
|
||||
or sender.get("login")
|
||||
or sender.get("username")
|
||||
or "unknown"
|
||||
)
|
||||
|
||||
pusher_username = (
|
||||
pusher.get("username")
|
||||
or pusher.get("login")
|
||||
or sender.get("login")
|
||||
or sender.get("username")
|
||||
or pusher_name
|
||||
or "unknown"
|
||||
)
|
||||
|
||||
commit_author = (
|
||||
author.get("name")
|
||||
or author.get("username")
|
||||
or author.get("email")
|
||||
or "unknown"
|
||||
)
|
||||
|
||||
commit_sha = commit.get("id") or commit.get("sha") or payload.get("after") or "unknown"
|
||||
|
||||
return {
|
||||
"pusher": str(pusher_name),
|
||||
"pusher_username": str(pusher_username),
|
||||
"commit_author": str(commit_author),
|
||||
"commit_sha": str(commit_sha),
|
||||
}
|
||||
|
||||
|
||||
def run_command(command: list[str], repo_name: str, deploy_env: dict[str, str]):
|
||||
env = os.environ.copy()
|
||||
env.update(deploy_env)
|
||||
|
||||
print(f"Deploy started: {repo_name}", flush=True)
|
||||
print(f"Command: {' '.join(command)}", flush=True)
|
||||
print(f"Trigger source: {env.get('APPFACTORY_TRIGGER_SOURCE')}", flush=True)
|
||||
print(f"Pusher: {env.get('APPFACTORY_PUSHER')}", flush=True)
|
||||
print(f"Commit author: {env.get('APPFACTORY_COMMIT_AUTHOR')}", flush=True)
|
||||
|
||||
result = subprocess.run(command, capture_output=True, text=True)
|
||||
result = subprocess.run(command, capture_output=True, text=True, env=env)
|
||||
|
||||
print(f"Deploy finished: {repo_name}", flush=True)
|
||||
print(f"Return code: {result.returncode}", flush=True)
|
||||
@@ -95,7 +136,6 @@ async def gitea_webhook(
|
||||
x_hub_signature_256: str | None = Header(default=None),
|
||||
):
|
||||
body = await request.body()
|
||||
|
||||
signature = x_gitea_signature or x_hub_signature_256 or x_hub_signature
|
||||
|
||||
verify_signature(body, signature)
|
||||
@@ -106,14 +146,25 @@ async def gitea_webhook(
|
||||
if not repo_name:
|
||||
raise HTTPException(status_code=400, detail="Missing repository name")
|
||||
|
||||
attr = extract_attribution(payload)
|
||||
|
||||
if repo_name in CORE_SERVICES:
|
||||
command = [CORE_DEPLOY_SCRIPT, repo_name]
|
||||
else:
|
||||
command = [APP_DEPLOY_SCRIPT, repo_name]
|
||||
|
||||
deploy_env = {
|
||||
"APPFACTORY_TRIGGER_SOURCE": "webhook",
|
||||
"APPFACTORY_TRIGGERED_BY_USERNAME": attr["pusher_username"],
|
||||
"APPFACTORY_TRIGGERED_BY_DISPLAY_NAME": attr["pusher"],
|
||||
"APPFACTORY_COMMIT_AUTHOR": attr["commit_author"],
|
||||
"APPFACTORY_PUSHER": attr["pusher"],
|
||||
"APPFACTORY_COMMIT_SHA": attr["commit_sha"],
|
||||
}
|
||||
|
||||
threading.Thread(
|
||||
target=run_command,
|
||||
args=(command, repo_name),
|
||||
args=(command, repo_name, deploy_env),
|
||||
daemon=True,
|
||||
).start()
|
||||
|
||||
@@ -121,4 +172,6 @@ async def gitea_webhook(
|
||||
"status": "accepted",
|
||||
"repo": repo_name,
|
||||
"core": repo_name in CORE_SERVICES,
|
||||
"triggered_by": attr["pusher_username"],
|
||||
"commit_author": attr["commit_author"],
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user