Skip to content

feat(dogfood/coder): add brew and mise to ubuntu images#24618

Merged
ThomasK33 merged 1 commit into
mainfrom
dogfood-image-fpm8
May 7, 2026
Merged

feat(dogfood/coder): add brew and mise to ubuntu images#24618
ThomasK33 merged 1 commit into
mainfrom
dogfood-image-fpm8

Conversation

@ThomasK33

@ThomasK33 ThomasK33 commented Apr 22, 2026

Copy link
Copy Markdown
Member

This adds Homebrew and mise to the Ubuntu dogfood images and makes mise shims win
PATH resolution for the coder user. It installs Homebrew in
/home/linuxbrew/.linuxbrew, installs the latest mise release (v2026.4.19) via
its verified GitHub release artifact, exposes mise at /usr/local/bin/mise, wires
HOMEBREW_* and MISE_DATA_DIR, and adds build-time checks for both tools. The
mise executable target lives in writable /opt/mise/bin so mise self-update
can replace it as the coder user. This also adds libc6-dev to the Go utility
stages so the existing CGO-backed tool installs keep building on newer Ubuntu
bases.

The dogfood template now mounts a dedicated /home/linuxbrew/ Docker volume in
addition to /home/coder/. Fresh volumes are seeded from the image-baked
Homebrew tree on first mount, while user-installed formulae persist across
workspace container recreation.

I revalidated the bootstrap on jammy and resolute base images with fresh mounted
/home/coder and /home/linuxbrew volumes. In those runs, brew install hello
succeeded, mise doctor reported no PATH or activation problems, mise self-update --force --yes --no-plugins 2026.4.19 succeeded as coder, and
mise use --global github:BurntSushi/ripgrep@14.1.1 moved rg resolution to
the mise shim after container recreation.


📋 Implementation Plan

Plan: add mise and Homebrew to the dogfood Ubuntu images with mise-first PATH

Goal

  • Make both dogfood Ubuntu images ship brew and mise.
  • Ensure mise doctor does not complain about activation/PATH ordering in the shell entrypoints we support.
  • Keep the implementation robust against the persistent /home/coder volume used by the dogfood template.

Verified context

  • The relevant image definitions are:
    • dogfood/coder/ubuntu-22.04/Dockerfile
    • dogfood/coder/ubuntu-26.04/Dockerfile
  • The dogfood template mounts a persistent home volume at /home/coder/ in
    dogfood/coder/main.tf:840-843, so required image-baked state should not
    live only under /home/coder.
  • Both Dockerfiles already manipulate PATH in multiple places:
    • Go appended early (:26)
    • Cargo prepended (ubuntu-26.04/Dockerfile:202-206; mirrored in 22.04)
    • Node via nvm prepended (ubuntu-26.04/Dockerfile:245-255; mirrored in
      22.04)
    • Final coder PATH prepends /home/coder/go/bin
      (ubuntu-26.04/Dockerfile:348-358; mirrored in 22.04)
  • COPY files / is already present in both Dockerfiles, so adding new global
    shell-init files is possible without Terraform changes.
  • scripts/lib.sh:94-124 uses command -v for dependency detection, so PATH
    order is the practical repo-level behavior we need to control.
  • .github/workflows/dogfood.yaml:99-126 builds both Ubuntu variants, and the
    22.04 image is still tagged latest, so both Dockerfiles must be updated in
    the same change.

Recommended implementation

Phase 1 — Bootstrap Homebrew and mise in both Ubuntu Dockerfiles

  1. Update both Dockerfiles in parallel:
    • dogfood/coder/ubuntu-22.04/Dockerfile
    • dogfood/coder/ubuntu-26.04/Dockerfile
  2. Add the minimum explicit Homebrew prerequisites that are missing from the
    current apt package set.
    • The images already install build-essential, curl, file, and git.
    • Audit whether procps must be added explicitly for Homebrew’s Linux
      requirements.
  3. Install Homebrew in the supported Linux prefix:
    • Prefix: /home/linuxbrew/.linuxbrew
    • Keep the install/build logic in the Dockerfile, before USER coder.
    • Make the resulting prefix writable by coder before switching users.
      Prefer the smallest-diff approach that leaves brew install ... usable as
      coder.
  4. Install mise to a stable image-owned path instead of relying on
    ~/.local/bin:
    • Preferred binary path: /usr/local/bin/mise
    • Use a pinned installation method that fits the current Dockerfile style
      (versioned release asset or otherwise explicitly pinned installer path).
  5. Add defensive build-time sanity checks near the install steps so the image
    fails early if assumptions are wrong:
    • test -x /usr/local/bin/mise
    • test -x /home/linuxbrew/.linuxbrew/bin/brew
    • brew --version
    • mise --version

Quality gate: both Dockerfiles build locally, and the resulting container can
run brew --version and mise --version as coder.

Phase 2 — Make mise win PATH resolution by default

  1. After USER coder in both Dockerfiles, define stable environment variables
    for the final shell/runtime behavior:
    • HOMEBREW_PREFIX=/home/linuxbrew/.linuxbrew
    • MISE_DATA_DIR=/home/coder/.local/share/mise
    • MISE_ACTIVATE_AGGRESSIVE=1 only if later shell activation proves
      necessary
  2. Replace the final PATH composition so it resolves in this order:
    1. mise shims
    2. Homebrew bin/sbin
    3. Existing /home/coder/go/bin
    4. Existing image/system PATH
  3. Keep the current Go/Rust/Node setup intact aside from the final PATH
    ordering. Add a short Dockerfile comment explaining that mise shims must be
    first so mise doctor and command -v resolve mise-managed tools ahead of
    Homebrew/system binaries.
  4. Do not rely on image-baked mise state under /home/coder for the
    initial implementation. The goal here is binary availability and path
    precedence, not preinstalling shared mise toolchains.

Quality gate: in a fresh container as coder, echo "$PATH" shows
mise shims before Homebrew, and mise doctor/mise doctor path show no PATH
or activation problem in the tested shell entrypoints.

Phase 3 — Add shell-init hardening only if smoke tests prove it is needed

  1. Start with the Dockerfile ENV PATH solution as the default behavior.
  2. If dogfooding shows that supported login shells still need shell integration
    beyond the final ENV PATH, add minimal global shell-init files under:
    • dogfood/coder/ubuntu-22.04/files/etc/profile.d/
    • dogfood/coder/ubuntu-26.04/files/etc/profile.d/
  3. If these files are needed, keep them narrowly scoped:
    • a Homebrew file that exports/evals brew shellenv
    • a mise file that only reinforces the intended shims-first behavior
  4. Avoid touching per-user dotfiles in /home/coder; they are the wrong place
    for required image behavior because of the persistent home volume.

Quality gate: if profile.d files are added, login-shell smoke tests pass and
we do not introduce new PATH-order regressions versus the Dockerfile-only path.

Acceptance criteria

  • Both Ubuntu dogfood Dockerfiles are updated in one change and still build.
  • brew is installed in /home/linuxbrew/.linuxbrew and is usable as coder.
  • mise is installed at /usr/local/bin/mise and is usable as coder.
  • mise doctor does not report an activation/PATH-ordering problem in the
    shell entrypoints we verify.
  • Final PATH precedence is:
    1. mise shims
    2. Homebrew bin/sbin
    3. existing user/tool paths
    4. system paths
  • Existing dogfood workflows still work for Go/Rust/Node tooling after the PATH
    change.
  • The change passes the dogfood image CI path in .github/workflows/dogfood.yaml.

Dogfooding and verification

  1. Build both images locally:
    • dogfood/coder/ubuntu-22.04
    • dogfood/coder/ubuntu-26.04
  2. Run each image with an empty mounted home volume at /home/coder to mimic
    the actual dogfood runtime constraint instead of only testing the image’s
    baked filesystem.
  3. Capture a short terminal recording and screenshots for each variant showing:
    • brew --prefix
    • brew --version
    • mise --version
    • echo "$PATH"
    • mise doctor
    • mise doctor path
  4. Verify at least one login-shell path and one non-login-shell path, so we can
    tell whether Dockerfile ENV PATH is sufficient or whether /etc/profile.d
    hardening is required.
  5. Add one tool-resolution smoke test that proves mise wins when configured:
    • install/use a small mise-managed runtime as coder
    • run which -a <tool>
    • run <tool> --version
  6. Verify existing image behavior did not regress:
    • go version
    • node --version
    • any other must-have image tools that were already on PATH
  7. Preserve the artifacts from dogfooding for review:
    • screenshots attached to the change summary
    • a short screen recording (or terminal recording) covering the smoke test

Risks and decision points

  • Homebrew ownership model: installing Homebrew during docker build is not
    enough by itself; the prefix must end up writable for coder.
  • Scope control: the initial change should solve mise doctor by fixing PATH
    precedence, not by introducing a larger mise-managed tool bootstrap.
  • Shell-init uncertainty: if the dogfood terminal entrypoints do not source
    /etc/profile, a Dockerfile ENV PATH fix may be sufficient and profile.d
    may be unnecessary. This should be decided by smoke tests, not by assumption.
  • Persistent home behavior: avoid any required implementation detail that
    only works if fresh volumes copy image-baked /home/coder contents.
Why this is the lowest-risk path

This plan keeps the initial implementation focused on the user’s stated goal:
install Homebrew and mise, then guarantee that mise-controlled paths win so
mise doctor stays quiet.

The main repo-specific constraint is the persistent /home/coder volume. That
pushes required binaries and ownership-sensitive state out of /home/coder
where possible, and it argues against relying on user dotfiles for required
image behavior.

Starting with Dockerfile-level install steps plus a final PATH reorder keeps the
diff small, makes behavior consistent across shells, and gives us a clean place
to add shell-init hardening only if the smoke tests prove it is necessary.


Generated with mux • Model: openai:gpt-5.5 • Thinking: xhigh

@ThomasK33 ThomasK33 marked this pull request as ready for review April 22, 2026 13:32
@ThomasK33 ThomasK33 requested a review from aslilac April 22, 2026 13:32
@ThomasK33 ThomasK33 force-pushed the dogfood-image-fpm8 branch from e66bc02 to 8d65209 Compare April 23, 2026 09:20

@aslilac aslilac left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm technically off until monday, but I saw this and got excited.

homebrew needs a bit more than this, as we need to update the terraform to mount a volume at /home/linuxbrew/. the current volume only mounts at /home/coder/.

I also am not super sure what the behavior is when you create files in a directory in the container image and then mount a volume there. all of the mise stuff that you're adding is in /home/coder/, which is good because it will be persisted, but does it all get copied into the volume? does it do that but only if the volume is empty or something? basically, we need to do some testing to see how exactly docker is gonna handle all of this. I'll be happy to help next week when I'm back if you don't have it figured out by then.

@ThomasK33 ThomasK33 force-pushed the dogfood-image-fpm8 branch 2 times, most recently from d2c63c4 to 70903d7 Compare April 24, 2026 11:20
@ThomasK33 ThomasK33 force-pushed the dogfood-image-fpm8 branch from 70903d7 to 02b4327 Compare May 4, 2026 15:31

@aslilac aslilac left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one (pair of?) nit(s), but I'm excited to test this out!

Comment thread dogfood/coder/main.tf
Comment thread dogfood/coder/ubuntu-26.04/Dockerfile Outdated
Comment thread dogfood/coder/ubuntu-22.04/Dockerfile Outdated
@ThomasK33 ThomasK33 force-pushed the dogfood-image-fpm8 branch from 02b4327 to 163e1ef Compare May 7, 2026 07:10
@ThomasK33 ThomasK33 merged commit f605d6b into main May 7, 2026
28 checks passed
@ThomasK33 ThomasK33 deleted the dogfood-image-fpm8 branch May 7, 2026 07:24
@github-actions github-actions Bot locked and limited conversation to collaborators May 7, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants