hive-c0re: remove dashboard peer-hives wiring (hyperhive#3294)

Removes the per-hive dashboard's "peer hives" display support:
`peer_hives` field on StateSnapshot, the `PeerHiveView` struct,
`parse_peer_hives()`, and `validate_cert_fingerprint()`. That surface
moved to swarm-ui's own hive roster page — no longer needed at the
hive level.

HYPERHIVE_PEERS itself is untouched: hive-agent::identity::peers()
still reads it for qualified agent labels, and the nix module still
forwards it to agent containers. Only this crate's dashboard-only
consumption is gone.

Verified: cargo build/clippy/test -p hive-c0re clean, grepped the
whole tree for stray peer_hives/PeerHiveView/parse_peer_hives
references after the removal — none left.
This commit is contained in:
iris 2026-08-15 17:37:25 +02:00
commit 32a353a9c5

View file

@ -120,12 +120,6 @@ pub(super) struct StateSnapshot {
/// var, set from `services.hyperhive.swarm.name`. `None` when
/// unset — chrome omits the swarm segment of the breadcrumb.
swarm_name: Option<String>,
/// Peer hives in the same swarm. Parsed from `HYPERHIVE_PEERS`
/// (JSON array of `{domain,cert_fingerprint}` objects, emitted by
/// the c0re NixOS module from `services.hyperhive.swarm.peerHives`
/// — the swarm's `hives` directory minus this hive).
/// Empty on single-hive deploys. Feeds the P33RS dashboard tab.
peer_hives: Vec<PeerHiveView>,
/// Server-level warnings for the dashboard's top-of-page banner
/// (currently host disk-pressure; more producers can be added
/// backend-side). Empty when all clear. Built by
@ -161,18 +155,6 @@ async fn infra_container_views() -> Vec<InfraContainerView> {
infra_containers
}
/// One peer hive for the P33RS dashboard tab. Derived from
/// `HYPERHIVE_PEERS` env; `url` is the peer's HTTPS dashboard root.
/// `cert_fingerprint` is `Some("sha256:<hex64>")` when the operator
/// pinned the peer's leaf in `services.hyperhive.swarm.hives`, which a
/// hive under the swarm root CA does not need.
#[derive(Serialize)]
struct PeerHiveView {
name: String,
url: String,
cert_fingerprint: Option<String>,
}
/// `OpQuestion` + computed `question_refs` / `answer_refs`. Built
/// from the snapshot read; the live channel attaches the same
/// fields directly on `QuestionAdded` / `QuestionResolved`.
@ -442,64 +424,11 @@ pub(super) async fn api_state(
swarm_name: std::env::var("HYPERHIVE_SWARM_NAME")
.ok()
.filter(|s| !s.is_empty()),
peer_hives: parse_peer_hives(),
server_warnings,
infra_containers,
})
}
/// Parse `HYPERHIVE_PEERS` env var into dashboard-ready `PeerHiveView`
/// entries. The env var is a JSON array of `{domain, cert_fingerprint}`
/// objects emitted by the c0re NixOS module from
/// `services.hyperhive.swarm.peerHives`. Each entry becomes
/// `{ name: domain, url: "https://domain/" }` for the P33RS tab.
/// Returns empty vec when unset (single-hive deploy).
fn parse_peer_hives() -> Vec<PeerHiveView> {
#[derive(serde::Deserialize)]
struct Raw {
domain: String,
cert_fingerprint: Option<String>,
}
let Ok(json) = std::env::var("HYPERHIVE_PEERS") else {
return Vec::new();
};
let Ok(raw): Result<Vec<Raw>, _> = serde_json::from_str(&json) else {
tracing::warn!("HYPERHIVE_PEERS is not valid JSON; ignoring");
return Vec::new();
};
raw.into_iter()
.map(|r| {
let cert_fingerprint = r.cert_fingerprint.and_then(|fp| {
if validate_cert_fingerprint(&fp) {
Some(fp)
} else {
tracing::warn!(
domain = %r.domain,
fingerprint = %fp,
"HYPERHIVE_PEERS: invalid cert_fingerprint format \
(expected `sha256:<64 hex chars>`); ignoring fingerprint"
);
None
}
});
PeerHiveView {
name: r.domain.clone(),
url: format!("https://{}/", r.domain),
cert_fingerprint,
}
})
.collect()
}
/// Validate a TLS certificate fingerprint string from `HYPERHIVE_PEERS`.
/// Accepts `sha256:<64 hex chars>` (upper or lower case).
fn validate_cert_fingerprint(fp: &str) -> bool {
let Some(hex) = fp.strip_prefix("sha256:") else {
return false;
};
hex.len() == 64 && hex.chars().all(|c| c.is_ascii_hexdigit())
}
/// Group live containers by their assigned web UI port; clusters with
/// more than one member are port-hash collisions the operator needs
/// to resolve by renaming. Manager (fixed at 8000) and sub-agents