Resolve ~ to /root in explicit mount targets
Previously only derived targets (when no target was specified) got
tilde expansion. Explicit targets like `target "~/downloads"` passed
through raw, which Docker cannot expand. Now both paths go through
resolve_container_tilde, backed by a CONTAINER_HOME constant that
documents the /root assumption.
Assisted-by: Claude Opus 4.6 via pi
diff --git a/src/config.rs b/src/config.rs
index 6dde657..82afd47 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -164,8 +164,8 @@ impl Mount {
}
let target = match &self.target {
- Some(t) => t.clone(),
- None => tilde_to_root(&self.source),
+ Some(t) => resolve_container_tilde(t),
+ None => resolve_container_tilde(&self.source),
};
Some(ResolvedMount {
@@ -196,12 +196,17 @@ impl ResolvedMount {
}
}
-/// Replace a leading `~` with `/root` to derive a container path.
-fn tilde_to_root(path: &str) -> String {
+/// Home directory inside the agent container. The ramekin Dockerfile runs
+/// everything as root, so `~` in container target paths maps here. If the
+/// image ever switches to a non-root user, update this constant.
+const CONTAINER_HOME: &str = "/root";
+
+/// Replace a leading `~` with the container home directory.
+fn resolve_container_tilde(path: &str) -> String {
if let Some(rest) = path.strip_prefix("~/") {
- format!("/root/{rest}")
+ format!("{CONTAINER_HOME}/{rest}")
} else if path == "~" {
- "/root".to_string()
+ CONTAINER_HOME.to_string()
} else {
path.to_string()
}
@@ -266,18 +271,21 @@ mod tests {
}
#[test]
- fn tilde_to_root_with_subpath() {
- assert_eq!(tilde_to_root("~/.config/git"), "/root/.config/git");
+ fn resolve_container_tilde_with_subpath() {
+ assert_eq!(
+ resolve_container_tilde("~/.config/git"),
+ "/root/.config/git"
+ );
}
#[test]
- fn tilde_to_root_bare() {
- assert_eq!(tilde_to_root("~"), "/root");
+ fn resolve_container_tilde_bare() {
+ assert_eq!(resolve_container_tilde("~"), "/root");
}
#[test]
- fn tilde_to_root_absolute_unchanged() {
- assert_eq!(tilde_to_root("/some/path"), "/some/path");
+ fn resolve_container_tilde_absolute_unchanged() {
+ assert_eq!(resolve_container_tilde("/some/path"), "/some/path");
}
#[test]
@@ -303,6 +311,17 @@ mod tests {
assert!(!resolved.writable);
}
+ #[test]
+ fn resolve_expands_tilde_in_explicit_target() {
+ let mount = Mount {
+ source: "/tmp".into(),
+ target: Some("~/downloads".into()),
+ writable: true,
+ };
+ let resolved = mount.resolve().unwrap();
+ assert_eq!(resolved.target, "/root/downloads");
+ }
+
#[test]
fn resolve_derives_target_from_source_when_no_tilde() {
let mount = Mount {