159 lines
5.2 KiB
Bash
Executable File
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"
|
|
|