Skip to content

fix: hand bind-mount writes back to the host user after container commands - #1

Open
lucasmundim wants to merge 2 commits into
renzora:mainfrom
lucasmundim:fix/host-owned-bind-mount-writes
Open

lucasmundim wants to merge 2 commits into
renzora:mainfrom
lucasmundim:fix/host-owned-bind-mount-writes

Conversation

@lucasmundim

@lucasmundim lucasmundim commented Aug 30, 2026

Copy link
Copy Markdown

Fixes #2

Problem

The toolchain containers run as root over the /app/src bind mount, so on Linux hosts everything a build writes to the checkout — dist/, plugin scaffolding under crates/ — lands owned by root:root.

The visible failure is renzora run on Linux: the engine editor's plugin loader stages a shadow copy of each plugin into plugins/.reload/ before loading it (that is what makes hot-reload possible), and a root-owned dist/ makes creating that directory fail, so every plugin fails to load and the editor boots with no Lua, no audio and no post-processing:

ERROR renzora_plugin::host::loader: [plugin] liblua.so failed: could not stage a copy to load: Permission denied (os error 13)
ERROR renzora_plugin::host::loader: [plugin] libaudio.so failed: could not stage a copy to load: Permission denied (os error 13)
... (repeated for all 67 plugins)

A root-owned dist/ also cannot be deleted by the user without sudo.

Fix

After any container command that writes to the bind mount (build, run, upx, add, remove), chown the written paths back to the checkout's owner from inside the container, where we are root anyway (dexec_ownedchown_to_host).

Design notes:

  • Why not docker create --user $(id -u): the images keep root-owned toolchains (rustup, osxcross, xwin, the NDK) and cargo's caches under root's home, so running the container as the host uid breaks builds. A targeted chown after the write is safe regardless of image internals.
  • The target uid/gid come from the checkout directory's owner, not the calling user, so a sudo renzora build still hands files back to whoever owns the checkout.
  • The chown runs even when the command fails — a failed build usually leaves partial output behind, which would otherwise stay root-owned.
  • Best-effort (|| true, output ignored): an ownership fixup must never fail a build that just succeeded.
  • Unix hosts only: Windows bind mounts have no unix ownership to fix, and macOS's VirtioFS already maps container writes to the host user (there the chown is a harmless no-op).
  • add/remove chown crates/ rather than just the new crate dir because the scaffold also rewrites crates/renzora_runtime/Cargo.toml.

Testing

  • cargo clippy --all-targets clean, cargo test passing.
  • Verified the mechanism against a live checkout container: docker exec <container> chown -R 1000:1000 dist restored host ownership of a root-owned dist/, after which the editor loads all 67 plugins again.

…mands

The toolchain containers run as root over the /app/src bind mount, so on
Linux every build left dist/ (and plugin scaffolding under crates/) owned
by root:root. The visible failure was 'renzora run': the editor's plugin
loader stages a shadow copy of each plugin into plugins/.reload/ before
loading, and a root-owned dist/ made that fail with 'Permission denied
(os error 13)' for every plugin, booting the editor with no Lua, no audio
and no post-processing. A root-owned dist/ also could not be removed
without sudo.

Fix: after any container command that writes to the bind mount (build,
run, upx, add, remove), chown the written paths back to the checkout's
owner from inside the container, where we are root anyway. Running the
whole container as the host uid was rejected because the images keep
root-owned toolchains (rustup, osxcross, xwin, NDK) and cargo caches
under root's home. The chown is best-effort and runs even when the
command fails, since a failed build usually leaves partial output behind.
The standalone-plugin workspace keeps its cargo target dir on the bind
mount (plugins/.cargo/config.toml in the engine sets target-dir there so
all plugins share one cache), so container builds root-own it too and a
later native plugin build fails on permissions.
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.

Linux: container builds leave dist/ (and scaffolded crates) owned by root, breaking plugin loading in the editor

1 participant