fix(entrypoint): chown $DEVA_HOME itself after UID remap - #507
Conversation
usermod -u implicitly chowns the home tree, and shadow's chown_tree chowns the top-level dir LAST. When the walk crosses live host mounts inside home, a transient error aborts the tree chown with rc=12 while passwd is already updated: the user becomes the host UID but /home/deva stays at the build UID with noble's HOME_MODE 750 -- untraversable, so every launch dies with "env: 'claude': Permission denied". The 7511464 whitelist chowns subdirs but never $DEVA_HOME itself; latent since 5807889 dropped the recursive home chown. Intermittent by nature: only bites when the walk races writes on the shared mounts. Chown the home dir explicitly, non-recursively, with the adapted DEVA_UID -- correct for both the half-succeeded and the failed-outright usermod variants. Verified by fault injection: a usermod stub that updates passwd, skips the chown, and exits 12 reproduces the brick unpatched and comes out clean patched. Close #506
|
Claude encountered an error after 1s —— View job I'll analyze this and get back to you. |
There was a problem hiding this comment.
Pull request overview
This PR fixes an intermittent container startup failure where a UID remap can leave $DEVA_HOME (/home/deva) owned by the build-time UID (with default mode 0750), making the remapped user unable to traverse their own home directory and causing env: 'claude': Permission denied. The change ensures the home directory itself is explicitly chowned (non-recursively) after the usermod UID remap logic, covering the “usermod partially succeeded” (rc=12) scenario described in #506.
Changes:
- Add an explicit, non-recursive
chown "$DEVA_UID:$DEVA_GID" "$DEVA_HOME"after theusermodblock insetup_nonroot_user()to repair ownership even ifusermod’s implicit tree chown aborts mid-walk. - Add a detailed devlog entry documenting the failure mode, reproduction, and rationale.
- Document the fix in
DEV-LOGS.mdandCHANGELOG.md.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| docker-entrypoint.sh | Adds explicit non-recursive chown of $DEVA_HOME after UID remap to prevent home traversal breakage when usermod chown_tree aborts. |
| docs/devlog/20260728-home-dir-chown-race.org | Forensics and rationale for the failure mode and the chosen minimal fix. |
| DEV-LOGS.md | Index entry summarizing the incident, fix, and remaining gap (no entrypoint test coverage). |
| CHANGELOG.md | Records the fix under Unreleased “Fixed” with user-facing symptom and root cause. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0a8365bee2
ℹ️ 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".
| # build-time UID with mode 750, so the remapped user cannot even | ||
| # traverse into its own home ("env: 'claude': Permission denied"). | ||
| # Chown the home dir itself explicitly, non-recursively. | ||
| chown "$DEVA_UID:$DEVA_GID" "$DEVA_HOME" 2>/dev/null || true |
There was a problem hiding this comment.
Run the home-directory repair on every entrypoint invocation
On a newly created persistent container, deva.sh starts the detached PID 1 entrypoint, sleeps only 0.3 seconds, and then invokes this entrypoint again with docker exec (deva.sh lines 4233, 4259, and 4287). Since usermod updates passwd before completing its potentially slow home-tree walk, the exec invocation can observe current_uid == DEVA_UID, skip this entire conditional, and reach the agent while PID 1 is still walking and /home/deva remains owned by the build UID. The same intermittent env: 'claude': Permission denied can therefore survive this fix; run the non-recursive home-directory ownership repair on every invocation after any UID adaptation, rather than only when that invocation detects a UID change.
Useful? React with 👍 / 👎.
Close #506
usermod's implicit home-tree chown walks live host mounts and chowns the top-level dir last; a mid-walk abort (rc=12, passwd already updated) leaves /home/deva at the build UID, mode 750, untraversable for the remapped user ->
env: 'claude': Permission denied. Whitelist chown (7511464) never covered $DEVA_HOME itself; latent since 5807889.One line of substance: explicit non-recursive chown of $DEVA_HOME after the usermod block, using the adapted DEVA_UID so the usermod-failed-outright variant stays consistent too.
Verified by fault injection (usermod stub: passwd updated, chown skipped, exit 12):
Forensics in docs/devlog/20260728-home-dir-chown-race.org.
🤖 Generated with Claude Code