# ci/laptop-runner/Dockerfile — a GitHub Actions self-hosted runner for this
# repository, on the owner's laptop, inside a container.
#
# Ubuntu 22.04 ON PURPOSE. ci.yml routes its pinned jobs (tauri-launch and the
# SUNDIALS/DAE builds) through CI_RUNNER_2204, whose contract is "the machine
# is genuinely Ubuntu 22.04", because the shipped .deb inherits the build
# host's glibc floor. A 22.04 container satisfies that honestly (glibc 2.35),
# so both CI_RUNNER and CI_RUNNER_2204 may point at this runner. Change the
# base image and CI_RUNNER_2204 must go back to hosted (docs/CI_RUNNER.md).
#
# The container is also the isolation: a runner executes whatever any branch
# pushes, including code written by assistants, and that must not run with
# the owner's user on the laptop. Nothing here mounts the Docker socket or a
# host directory; the runner's home is a named volume (compose.yml).
#
# Build args:
#   RUNNER_VERSION  required — the version shown by Settings → Actions →
#                   Runners → New self-hosted runner (for example 2.331.0)
#   RUNNER_SHA256   optional — the SHA-256 shown on that page; checked when given
#   RUSTUP_VERSION  rustup-init release, checked against its published .sha256
# syntax=docker/dockerfile:1
FROM ubuntu:22.04

ARG RUNNER_VERSION
ARG RUNNER_SHA256=""
ARG RUSTUP_VERSION=1.27.1
ENV DEBIAN_FRONTEND=noninteractive \
    RUNNER_MANUALLY_TRAP_SIG=1 \
    ACTIONS_RUNNER_PRINT_LOG_TO_STDOUT=1

# What the routed jobs install with `sudo apt-get` on a hosted runner
# (tauri-launch's "Linux build and headless-launch dependencies", browser-e2e's
# `npx playwright install-deps chromium`), what the SUNDIALS and KLU source
# builds record and run (cmake, cc, c++, ar, ld, nm, tar), what Godot's
# headless editor links against, and what the runner binary itself needs. Pre-installing them makes
# each job's own apt step quick; the steps themselves still run, unchanged.
RUN apt-get update && apt-get install -y --no-install-recommends \
      ca-certificates curl wget git sudo unzip zip jq file xdg-utils xvfb \
      build-essential cmake pkg-config libssl-dev patchelf \
      libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev \
      python3 python3-pip python3-venv \
      libxcursor1 libxinerama1 libxrandr2 libxi6 libgl1 libglu1-mesa \
      libasound2 libpulse0 libfontconfig1 libdbus-1-3 libudev1 \
      libnss3 libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 libxkbcommon0 \
      libxcomposite1 libxdamage1 libxfixes3 libgbm1 libpango-1.0-0 libcairo2 \
    && rm -rf /var/lib/apt/lists/*

# An unprivileged user; sudo inside the container only, because three job
# steps call `sudo apt-get` and the launch smoke installs, reinstalls and
# removes the .deb.
RUN useradd -m -s /bin/bash runner \
    && echo 'runner ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/runner \
    && chmod 0440 /etc/sudoers.d/runner

# The runner distribution, unpacked once into the image and copied into the
# persistent home on first start (entrypoint.sh) so registration survives
# restarts and rebuilds.
RUN test -n "${RUNNER_VERSION}" \
      || { echo 'build arg RUNNER_VERSION is required: copy it from Settings → Actions → Runners → New self-hosted runner' >&2; exit 1; } \
    && mkdir -p /opt/runner-dist && cd /opt/runner-dist \
    && curl -fsSL -o runner.tar.gz \
         "https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz" \
    && if [ -n "${RUNNER_SHA256}" ]; then echo "${RUNNER_SHA256}  runner.tar.gz" | sha256sum -c -; fi \
    && tar xzf runner.tar.gz && rm runner.tar.gz \
    && ./bin/installdependencies.sh \
    && rm -rf /var/lib/apt/lists/* \
    && chown -R runner:runner /opt/runner-dist

USER runner
# APPIMAGE_EXTRACT_AND_RUN: AppImage tools and the built AppImage run without
# FUSE, which a container does not have (the launch smoke already sets it).
ENV HOME=/home/runner \
    APPIMAGE_EXTRACT_AND_RUN=1 \
    RUSTUP_HOME=/home/runner/.rustup \
    CARGO_HOME=/home/runner/.cargo \
    PATH=/home/runner/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
WORKDIR /home/runner

# rustup, checked against the .sha256 rust-lang publishes next to the binary.
# Toolchains are NOT baked in: the jobs' own dtolnay/rust-toolchain steps
# install the exact versions the workflow pins through this rustup, and Node
# comes from actions/setup-node the same way. The image can therefore never
# disagree with the workflow about a version.
RUN curl -fsSL -o /tmp/rustup-init \
      "https://static.rust-lang.org/rustup/archive/${RUSTUP_VERSION}/x86_64-unknown-linux-gnu/rustup-init" \
    && curl -fsSL -o /tmp/rustup-init.sha256 \
      "https://static.rust-lang.org/rustup/archive/${RUSTUP_VERSION}/x86_64-unknown-linux-gnu/rustup-init.sha256" \
    && test "$(sha256sum /tmp/rustup-init | cut -d' ' -f1)" = "$(cut -d' ' -f1 /tmp/rustup-init.sha256)" \
    && chmod +x /tmp/rustup-init \
    && /tmp/rustup-init -y --no-modify-path --default-toolchain none \
    && rm /tmp/rustup-init /tmp/rustup-init.sha256

COPY --chown=runner:runner --chmod=755 entrypoint.sh /usr/local/bin/runner-entrypoint
ENTRYPOINT ["/usr/local/bin/runner-entrypoint"]
