Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use bot token to create org hook #24

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 71 additions & 55 deletions github/create_webhook.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@ set -o nounset
set -o pipefail

IFS=$'\n\t'
SCRIPT_FOLDER="$(dirname "$(readlink -f "${0}")")"
CI_ADMIN_ROOT="${SCRIPT_FOLDER}/.."

TOKEN="$("${CI_ADMIN_ROOT}/utils/local_config.sh" "get_var" "access_token" "github")"
#shellcheck disable=SC2089
EVENTS='["push","pull_request"]'
SCRIPT_FOLDER="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")"
#shellcheck disable=SC1091
source "${SCRIPT_FOLDER}/../pass/pass_wrapper.sh"

GITHUB_PASS_DOMAIN="github.com"

CI_ADMIN_ROOT="${SCRIPT_FOLDER}/.."
LOCAL_TOKEN="$("${CI_ADMIN_ROOT}/utils/local_config.sh" "get_var" "access_token" "github")"

help() {
printf "Available commands:\n"
Expand All @@ -29,12 +32,58 @@ help() {
exit 0
}

org() {
create_github_hook() {
local token="$1"
local type="$2"
local org="$3"
local webhook_url="$4"
local events="$5"

curl -sS \
-w "\n%{http_code}" \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${token}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/${type}/${org}/hooks" \
-d '{"name":"web","active":true,"events":'${events}',"config":{"url":"'${webhook_url}'","content_type":"json"}}'
}

process_response() {
local response="$1"
local message="$2"
local http_code
local content

http_code=$(echo "${response}" | tail -n 1)
content=$(echo "${response}" | head -n -1)

case "${http_code}" in
201)
echo "INFO: Webhook created successfully with ${message}."
return 0
;;
422)
echo "INFO: Webhook already exists for ${message}."
return 0
;;
*)
echo "ERROR: Failed to create webhook with ${message}. Check org/repo permissions and if the token has the ability to create webhooks."
printf " Message: %s\n" "$(echo "${content}" | jq '.message')"
return 1
;;
esac
}

create_hook() {
local project_name="${1:-}"
local org="${2:-}"
local hook_type="${3:-}"

local short_name="${project_name##*.}"
local webhook_url="https://ci.eclipse.org/${short_name}/github-webhook/"

local events='["push","pull_request"]'

# check that project name is not empty
if [[ -z "${project_name}" ]]; then
printf "ERROR: a project name must be given.\n"
Expand All @@ -47,60 +96,27 @@ org() {
exit 1
fi

bot_token=$(passw cbi "bots/${project_name}/${GITHUB_PASS_DOMAIN}/api-token")

echo "Creating organization webhook..."

Copy link
Contributor

@netomi netomi Sep 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could add a check if the token has the appropriate scope:

has_scope="$(curl -sS -f -I -H "Authorization: token ..." https://api.github.com | grep "^x-oauth-scopes" | grep "admin:org_hook" | wc -l)"

if [ ${has_scope} != "1" ] then
  # use webmaster token
fi

and if the token has the scope, use it, otherwise fallback to the webmaster token.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. @heurtematte can you add Thomas' suggestion?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I finally decided to do it differently.

The token can have the all scope needed but this doesn't mean that the token can access the org or the repository.

I choose to test first with bot token then with cbi config token.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@heurtematte you did not want to check if the token has the admin:org_hook scope?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realized I've had messages pending for weeks now...

With the refactor code, I don't see the need to test the scope.
The logic is: Create the webhook first with the token bot account. If it fails, it falls back to the cbi config file token.

local response
response="$(curl -sS\
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${TOKEN}"\
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/orgs/${org}/hooks" \
-d '{"name":"web","active":true,"events":'${EVENTS}',"config":{"url":"'${webhook_url}'","content_type":"json"}}')"

if [[ "$(echo "${response}" | jq .errors)" != "null" ]] || [[ "$(echo "${response}" | jq .message)" != "null" ]]; then
echo "ERROR:"
printf " Message: %s\n" "$(echo "${response}" | jq '.message')"
printf " Errors/Message: %s\n" "$(echo "${response}" | jq '.errors[].message')"
response=$(create_github_hook "${bot_token}" "${hook_type}" "${org}" "${webhook_url}" "${events}")
if ! process_response "${response}" "${project_name} project and bot token"; then
echo "INFO: Try with CBI token"
response=$(create_github_hook "${LOCAL_TOKEN}" "${hook_type}" "${org}" "${webhook_url}" "${events}")
if ! process_response "${response}" "${project_name} project and cbi config token"; then
echo "ERROR: Failed to create webhook for ${project_name} project."
exit 1
fi
fi
}

repo() {
local project_name="${1:-}"
local repo="${2:-}" # org/repo
local short_name="${project_name##*.}"
local webhook_url="https://ci.eclipse.org/${short_name}/github-webhook/"

# check that project name is not empty
if [[ -z "${project_name}" ]]; then
printf "ERROR: a project name must be given.\n"
exit 1
fi

# check that repo name is not empty
if [[ -z "${repo}" ]]; then
printf "ERROR: a GitHub repo name (org/repo) must be given.\n"
exit 1
fi

echo "Creating repo webhook..."
org() {
create_hook "$1" "$2" "orgs"
}

local response
response="$(curl -sS\
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${TOKEN}"\
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/repos/${repo}/hooks" \
-d '{"name":"web","active":true,"events":'${EVENTS}',"config":{"url":"'${webhook_url}'","content_type":"json"}}')"

if [[ "$(echo "${response}" | jq .errors)" != "null" ]] || [[ "$(echo "${response}" | jq .message)" != "null" ]]; then
echo "ERROR:"
printf " Message: %s\n" "$(echo "${response}" | jq '.message')"
printf " Errors/Message: %s\n" "$(echo "${response}" | jq '.errors[].message')"
else
echo "Webhook created."
fi
repo() {
create_hook "$1" "$2" "repos"
}

"$@"
Expand Down