hive-priv: overlay the knowledge .git only when the clone has one, so agents start before the first clone
This commit is contained in:
parent
513530ae35
commit
78b0451ed1
1 changed files with 35 additions and 8 deletions
|
|
@ -414,9 +414,15 @@ fn validate_cpu_quota(value: &str) -> Result<()> {
|
|||
///
|
||||
/// An overlay rather than an exported copy: there is no second tree to keep in
|
||||
/// sync, so nothing can go stale, and no code path has to remember to refresh
|
||||
/// it. It is applied unconditionally: the directory is created empty and cloned
|
||||
/// into later, so a container started before the clone must already hide the
|
||||
/// `.git` that arrives.
|
||||
/// it.
|
||||
///
|
||||
/// Applied only when the bind's host source has a `.git` entry. nspawn creates
|
||||
/// the mount point inside the read-only bind, and a read-only mount refuses
|
||||
/// that (`EROFS`) where nothing exists to mount over, which fails the whole
|
||||
/// container start while the first clone is missing. A container started
|
||||
/// before that clone has no overlay, so it sees the `.git` that arrives until
|
||||
/// its next start rewrites these flags. The entry is looked up without
|
||||
/// following a symlink, and a symlink named `.git` counts as present.
|
||||
///
|
||||
/// ⚠️ Ordering matters: these must be appended **after** the `--bind` flags so
|
||||
/// nspawn mounts them on top of the already-mounted trees.
|
||||
|
|
@ -424,6 +430,7 @@ fn git_overlay_flags(binds: &[BindMount]) -> Vec<String> {
|
|||
binds
|
||||
.iter()
|
||||
.filter(|b| b.container_path == "/knowledge")
|
||||
.filter(|b| std::fs::symlink_metadata(Path::new(&b.host_path).join(".git")).is_ok())
|
||||
.map(|b| format!("--tmpfs={}/.git", b.container_path))
|
||||
.collect()
|
||||
}
|
||||
|
|
@ -814,19 +821,33 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
/// The knowledge tree gets its `.git` overlaid, whatever its source holds:
|
||||
/// it is cloned into after the container may have started, so the overlay
|
||||
/// does not wait for a `.git` to exist.
|
||||
/// The knowledge tree gets its `.git` overlaid when its source holds one.
|
||||
/// Without one the overlay is left out, since nspawn cannot create the
|
||||
/// mount point inside the read-only bind and the container would not start.
|
||||
#[test]
|
||||
fn the_knowledge_tree_gets_its_dot_git_hidden() {
|
||||
fn the_knowledge_dot_git_is_hidden_only_where_there_is_one() {
|
||||
let flags = git_overlay_flags(&[bind_from(&repo_source(), "/knowledge")]);
|
||||
assert_eq!(flags, ["--tmpfs=/knowledge/.git"]);
|
||||
let empty = scratch().to_string_lossy().into_owned();
|
||||
let flags = git_overlay_flags(&[bind_from(&empty, "/knowledge")]);
|
||||
assert!(
|
||||
flags.is_empty(),
|
||||
"overlaid a source with no .git: {flags:?}"
|
||||
);
|
||||
}
|
||||
|
||||
/// A symlink named `.git` is not followed: it counts as present, even
|
||||
/// dangling, so the path it leads to is hidden rather than skipped.
|
||||
#[test]
|
||||
fn a_dangling_dot_git_symlink_still_gets_the_overlay() {
|
||||
let dir = scratch();
|
||||
std::os::unix::fs::symlink("/nonexistent", dir.join(".git")).unwrap();
|
||||
let src = dir.to_string_lossy().into_owned();
|
||||
let flags = git_overlay_flags(&[bind_from(&src, "/knowledge")]);
|
||||
assert_eq!(flags, ["--tmpfs=/knowledge/.git"]);
|
||||
}
|
||||
|
||||
/// ...and nothing else does. A blanket "overlay .git on every bind"
|
||||
/// No other mount is overlaid. A blanket "overlay .git on every bind"
|
||||
/// would mask a real `.git` under `state/`, where an agent legitimately
|
||||
/// keeps working clones of its own.
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Reference in a new issue