Skip to content

🤖 fix: support Docker images with non-root default users - #1587

Merged
ethanndickson merged 2 commits into
mainfrom
docker-mfc0
Jan 13, 2026
Merged

🤖 fix: support Docker images with non-root default users#1587
ethanndickson merged 2 commits into
mainfrom
docker-mfc0

Conversation

@ethanndickson

Copy link
Copy Markdown
Member

Problem

Docker images like codercom/enterprise-base and codercom/example-base run as a non-root user by default (e.g., coder with uid 1000). Previously, DockerRuntime failed with "Permission denied" errors:

During workspace creation:

Preparing workspace directory...
Failed to create workspace directory: mkdir: cannot create directory '/src': Permission denied
mkdir: cannot create directory '/var/mux': Permission denied

During streaming (after workspace created):

Error: Failed to stream message: Failed to create temp directory /root/.mux-tmp/...: exit code 1

Root Cause

  1. mkdir /src and mkdir /var/mux/plans ran as the container's default user, which doesn't have permission to create top-level directories
  2. ~ was hardcoded to resolve to /root, but non-root users can't write there

Solution

  • Detect container's default user (uid/gid/home) after container creation via id -u, id -g, echo $HOME
  • Create workspace directories using docker exec --user root, then chown to the container user
  • Resolve ~ paths using the detected home directory instead of hardcoded /root

Images That Now Work

Image Default User Previously Now
codercom/enterprise-base coder (1000) ❌ Permission denied ✅ Works
codercom/example-base coder (1000) ❌ Permission denied ✅ Works
node:20, ubuntu, etc. root (0) ✅ Works ✅ Works (unchanged)

Why This Is Safe (No Migration Required)

  • Workspace config entries unchanged - same structure, same container name derivation
  • Existing containers not modified - we don't retroactively chown or restructure existing containers
  • Root-based images behave identically - uid=0 detected, home=/root, same as before
  • User detection runs lazily - ensureReady() detects user info when container starts, so existing workspaces automatically get correct ~ resolution on next use

Testing

Tested with codercom/example-base:latest:

  • ✅ Workspace creation succeeds
  • ✅ Streaming works (temp dirs created in /home/coder/.mux-tmp/...)
  • ✅ VS Code Dev Containers can attach and edit /src

Generated with mux • Model: anthropic:claude-opus-4-5 • Thinking: high • Cost: $3.77

Images like codercom/enterprise-base and codercom/example-base run as a
non-root user (e.g., 'coder' with uid 1000) by default. Previously,
DockerRuntime failed with 'Permission denied' when trying to:

1. Create /src and /var/mux/plans directories during workspace init
2. Create ~/.mux-tmp/... temp directories during streaming (resolved to
   /root which non-root users cannot write to)

Changes:
- Detect container's default user (uid/gid/home) after container creation
- Create workspace directories as root, then chown to container user
- Resolve ~ paths using detected home instead of hardcoded /root

This fix is safe for existing workspaces:
- No migration required - workspace config entries unchanged
- Container names derived the same way (getContainerName)
- Existing containers not modified on upgrade
- For root-based images: behavior unchanged (uid=0, home=/root)
- For non-root images: ~ now correctly resolves to user's home

The user detection runs in ensureReady() so existing workspaces
automatically get correct ~ resolution on next use.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

initLogger.logStep("Cloning repository in destination...");
const cloneResult = await runDockerCommand(
`docker exec ${destContainerName} git clone ${containerBundlePath} ${CONTAINER_SRC_DIR}`,
300000

P1 Badge Create /src before cloning for non-root images

In forkWorkspace, the destination container is only prepared for /var/mux, then git clone is executed into /src as the container’s default user. On images that default to a non-root user (the newly supported scenario), /src typically doesn’t exist and the user can’t create top-level directories, so the clone fails with Permission denied. createWorkspace now fixes this by creating /src as root and chowning it, but the fork path doesn’t mirror that, so forks of non-root images will still fail.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

forkWorkspace was only creating /var/mux/plans as root, then relying on
git clone to create /src. But on non-root images, the container user
cannot create top-level directories, so the clone fails.

Now mirrors createWorkspace: create /src as root and chown before clone.
@ethanndickson

Copy link
Copy Markdown
Member Author

@codex review

Fixed the forkWorkspace issue: now creating /src as root before git clone, matching the createWorkspace behavior.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep it up!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ethanndickson
ethanndickson added this pull request to the merge queue Jan 13, 2026
Merged via the queue into main with commit 3a26323 Jan 13, 2026
21 checks passed
@ethanndickson
ethanndickson deleted the docker-mfc0 branch January 13, 2026 01:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant