Skip to content

fix(executor): mount writable tmpfs over ~/.cache (alt to #135 env redirect)#137

Draft
las7 wants to merge 1 commit into
mainfrom
las7/fix/writable-cache-tmpfs
Draft

fix(executor): mount writable tmpfs over ~/.cache (alt to #135 env redirect)#137
las7 wants to merge 1 commit into
mainfrom
las7/fix/writable-cache-tmpfs

Conversation

@las7

@las7 las7 commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

Draft for side-by-side comparison with the merged cache fix (#135). Same goal,
different mechanism. Not meant to auto-merge: pick one approach.

The two approaches

#135 (merged) This PR
Mechanism entrypoint.sh exports XDG_CACHE_HOME/MPLCONFIGDIR -> /tmp/.cache Mount a writable tmpfs over ~/.cache itself in the run args
Where caches land /tmp (shared with site-packages etc.) dedicated /home/sandbox/.cache tmpfs
Covers libs that ignore XDG_CACHE_HOME and hardcode ~/.cache ❌ no ✅ yes (conventional path)
Ownership entrypoint chown (needs CAP_CHOWN, which --cap-drop=ALL removes) mode=1777, no chown needed
Size control shares /tmp budget own knob: container_limits.cache_tmpfs_size (default 256m)
Surface 4-line entrypoint edit container-arg + config change (worker.py, sandbox.py, config.py)

Why I think the tmpfs-over-~/.cache mechanism is cleaner

  • Conventional path -> works for any library that writes under ~/.cache, not just
    the XDG-aware ones we enumerated.
  • mode=1777 lets the unprivileged sandbox user write without CAP_CHOWN. The
    container runs --cap-drop=ALL keeping only SETUID/SETGID (docker.py), so fix(executor): redirect lib cache dirs to writable /tmp + document filesystem/cache model #135's
    entrypoint chown -R sandbox:sandbox is on shaky ground; this sidesteps it.
  • Dedicated, independently configurable size that does not compete with /tmp.

Security

Unchanged posture. The --read-only root filesystem stays read-only; this adds one
bounded, ephemeral writable mount, the same class of thing as the existing /tmp
tmpfs. It does not make the image writable. The mount mirrors /tmp's exec policy
(exec only when runtime deps are installed on the server path).

Scope / honesty

  • Applied to both execution paths (server CodeExecutor and library Sandbox) via
    their run-arg builders, so they cannot drift.
  • entrypoint.sh keeps a single MPLCONFIGDIR line, matplotlib's config dir lives
    outside ~/.cache.
  • Still does not make large ML model downloads persist (/tmp and ~/.cache are
    both RAM-backed and wiped per run). Pre-staging remains the answer for those; see the
    updated docs/guide/filesystem-and-caches.md.
  • Validated: ruff clean, config + isolation/sandbox tests pass (138 passed, 10 skipped).
    Not runtime-verified end-to-end, confirming the tmpfs mount + library writes needs
    an executor image rebuild + container run (same deploy caveat as fix(executor): redirect lib cache dirs to writable /tmp + document filesystem/cache model #135).

If we take this, we should revert the #135 entrypoint redirect (this PR already removes it).

🤖 Generated with Claude Code

…rect

Alternative to the #135 cache fix. Instead of redirecting XDG_CACHE_HOME /
MPLCONFIGDIR to /tmp from the entrypoint, mount a writable tmpfs directly over
the sandbox user's ~/.cache in the container run args:

  --tmpfs=/home/sandbox/.cache:rw,...,mode=1777,size=<cache_tmpfs_size>

Why this is cleaner:
- Caches live at their conventional path, so libraries that hardcode ~/.cache
  and ignore XDG_CACHE_HOME also work, no per-variable allowlist to maintain.
- mode=1777 lets the dropped sandbox user write without CAP_CHOWN (the container
  runs --cap-drop=ALL keeping only SETUID/SETGID), so it does not depend on the
  entrypoint chown that #135 used.
- Dedicated, independently configurable size (container_limits.cache_tmpfs_size,
  default 256m) that does not compete with /tmp's budget.

The --read-only root filesystem is unchanged; this only adds one bounded,
ephemeral writable mount (same class as the existing /tmp tmpfs). Applied to
both the server CodeExecutor and the library Sandbox via their run-arg builders.
entrypoint keeps a single MPLCONFIGDIR line for matplotlib's config dir, which
lives outside ~/.cache. Docs and config reference updated.

Trade-off vs #135: this is a container-arg/config change (worker.py, sandbox.py,
config.py) rather than a 4-line entrypoint edit. It still does not make large ML
model downloads persist, /tmp and ~/.cache are both RAM-backed and ephemeral;
pre-staging remains the answer for those.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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