Watch
0
0
Fork
You've already forked hyperhive
0

record whether an agent's config sets privateUsers in its closure record

This commit is contained in:
atlas 2026-11-01 16:05:36 +01:00 • committed by mara
commit 3ca660e558
2 changed files with 178 additions and 6 deletions

View file

@ -288,12 +288,13 @@ async fn rebuild(world: &impl World, agent: &str, stored: Stored) -> Outcome {
return Outcome::Unavailable;
}
};
let (out_path, system, cached) = match reply {
let (out_path, system, cached, private_users) = match reply {
FromMetaReply::Built {
out_path,
system,
cached,
} => (out_path, system, cached),
private_users,
} => (out_path, system, cached, private_users),
FromMetaReply::Failed { error_tail } => {
tracing::warn!(%agent, %meta_rev, %error_tail, "cache miss: the rebuild failed");
return Outcome::Failed;
@ -321,6 +322,7 @@ async fn rebuild(world: &impl World, agent: &str, stored: Stored) -> Outcome {
system,
built_unix: unix_now(),
cached: true,
private_users,
};
match replace_if_current(world, agent, &now).await {
Ok(true) => Outcome::PathChanged,
@ -558,6 +560,7 @@ mod tests {
system: "x86_64-linux".to_owned(),
built_unix: 7,
cached,
private_users: false,
}
}
@ -644,6 +647,7 @@ mod tests {
out_path: out_path.to_owned(),
system: "x86_64-linux".to_owned(),
cached,
private_users: false,
}
}
@ -888,6 +892,32 @@ mod tests {
);
}
/// The record a rebuild at another path writes carries what the builder
/// answered about the user namespace, not what the old record held.
#[tokio::test]
async fn the_replacement_record_carries_the_rebuilds_private_users_answer() {
let other = path("iris-other");
let FromMetaReply::Built {
out_path,
system,
cached,
..
} = built(&other, true)
else {
unreachable!()
};
let answer = FromMetaReply::Built {
out_path,
system,
cached,
private_users: true,
};
let world = Fake::missing(&["iris"]).answering("iris", answer);
pass_at(&world, &mut Backoff::default(), Instant::now()).await;
let writes = world.writes();
assert_eq!(writes.len(), 1);
assert!(writes[0].1.private_users);
}
#[tokio::test]
async fn another_path_leaves_a_record_that_moved_on() {
let world = Fake::missing(&["iris"]).answering("iris", built(&path("iris-other"), true));

View file

@ -370,6 +370,7 @@ pub(crate) async fn run(
out_path,
system,
cached,
private_users,
}) => {
let built_rev = meta_rev.clone();
let closure = AgentClosure {
@ -378,6 +379,7 @@ pub(crate) async fn run(
system,
built_unix: unix_now(),
cached,
private_users,
};
match queue.record(&agent, &closure).await {
Ok(()) => {
@ -486,10 +488,15 @@ mod tests {
}
fn built_cached(cached: bool) -> Self {
Self::built_with(cached, false)
}
fn built_with(cached: bool, private_users: bool) -> Self {
Self::answering(Ok(FromMetaReply::Built {
out_path: "/nix/store/x-toplevel".to_owned(),
system: "x86_64-linux".to_owned(),
cached,
private_users,
}))
}
}
@ -617,6 +624,22 @@ mod tests {
}
}
/// The record says what the builder said about the agent's user namespace,
/// both ways; a builder that said nothing leaves it off.
#[tokio::test]
async fn the_record_carries_the_builders_private_users_answer() {
for private_users in [true, false] {
let queue = FakeQueue::built_with(true, private_users);
let outcome = run_with(&FakeHead::reading(Ok(Some(REV))), &queue).await;
assert_eq!(outcome, Outcome::Done);
let recorded = queue.recorded.lock().unwrap();
let [(_, closure)] = recorded.as_slice() else {
panic!("one record: {recorded:?}")
};
assert_eq!(closure.private_users, private_users);
}
}
/// Any `nix` failure, a timeout included, fails the node at once with what
/// the builder said: not a no-verdict failure, and nothing is recorded. The
/// green test above is the control that a record is written when the build
@ -898,6 +921,7 @@ mod tests {
system: "x86_64-linux".to_owned(),
built_unix: 1,
cached: false,
private_users: true,
};
client.record("atlas", &closure).await.expect("written");
closure.store_path = "/nix/store/b".to_owned();