Watch
0
0
Fork
You've already forked hyperhive
0

hive-c0re: validate forge env at startup; char-safe short revs

HIVE_FORGE_URL (set + parseable) and HIVE_ASSETS_DIR are checked once in
main before workers start. Short revs in container_view and pr_status
take 12 chars instead of byte-slicing.
This commit is contained in:
atlas 2026-10-09 10:10:24 +02:00 • committed by mara
commit 6bb13f964d
4 changed files with 56 additions and 6 deletions

View file

@ -187,7 +187,7 @@ pub async fn build_all(hive: &crate::coordinator::HiveEnv) -> anyhow::Result<Vec
.map(std::string::String::as_str);
let needs_update =
crate::auto_update::agent_config_pending(logical.as_str(), deployed_full).await;
let deployed_sha = deployed_full.map(|s| s[..s.len().min(12)].to_owned());
let deployed_sha = deployed_full.map(short_rev);
// One `systemctl` call for both facts: `unit_state` is the same
// shell-out `is_running` makes, minus `--quiet`. Asking twice would
// double the per-agent subprocess count on every SSE scan.
@ -449,9 +449,28 @@ fn parse_locked_revs(raw: &str) -> HashMap<String, String> {
out
}
/// First 12 characters of a rev. Counts chars, not bytes: the value comes
/// from `flake.lock` JSON, and a byte slice at 12 can split a multi-byte char.
fn short_rev(rev: &str) -> String {
rev.chars().take(12).collect()
}
#[cfg(test)]
mod tests {
use super::parse_locked_revs;
use super::{parse_locked_revs, short_rev};
#[test]
fn short_rev_truncates_and_keeps_short() {
assert_eq!(short_rev("0123456789abcdef"), "0123456789ab");
assert_eq!(short_rev("abc123"), "abc123");
}
#[test]
fn short_rev_survives_multibyte_at_boundary() {
// 'é' is 2 bytes and straddles byte index 12.
let rev = "0123456789aébcdef";
assert_eq!(short_rev(rev), "0123456789aé");
}
/// Shape of a real `meta/flake.lock`: `root` names a node whose
/// `inputs` map alias → node name, and each node carries `locked.rev`.