🥇 export from upstream (3b6ef04)
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
# Mount Tilde Expansion
|
||||
|
||||
**Date:** 2026-05-23
|
||||
**Status:** Approved
|
||||
|
||||
## Problem
|
||||
|
||||
Mount paths in `.sandcage.yml` use `~` for portability (e.g. `~/.ssh:/home/agent/.ssh:ro`).
|
||||
Sandcage passes these strings verbatim as `-v` flags to `docker compose run` via Rust's
|
||||
`Command::new()`, which does not invoke a shell. Since `~` is a shell expansion feature,
|
||||
Docker receives the literal string `~/.ssh` and either:
|
||||
|
||||
- **Windows:** Errors with "invalid characters for a local volume name"
|
||||
- **Linux/macOS:** Creates a literal `~` directory relative to CWD
|
||||
|
||||
## Platform Matrix
|
||||
|
||||
| Environment | `dirs::home_dir()` | Docker path format | Notes |
|
||||
|---|---|---|---|
|
||||
| Native Windows (PowerShell/cmd) | `C:\Users\<user>` | `C:/Users/<user>/...` | Forward slashes required |
|
||||
| MINGW / Git Bash | `C:\Users\<user>` (via Rust) | `C:/Users/<user>/...` | Rust bypasses MSYS path mangling |
|
||||
| WSL (Linux binary) | `/home/<user>` | `/home/<user>/...` | Native Linux paths |
|
||||
| Native Linux | `/home/<user>` | `/home/<user>/...` | Straightforward |
|
||||
| macOS | `/Users/<user>` | `/Users/<user>/...` | Straightforward |
|
||||
|
||||
Key insight: Rust's `Command::new()` spawns Docker directly — no shell involved — so
|
||||
the environment (PowerShell, Git Bash, etc.) is irrelevant. `dirs::home_dir()` returns
|
||||
the correct native path on every platform.
|
||||
|
||||
## Design
|
||||
|
||||
### Approach: Expand at mount-pass-through time
|
||||
|
||||
Config files keep the portable `~` form. Expansion happens only when building Docker
|
||||
CLI args.
|
||||
|
||||
### Implementation
|
||||
|
||||
Add `expand_mount_path(mount: &str) -> String` in `docker.rs`:
|
||||
|
||||
1. Split mount on `:` to extract host path, container path, and optional mode.
|
||||
2. If host path starts with `~/` or equals `~`, replace the `~` prefix with
|
||||
`dirs::home_dir()`.
|
||||
3. On Windows (`cfg!(windows)`), normalize host path separators to forward slashes.
|
||||
4. Rejoin parts with `:` and return.
|
||||
|
||||
Call site: `build_run_args()` in `docker.rs`, replacing the current
|
||||
`args.push(mount.clone())` with `args.push(expand_mount_path(mount))`.
|
||||
|
||||
### Edge Cases
|
||||
|
||||
| Input | Output (Linux) | Output (Windows) |
|
||||
|---|---|---|
|
||||
| `~/.ssh:/home/agent/.ssh:ro` | `/home/user/.ssh:/home/agent/.ssh:ro` | `C:/Users/user/.ssh:/home/agent/.ssh:ro` |
|
||||
| `~:/container` | `/home/user:/container` | `C:/Users/user:/container` |
|
||||
| `/absolute:/container:ro` | `/absolute:/container:ro` (unchanged) | `/absolute:/container:ro` (unchanged) |
|
||||
| `./relative:/container` | `./relative:/container` (unchanged) | `./relative:/container` (unchanged) |
|
||||
|
||||
### Not in Scope
|
||||
|
||||
- `$HOME` / `${HOME}` expansion
|
||||
- `~otheruser/` expansion
|
||||
- Environment variable substitution in mount paths
|
||||
|
||||
### Testing
|
||||
|
||||
- Unit tests for `expand_mount_path` covering all edge cases above.
|
||||
- Update existing `build_run_args` tests that assert literal `~/.ssh` to assert the
|
||||
expanded absolute path.
|
||||
|
||||
### Files Changed
|
||||
|
||||
- `crates/sandcage/src/docker.rs` — add `expand_mount_path`, call it in `build_run_args`
|
||||
- Existing tests in `docker.rs` — update mount assertions
|
||||
Reference in New Issue
Block a user