refactor(agent-images): use explicit Debian base
tracker-policy-pr / check-pr (pull_request) Successful in 13s
test / integration-docker (pull_request) Successful in 36s
test / unit (pull_request) Successful in 43s
lint / lint (push) Successful in 50s
test / integration-firecracker (pull_request) Failing after 7m18s
test / coverage (pull_request) Has been skipped
test / publish-infra (pull_request) Has been skipped

This commit is contained in:
2026-07-21 17:40:18 +00:00
parent 7e5ffd9674
commit 51b82f80d1
5 changed files with 55 additions and 29 deletions
+12 -8
View File
@@ -8,15 +8,15 @@
# Layer ordering is deliberate: the npm install lives in its own layer so
# changes to the rest of the repo (or to the CMD) don't bust it.
# Current Node LTS; slim variant keeps the image small while still
# providing apt-get for any future additions.
FROM node:22-trixie-slim
# Debian stable is the supported userspace. The provider's Node.js runtime is
# installed explicitly below rather than inherited from a language image.
FROM debian:trixie-slim
# Install runtime system deps. claude-code shells out to git for several
# features (status checks, commits, PR creation) — without git in the
# image, those features fail in surprising ways once the user does any
# real work. ca-certificates is already in the slim base; listed for
# clarity in case the base ever drops it. curl is here so any
# real work. ca-certificates is installed explicitly for TLS clients. curl is
# here so any
# HTTPS_PROXY-aware tool (curl itself, plus anything that shells out
# to it) works against egress's bumped TLS without the agent needing
# local DNS.
@@ -30,8 +30,13 @@ RUN apt-get update \
ripgrep \
iproute2 \
dnsutils \
nodejs \
npm \
&& rm -rf /var/lib/apt/lists/*
RUN groupadd --gid 1000 node \
&& useradd --uid 1000 --gid node --shell /bin/bash --create-home node
# App-specific deps. Python isn't required by claude-code itself
# (claude-code is a Node CLI), but is convenient for the agent to
# shell out to for ad-hoc scripts. Kept on its own layer so it can
@@ -52,9 +57,8 @@ RUN npm install -g --no-fund --no-audit @anthropic-ai/claude-code@2.1.172 \
# suppress bot-bottle's git-gate insteadOf rules.
RUN install -d -o node -g node -m 755 /home/node/.config /home/node/.config/git
# Run as a non-root user. The node image already provides a `node` user
# (uid 1000) with a home directory, which is where claude-code will write
# its session state.
# Run as the explicitly-created non-root user. Claude Code writes its session
# state under this user's home directory.
USER node
WORKDIR /home/node
+10 -7
View File
@@ -1,9 +1,9 @@
# bot-bottle Codex provider image.
#
# Mirrors the default Claude image shape: Node LTS, git/network tooling,
# non-root node user, and the provider CLI installed for that user.
# Mirrors the default Claude image shape: Debian stable, git/network tooling,
# a non-root runtime user, and the provider CLI installed for that user.
FROM node:22-trixie-slim
FROM debian:trixie-slim
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
@@ -16,8 +16,11 @@ RUN apt-get update \
ripgrep \
&& rm -rf /var/lib/apt/lists/*
# App-specific deps. Python isn't required by codex itself
# (codex is a Node CLI), but is convenient for the agent to shell
RUN groupadd --gid 1000 node \
&& useradd --uid 1000 --gid node --shell /bin/bash --create-home node
# App-specific deps. Python isn't required by Codex itself, but is convenient
# for the agent to shell
# out to for ad-hoc scripts. Kept on its own layer so it can be
# moved to a downstream image if the base ever needs to shrink.
RUN apt-get update \
@@ -32,8 +35,8 @@ WORKDIR /home/node
ENV PATH="/home/node/.local/bin:${PATH}"
# Remote-control support requires the standalone Codex install layout
# under ~/.codex/packages/standalone/current. The npm package can run
# the TUI, but remote-control commands expect this installer-owned path.
# under ~/.codex/packages/standalone/current. Remote-control commands expect
# this installer-owned path.
RUN mkdir -p /home/node/.codex \
&& curl -fsSL https://chatgpt.com/codex/install.sh | sh
+7 -2
View File
@@ -1,8 +1,8 @@
# bot-bottle Pi provider image.
#
# Node LTS, git/network tooling, and the Pi coding-agent CLI installed globally.
# Debian stable, git/network tooling, and the Pi coding-agent CLI.
FROM node:22-trixie-slim
FROM debian:trixie-slim
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
@@ -13,9 +13,14 @@ RUN apt-get update \
openssh-client \
podman \
ripgrep \
nodejs \
npm \
&& ln -s /usr/bin/fdfind /usr/local/bin/fd \
&& rm -rf /var/lib/apt/lists/*
RUN groupadd --gid 1000 node \
&& useradd --uid 1000 --gid node --shell /bin/bash --create-home node
RUN apt-get update \
&& apt-get install -y --no-install-recommends python3 python3-pip python3-venv \
&& rm -rf /var/lib/apt/lists/*
@@ -13,16 +13,18 @@ userspace and an OCI container tool without requiring per-project setup.
## Problem
The Claude, Codex, and Pi images inherit the generic `node:22-slim` tag. That
tag does not state which Debian release the project supports and currently
leaves the images on the older Bookworm release. None of the built-in images
installs Podman, so tasks that need to inspect or build OCI images must first
modify the bottle or cannot run at all.
The Claude, Codex, and Pi images inherited the generic `node:22-slim` tag. That
tag did not make Debian the explicit supported base and left the images on the
older Bookworm release. None of the built-in images installed Podman, so tasks
that need to inspect or build OCI images first had to modify the bottle or
could not run at all.
## Goals / success criteria
- Every Dockerfile under `bot_bottle/contrib/*/Dockerfile` explicitly inherits
`node:22-trixie-slim`, based on Debian 13 (the current stable release).
`debian:trixie-slim`, Debian 13 (the current stable release).
- Every image explicitly creates the non-root `node` runtime user with UID and
GID 1000 instead of relying on a language image to provide it.
- Every built-in agent image installs Podman from Debian stable.
- Every built-in agent image retains an SSH client for Git-over-SSH workflows.
- The non-root agent user owns a traversable XDG Git configuration directory,
@@ -39,9 +41,10 @@ modify the bottle or cannot run at all.
## Design
Use the explicit `node:22-trixie-slim` base rather than the floating `slim`
variant. Install the `podman` package with each image's existing `apt-get`
Use the explicit `debian:trixie-slim` base. Install Node.js and npm from Debian
stable where a provider needs them, and create the common `node` runtime user
explicitly. Install the `podman` package with each image's existing `apt-get`
dependency layer, so package metadata and caches are still removed in the same
layer. Treat Debian stable as the Podman stability and update channel; this
keeps the images stdlib/distribution-first and avoids adding a third-party
package repository.
layer. Treat Debian stable as the Node.js and Podman stability and update
channel; this keeps the images distribution-first and avoids adding a
third-party package repository.
+12 -1
View File
@@ -18,7 +18,18 @@ class TestBuiltinAgentImages(unittest.TestCase):
with self.subTest(provider=dockerfile.parent.name):
self.assertRegex(
dockerfile.read_text(),
r"(?m)^FROM node:22-trixie-slim\s*$",
r"(?m)^FROM debian:trixie-slim\s*$",
)
def test_all_create_node_runtime_user(self):
for dockerfile in _AGENT_DOCKERFILES:
with self.subTest(provider=dockerfile.parent.name):
dockerfile_text = dockerfile.read_text()
self.assertIn("groupadd --gid 1000 node", dockerfile_text)
self.assertIn(
"useradd --uid 1000 --gid node --shell /bin/bash "
"--create-home node",
dockerfile_text,
)
def test_all_install_podman(self):