Skip to content

fix(docker): HOME=/tmp in --docker sandbox to fix EROFS for tools needing writable $HOME - #18

Merged
tbrandenburg merged 1 commit into
mainfrom
fix/issue-17-docker-home
Sep 6, 2026
Merged

tbrandenburg merged 1 commit into
mainfrom
fix/issue-17-docker-home

Conversation

@tbrandenburg

Copy link
Copy Markdown
Owner

Issues fixed

Fixes #17

Summary

--docker's hardened sandbox (src/docker-run.js) runs the container with a --read-only root filesystem plus only /tmp mounted as a writable tmpfs. Any tool invoked inside the container that writes config/state under $HOME (e.g. opencode, invoked via the agent node from @tbrandenburg/node-red-agents) failed with EROFS: read-only file system, mkdir '.../.local', since the container's default HOME (/root, /home/node, etc., depending on base image) sits on the read-only rootfs.

This sets -e HOME=/tmp unconditionally in buildRunArgs(), so $HOME always resolves onto the writable tmpfs, across all three --docker modes (default sandbox image, derived image from an arbitrary base, and custom Dockerfile).

Research summary (preceding this change)

A dedicated research pass validated the fix approach before implementation:

  • Confirmed HOME=/tmp alone (no XDG_* vars) is sufficient — opencode derives all XDG-style paths (.cache, .config, .local/share, .local/state) from $HOME when no XDG var is explicitly set, so a single env var fixes every one of them at once. Setting XDG vars individually is strictly more fragile (each one only covers one subpath; missing any one reintroduces the bug for that path).
  • Confirmed build-time HOME (used during RUN npm install -g ... in defaultDockerfile()/derivedDockerfile()) is entirely separate from this runtime docker run env var — zero interaction, src/docker-image.js untouched.
  • Confirmed no collision with the existing npm_config_cache=/tmp/.npm-cache env var (different subpath under the same tmpfs); --tmpfs /tmp is world-writable by default.
  • Confirmed @tbrandenburg/node-red-agents's agent node has no HOME/XDG handling of its own — it purely inherits process.env, confirming the fix belongs in node-red-cli's docker-run.js.

Validation commands run

  • make ci (format + lint + test + audit) from the fix branch: 116/116 tests pass (including real Docker integration tests against the local daemon), lint clean, 0 npm audit vulnerabilities.

E2E coverage

Real end-to-end verification using an inline link in -> agent (opencode, direct runtime) -> link out (return) flow, run via bin/node-red-cli from this branch (fix applied):

(Before this fix, the --docker run failed with EROFS: read-only file system, mkdir '/root/.local' / '/home/node/.local'.)

Risks / follow-ups

  • Low risk: purely additive env var, unconditional, covered by unit + integration + manual e2e tests, all passing.
  • No unrelated issues found during this fix. (Note, not a bug: --docker without --node-modules still blocks all outbound network by design (--network none) — any agent/tool needing internet access, like opencode calling its API, requires --node-modules to be passed too, as already documented behavior unrelated to this fix.)

…needing writable $HOME

The hardened --docker sandbox runs the container with a read-only root
filesystem plus only /tmp as a writable tmpfs. Any tool invoked inside
(e.g. opencode via the node-red-agents agent node) that writes
config/state under $HOME (e.g. $HOME/.local) failed with EROFS,
since the container's default HOME sits on the read-only rootfs.

Sets HOME=/tmp unconditionally in buildRunArgs() so $HOME always
resolves to the writable tmpfs, across all --docker modes (default
image, derived image, custom Dockerfile).

Fixes #17
@tbrandenburg
tbrandenburg merged commit 2dbc4a8 into main Sep 6, 2026
7 checks passed
@tbrandenburg
tbrandenburg deleted the fix/issue-17-docker-home branch September 6, 2026 13:06
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.

--docker: hardened read-only rootfs breaks tools needing writable $HOME (e.g. opencode agent node)

1 participant