refactor(#2502): thread forge_base param into render_flake, drop the localhost fallback

Per operator review (#2547): remove the never-reached branch. render_flake
read HIVE_FORGE_URL inline with an unwrap_or_else(localhost:3000) fallback
that can't be hit — the daemon always sets HIVE_FORGE_URL (environment.nix)
— and the localhost URL wouldn't match the domain-scoped credential helper
anyway. Thread forge_base as an explicit param instead: the caller
sync_agents passes forge::forge_http_base(), tests pass it explicitly. This
removes the dead branch AND the hidden env-read, and drops the racy env
set_var from the forge-url test. render_flake is pure/param-driven again.
This commit is contained in:
atlas 2026-07-16 21:08:04 +02:00 committed by mara
commit 87f8e936d5

View file

@ -74,6 +74,7 @@ pub async fn sync_agents(hive: &HiveEnv, agents: &[AgentSpec]) -> Result<()> {
&hive.operator_pronouns,
&hive.context_window_tokens,
agents,
crate::forge::forge_http_base(),
);
let flake_path = dir.join("flake.nix");
let on_disk = std::fs::read_to_string(&flake_path).unwrap_or_default();
@ -634,6 +635,11 @@ pub async fn bulk_commit_topology(
Ok(changed)
}
#[allow(
clippy::too_many_arguments,
reason = "many genuine flake inputs (source flakes, port, pronouns, tokens, \
agents, forge base); a params struct would just move the same fields"
)]
fn render_flake(
hyperhive_flake: &str,
docs_flake: &str,
@ -642,6 +648,7 @@ fn render_flake(
operator_pronouns: &str,
context_window_tokens: &std::collections::HashMap<String, u64>,
agents: &[AgentSpec],
forge_base: &str,
) -> String {
render_flake_with_lookup(
hyperhive_flake,
@ -651,6 +658,7 @@ fn render_flake(
operator_pronouns,
context_window_tokens,
agents,
forge_base,
agent_canonical_inputs,
)
}
@ -927,6 +935,7 @@ fn render_flake_with_lookup<F>(
operator_pronouns: &str,
context_window_tokens: &std::collections::HashMap<String, u64>,
agents: &[AgentSpec],
forge_base: &str,
lookup: F,
) -> String
where
@ -972,18 +981,12 @@ where
out.push_str(" hyperhive-docs.flake = false;\n");
}
// Each agent's *persistent* config input is its canonical repo on the
// forge (`git+http://<forge>/agent-configs/<name>.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/<name>` 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());
// forge (`git+{forge_base}/agent-configs/<name>.git`, `forge_base` supplied
// by the caller from `HIVE_FORGE_URL`), 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/<name>` override (`agent_input_override`), so a deploy
// never does a network fetch — only the persistent input tracks the forge.
for spec in agents {
let _ = writeln!(
out,
@ -1535,6 +1538,7 @@ mod tests {
"she/her",
&std::collections::HashMap::new(),
&[sample_spec("alice", false, 9001)],
"http://forge.test",
);
// nixpkgs is a top-level input with an explicit URL; hyperhive
// follows it.
@ -1578,6 +1582,7 @@ mod tests {
"she/her",
&std::collections::HashMap::new(),
&[sample_spec("alice", false, 9001)],
"http://forge.test",
);
assert!(
!out.contains("hyperhive-docs"),
@ -1597,6 +1602,7 @@ mod tests {
"she/her",
&std::collections::HashMap::new(),
&[sample_spec("alice", false, 9001)],
"http://forge.test",
);
assert!(
out.contains("nixpkgs.follows = \"hyperhive/nixpkgs\""),
@ -1630,6 +1636,7 @@ mod tests {
sample_spec("bitburner", false, 9002),
sample_spec("dmatrix", false, 9003),
],
"http://forge.test",
lookup,
);
// bitburner declares nixpkgs → follows emitted.
@ -1658,6 +1665,7 @@ mod tests {
"she/her",
&std::collections::HashMap::new(),
&[sample_spec("alice", false, 9001)],
"http://forge.test",
|_| Vec::new(),
);
// No agent-side follows when the lookup reports nothing
@ -1692,6 +1700,7 @@ mod tests {
"she/her",
&std::collections::HashMap::new(),
&[sample_spec("alice", false, 9001)],
"http://forge.test",
);
unsafe {
std::env::remove_var("HIVE_FORGE_URL");
@ -1721,12 +1730,7 @@ mod tests {
// `applied/<n>` 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");
}
// `forge_base` is an explicit param now, so no env mutation is needed.
let out = render_flake(
"github:example/hyperhive",
"path:/nix/store/bbbb-hyperhive-docs-source",
@ -1735,10 +1739,8 @@ mod tests {
"she/her",
&std::collections::HashMap::new(),
&[sample_spec("alice", false, 9001)],
"http://forge.example.test",
);
unsafe {
std::env::remove_var("HIVE_FORGE_URL");
}
assert!(
out.contains(
"agent-alice.url = \"git+http://forge.example.test/agent-configs/alice.git\""
@ -1777,6 +1779,7 @@ mod tests {
"she/her",
&std::collections::HashMap::new(),
&[sample_spec("alice", false, 9001)],
"http://forge.test",
)
};
@ -1859,6 +1862,7 @@ mod tests {
"she/her",
&std::collections::HashMap::new(),
&[sample_spec("alice", false, 9001)],
"http://forge.test",
)
};
unsafe {
@ -1943,6 +1947,7 @@ mod tests {
"she/her",
&std::collections::HashMap::new(),
&[sample_spec("alice", false, 9001)],
"http://forge.test",
)
};
unsafe {