fix: mount config profile files individually instead of replacing directories

The previous sorting fix exposed a deeper bug: ResolvedMount always
mounted its staging directory as a single bind mount. When a config
profile mount targeted /workspace/x/y and contained a single file
z.json, the staging directory (containing only z.json) replaced the
ENTIRE /workspace/x/y directory, hiding all sibling files from git
repo mounts.

- Change apply_resolved_profile to mount each file individually:
  - source: staging_dir/relative_path
  - target: expanded_target/relative_path
  - Sibling files from other mounts are preserved.
  - Empty mounts produce no volume entries.

- Keep volume sorting (parent paths before child paths) which is
  still necessary for directory mounts and ensures parent dirs exist
  before file mounts inside them.

- Add 4 unit tests for file-level mount behavior.

Quality gates: pytest (218 passed, 6 pre-existing), tsc --noEmit (clean)
This commit is contained in:
Alex Blank
2026-05-29 11:58:50 +02:00
parent 202533fbb1
commit ea006b68c2
3 changed files with 156 additions and 7 deletions
@@ -494,13 +494,16 @@ def apply_resolved_profile(
full_path.parent.mkdir(parents=True, exist_ok=True)
full_path.write_text(content)
volume_mounts.append(
{
"source": str(mount_dir),
"target": expanded_target,
"type": "bind",
}
)
# Mount each file individually so sibling files from other mounts
# (e.g. git repo directories) are preserved.
file_target = os.path.join(expanded_target, file_path)
volume_mounts.append(
{
"source": str(full_path),
"target": file_target,
"type": "bind",
}
)
return env_vars, files, volume_mounts, resolved.runtime_hints