# syntax=docker/dockerfile:1.7 FROM ubuntu:24.04 ARG SANDBOX_UID=1001 ARG SANDBOX_GID=1001 ARG TARGETARCH ENV DEBIAN_FRONTEND=noninteractive ENV NODE_VERSION=25.9.0 RUN --mount=type=cache,id=lab-ubuntu-apt-cache,target=/var/cache/apt,sharing=locked \ --mount=type=cache,id=lab-ubuntu-apt-lists,target=/var/lib/apt,sharing=locked \ apt-get update \ && apt-get upgrade -y \ && apt-get install -y --no-install-recommends \ bash \ ca-certificates \ curl \ file \ git \ jq \ libatomic1 \ python3 \ python3-pip \ python3-venv \ ripgrep \ rsync \ sudo \ tini \ unzip \ wget \ xz-utils \ && rm -rf /var/lib/apt/lists/* RUN set -eux; \ case "${TARGETARCH:-amd64}" in \ amd64) NODE_ARCH="x64" ;; \ arm64) NODE_ARCH="arm64" ;; \ *) echo "Unsupported TARGETARCH: ${TARGETARCH:-unset}" >&2; exit 1 ;; \ esac; \ curl -fsSLO "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-${NODE_ARCH}.tar.xz"; \ tar -xJf "node-v${NODE_VERSION}-linux-${NODE_ARCH}.tar.xz" -C /usr/local --strip-components=1; \ rm -f "node-v${NODE_VERSION}-linux-${NODE_ARCH}.tar.xz"; \ node --version; \ npm --version RUN if ! getent group sandbox >/dev/null; then groupadd -g ${SANDBOX_GID} sandbox; fi \ && if ! id -u sandbox >/dev/null 2>&1; then useradd -m -u ${SANDBOX_UID} -g ${SANDBOX_GID} -s /bin/bash sandbox; fi \ && echo 'sandbox ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/sandbox \ && chmod 0440 /etc/sudoers.d/sandbox RUN mkdir -p \ /opt/sandbox-home-skel/.config \ /opt/sandbox-home-skel/.local/bin \ /opt/sandbox-home-skel/.local/lib/node_modules \ /opt/sandbox-home-skel/.cache \ /opt/sandbox-home-skel/.ssh \ /opt/sandbox-home-skel/.npm \ /opt/sandbox-home-skel/.cargo/bin \ && printf '%s\n' \ 'export PATH="$HOME/.local/bin:$HOME/.cargo/bin:$PATH"' \ 'export NPM_CONFIG_PREFIX="$HOME/.local"' \ 'export npm_config_prefix="$HOME/.local"' \ 'export EDITOR=vi' \ >> /opt/sandbox-home-skel/.bashrc \ && printf '%s\n' \ 'prefix=/home/sandbox/.local' \ 'cache=/home/sandbox/.npm' \ > /opt/sandbox-home-skel/.npmrc \ && printf '%s\n' \ '[user]' \ ' name = sandbox' \ ' email = sandbox@example.invalid' \ > /opt/sandbox-home-skel/.gitconfig \ && touch /opt/sandbox-home-skel/.hushlogin \ && chown -R sandbox:sandbox /opt/sandbox-home-skel ENV HOME=/home/sandbox ENV NPM_CONFIG_PREFIX=/home/sandbox/.local ENV npm_config_prefix=/home/sandbox/.local ENV PATH=/home/sandbox/.local/bin:/home/sandbox/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin COPY --chmod=755 <<'EOF' /usr/local/bin/sandbox-entrypoint.sh #!/usr/bin/env bash set -euo pipefail HOME_DIR="${HOME:-/home/sandbox}" SKEL_DIR="/opt/sandbox-home-skel" SEED_MARKER="${HOME_DIR}/.sandbox-home-seeded" mkdir -p "${HOME_DIR}" "${HOME_DIR}/.local/bin" "${HOME_DIR}/.local/lib/node_modules" "${HOME_DIR}/.npm" if [ ! -e "${SEED_MARKER}" ]; then rsync -a --no-o --no-g --ignore-existing "${SKEL_DIR}/" "${HOME_DIR}/" touch "${SEED_MARKER}" fi cd /workspace 2>/dev/null || cd "${HOME_DIR}" exec "$@" EOF USER sandbox WORKDIR /workspace ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/bin/sandbox-entrypoint.sh"] CMD ["sleep", "infinity"]