| 1 | # Diffinery runner image (Cloudflare Containers, linux/amd64). |
| 2 | # Build context: containers/runner. Run `pnpm build` first so dist/agent.mjs exists. |
| 3 | # |
| 4 | # docker build --platform linux/amd64 -t diffinery-runner containers/runner |
| 5 | ARG BASE_IMAGE=ubuntu:24.04 |
| 6 | FROM ${BASE_IMAGE} |
| 7 | |
| 8 | ARG NODE_VERSION=22.22.0 |
| 9 | |
| 10 | ENV DEBIAN_FRONTEND=noninteractive \ |
| 11 | LANG=C.UTF-8 \ |
| 12 | LC_ALL=C.UTF-8 \ |
| 13 | DIFFINERY_WORK_ROOT=/workspace \ |
| 14 | RUNNER_TOOL_CACHE=/opt/hostedtoolcache \ |
| 15 | AGENT_TOOLSDIRECTORY=/opt/hostedtoolcache \ |
| 16 | COREPACK_ENABLE_DOWNLOAD_PROMPT=0 \ |
| 17 | # What hosted ubuntu-24.04 runners report; setup-* actions key their caches on it. |
| 18 | ImageOS=ubuntu24 \ |
| 19 | ImageVersion=20250101.1 \ |
| 20 | # Ubuntu 24.04 marks the system Python as externally managed (PEP 668); |
| 21 | # CI scripts commonly `pip install` directly, so allow it like hosted runners do. |
| 22 | PIP_BREAK_SYSTEM_PACKAGES=1 |
| 23 | |
| 24 | # The -dev libraries are what ruby/setup-ruby's prebuilt Rubies link against (psych needs |
| 25 | # libyaml) and what gems' native extensions build with, as on hosted runners. |
| 26 | RUN apt-get update \ |
| 27 | && apt-get install -y --no-install-recommends \ |
| 28 | ca-certificates curl git git-lfs jq zip unzip xz-utils tar gzip zstd \ |
| 29 | build-essential pkg-config openssh-client gnupg \ |
| 30 | python3 python3-pip python3-venv python-is-python3 \ |
| 31 | libyaml-dev libssl-dev libffi-dev zlib1g-dev libreadline-dev libgmp-dev \ |
| 32 | && git config --system --add safe.directory '*' \ |
| 33 | && git lfs install --system --skip-repo \ |
| 34 | && apt-get clean \ |
| 35 | && rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/* |
| 36 | |
| 37 | # Node.js LTS from the official tarball (checksum-verified), with corepack shims for pnpm/yarn. |
| 38 | RUN set -eux; \ |
| 39 | cd /tmp; \ |
| 40 | file="node-v${NODE_VERSION}-linux-x64.tar.xz"; \ |
| 41 | curl -fsSLO "https://nodejs.org/dist/v${NODE_VERSION}/${file}"; \ |
| 42 | curl -fsSL "https://nodejs.org/dist/v${NODE_VERSION}/SHASUMS256.txt" | grep " ${file}\$" | sha256sum -c -; \ |
| 43 | tar -xJf "${file}" -C /usr/local --strip-components=1 --no-same-owner \ |
| 44 | --exclude='*/CHANGELOG.md' --exclude='*/README.md' --exclude='*/LICENSE' --exclude='*/include/*' --exclude='*/share/doc/*'; \ |
| 45 | rm -f "${file}"; \ |
| 46 | corepack enable; \ |
| 47 | corepack prepare pnpm@10.28.0 --activate; \ |
| 48 | corepack prepare yarn@1.22.22 --activate; \ |
| 49 | node --version; npm --version; pnpm --version; yarn --version; \ |
| 50 | npm cache clean --force; \ |
| 51 | rm -rf /root/.npm /tmp/* |
| 52 | |
| 53 | # nvm, as on hosted runners: login shells (`shell: bash -l {0}`) can `nvm install` other Node.js versions. |
| 54 | # A fixed tag, checked against its commit. |
| 55 | ARG NVM_VERSION=v0.40.7 |
| 56 | ARG NVM_COMMIT=f0b0c6bb0b281ceeb106c8cf9ab8fde141215092 |
| 57 | ENV NVM_DIR=/usr/local/nvm |
| 58 | RUN set -eux; \ |
| 59 | git clone -q --depth 1 --branch "${NVM_VERSION}" https://github.com/nvm-sh/nvm.git "${NVM_DIR}"; \ |
| 60 | test "$(git -C "${NVM_DIR}" rev-parse HEAD)" = "${NVM_COMMIT}"; \ |
| 61 | rm -rf "${NVM_DIR}/.git"; \ |
| 62 | printf '%s\n' 'export NVM_DIR=/usr/local/nvm' '[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"' > /etc/profile.d/nvm.sh; \ |
| 63 | bash -lc 'nvm --version' |
| 64 | |
| 65 | # GitHub CLI (preinstalled on hosted runners; workflows call `gh` with GH_TOKEN). |
| 66 | RUN set -eux; \ |
| 67 | install -m 0755 -d /etc/apt/keyrings; \ |
| 68 | curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg -o /etc/apt/keyrings/githubcli-archive-keyring.gpg; \ |
| 69 | echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" > /etc/apt/sources.list.d/github-cli.list; \ |
| 70 | apt-get update; \ |
| 71 | apt-get install -y --no-install-recommends gh; \ |
| 72 | apt-get clean; \ |
| 73 | rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/* |
| 74 | |
| 75 | # Docker Engine, started on first use by the /usr/local/bin/docker wrapper. Cloudflare |
| 76 | # Containers run it rootful with iptables, so bridge networks, service DNS, port |
| 77 | # publishing and builds all work like on GitHub's hosted runners. |
| 78 | RUN set -eux; \ |
| 79 | install -m 0755 -d /etc/apt/keyrings; \ |
| 80 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc; \ |
| 81 | echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu noble stable" > /etc/apt/sources.list.d/docker.list; \ |
| 82 | apt-get update; \ |
| 83 | apt-get install -y --no-install-recommends docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin iptables; \ |
| 84 | apt-get clean; \ |
| 85 | rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/* |
| 86 | COPY image/daemon.json /etc/docker/daemon.json |
| 87 | COPY image/docker /usr/local/bin/docker |
| 88 | |
| 89 | RUN mkdir -p /workspace /opt/hostedtoolcache /opt/diffinery |
| 90 | # image-tag (written by scripts/runner-image.sh) names this image in each job's log and API. |
| 91 | COPY dist/agent.mjs dist/image-tag* /opt/diffinery/ |
| 92 | |
| 93 | WORKDIR /workspace |
| 94 | EXPOSE 8080 |
| 95 | ENTRYPOINT ["node", "/opt/diffinery/agent.mjs"] |