├── SECURITY.md ├── CONTRIBUTING.md ├── scr ├── install_actions.sh ├── token.sh ├── app_token.sh └── entrypoint.sh ├── LICENSE ├── Dockerfile ├── gha_runner_create.sh └── README.md /SECURITY.md: -------------------------------------------------------------------------------- 1 | TBD 2 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | TBD 2 | 3 | -------------------------------------------------------------------------------- /scr/install_actions.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -ex 2 | GH_RUNNER_VERSION=$1 3 | TARGETPLATFORM=$2 4 | 5 | export TARGET_ARCH="x64" 6 | if [[ $TARGETPLATFORM == "linux/arm64" ]]; then 7 | export TARGET_ARCH="arm64" 8 | fi 9 | curl -L "https://github.com/actions/runner/releases/download/v${GH_RUNNER_VERSION}/actions-runner-linux-${TARGET_ARCH}-${GH_RUNNER_VERSION}.tar.gz" > actions.tar.gz 10 | tar -zxf actions.tar.gz 11 | rm -f actions.tar.gz 12 | ./bin/installdependencies.sh 13 | mkdir /_work 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Marcus Young 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # Github-Actions runner image. 3 | # 4 | 5 | FROM rodnymolina588/ubuntu-jammy-docker 6 | LABEL maintainer="rodny.molina@docker.com" 7 | 8 | ENV AGENT_TOOLSDIRECTORY=/opt/hostedtoolcache 9 | RUN mkdir -p /opt/hostedtoolcache 10 | 11 | ARG GH_RUNNER_VERSION="2.309.0" 12 | 13 | ARG TARGETPLATFORM 14 | 15 | SHELL ["/bin/bash", "-o", "pipefail", "-c"] 16 | 17 | RUN apt-get update && apt-get install -y --no-install-recommends dumb-init jq \ 18 | && groupadd -g 121 runner \ 19 | && useradd -mr -d /home/runner -u 1001 -g 121 runner \ 20 | && usermod -aG sudo runner \ 21 | && usermod -aG docker runner \ 22 | && echo '%sudo ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers 23 | 24 | WORKDIR /actions-runner 25 | COPY scr/install_actions.sh /actions-runner 26 | 27 | RUN chmod +x /actions-runner/install_actions.sh \ 28 | && /actions-runner/install_actions.sh ${GH_RUNNER_VERSION} ${TARGETPLATFORM} \ 29 | && rm /actions-runner/install_actions.sh \ 30 | && chown runner /_work /actions-runner /opt/hostedtoolcache 31 | 32 | COPY scr/token.sh scr/entrypoint.sh scr/app_token.sh / 33 | RUN chmod +x /token.sh /entrypoint.sh /app_token.sh 34 | 35 | ENTRYPOINT ["/entrypoint.sh"] 36 | CMD ["./bin/Runner.Listener", "run", "--startuptype", "service"] 37 | -------------------------------------------------------------------------------- /gha_runner_create.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Simple bash wrapper to create sysbox-based github-actions runners. Script can be easily 4 | # extended to accommodate the various config options offered by the GHA runner. 5 | # 6 | 7 | set -o errexit 8 | set -o pipefail 9 | set -o nounset 10 | 11 | # Function creates a per-repo runner; it can be easily extended to support org-level 12 | # runners by passing a PAT as ACCESS_TOKEN and set RUNNER_SCOPE="org". 13 | function create_sysbox_gha_runner { 14 | name=$1 15 | org=$2 16 | repo=$3 17 | token=$4 18 | 19 | docker rm -f $name >/dev/null 2>&1 || true 20 | 21 | docker run -d --restart=always \ 22 | --runtime=sysbox-runc \ 23 | -e REPO_URL="https://github.com/${org}/${repo}" \ 24 | -e RUNNER_TOKEN="$token" \ 25 | -e RUNNER_NAME="$name" \ 26 | -e RUNNER_GROUP="" \ 27 | -e LABELS="" \ 28 | --name "$name" rodnymolina588/gha-sysbox-runner:latest 29 | } 30 | 31 | function main() { 32 | if [[ $# -ne 4 ]]; then 33 | printf "\nerror: Unexpected number of arguments provided\n" 34 | printf "\nUsage: ./gha_runner_create.sh \n\n" 35 | exit 2 36 | fi 37 | 38 | create_sysbox_gha_runner "$1" "$2" "$3" "$4" 39 | } 40 | 41 | main "$@" 42 | -------------------------------------------------------------------------------- /scr/token.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | _GITHUB_HOST=${GITHUB_HOST:="github.com"} 4 | 5 | # If URL is not github.com then use the enterprise api endpoint 6 | if [[ ${GITHUB_HOST} = "github.com" ]]; then 7 | URI="https://api.${_GITHUB_HOST}" 8 | else 9 | URI="https://${_GITHUB_HOST}/api/v3" 10 | fi 11 | 12 | API_VERSION=v3 13 | API_HEADER="Accept: application/vnd.github.${API_VERSION}+json" 14 | AUTH_HEADER="Authorization: token ${ACCESS_TOKEN}" 15 | CONTENT_LENGTH_HEADER="Content-Length: 0" 16 | 17 | case ${RUNNER_SCOPE} in 18 | org*) 19 | _FULL_URL="${URI}/orgs/${ORG_NAME}/actions/runners/registration-token" 20 | ;; 21 | 22 | ent*) 23 | _FULL_URL="${URI}/enterprises/${ENTERPRISE_NAME}/actions/runners/registration-token" 24 | ;; 25 | 26 | *) 27 | _PROTO="https://" 28 | # shellcheck disable=SC2116 29 | _URL="$(echo "${REPO_URL/${_PROTO}/}")" 30 | _PATH="$(echo "${_URL}" | grep / | cut -d/ -f2-)" 31 | _ACCOUNT="$(echo "${_PATH}" | cut -d/ -f1)" 32 | _REPO="$(echo "${_PATH}" | cut -d/ -f2)" 33 | _FULL_URL="${URI}/repos/${_ACCOUNT}/${_REPO}/actions/runners/registration-token" 34 | ;; 35 | esac 36 | 37 | RUNNER_TOKEN="$(curl -XPOST -fsSL \ 38 | -H "${CONTENT_LENGTH_HEADER}" \ 39 | -H "${AUTH_HEADER}" \ 40 | -H "${API_HEADER}" \ 41 | "${_FULL_URL}" \ 42 | | jq -r '.token')" 43 | 44 | echo "{\"token\": \"${RUNNER_TOKEN}\", \"full_url\": \"${_FULL_URL}\"}" 45 | -------------------------------------------------------------------------------- /scr/app_token.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Request an ACCESS_TOKEN to be used by a GitHub APP 4 | # Environment variable that need to be set up: 5 | # * APP_ID, the GitHub's app ID 6 | # * APP_PRIVATE_KEY, the content of GitHub app's private key in PEM format. 7 | # * APP_LOGIN, the login name used to install GitHub's app 8 | # 9 | # https://github.com/orgs/community/discussions/24743#discussioncomment-3245300 10 | # 11 | 12 | set -o pipefail 13 | 14 | _GITHUB_HOST=${GITHUB_HOST:="github.com"} 15 | 16 | # If URL is not github.com then use the enterprise api endpoint 17 | if [[ ${GITHUB_HOST} = "github.com" ]]; then 18 | URI="https://api.${_GITHUB_HOST}" 19 | else 20 | URI="https://${_GITHUB_HOST}/api/v3" 21 | fi 22 | 23 | API_VERSION=v3 24 | API_HEADER="Accept: application/vnd.github.${API_VERSION}+json" 25 | CONTENT_LENGTH_HEADER="Content-Length: 0" 26 | APP_INSTALLATIONS_URI="${URI}/app/installations" 27 | 28 | 29 | # JWT parameters based off 30 | # https://docs.github.com/en/developers/apps/building-github-apps/authenticating-with-github-apps#authenticating-as-a-github-app 31 | # 32 | # JWT token issuance and expiration parameters 33 | JWT_IAT_DRIFT=60 34 | JWT_EXP_DELTA=600 35 | 36 | JWT_JOSE_HEADER='{ 37 | "alg": "RS256", 38 | "typ": "JWT" 39 | }' 40 | 41 | 42 | build_jwt_payload() { 43 | now=$(date +%s) 44 | iat=$((now - JWT_IAT_DRIFT)) 45 | jq -c \ 46 | --arg iat_str "${iat}" \ 47 | --arg exp_delta_str "${JWT_EXP_DELTA}" \ 48 | --arg app_id_str "${APP_ID}" \ 49 | ' 50 | ($iat_str | tonumber) as $iat 51 | | ($exp_delta_str | tonumber) as $exp_delta 52 | | ($app_id_str | tonumber) as $app_id 53 | | .iat = $iat 54 | | .exp = ($iat + $exp_delta) 55 | | .iss = $app_id 56 | ' <<< "{}" | tr -d '\n' 57 | } 58 | 59 | base64url() { 60 | base64 | tr '+/' '-_' | tr -d '=\n' 61 | } 62 | 63 | rs256_sign() { 64 | openssl dgst -binary -sha256 -sign <(echo "$1") 65 | } 66 | 67 | request_access_token() { 68 | jwt_payload=$(build_jwt_payload) 69 | encoded_jwt_parts=$(base64url <<<"${JWT_JOSE_HEADER}").$(base64url <<<"${jwt_payload}") 70 | encoded_mac=$(echo -n "${encoded_jwt_parts}" | rs256_sign "${APP_PRIVATE_KEY}" | base64url) 71 | generated_jwt="${encoded_jwt_parts}.${encoded_mac}" 72 | 73 | auth_header="Authorization: Bearer ${generated_jwt}" 74 | 75 | app_installations_response=$(curl -sX GET \ 76 | -H "${auth_header}" \ 77 | -H "${API_HEADER}" \ 78 | "${APP_INSTALLATIONS_URI}" \ 79 | ) 80 | access_token_url=$(echo "${app_installations_response}" | jq --raw-output '.[] | select (.account.login == "'"${APP_LOGIN}"'" and .app_id == '"${APP_ID}"') .access_tokens_url') 81 | curl -sX POST \ 82 | -H "${CONTENT_LENGTH_HEADER}" \ 83 | -H "${auth_header}" \ 84 | -H "${API_HEADER}" \ 85 | "${access_token_url}" | \ 86 | jq --raw-output .token 87 | } 88 | 89 | request_access_token 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Sysbox-Powered Github Actions Runner 2 | ==================================== 3 | 4 | The GitHub-action runner image generated by this repository is expected to be powered by the [Sysbox](https://github.com/nestybox/sysbox) container runtime. The runner binary being utilized and the associated configuration process have been extracted and documented [here](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/hosting-your-own-runners). 5 | 6 | There are similar containerized github-actions runners (GHA) out there, such as the one this repository is originally [based on](https://github.com/myoung34/docker-github-actions-runner). However, our main purpose is to offer differentiated value by utilizing the Sysbox runtime. 7 | 8 | Finally, I'd like to point out that the scope of this repository is limited to Docker-generated GHA runner deployments. Please refer to the [GHA-controller](https://github.com/actions/actions-runner-controller) project for Kubernetes scenarios. 9 | 10 | ## Why Sysbox? 11 | 12 | These are some of the issues we have identified to justify the creation of this repository: 13 | 14 | * Equivalent solutions rely on the execution of `privileged` containers, which are known to pose serious security challenges. 15 | * Other solutions bind-mount the host's docker-engine socket into the GHA runner container, representing a security threat. 16 | * The above limitations constrain the use of one GHA runner per host. That is, `privileged` containers offer weak isolation among containers/host, and a single docker-engine can't be shared across multiple docker-clis. 17 | 18 | Sysbox addresses the above challenges by providing stronger isolation among GHA runner instances and between runners and the host. Sysbox also allows the execution of Docker binaries (and plugins) within a container without resorting to `privileged` containers. In consequence, Sysbox can be used to host multiple GHA runners within the same machine. 19 | 20 | ## Quick-Start ## 21 | 22 | * Install Sysbox runtime in a Linux VM as indicated [here](https://github.com/nestybox/sysbox#installing-sysbox). Alternatively (easiest approach), launch an EC2 instance using Docker's DinD AMI (todo: provide details), which already contains all the required components. 23 | 24 | * Git clone this repo and execute the `gha_runner_create.sh` script with the following parameters: 25 | 26 | ``` 27 | $ ./gha_runner_create.sh 28 | ``` 29 | 30 | Example: 31 | 32 | ``` 33 | $ ./gha_runner_create.sh gha-runner-1 nestybox sysbox-pkgr AEEK3VNZQDRMZVBWK5QFV6DFDCYMY 34 | 27dfce314877c7dcc19110d04b61a3904d24fa093aace80e63a9cff8676abede 35 | $ 36 | ``` 37 | 38 | Note 1: The runner-token must be previously generated by going through the simple steps depicted in this GH [guide](https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/adding-self-hosted-runners#adding-a-self-hosted-runner-to-a-repository). Notice that we only need to extract the `runner-token` displayed in the GH instructions, hence, there's no need to complete the suggested steps (our runner will take care of this process for us). 39 | 40 | Note 2: This script can be easily modified to use a GH Personal-Access-Token, further simplifying the runner creation process since we wouldn't need to obtain a runner-token. 41 | -------------------------------------------------------------------------------- /scr/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/dumb-init /bin/bash 2 | # shellcheck shell=bash 3 | 4 | export RUNNER_ALLOW_RUNASROOT=1 5 | export PATH=${PATH}:/actions-runner 6 | 7 | # Un-export these, so that they must be passed explicitly to the environment of 8 | # any command that needs them. This may help prevent leaks. 9 | export -n ACCESS_TOKEN 10 | export -n RUNNER_TOKEN 11 | export -n APP_ID 12 | export -n APP_PRIVATE_KEY 13 | 14 | deregister_runner() { 15 | echo "Caught SIGTERM. Deregistering runner" 16 | if [[ -n "${ACCESS_TOKEN}" ]]; then 17 | _TOKEN=$(ACCESS_TOKEN="${ACCESS_TOKEN}" bash /token.sh) 18 | RUNNER_TOKEN=$(echo "${_TOKEN}" | jq -r .token) 19 | fi 20 | ./config.sh remove --token "${RUNNER_TOKEN}" 21 | exit 22 | } 23 | 24 | _DISABLE_AUTOMATIC_DEREGISTRATION=${DISABLE_AUTOMATIC_DEREGISTRATION:-false} 25 | 26 | _RANDOM_RUNNER_SUFFIX=${RANDOM_RUNNER_SUFFIX:="true"} 27 | 28 | _RUNNER_NAME=${RUNNER_NAME:-${RUNNER_NAME_PREFIX:-github-runner}-$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13 ; echo '')} 29 | if [[ ${RANDOM_RUNNER_SUFFIX} != "true" ]]; then 30 | # In some cases this file does not exist 31 | if [[ -f "/etc/hostname" ]]; then 32 | # in some cases it can also be empty 33 | if [[ $(stat --printf="%s" /etc/hostname) -ne 0 ]]; then 34 | _RUNNER_NAME=${RUNNER_NAME:-${RUNNER_NAME_PREFIX:-github-runner}-$(cat /etc/hostname)} 35 | echo "RANDOM_RUNNER_SUFFIX is ${RANDOM_RUNNER_SUFFIX}. /etc/hostname exists and has content. Setting runner name to ${_RUNNER_NAME}" 36 | else 37 | echo "RANDOM_RUNNER_SUFFIX is ${RANDOM_RUNNER_SUFFIX} ./etc/hostname exists but is empty. Not using /etc/hostname." 38 | fi 39 | else 40 | echo "RANDOM_RUNNER_SUFFIX is ${RANDOM_RUNNER_SUFFIX} but /etc/hostname does not exist. Not using /etc/hostname." 41 | fi 42 | fi 43 | 44 | _RUNNER_WORKDIR=${RUNNER_WORKDIR:-/_work/${_RUNNER_NAME}} 45 | _LABELS=${LABELS:-default} 46 | _RUNNER_GROUP=${RUNNER_GROUP:-Default} 47 | _GITHUB_HOST=${GITHUB_HOST:="github.com"} 48 | _RUN_AS_ROOT=${RUN_AS_ROOT:="true"} 49 | _START_DOCKER_SERVICE=${START_DOCKER_SERVICE:="true"} 50 | 51 | # ensure backwards compatibility 52 | if [[ -z ${RUNNER_SCOPE} ]]; then 53 | if [[ ${ORG_RUNNER} == "true" ]]; then 54 | echo 'ORG_RUNNER is now deprecated. Please use RUNNER_SCOPE="org" instead.' 55 | export RUNNER_SCOPE="org" 56 | else 57 | export RUNNER_SCOPE="repo" 58 | fi 59 | fi 60 | 61 | RUNNER_SCOPE="${RUNNER_SCOPE,,}" # to lowercase 62 | 63 | case ${RUNNER_SCOPE} in 64 | org*) 65 | [[ -z ${ORG_NAME} ]] && ( echo "ORG_NAME required for org runners"; exit 1 ) 66 | _SHORT_URL="https://${_GITHUB_HOST}/${ORG_NAME}" 67 | RUNNER_SCOPE="org" 68 | if [[ -n "${APP_ID}" ]] && [[ -z "${APP_LOGIN}" ]]; then 69 | APP_LOGIN=${ORG_NAME} 70 | fi 71 | ;; 72 | 73 | ent*) 74 | [[ -z ${ENTERPRISE_NAME} ]] && ( echo "ENTERPRISE_NAME required for enterprise runners"; exit 1 ) 75 | _SHORT_URL="https://${_GITHUB_HOST}/enterprises/${ENTERPRISE_NAME}" 76 | RUNNER_SCOPE="enterprise" 77 | ;; 78 | 79 | *) 80 | [[ -z ${REPO_URL} ]] && ( echo "REPO_URL required for repo runners"; exit 1 ) 81 | _SHORT_URL=${REPO_URL} 82 | RUNNER_SCOPE="repo" 83 | if [[ -n "${APP_ID}" ]] && [[ -z "${APP_LOGIN}" ]]; then 84 | APP_LOGIN=${REPO_URL%/*} 85 | APP_LOGIN=${APP_LOGIN##*/} 86 | fi 87 | ;; 88 | esac 89 | 90 | configure_runner() { 91 | ARGS=() 92 | if [[ -n "${APP_ID}" ]] && [[ -n "${APP_PRIVATE_KEY}" ]] && [[ -n "${APP_LOGIN}" ]]; then 93 | if [[ -n "${ACCESS_TOKEN}" ]] || [[ -n "${RUNNER_TOKEN}" ]]; then 94 | echo "ERROR: ACCESS_TOKEN or RUNNER_TOKEN provided but are mutually exclusive with APP_ID, APP_PRIVATE_KEY and APP_LOGIN." >&2 95 | exit 1 96 | fi 97 | echo "Obtaining access token for app_id ${APP_ID} and login ${APP_LOGIN}" 98 | nl=" 99 | " 100 | ACCESS_TOKEN=$(APP_ID="${APP_ID}" APP_PRIVATE_KEY="${APP_PRIVATE_KEY//\\n/${nl}}" APP_LOGIN="${APP_LOGIN}" bash /app_token.sh) 101 | elif [[ -n "${APP_ID}" ]] || [[ -n "${APP_PRIVATE_KEY}" ]] || [[ -n "${APP_LOGIN}" ]]; then 102 | echo "ERROR: All of APP_ID, APP_PRIVATE_KEY and APP_LOGIN must be specified." >&2 103 | exit 1 104 | fi 105 | 106 | if [[ -n "${ACCESS_TOKEN}" ]]; then 107 | echo "Obtaining the token of the runner" 108 | _TOKEN=$(ACCESS_TOKEN="${ACCESS_TOKEN}" bash /token.sh) 109 | RUNNER_TOKEN=$(echo "${_TOKEN}" | jq -r .token) 110 | fi 111 | 112 | # shellcheck disable=SC2153 113 | if [ -n "${EPHEMERAL}" ]; then 114 | echo "Ephemeral option is enabled" 115 | ARGS+=("--ephemeral") 116 | fi 117 | 118 | if [ -n "${DISABLE_AUTO_UPDATE}" ]; then 119 | echo "Disable auto update option is enabled" 120 | ARGS+=("--disableupdate") 121 | fi 122 | 123 | echo "Configuring" 124 | ./config.sh \ 125 | --url "${_SHORT_URL}" \ 126 | --token "${RUNNER_TOKEN}" \ 127 | --name "${_RUNNER_NAME}" \ 128 | --work "${_RUNNER_WORKDIR}" \ 129 | --labels "${_LABELS}" \ 130 | --runnergroup "${_RUNNER_GROUP}" \ 131 | --unattended \ 132 | --replace \ 133 | "${ARGS[@]}" 134 | 135 | [[ ! -d "${_RUNNER_WORKDIR}" ]] && mkdir "${_RUNNER_WORKDIR}" 136 | 137 | } 138 | 139 | 140 | # Opt into runner reusage because a value was given 141 | if [[ -n "${CONFIGURED_ACTIONS_RUNNER_FILES_DIR}" ]]; then 142 | echo "Runner reusage is enabled" 143 | 144 | # directory exists, copy the data 145 | if [[ -d "${CONFIGURED_ACTIONS_RUNNER_FILES_DIR}" ]]; then 146 | echo "Copying previous data" 147 | cp -p -r "${CONFIGURED_ACTIONS_RUNNER_FILES_DIR}/." "/actions-runner" 148 | fi 149 | 150 | if [ -f "/actions-runner/.runner" ]; then 151 | echo "The runner has already been configured" 152 | else 153 | configure_runner 154 | fi 155 | else 156 | echo "Runner reusage is disabled" 157 | configure_runner 158 | fi 159 | 160 | if [[ -n "${CONFIGURED_ACTIONS_RUNNER_FILES_DIR}" ]]; then 161 | echo "Reusage is enabled. Storing data to ${CONFIGURED_ACTIONS_RUNNER_FILES_DIR}" 162 | # Quoting (even with double-quotes) the regexp brokes the copying 163 | cp -p -r "/actions-runner/_diag" "/actions-runner/svc.sh" /actions-runner/.[^.]* "${CONFIGURED_ACTIONS_RUNNER_FILES_DIR}" 164 | fi 165 | 166 | if [[ ${_DISABLE_AUTOMATIC_DEREGISTRATION} == "false" ]]; then 167 | trap deregister_runner SIGINT SIGQUIT SIGTERM INT TERM QUIT 168 | fi 169 | 170 | # Start docker service if needed (e.g. for docker-in-docker) 171 | if [[ ${_START_DOCKER_SERVICE} == "true" ]]; then 172 | echo "Starting docker service" 173 | _PREFIX="" 174 | [[ ${_RUN_AS_ROOT} != "true" ]] && _PREFIX="sudo" 175 | ${_PREFIX} service docker start 176 | fi 177 | 178 | # Container's command (CMD) execution as runner user 179 | 180 | 181 | if [[ ${_RUN_AS_ROOT} == "true" ]]; then 182 | if [[ $(id -u) -eq 0 ]]; then 183 | "$@" 184 | else 185 | echo "ERROR: RUN_AS_ROOT env var is set to true but the user has been overridden and is not running as root, but UID '$(id -u)'" 186 | exit 1 187 | fi 188 | else 189 | if [[ $(id -u) -eq 0 ]]; then 190 | [[ -n "${CONFIGURED_ACTIONS_RUNNER_FILES_DIR}" ]] && chown -R runner "${CONFIGURED_ACTIONS_RUNNER_FILES_DIR}" 191 | chown -R runner "${_RUNNER_WORKDIR}" /actions-runner 192 | # The toolcache is not recursively chowned to avoid recursing over prepulated tooling in derived docker images 193 | chown runner /opt/hostedtoolcache/ 194 | /usr/sbin/gosu runner "$@" 195 | else 196 | "$@" 197 | fi 198 | fi 199 | --------------------------------------------------------------------------------