fix(containers): compose profile and Git mounts safely
Stage profile sources per instance and compose overlapping bind mounts so Docker cannot mask Git content or leave writable files root-owned.\n\n- preserve shared Git clones while applying profile overlays\n- add mount composition and ownership regression coverage\n- update OpenSpec tracking
This commit is contained in:
@@ -12,6 +12,7 @@ After implementing configurable tool container home directories, new `pi-agent`
|
||||
4. `npm_global` packages are installed with `RUN npm install -g ...` as root into the system npm prefix, so the non-root container user cannot update them.
|
||||
5. Once the repo mount moves out of `/workspace`, the generated `/workspace` compatibility symlink is created in the image as root. The non-root entrypoint cannot replace it (write permission is required on `/`), so container startup fails.
|
||||
6. Older images baked a literal `{{WORKSPACE_NAME}}` directory into `/home/user`, which survives alongside the real repo-named mount directory.
|
||||
7. Config-profile file mounts use canonical profile storage owned by the API process. A non-root container user therefore cannot write to writable bind mounts. When a directory-level profile mount and a Git mount share or nest under the same target, Docker bind mounting masks the earlier source rather than merging their files.
|
||||
|
||||
## Fix
|
||||
|
||||
@@ -40,7 +41,9 @@ After implementing configurable tool container home directories, new `pi-agent`
|
||||
6. Remove the explicit repo mount from the built-in `pi-agent` manifest so the repo mount is synthesized by `compile_compose` rather than depending on tool config. Add a follow-up Alembic data migration that strips the `source_type: repo` mount from the manifest.
|
||||
7. Add `_get_repository_mount_name()` helper. When the instance is bound to a workspace, the helper returns the basename of `workspace.path`. For legacy repo-only instances it falls back to parsing the remote URL like `git clone` would, then to the user-provided repository name.
|
||||
8. Switch workspace storage layout to `/data/working-copies/{workspace_id}/{repo_name}/` so `git clone` creates the repo-named directory naturally, making `workspace.path.basename` the correct container mount name. This replaces the previous `/data/working-copies/{repo_id}/{workspace_name}/` layout.
|
||||
9. Update unit tests for the new behavior.
|
||||
9. Stage every config-profile bind-mount source into the instance directory before compose generation. This makes writable mounts user-owned without changing the shared canonical profile source.
|
||||
10. Replace overlapping profile and Git bind mounts with a per-instance composite source. The composite copies Git content first and profile content second, preserving Git siblings while allowing profile files to override matching paths; it is then chowned with the other staged mounts. This removes duplicate/nested Docker mounts rather than relying on mount order to merge them.
|
||||
11. Update unit tests for the new behavior.
|
||||
|
||||
## Affected files
|
||||
|
||||
|
||||
@@ -12,5 +12,8 @@
|
||||
- [x] Remove compose-level `user: 0:0` override so entrypoint can drop privileges
|
||||
- [x] Pass manifest-declared container user to terminal sessions via `docker exec --user`
|
||||
- [x] Update unit tests for container user/terminal changes
|
||||
- [x] Stage profile bind mounts per instance so writable sources are owned by the container user
|
||||
- [x] Composite overlapping profile and Git mounts into one per-instance bind source
|
||||
- [x] Add regression tests for mount composition, ownership staging, and mount order
|
||||
- [ ] Run quality gates for container user/terminal changes
|
||||
- [ ] Commit and push
|
||||
|
||||
Reference in New Issue
Block a user