docs: add Docker toolbox/custom-image contract and examples (#2217)

- Document default image contract (non-root, no sudo, conservative)
- Add opt-in toolbox image pattern with passwordless sudo
- Include Dockerfile.toolbox example
- Document multi-project volume pattern
- Add bootstrap script, custom CA certificate, and proxy workflows
- Clarify that bootstrap/CA workflows require the opt-in toolbox image
This commit is contained in:
Hunter Bown
2026-05-26 16:37:33 -05:00
parent aa83446d6b
commit 671aa4810e
2 changed files with 167 additions and 0 deletions
+138
View File
@@ -36,6 +36,144 @@ docker run --rm -it \
Replace `vX.Y.Z` with a tag from
[GitHub Releases](https://github.com/Hmbown/CodeWhale/releases).
## Default image contract
`ghcr.io/hmbown/codewhale:latest` and the semver tags are conservative runtime
images:
- the container runs as the non-root `codewhale` user with UID/GID `1000:1000`
- the image does not grant passwordless `sudo`
- the image is meant to run CodeWhale against mounted workspaces, not to mutate
the base operating system at runtime
- user state belongs in a volume mounted at `/home/codewhale/.deepseek`
That default is intentional. Keep using it for the smallest trust boundary. If a
project needs `apt-get`, compiler toolchains, Node/Python package managers,
custom CA certificates, or other host-like setup inside Docker, build an
explicit toolbox image instead of changing the default image contract.
## Opt-in toolbox/custom image
The repository includes an example
[`docs/examples/Dockerfile.toolbox`](examples/Dockerfile.toolbox) that extends
the official image with passwordless `sudo` and common development packages.
Build it with a pinned CodeWhale tag when you want repeatable project
environments:
```bash
docker build -f docs/examples/Dockerfile.toolbox \
--build-arg CODEWHALE_IMAGE=ghcr.io/hmbown/codewhale:vX.Y.Z \
--build-arg TOOLBOX_PACKAGES="git openssh-client curl build-essential pkg-config python3 python3-pip nodejs npm" \
-t codewhale-toolbox:my-project .
```
Use `latest` only for throwaway testing. For shared projects, keep the
`CODEWHALE_IMAGE` value pinned and review package additions like any other
development-environment change.
Run the toolbox image with the same workspace and state mounts:
```bash
docker volume create codewhale-my-project-home
docker run --rm -it \
-e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
-v codewhale-my-project-home:/home/codewhale/.deepseek \
-v "$PWD:/workspace" \
-w /workspace \
codewhale-toolbox:my-project
```
Inside this opt-in image, CodeWhale can use commands such as
`sudo apt-get update` and `sudo apt-get install -y <package>`. For repeatable
containers, prefer baking those packages into the toolbox Dockerfile instead of
letting a long-lived container drift.
Do not bake API keys, SSH private keys, or other secrets into custom images.
Pass API keys at runtime and mount any SSH material deliberately, preferably
read-only and only for projects that need it.
## Multiple independent projects
Use one named state volume per project so sessions, config, skills, memory, and
the offline queue do not bleed across workspaces:
```bash
project="$(basename "$PWD")"
image="codewhale-toolbox:${project}"
docker volume create "codewhale-${project}-home"
docker run --rm -it \
--name "codewhale-${project}" \
-e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
-v "codewhale-${project}-home:/home/codewhale/.deepseek" \
-v "$PWD:/workspace" \
-w /workspace \
"$image"
```
For projects with different toolchains, build different toolbox tags, for
example `codewhale-toolbox:frontend` and `codewhale-toolbox:backend`. The
separate launcher idea discussed in issue #2217 can build on this contract, but
it is intentionally outside the core Docker image.
## Project bootstrap scripts
CodeWhale does not automatically execute `.deepseek/setup.sh` or
`.codewhale/setup.sh`. If you keep one of those files as a local project
recipe, run it explicitly. For shared team setup, prefer a committed project
script or the toolbox Dockerfile so the environment can be reviewed and
rebuilt.
For example, to run a committed bootstrap script before starting CodeWhale:
```bash
docker run --rm -it \
-e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
-v codewhale-my-project-home:/home/codewhale/.deepseek \
-v "$PWD:/workspace" \
-w /workspace \
--entrypoint bash \
codewhale-toolbox:my-project \
-lc './scripts/bootstrap-dev.sh && exec codewhale'
```
Use the toolbox image for bootstrap scripts that need `sudo`. The default image
will not elevate privileges.
## Custom CA certificates and proxies
For corporate proxies, dev-sidecar, or self-signed internal services, prefer
baking trusted CA certificates into a custom toolbox image:
```dockerfile
USER root
COPY docker/certs/*.crt /usr/local/share/ca-certificates/
RUN update-ca-certificates
USER codewhale
```
All files copied into `/usr/local/share/ca-certificates/` must use the `.crt`
extension. Keep private CA material out of public images.
For a local-only run, mount certificates read-only and update the trust store at
container start:
```bash
docker run --rm -it \
-e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
-v codewhale-my-project-home:/home/codewhale/.deepseek \
-v "$PWD:/workspace" \
-v "$PWD/docker/certs:/usr/local/share/ca-certificates/local:ro" \
-w /workspace \
--entrypoint bash \
codewhale-toolbox:my-project \
-lc 'sudo update-ca-certificates && exec codewhale'
```
This CA workflow requires the opt-in toolbox image because the default image
does not include passwordless `sudo`.
## Local build
Build the image locally from a checkout:
+29
View File
@@ -0,0 +1,29 @@
# syntax=docker/dockerfile:1
#
# Opt-in CodeWhale toolbox image.
#
# The published ghcr.io/hmbown/codewhale:latest image intentionally stays
# minimal, non-root, and without passwordless sudo. Use this Dockerfile only for
# workspaces where you deliberately want package installation, custom CA setup,
# or project-specific build tools inside the container.
#
# Example:
# docker build -f docs/examples/Dockerfile.toolbox \
# --build-arg CODEWHALE_IMAGE=ghcr.io/hmbown/codewhale:vX.Y.Z \
# --build-arg TOOLBOX_PACKAGES="git openssh-client curl build-essential pkg-config python3 python3-pip nodejs npm" \
# -t codewhale-toolbox:my-project .
ARG CODEWHALE_IMAGE=ghcr.io/hmbown/codewhale:latest
FROM ${CODEWHALE_IMAGE}
USER root
ARG TOOLBOX_PACKAGES="git openssh-client curl build-essential pkg-config python3 python3-pip nodejs npm"
RUN apt-get update \
&& apt-get install -y --no-install-recommends sudo ${TOOLBOX_PACKAGES} \
&& rm -rf /var/lib/apt/lists/* \
&& printf '%s\n' 'codewhale ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/codewhale-nopasswd \
&& chmod 0440 /etc/sudoers.d/codewhale-nopasswd
USER codewhale
WORKDIR /workspace