This commit is contained in:
Jarek Rozanski 2026-09-27 10:59:40 +02:00
commit 134a7e16ae
No known key found for this signature in database
4 changed files with 210 additions and 0 deletions

119
Containerfile Normal file
View file

@ -0,0 +1,119 @@
# OpenCode dev sandbox: rootless-Podman container with JDK 25, Node 24, pnpm,
# git, curl, and a hash-pinned build of OpenCode (github.com/anomalyco/opencode).
#
# Built as three stages: JDK and Node are pulled from their official upstream
# images and copied (not apt-installed) into a slim Debian final stage, to
# keep the image small while staying on a mainstream glibc distro.
# ---- Stage: JDK source ------------------------------------------------------
# JDK 24 is EOL (Adoptium stopped building it Sept 2025; no 24-jdk* images
# exist). JDK 25 is the current LTS. Built on Ubuntu Noble (glibc 2.39), which
# is older than Debian Trixie's glibc (2.40) below -- copying a binary linked
# against an older glibc into a newer-glibc environment is safe.
FROM eclipse-temurin:25-jdk-noble AS jdk-source
# ---- Stage: Node source ------------------------------------------------------
# Node 24 is the current Active LTS. Matched to the same Debian release as the
# final base so glibc versions are identical -- no compatibility risk at all.
FROM node:24-trixie-slim AS node-source
# ---- Final stage --------------------------------------------------------------
FROM debian:trixie-slim AS final
# Re-declared here: build ARGs don't cross stage boundaries implicitly.
# Auto-populated by podman/buildah from the build host's native platform on a
# plain `podman build` (no --platform needed) for same-arch builds, which
# covers building on either Apple Silicon or Intel Macs. Cross-arch builds
# would need an explicit --platform flag (out of scope for this project).
ARG TARGETARCH
# OpenCode version + per-arch SHA256 pins. Re-verified by hand against the
# actual release assets (curl + sha256sum), not just copied from a summary:
# curl -fsSL -o oc.tar.gz https://github.com/anomalyco/opencode/releases/download/v<ver>/opencode-linux-<x64|arm64>.tar.gz
# sha256sum oc.tar.gz
# Re-run this whenever OPENCODE_VERSION is bumped, and update the two hashes.
ARG OPENCODE_VERSION=1.18.32
ARG OPENCODE_SHA256_AMD64=3046e0404fdc60fb80307e7a47824ba07477364178a4d09baa8548496dd6d43b
ARG OPENCODE_SHA256_ARM64=568461b7d4d8c19865c97e9a1102e613049c6039d01fe772154de873c1865840
# pnpm version, installed via pnpm's own standalone script (not Corepack --
# the pnpm team doesn't recommend Corepack, and Node 25+ dropped bundling it).
ARG PNPM_VERSION=12.6.0
# ca-certificates : TLS roots for curl/git/npm/pnpm/JVM.
# fontconfig,
# libfreetype6 : Temurin's font subsystem needs these even headless.
# libstdc++6 : native runtime needed by libjvm.so and native Node addons.
# git, curl : required tools.
# tar : needed to extract the OpenCode release archive; not
# guaranteed present on a trimmed slim base.
# openssh-client : without it, `git clone git@...` silently fails.
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
ca-certificates \
fontconfig \
libfreetype6 \
libstdc++6 \
git \
curl \
tar \
openssh-client && \
rm -rf /var/lib/apt/lists/*
# --- JDK / Node, copied from the source stages ---------------------------------
COPY --from=jdk-source /opt/java/openjdk /opt/java/openjdk
COPY --from=node-source /usr/local/bin /usr/local/bin
COPY --from=node-source /usr/local/lib/node_modules /usr/local/lib/node_modules
# /usr/local/bin is already on Debian's default PATH, so node/npm/npx need no
# extra PATH entry. JAVA_HOME/bin and PNPM_HOME are non-standard and need one.
ENV JAVA_HOME=/opt/java/openjdk
ENV PNPM_HOME=/opt/pnpm
ENV PATH="${JAVA_HOME}/bin:${PNPM_HOME}/bin:${PATH}"
# Fixed HOME: the container is run with --userns=keep-id, so the runtime UID
# is whatever host user invoked `podman run`, which has no /etc/passwd entry
# inside the image. A plain ENV HOME is unaffected by that UID mapping, so we
# pin it here and make it world-writable (sticky bit, like /tmp) so any mapped
# UID can use it.
ENV HOME=/home/dev
# Belt-and-suspenders on top of OpenCode's default (~/.config/opencode):
# OPENCODE_CONFIG_DIR is OpenCode's one confirmed config-location override.
ENV OPENCODE_CONFIG_DIR=/home/dev/.config/opencode
RUN mkdir -p /home/dev && chmod 1777 /home/dev
# pnpm: standalone installer, pinned version. SHELL must be set explicitly --
# the installer can't infer a shell type inside a minimal `RUN` environment
# with no interactive shell, and errors out (ERR_PNPM_UNKNOWN_SHELL) otherwise.
RUN curl -fsSL https://get.pnpm.io/install.sh | env PNPM_VERSION="${PNPM_VERSION}" SHELL=/bin/bash sh - && \
chmod -R a+rX "${PNPM_HOME}"
# OpenCode: arch-aware fetch, SHA256 verification, install.
# Asset naming uses "x64" for the amd64 arch, not "amd64".
# Confirmed layout: both tarballs contain the binary flat at top level as
# "opencode" (no subdirectory nesting).
RUN set -eu; \
case "$TARGETARCH" in \
amd64) OC_ARCH=x64; OC_SHA256="$OPENCODE_SHA256_AMD64" ;; \
arm64) OC_ARCH=arm64; OC_SHA256="$OPENCODE_SHA256_ARM64" ;; \
*) echo "ERROR: unsupported TARGETARCH='$TARGETARCH'" >&2; exit 1 ;; \
esac; \
curl -fsSL -o /tmp/opencode.tar.gz \
"https://github.com/anomalyco/opencode/releases/download/v${OPENCODE_VERSION}/opencode-linux-${OC_ARCH}.tar.gz"; \
printf '%s /tmp/opencode.tar.gz\n' "$OC_SHA256" | sha256sum -c -; \
mkdir -p /tmp/opencode-extract; \
tar -xzf /tmp/opencode.tar.gz -C /tmp/opencode-extract; \
install -m 0755 /tmp/opencode-extract/opencode /usr/local/bin/opencode; \
rm -rf /tmp/opencode.tar.gz /tmp/opencode-extract
# Build-time smoke tests: fail here, not at first `make opencode`.
RUN { ldd /usr/local/bin/opencode || true; } | tee /tmp/opencode-ldd.txt && \
if grep -qi "not found" /tmp/opencode-ldd.txt; then \
echo "ERROR: opencode binary has unresolved shared library dependencies" >&2; \
exit 1; \
fi && \
rm -f /tmp/opencode-ldd.txt
RUN java -version && node --version && pnpm --version && git --version && curl --version
WORKDIR /workspace
CMD ["opencode"]