feat: expand ~ and $HOME in mount target paths
- Add expand_container_path() helper that resolves ~/ and $HOME/ prefixes
- Add get_manifest_home_dir() to compute /home/{user.name} or /root from manifest
- Set ENV HOME=... and ENV USER=... in generated Dockerfile for runtime compatibility
- Pass home_dir through instance creation and startup pipeline
- Expand mount targets in apply_resolved_profile() for regular profile mounts
- Expand mapping targets in _resolve_git_mount_mappings() for git mounts
- Expand working_directory and volume targets in _modify_compose_file()
- Update _prepare_manifest_instance to return home_dir alongside image tag
- Fetch tool_type early in start_instance to determine home_dir before profile application
Quality gates: pytest 188 passed, frontend typecheck clean
Addresses: home-path-expansion
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
# Design: ~ / $HOME Expansion in Mount Paths
|
||||
|
||||
## Architecture
|
||||
|
||||
### New Helpers
|
||||
|
||||
#### `expand_container_path(path: str, home_dir: str) -> str`
|
||||
Located in `config_profile_resolver.py` (or new shared module).
|
||||
|
||||
```python
|
||||
def expand_container_path(path: str, home_dir: str) -> str:
|
||||
if path.startswith("~/"):
|
||||
return os.path.join(home_dir, path[2:])
|
||||
if path == "~":
|
||||
return home_dir
|
||||
path = path.replace("$HOME/", home_dir + "/")
|
||||
path = path.replace("$HOME", home_dir)
|
||||
return path
|
||||
```
|
||||
|
||||
#### `get_manifest_home_dir(manifest: dict) -> str`
|
||||
Located in `manifest_compiler.py`.
|
||||
|
||||
```python
|
||||
def get_manifest_home_dir(manifest: dict) -> str:
|
||||
user = manifest.get("user")
|
||||
if user and user.get("name"):
|
||||
return f"/home/{user['name']}"
|
||||
return "/root"
|
||||
```
|
||||
|
||||
#### `get_tool_home_dir(tool_type: ToolType, manifest: dict | None) -> str`
|
||||
Located in `tool_instances.py` or `manifest_compiler.py`.
|
||||
|
||||
```python
|
||||
def get_tool_home_dir(tool_type: ToolType, manifest: dict | None = None) -> str:
|
||||
if tool_type.definition_type == "manifest" and manifest:
|
||||
return get_manifest_home_dir(manifest)
|
||||
return "/root"
|
||||
```
|
||||
|
||||
### Pipeline Changes
|
||||
|
||||
#### `create_instance` flow
|
||||
|
||||
1. Determine `home_dir` from tool type + manifest (if manifest-based)
|
||||
2. Pass `home_dir` to `_modify_compose_file()` — expand mount targets in compose
|
||||
|
||||
#### `start_instance` flow
|
||||
|
||||
1. Determine `home_dir` from tool type + resolved manifest
|
||||
2. Pass `home_dir` to `apply_resolved_profile()` — expand profile mount targets
|
||||
3. Pass `home_dir` to `_resolve_git_mounts()` — expand git mount mapping targets
|
||||
|
||||
#### `apply_resolved_profile()`
|
||||
|
||||
```python
|
||||
def apply_resolved_profile(
|
||||
instance_dir: str,
|
||||
resolved: ResolvedProfile,
|
||||
home_dir: str = "/root",
|
||||
) -> tuple[...]:
|
||||
...
|
||||
for mount in resolved.mounts.values():
|
||||
target = expand_container_path(mount.target, home_dir)
|
||||
...
|
||||
```
|
||||
|
||||
#### `_resolve_git_mount_mappings()`
|
||||
|
||||
```python
|
||||
def _resolve_git_mount_mappings(
|
||||
repo_path: str,
|
||||
mappings: list[dict],
|
||||
working_directory: str | None,
|
||||
home_dir: str = "/root",
|
||||
) -> list[dict]:
|
||||
...
|
||||
final_target = expand_container_path(target_path, home_dir)
|
||||
...
|
||||
```
|
||||
|
||||
### Dockerfile Change
|
||||
|
||||
In `compile_dockerfile()`, after user creation, set `HOME`:
|
||||
|
||||
```python
|
||||
if user:
|
||||
home = f"/home/{user['name']}"
|
||||
lines.append(f"ENV HOME={home}")
|
||||
lines.append(f"ENV USER={user['name']}")
|
||||
```
|
||||
|
||||
### File Changes
|
||||
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `apps/api/src/services/config_profile_resolver.py` | Add `expand_container_path()`, apply in `apply_resolved_profile()` |
|
||||
| `apps/api/src/services/manifest_compiler.py` | Add `get_manifest_home_dir()`, set `HOME`/`USER` env in Dockerfile |
|
||||
| `apps/api/src/api/tool_instances.py` | Determine `home_dir`, pass through all mount resolution functions |
|
||||
| `apps/api/tests/unit/test_home_path_expansion.py` | New unit tests |
|
||||
| `apps/api/tests/unit/test_manifest_compiler.py` | Add tests for `get_manifest_home_dir` and Dockerfile `HOME` env |
|
||||
Reference in New Issue
Block a user