mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-08-27 02:34:53 +00:00
Add three options to `services.github-runners.<name>`: - `githubApp`: authenticate via a GitHub App installation instead of a `tokenFile`. The service derives a short-lived installation token from the App's private key on each start, registers the runner, and de-registers it on stop. The PEM key is a deployed secret, never copied into the store. - `count`: fan a single entry out into N identical runner services. `github-runner-<name>` is unchanged for `count == 1`, suffixed `-<n>` for `count > 1`. - `orgs`: serve several organisations (or repositories) from one entry, fanning out into `github-runner-<name>-<org>-<n>`. The entry-level auth is shared across orgs and only the App `login` changes per org; the per-org `count` defaults to the entry-level `count`. This brings the multi-org consumption shape of the soon-to-be-removed srvos runner role (nix-community/srvos#836, nix-community/srvos#837) into nixpkgs. An entry without `orgs` and with the default `count = 1` is unchanged, so existing runners do not re-register.
89 lines
2.7 KiB
Bash
89 lines
2.7 KiB
Bash
# shellcheck shell=bash
|
|
# Request an installation access token for a GitHub App.
|
|
#
|
|
# Adapted from https://github.com/myoung34/docker-github-actions-runner (MIT,
|
|
# Copyright (c) 2020 Marcus Young), see:
|
|
# https://github.com/orgs/community/discussions/24743#discussioncomment-3245300
|
|
#
|
|
# Expects the following environment variables:
|
|
# * APP_ID the GitHub App's ID
|
|
# * APP_PRIVATE_KEY the GitHub App's PEM-encoded private key (contents)
|
|
# * APP_LOGIN the org/user login the App is installed on
|
|
# * GITHUB_HOST optional, defaults to github.com (set for GHES)
|
|
#
|
|
# Prints the installation access token (prefixed with `ghs_`) to stdout.
|
|
|
|
_GITHUB_HOST=${GITHUB_HOST:="github.com"}
|
|
|
|
# If the host is not github.com, use the GitHub Enterprise Server API endpoint.
|
|
if [[ ${_GITHUB_HOST} == "github.com" ]]; then
|
|
URI="https://api.${_GITHUB_HOST}"
|
|
else
|
|
URI="https://${_GITHUB_HOST}/api/v3"
|
|
fi
|
|
|
|
API_VERSION=v3
|
|
API_HEADER="Accept: application/vnd.github.${API_VERSION}+json"
|
|
CONTENT_LENGTH_HEADER="Content-Length: 0"
|
|
APP_INSTALLATIONS_URI="${URI}/app/installations"
|
|
|
|
# JWT token issuance and expiration parameters, see:
|
|
# https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-json-web-token-jwt-for-a-github-app
|
|
JWT_IAT_DRIFT=60
|
|
JWT_EXP_DELTA=600
|
|
|
|
JWT_JOSE_HEADER='{
|
|
"alg": "RS256",
|
|
"typ": "JWT"
|
|
}'
|
|
|
|
build_jwt_payload() {
|
|
now=$(date +%s)
|
|
iat=$((now - JWT_IAT_DRIFT))
|
|
jq -c \
|
|
--arg iat_str "${iat}" \
|
|
--arg exp_delta_str "${JWT_EXP_DELTA}" \
|
|
--arg app_id_str "${APP_ID}" \
|
|
'
|
|
($iat_str | tonumber) as $iat
|
|
| ($exp_delta_str | tonumber) as $exp_delta
|
|
| ($app_id_str | tonumber) as $app_id
|
|
| .iat = $iat
|
|
| .exp = ($iat + $exp_delta)
|
|
| .iss = $app_id
|
|
' <<<"{}" | tr -d '\n'
|
|
}
|
|
|
|
base64url() {
|
|
base64 | tr '+/' '-_' | tr -d '=\n'
|
|
}
|
|
|
|
rs256_sign() {
|
|
openssl dgst -binary -sha256 -sign <(echo "$1")
|
|
}
|
|
|
|
request_access_token() {
|
|
jwt_payload=$(build_jwt_payload)
|
|
encoded_jwt_parts=$(base64url <<<"${JWT_JOSE_HEADER}").$(base64url <<<"${jwt_payload}")
|
|
encoded_mac=$(echo -n "${encoded_jwt_parts}" | rs256_sign "${APP_PRIVATE_KEY}" | base64url)
|
|
generated_jwt="${encoded_jwt_parts}.${encoded_mac}"
|
|
|
|
auth_header="Authorization: Bearer ${generated_jwt}"
|
|
|
|
app_installations_response=$(
|
|
curl -fsSX GET \
|
|
-H "${auth_header}" \
|
|
-H "${API_HEADER}" \
|
|
"${APP_INSTALLATIONS_URI}"
|
|
)
|
|
access_token_url=$(echo "${app_installations_response}" | jq --raw-output '.[] | select (.account.login == "'"${APP_LOGIN}"'" and .app_id == '"${APP_ID}"') .access_tokens_url')
|
|
curl -fsSX POST \
|
|
-H "${CONTENT_LENGTH_HEADER}" \
|
|
-H "${auth_header}" \
|
|
-H "${API_HEADER}" \
|
|
"${access_token_url}" |
|
|
jq --raw-output .token
|
|
}
|
|
|
|
request_access_token
|