fix(ci): run the container as the invoking user, not root #57

Merged
fabi merged 1 commits from fix/ci-run-file-ownership into main 2026-09-19 18:48:21 +00:00
Owner

Docker on the dev boxes is rootful, so without --user every byte docker/ci/run writes into the bind-mounted repo is owned by root — and the user then needs sudo to delete their own build artifacts.

This is not hypothetical

  • export/ in a working tree held 227 root-owned paths (149 MB) left by earlier runs.
  • The sylpheed.db regen command in the workspace CLAUDE.md writes straight into /work, so the analysis DB lands root-owned every time.
  • A root-owned leftover is exactly what survived this machine's cleanup and had to be sudo rm'd.

Why it is not just adding --user

The daemon creates a named volume root-owned, so a --user container cannot write /cargo or /target at all — the build fails instantly. So the runner now takes ownership of both volumes first:

  • Once, and only when it is actually wrong. A recursive chown across a ~36 GB target volume is not something to repeat on every invocation.
  • Both volumes sampled, not one. They are chowned together but can drift apart if an older root-owned run created only one.

Volume names become overridable (SYLPH_CI_CARGO_VOL / SYLPH_CI_TARGET_VOL) — which is what let the chown path be tested against throwaway volumes instead of the real caches.

Measured, not assumed

check result
fresh root-owned volumes chowns once, then writes as uid 1000
second run no chown — correctly cached
cargo check -p sylpheed-ppc through the runner passes, exit 0
file touched in /work owned fabi:fabi, removable without sudo

On #53

The new block sits above the corpus-mount section that #53 rewrites, and git merge-tree confirms the two merge cleanly. Order of merge does not matter.

Docker on the dev boxes is **rootful**, so without `--user` every byte `docker/ci/run` writes into the bind-mounted repo is owned by **root** — and the user then needs `sudo` to delete their own build artifacts. ### This is not hypothetical - `export/` in a working tree held **227 root-owned paths (149 MB)** left by earlier runs. - The `sylpheed.db` regen command in the workspace `CLAUDE.md` writes straight into `/work`, so the analysis DB lands root-owned **every time**. - A root-owned leftover is exactly what survived this machine's cleanup and had to be `sudo rm`'d. ### Why it is not just adding `--user` The daemon creates a named volume **root-owned**, so a `--user` container cannot write `/cargo` or `/target` at all — the build fails instantly. So the runner now takes ownership of both volumes first: - **Once, and only when it is actually wrong.** A recursive chown across a ~36 GB target volume is not something to repeat on every invocation. - **Both volumes sampled, not one.** They are chowned together but can drift apart if an older root-owned run created only one. Volume names become overridable (`SYLPH_CI_CARGO_VOL` / `SYLPH_CI_TARGET_VOL`) — which is what let the chown path be tested against throwaway volumes instead of the real caches. ### Measured, not assumed | check | result | |---|---| | fresh root-owned volumes | chowns once, then writes as uid 1000 ✅ | | second run | no chown — correctly cached ✅ | | `cargo check -p sylpheed-ppc` through the runner | passes, exit 0 ✅ | | file touched in `/work` | owned `fabi:fabi`, removable without `sudo` ✅ | ### On #53 The new block sits **above** the corpus-mount section that #53 rewrites, and `git merge-tree` confirms the two **merge cleanly**. Order of merge does not matter.
fabi added 1 commit 2026-09-18 19:30:54 +00:00
fix(ci): run the container as the invoking user, not root
All checks were successful
CI / Native — linux (pull_request) Successful in 2h12m2s
CI / WASM — Web (pull_request) Successful in 32m25s
CI / Formatting (pull_request) Successful in 2m7s
3b387125e2
Docker on the dev boxes is rootful, so without `--user` every byte the build
writes into the bind-mounted repo is owned by root and the user needs `sudo` to
delete their own artifacts. This is not hypothetical: `export/` in a working
tree held 227 root-owned paths (149 MB) from earlier runs, and the `sylpheed.db`
regen in the workspace CLAUDE.md writes straight into /work, so it lands
root-owned every time.

The catch is that the daemon creates a named volume root-owned, so a `--user`
container cannot write /cargo or /target at all. So take ownership of both
volumes first -- once, and only when it is actually wrong, since a recursive
chown across a ~36 GB target volume is not something to repeat per invocation.
Both are sampled, not just one, because an older run can leave them drifted.

Volume names become overridable (SYLPH_CI_CARGO_VOL / SYLPH_CI_TARGET_VOL),
which is what let the chown path be tested without touching the real caches.

Placed above the corpus-mount block so it does not collide with #53.

Measured, not assumed:
  * fresh root-owned volumes  -> chowns once, then writes as uid 1000
  * second run                -> no chown, correctly cached
  * `cargo check -p sylpheed-ppc` through the runner -> passes, exit 0
  * a file touched in /work   -> owned fabi:fabi, removable without sudo

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
fabi merged commit 00a4ef20df into main 2026-09-19 18:48:21 +00:00
Sign in to join this conversation.