# 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/opencode-linux-.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"]