diff --git a/hive-c0re/src/meta.rs b/hive-c0re/src/meta.rs index 66f61023..2a6ef2ea 100644 --- a/hive-c0re/src/meta.rs +++ b/hive-c0re/src/meta.rs @@ -923,12 +923,25 @@ where let _ = writeln!(out, " hyperhive-docs.url = \"{docs_flake}\";"); out.push_str(" hyperhive-docs.flake = false;\n"); } + // Each agent's *persistent* config input is its canonical repo on the + // forge (`git+http:///agent-configs/.git`), authenticated by + // hive-core's git credential helper (which reads the live `forge-core-token` + // — no token in the URL or lock). The deploy re-lock + `verify_commit` eval + // keep pinning the local `applied/` override (`agent_input_override`), + // so a deploy never does a network fetch — only the persistent input tracks + // the forge. `HIVE_FORGE_URL` is the in-cluster gateway vhost, already + // forwarded into hive-core's env; fall back to the local forge for legacy + // deploys that predate the forwarding. + let forge_base = std::env::var("HIVE_FORGE_URL") + .ok() + .filter(|v| !v.is_empty()) + .unwrap_or_else(|| "http://localhost:3000".to_string()); for spec in agents { let _ = writeln!( out, - " agent-{}.url = \"git+file://{}\";", - spec.name, - crate::paths::applied_dir(&spec.name).display(), + " agent-{name}.url = \"git+{forge_base}/{org}/{name}.git\";", + name = spec.name, + org = crate::forge::CONFIG_ORG, ); // For each canonical input the agent declares in its own // `flake.nix` (detected by reading its applied `flake.lock`), @@ -1639,6 +1652,43 @@ mod tests { ); } + #[test] + fn render_flake_agent_input_points_at_forge_config_repo() { + // The persistent agent config input must reference the canonical + // repo on the forge (git+http, org `agent-configs`), NOT the local + // `applied/` checkout — that's what lets the config live on the + // forge instead of a hand-synced local copy. Auth is out-of-band via + // hive-core's git credential helper, so no creds appear in the URL. + // + // SAFETY: single-threaded mutation of a process env var the other + // tests don't assert the absence of; restored before returning. + unsafe { + std::env::set_var("HIVE_FORGE_URL", "http://forge.example.test"); + } + let out = render_flake( + "github:example/hyperhive", + "path:/nix/store/bbbb-hyperhive-docs-source", + "path:/nix/store/aaaa-nixpkgs-source", + 8000, + "she/her", + &std::collections::HashMap::new(), + &[sample_spec("alice", false, 9001)], + ); + unsafe { + std::env::remove_var("HIVE_FORGE_URL"); + } + assert!( + out.contains( + "agent-alice.url = \"git+http://forge.example.test/agent-configs/alice.git\"" + ), + "expected the agent input to point at the forge config repo:\n{out}" + ); + assert!( + !out.contains("agent-alice.url = \"git+file://"), + "the local applied/ path must no longer be the persistent input:\n{out}" + ); + } + #[test] fn render_flake_embeds_hive_ca_when_signalled() { // When hive-tls.nix signals a self-signed hive CA via