website/resources/dumb-cd-webhooks/handle-webhook.sh

159 lines
5.2 KiB
Bash
Executable File

#!/bin/bash
set -euo pipefail
GITHUB_WEBHOOK_SECRET=REDACTED
GITHUB_API_TOKEN=REDACTED
GITHUB_API_USER=REDACTED
MAIN_BRANCH=master
CD_SCRIPT="/var/lib/path-to-your-backend/continuous-delivery.sh"
ENFORCE_HMAC=1
function log {
systemd-cat -t 'GitHub webhook handler' $@
}
function send_response {
printf "Sending response: %s\n" "$1" | log -p info
printf "HTTP/1.1 %s\r\n" "$1"
printf "Server: TauroServer CI/CD\r\n"
printf "Connection: close\r\n"
printf "Content-Type: application/octet-stream\r\n"
printf "Content-Length: $(($(wc -c <<<"$2") - 1))\r\n"
printf "\r\n"
printf '%s' "$2"
}
content_length=0
delivery_id=none
ghsig=none
event_type=none
read method path version
printf "Request method: $method\n" | log -p debug
printf "Request path: $path\n" | log -p debug
printf "HTTP version: $version\n" | log -p debug
while IFS=: read -r key val; do
[[ "$key" == "$(printf '\r\n')" ]] && break;
val=$(tr -d '\r\n' <<<"$val")
case "$key" in
"Content-Length")
content_length="${val# }"
;;
"X-GitHub-Delivery")
delivery_id="${val# }"
;;
"X-GitHub-Event")
event_type="${val# }"
;;
"X-Hub-Signature-256")
ghsig=$val
;;
*)
;;
esac
printf 'Header: %s: %s\n' "$key" "$val" | log -p debug
done
printf "Trying to read request content... %s bytes\n" "$content_length" | log -p info
content=$(dd bs=1 count="$content_length" 2> >(log -p debug) )
# xxd <<<"$content" >&2
mysig=$(printf '%s' "$content" | openssl dgst -sha256 -hmac $GITHUB_WEBHOOK_SECRET)
if [[ "${mysig#* }" == "${ghsig#*=}" ]]; then
log -p notice <<<"HMAC signatures match, proceeding further."
else
log -p warning <<<"HMAC signatures do not match! Request is not authenticated!"
if [[ $ENFORCE_HMAC != 0 ]]; then
send_response "401 Unauthorized" "Provide signature as HTTP header."
log -p err <<<"Exiting now because HMAC signature enforcing is required."
exit 1
fi
fi
if [[ "$event_type" == "none" ]]; then
send_response "400 Bad Request" "Please provide event type as HTTP header."
log -p err <<<"X-GitHub-Event header was not provided."
exit 1
fi
if [[ "$delivery_id" == "none" ]]; then
send_response "400 Bad Request" "Please provide delivery ID as HTTP header."
log -p err <<<"X-GitHub-Delivery header was not provided."
exit 1
fi
printf "GitHub Delivery ID: %s\n" "$delivery_id" | log -p info
printf "GitHub Event type: %s\n" "$event_type" | log -p info
case "$event_type" in
"ping")
send_response "204 No Content" ""
exit 0
;;
"workflow_run")
send_response "200 OK" "Acknowledged workflow run!"
;;
*)
send_response "204 No Content" ""
exit 0
;;
esac
IFS=$'\n' read -r -d '' action branch workflow_status name conclusion url artifacts \
commit message author < <(
jq -r '.action,
.workflow_run.head_branch,
.workflow_run.status,
.workflow_run.name,
.workflow_run.conclusion,
.workflow_run.html_url,
.workflow_run.artifacts_url,
.workflow_run.head_commit.id,
.workflow_run.head_commit.message,
.workflow_run.head_commit.author.name' <<<"$content") || true
printf 'Workflow run "%s" %s! See %s\n' "$name" "$workflow_status" "$url" | log -p notice
printf 'Head commit SHA: %s\n' "$commit" | log -p info
printf 'Head commit message: %s\n' "$message" | log -p info
printf 'Commit author: %s\n' "$author" | log -p info
if [[ "$action" != "completed" ]] || \
[[ "$conclusion" != "success" ]] || \
[[ "$branch" != "$MAIN_BRANCH" ]]; then exit 0; fi
log -p notice <<<"Proceeding with continuous delivery!"
function download_artifacts {
# $1: URL
# $2: directory to download artifacts to
pushd "$2" &>/dev/null
artifacts_payload=$(curl --no-progress-meter -u "$GITHUB_API_USER:$GITHUB_API_TOKEN" "$1" 2> >(log -p debug))
artifacts_amount=$(jq -r '.total_count' <<<"$artifacts_payload")
for i in $(seq 1 "$artifacts_amount"); do
printf 'Downloading artifact %s/%s...\n' "$i" "$artifacts_amount" | log -p info
name=$(jq -r ".artifacts[$((i - 1))].name" <<<"$artifacts_payload")
url=$(jq -r ".artifacts[$((i - 1))].archive_download_url" <<<"$artifacts_payload")
printf 'Artifact name: "%s" (downloading from %s)\n' "$name" "$url" | log -p info
tmpfile=$(mktemp)
printf 'Downloading ZIP to %s\n' "$tmpfile" | log -p debug
curl --no-progress-meter -L -u "$GITHUB_API_USER:$GITHUB_API_TOKEN" --output "$tmpfile" "$url" 2> >(log -p debug)
mkdir "$name"
printf 'Unzipping into %s...\n' "$2/$name" | log -p debug
unzip "$tmpfile" -d "$2/$name" | log -p debug
rm "$tmpfile"
done
popd &>/dev/null
}
artifacts_dir=$(mktemp -d)
printf 'Downloading artifacts to %s...\n' "$artifacts_dir" | log -p info
download_artifacts "$artifacts" "$artifacts_dir"
printf 'Running CD script!\n' | log -p notice
$CD_SCRIPT "$artifacts_dir" "$branch" "$commit" 2>&1 | log -t "CD script" -p info
printf 'Deleting artifacts directory...\n' | log -p info
rm -r "$artifacts_dir"