docs: tool container home directory design, plan, and test plan
- Add design doc / ADR for configurable /home/user home directory - Add implementation plan with phased rollout - Add test plan / QA checklist - Update OpenSpec task for home-path-expansion
This commit is contained in:
@@ -1,75 +1,167 @@
|
||||
# Tasks: ~ / $HOME Expansion in Mount Paths
|
||||
# Tasks: Tool Container Home Directory
|
||||
|
||||
## T1: Backend — Core helpers and pipeline
|
||||
## Overview
|
||||
|
||||
### T1.1: Add `expand_container_path` helper
|
||||
**File**: `apps/api/src/services/config_profile_resolver.py`
|
||||
- Add `expand_container_path(path: str, home_dir: str) -> str`
|
||||
- Handle `~/`, `~`, `$HOME/`, `$HOME` patterns
|
||||
- Must not expand if path doesn't start with these patterns
|
||||
This task extends the earlier `home-path-expansion` work into a full configurable workspace/home directory for tool containers. It is tracked as the implementation of `openspec/designs/tool-container-home-directory.md`.
|
||||
|
||||
### T1.2: Add `get_manifest_home_dir` helper
|
||||
**File**: `apps/api/src/services/manifest_compiler.py`
|
||||
- Add `get_manifest_home_dir(manifest: dict) -> str`
|
||||
- Returns `/home/{user.name}` if user block exists, else `/root`
|
||||
## T1: Schema and migration
|
||||
|
||||
### T1.3: Set `HOME` and `USER` env vars in Dockerfile
|
||||
**File**: `apps/api/src/services/manifest_compiler.py`
|
||||
- In `compile_dockerfile()`, after user creation block, add `ENV HOME=...` and `ENV USER=...`
|
||||
- Update existing manifest compiler tests
|
||||
### T1.1: Add `home_directory` column to `ToolType`
|
||||
|
||||
### T1.4: Update `apply_resolved_profile` to expand paths
|
||||
**File**: `apps/api/src/services/config_profile_resolver.py`
|
||||
- Add `home_dir: str = "/root"` parameter
|
||||
- Expand mount targets before creating mount directories and volume entries
|
||||
**File**: `apps/api/src/models/tool/tool_type.py`
|
||||
|
||||
### T1.5: Update git mount resolution to expand paths
|
||||
**File**: `apps/api/src/api/tool_instances.py`
|
||||
- Add `home_dir: str = "/root"` parameter to `_resolve_git_mount_mappings()`
|
||||
- Expand mapping target paths before resolving
|
||||
- Add `home_dir` parameter to `_resolve_git_mounts()` and `_resolve_single_git_mount()`
|
||||
- Add `home_directory: Mapped[str]` column.
|
||||
- Non-nullable with server default `"/home/user"`.
|
||||
|
||||
### T1.6: Determine home_dir in instance lifecycle
|
||||
**File**: `apps/api/src/api/tool_instances.py`
|
||||
- In `create_instance`: determine `home_dir` from tool type + manifest (if manifest), pass to `_modify_compose_file`
|
||||
- In `start_instance`: determine `home_dir` from tool type + resolved manifest, pass to `apply_resolved_profile` and `_resolve_git_mounts`
|
||||
- In `_prepare_manifest_instance`: return `home_dir` alongside image_tag and compose_content
|
||||
### T1.2: Alembic migration for legacy tool types
|
||||
|
||||
### T1.7: Update `_modify_compose_file` to expand paths
|
||||
**File**: `apps/api/src/api/tool_instances.py`
|
||||
- Add `home_dir: str = "/root"` parameter
|
||||
- Expand `working_directory` and any mount targets in extra_volumes
|
||||
**File**: `apps/api/alembic/versions/<new>_add_tool_type_home_directory.py`
|
||||
|
||||
### T1.8: Unit tests
|
||||
**File**: `apps/api/tests/unit/test_home_path_expansion.py` (new)
|
||||
- Test `expand_container_path` with `~`, `~/foo`, `$HOME`, `$HOME/foo`, `/abs/path`, `rel/path`
|
||||
- Test `get_manifest_home_dir` with user, without user
|
||||
- Add the column.
|
||||
- Set existing rows to `/home/user`.
|
||||
- Rewrite `compose_template` and `dockerfile_template` to replace `/workspace` with `/home/user/{{WORKSPACE_NAME}}` where applicable.
|
||||
- Provide downgrade that reverses rewrites and drops the column.
|
||||
|
||||
**File**: `apps/api/tests/unit/test_manifest_compiler.py`
|
||||
- Test Dockerfile contains `ENV HOME=...` for user-based manifests
|
||||
- Test Dockerfile contains `ENV HOME=/root` for root manifests
|
||||
## T2: Manifest compiler
|
||||
|
||||
---
|
||||
### T2.1: Honor `manifest.home_directory`
|
||||
|
||||
## T2: Verification
|
||||
**File**: `apps/api/src/services/build/manifest_compiler.py`
|
||||
|
||||
- Update `get_manifest_home_dir()` to return `manifest.home_directory` if present, else derive from `user.name`, else `/root`.
|
||||
|
||||
### T2.2: Dockerfile generation
|
||||
|
||||
**File**: `apps/api/src/services/build/manifest_compiler.py`
|
||||
|
||||
- Set `ENV HOME={home_directory}` and `ENV USER={user.name}`.
|
||||
- Set `WORKDIR {home_directory}` unless overridden by `runtime.working_dir`.
|
||||
- Create `/workspace` symlink pointing to `{home_directory}/{{WORKSPACE_NAME}}` placeholder or create it at runtime.
|
||||
|
||||
### T2.3: Compose generation
|
||||
|
||||
**File**: `apps/api/src/services/build/manifest_compiler.py`
|
||||
|
||||
- Use `{home_directory}/{repo_name}` as default repo mount target when the manifest has no explicit repo mount.
|
||||
- Keep `~`/`$HOME` expansion base equal to `home_directory`.
|
||||
|
||||
## T3: Legacy instance generation
|
||||
|
||||
### T3.1: Dockerfile-based tools
|
||||
|
||||
**File**: `apps/api/src/services/tool/instance_service.py`
|
||||
|
||||
- Use `tool_type.home_directory` (default `/home/user`).
|
||||
- Mount `{repo_path}:{home_directory}/{repo_name}`.
|
||||
- Ensure `/workspace` symlink exists.
|
||||
|
||||
### T3.2: Compose-based tools
|
||||
|
||||
**File**: `apps/api/src/services/docker/compose.py`, `apps/api/src/services/tool/instance_service.py`
|
||||
|
||||
- Add `WORKSPACE_NAME` and `HOME_DIRECTORY` to template variables.
|
||||
- Validate migrated templates render correctly.
|
||||
|
||||
## T4: Config-profile and git mount expansion
|
||||
|
||||
### T4.1: Thread `home_dir` through startup
|
||||
|
||||
**File**: `apps/api/src/services/tool/instance_service.py`
|
||||
|
||||
- Compute `home_dir` from ToolType/manifest in `start_tool_instance()`.
|
||||
- Pass to `apply_resolved_profile()` and `resolve_git_mounts()`.
|
||||
|
||||
### T4.2: Verify `~`/`$HOME` expansion
|
||||
|
||||
**File**: `apps/api/src/services/config/config_profile_resolver.py`
|
||||
|
||||
- Ensure `expand_container_path()` is called with the resolved `home_dir`.
|
||||
|
||||
## T5: Entrypoint permission fixer
|
||||
|
||||
### T5.1: Generate permission-fixing entrypoint
|
||||
|
||||
**File**: `apps/api/src/services/build/manifest_compiler.py`
|
||||
|
||||
- Generate a startup script that chowns `{home_directory}` and mounted paths to the container user.
|
||||
- Create `/workspace` symlink at runtime if needed.
|
||||
- Avoid recursive chown of large repo subtrees.
|
||||
|
||||
### T5.2: Base image support
|
||||
|
||||
**File**: `tool-images/base.dockerfile` (optional)
|
||||
|
||||
- Ensure `sudo` is available and the runtime user can elevate if the fixer runs inside the base image.
|
||||
|
||||
## T6: Tests
|
||||
|
||||
### T6.1: Unit tests
|
||||
|
||||
**Files**:
|
||||
- `apps/api/tests/unit/test_home_path_expansion.py`
|
||||
- `apps/api/tests/unit/test_manifest_compiler.py`
|
||||
- `apps/api/tests/unit/test_instance_service.py`
|
||||
- `apps/api/tests/unit/test_alembic_migrations.py`
|
||||
|
||||
Cover:
|
||||
- `expand_container_path` edge cases.
|
||||
- `get_manifest_home_dir` precedence.
|
||||
- `compile_dockerfile`/`compile_compose` behavior.
|
||||
- Legacy instance mount target.
|
||||
- Alembic migration round-trip.
|
||||
|
||||
### T6.2: Integration tests
|
||||
|
||||
**File**: `apps/api/tests/integration/test_tool_instance_lifecycle.py`
|
||||
|
||||
Cover:
|
||||
- Container starts with `HOME=/home/user` and repo at `/home/user/{repo_name}`.
|
||||
- `/workspace` symlink works.
|
||||
- Config-profile and git mounts under `~` are writable.
|
||||
- Explicit manifest repo mount target is preserved.
|
||||
|
||||
## T7: Verification
|
||||
|
||||
### T7.1: Run affected tests
|
||||
|
||||
### T2.1: Run all affected tests
|
||||
```bash
|
||||
cd apps/api && pytest tests/unit/test_home_path_expansion.py tests/unit/test_manifest_compiler.py tests/unit/test_config_profile_resolver.py tests/unit/test_git_mounts.py -xvs
|
||||
cd apps/api
|
||||
pytest tests/unit/test_home_path_expansion.py tests/unit/test_manifest_compiler.py tests/unit/test_instance_service.py tests/unit/test_alembic_migrations.py -xvs
|
||||
pytest tests/integration/test_tool_instance_lifecycle.py -xvs
|
||||
```
|
||||
|
||||
### T2.2: Frontend typecheck
|
||||
### T7.2: Alembic round-trip
|
||||
|
||||
```bash
|
||||
cd apps/api
|
||||
alembic upgrade head
|
||||
alembic downgrade -1
|
||||
alembic upgrade head
|
||||
```
|
||||
|
||||
### T7.3: Frontend typecheck
|
||||
|
||||
```bash
|
||||
cd apps/web && npm run typecheck
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Estimation
|
||||
|
||||
| Task | Effort | Files |
|
||||
|------|--------|-------|
|
||||
| T1.1-T1.7 | 2h | 3 |
|
||||
| T1.8 | 1h | 2 |
|
||||
| T2.1-T2.2 | 0.5h | — |
|
||||
| **Total** | **3.5h** | **5** |
|
||||
| T1 | 1h | 2 |
|
||||
| T2 | 2h | 1 |
|
||||
| T3 | 2h | 2 |
|
||||
| T4 | 1h | 2 |
|
||||
| T5 | 2h | 2 |
|
||||
| T6 | 3h | 4 |
|
||||
| T7 | 1h | — |
|
||||
| **Total** | **12h** | **13** |
|
||||
|
||||
## Related Documents
|
||||
|
||||
- `openspec/designs/tool-container-home-directory.md`
|
||||
- `docs/superpowers/plans/tool-container-home-directory.md`
|
||||
- `docs/superpowers/specs/tool-container-home-directory-test-plan.md`
|
||||
- `openspec/designs/home-path-expansion.md`
|
||||
- `openspec/specs/home-path-expansion.md`
|
||||
|
||||
Reference in New Issue
Block a user