diff --git a/AGENTS.md b/AGENTS.md index bac71e4..38f56cf 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -70,7 +70,7 @@ cd /tmp && npm pack @earendil-works/pi-coding-agent@0.75.5 && tar -xzf earendil- Release-day checklist: README → (regenerate DOCKER_HUB.md only if HUB_TEMPLATE changed) → promote CHANGELOG Unreleased → grep AGENTS.md for stale counts → commit → tag → push tag. **Between releases the same coupling applies.** Doc drift is not just a release-day concern — a workflow tweak, entrypoint change, or `generate-config.py` refactor can leave any of these four files lying. Before committing a non-release change, grep the docs for references to what you touched: `git diff --name-only HEAD | xargs -I{} grep -l 'thing-you-changed' README.md AGENTS.md DOCKER_HUB.md .gitea/README.md .env.example`. If a doc says "four variants" / "two phases" / "runs on amd64 only" and your change made that no longer true, fix it in the same commit. -- **GitHub/Gitea-sourced binaries float by default** — gosu, fzf, git-lfs, nvim, bat, eza, zoxide, uv, gitea-mcp, Go, oh-my-opencode-slim all default to `latest`. Each build-time install step reads the `/releases/latest` Location redirect (or the go.dev JSON feed for Go) and derives the concrete version. Use the same `ARCH` case-switch pattern for multi-arch support (amd64/arm64). Intentional pins: `OPENCODE_VERSION` (drives the image tag), `NODE_VERSION=22` (major pin), `DEBIAN_VERSION=trixie-slim` (OS base). Adding a new upstream tool: follow the existing floated-version pattern, don't hardcode a specific tag. +- **GitHub/Gitea-sourced binaries float by default** — gosu, fzf, git-lfs, gitleaks, nvim, bat, eza, zoxide, uv, gitea-mcp, Go, oh-my-opencode-slim all default to `latest`. Each build-time install step reads the `/releases/latest` Location redirect (or the go.dev JSON feed for Go) and derives the concrete version. Use the same `ARCH` case-switch pattern for multi-arch support (amd64/arm64) — mind project-specific arch-name deviations (gitleaks uses `x64`, bat/eza/zoxide use `x86_64`/`aarch64`, gosu uses `amd64`/`arm64`). Intentional pins: `OPENCODE_VERSION` (drives the image tag), `NODE_VERSION=22` (major pin), `DEBIAN_VERSION=trixie-slim` (OS base). Adding a new upstream tool: follow the existing floated-version pattern, don't hardcode a specific tag. - **Resolved versions are logged by the smoke test** — `scripts/smoke-test.sh` prints a "Resolved component versions" table as its first step. CI logs always capture what got baked into a given image even when ARGs default to `latest`. - **`PI_VERSION` and `OMOS_VERSION` MUST be passed by CI as concrete versions**, not left at the `latest` default. The npm install steps in `Dockerfile.variant` (`npm install -g @earendil-works/pi-coding-agent` / `oh-my-opencode-slim@${OMOS_VERSION}`) produce identical layer-hashes when the ARG values are byte-identical across builds; combined with the registry buildcache (`base-buildcache`) the layer gets reused even when `latest` would have resolved to a newer upstream. This is the same class of bug that bit pi-devbox v0.74.0 → v0.75.5 (silent same-bytes-across-releases regression discovered 2026-05-23, fixed in pi-devbox v0.75.5b). It is currently *masked* in opencode-devbox by `OPENCODE_VERSION` being a hard-coded ARG that bumps every release — that bump invalidates the parent-chain cache key for the downstream pi/omos layers — but the masking would fail the moment a `vN.N.Nb` opencode-version-unchanged release ships that only bumps pi or omos. Preventative fix: `.gitea/workflows/docker-publish-split.yml` has a `resolve-versions` job that runs `npm view @earendil-works/pi-coding-agent version` and `npm view oh-my-opencode-slim version`, exposing concrete values as outputs that every variant smoke + build job consumes via build-args. Smoke tests assert via `EXPECTED_PI_VERSION` / `EXPECTED_OMOS_VERSION` env vars — would catch the regression on the next release rather than four releases later. **If you change the variant build-args list, the resolve-versions job, or the smoke EXPECTED_*_VERSION wiring, audit all affected jobs in lockstep.** - **Shell scripts use `set -euo pipefail`** — both entrypoints are strict. Errors in volume chown or SSH permission operations are intentionally suppressed with `|| true`. diff --git a/CHANGELOG.md b/CHANGELOG.md index 9aca7df..9b3e8d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,17 @@ Tags follow `v{opencode_version}[letter]` — bare tag for the first build on a ## Unreleased +### Base: gitleaks added; git-crypt confirmed already installed + +`gitleaks` is now baked into `Dockerfile.base` (Go-compiled binary fetched from GitHub releases, same `/releases/latest` redirect-resolution pattern as gosu/fzf/git-lfs/etc.). It pairs with `git-crypt`, which has been installed via apt all along but wasn't asserted by smoke or called out in user-facing docs. Several of the user's repos use both as part of their secret-management setup (gitleaks pre-commit hook + git-crypt for selectively-encrypted canonical config); having them in the devbox means `pi install`-style hooks fire correctly inside the container instead of warning that gitleaks is missing. + +- **`Dockerfile.base`** — new `GITLEAKS_VERSION=latest` ARG + install RUN block right after `git-lfs`. Arch suffix is `x64` (not `x86_64` or `amd64`) on this project; comment in the Dockerfile flags the deviation. Adds ~21 MB to the base layer. +- **`scripts/smoke-test.sh`** — adds `git-crypt` and `gitleaks` to the "Resolved component versions" table and to the "Core binaries" assertion list. Now fails fast if either binary disappears from the base. +- **`README.md`** — "What's in the image" tree updated to name `gitleaks` alongside `git-crypt` in the dev-tools line. +- **No threshold bumps:** 21 MB on a 2500–3700 MB envelope is noise; existing variant thresholds keep their headroom. + +This is a base-layer change — `base-decide` will compute a fresh `base-`, `build-base` will run on the next release (no cache hit), and all four variants will rebuild against the new base. **Downstream pi-devbox** picks up gitleaks automatically on its next release that resolves `joakimp/opencode-devbox:base-latest` to the new digest — no Dockerfile change needed there. + ### CI: preventative fix for PI_VERSION/OMOS_VERSION cache-hit silent regression Mirrors the pi-devbox v0.75.5b fix (2026-05-23) onto the four-variant pipeline here. The `with-pi`, `omos`, and `omos-with-pi` variants all install upstream npm packages (`@earendil-works/pi-coding-agent`, `oh-my-opencode-slim`) whose `*_VERSION` build-args defaulted to `latest`. When the build-arg string is byte-identical across builds, the resulting layer-hash is identical, and the registry buildcache (`base-buildcache` / variant cache-from chain) silently reuses the layer from whatever upstream version was current when the cache was first populated — the same mechanism that caused pi-devbox v0.74.0 through v0.75.5 to ship the same image bytes. diff --git a/Dockerfile.base b/Dockerfile.base index c50fff4..2dd15fc 100644 --- a/Dockerfile.base +++ b/Dockerfile.base @@ -126,6 +126,24 @@ RUN ARCH=$(case "${TARGETARCH}" in amd64) echo "amd64" ;; arm64) echo "arm64" ;; git lfs install --system && \ git-lfs --version +# gitleaks — secret scanner (used as a pre-commit hook in several of the +# repos this devbox is meant to operate on; pairs with git-crypt below). +# Distributed as a Go-compiled tarball; arch suffix is `x64` (not `x86_64` +# or `amd64`) on this project — mind the deviation from the surrounding +# tools' naming. +ARG GITLEAKS_VERSION=latest +RUN ARCH=$(case "${TARGETARCH}" in amd64) echo "x64" ;; arm64) echo "arm64" ;; *) echo "x64" ;; esac) && \ + V="${GITLEAKS_VERSION}" && \ + if [ "$V" = "latest" ]; then \ + V=$(curl -sI --retry 5 --retry-delay 5 --retry-all-errors "https://github.com/gitleaks/gitleaks/releases/latest" | awk 'tolower($1)=="location:" { sub(/\r$/,"",$2); n=split($2,a,"/"); print a[n] }'); \ + fi && \ + V="${V#v}" && \ + [ -n "$V" ] && \ + echo "Installing gitleaks ${V}" && \ + curl -fsSL --retry 5 --retry-delay 5 --retry-all-errors "https://github.com/gitleaks/gitleaks/releases/download/v${V}/gitleaks_${V}_linux_${ARCH}.tar.gz" | tar -xz -C /usr/local/bin gitleaks && \ + chmod +x /usr/local/bin/gitleaks && \ + gitleaks version + # neovim — modern text editor ARG NVIM_VERSION=latest RUN ARCH=$(case "${TARGETARCH}" in amd64) echo "x86_64" ;; arm64) echo "arm64" ;; *) echo "x86_64" ;; esac) && \ diff --git a/README.md b/README.md index c49ea0d..bc7b874 100644 --- a/README.md +++ b/README.md @@ -762,7 +762,7 @@ Container (Debian trixie) ├── oh-my-opencode-slim (optional — multi-agent orchestration plugin, includes Bun) ├── AWS CLI v2 (SSO + Bedrock auth) ├── neovim 0.12, tmux, htop, bat, eza, zoxide, uv, rustup, make, gcc, g++, rsync -├── git, git-crypt, age, ssh, ripgrep, fd, fzf, jq, curl, tree +├── git, git-crypt, age, gitleaks, ssh, ripgrep, fd, fzf, jq, curl, tree ├── Node.js (for MCP servers) ├── Bun (optional — included with oh-my-opencode-slim) ├── entrypoint.sh (UID adjustment, git config, provider setup) diff --git a/scripts/smoke-test.sh b/scripts/smoke-test.sh index 11d6743..8cfb1d0 100755 --- a/scripts/smoke-test.sh +++ b/scripts/smoke-test.sh @@ -87,6 +87,8 @@ docker run --rm --entrypoint="" "$IMAGE" sh -c ' printf " %-15s %s\n" "rg" "$(rg --version | head -1)" printf " %-15s %s\n" "gosu" "$(gosu --version)" printf " %-15s %s\n" "git-lfs" "$(git-lfs --version)" + printf " %-15s %s\n" "git-crypt" "$(git-crypt --version 2>&1 | head -1)" + printf " %-15s %s\n" "gitleaks" "$(gitleaks version 2>&1 | head -1)" printf " %-15s %s\n" "gitea-mcp" "$(gitea-mcp --version 2>&1 | head -1)" printf " %-15s %s\n" "aws" "$(aws --version 2>&1)" if command -v bun >/dev/null 2>&1; then @@ -122,6 +124,8 @@ run "fzf" "fzf --version" run "fd" "fd --version" run "rg" "rg --version | head -1" run "jq" "jq --version" +run "git-crypt" "git-crypt --version | head -1" +run "gitleaks" "gitleaks version" run "aws" "aws --version" run "gitea-mcp" "gitea-mcp --version" run "gosu" "gosu --version"