From a024ca65c05639596a5e33fc35f2b4905046caab Mon Sep 17 00:00:00 2001 From: damocles Date: Wed, 20 May 2026 16:24:01 +0200 Subject: [PATCH] fix: align forge user email to git user.email so commits link to profiles agent users were created with {name}@hive.local but git commits use {name}@hyperhive (set by meta::render_flake). forgejo matches by email, so no profile link appeared on any commit. - extract agent_email() helper returning {name}@hyperhive - use it in ensure_user_exists (new users) - add ensure_user_email() that runs gitea admin user edit to patch existing users; called from ensure_all on every startup sweep Closes #64 --- hive-c0re/src/forge.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/hive-c0re/src/forge.rs b/hive-c0re/src/forge.rs index 6390c81..5adfe4d 100644 --- a/hive-c0re/src/forge.rs +++ b/hive-c0re/src/forge.rs @@ -131,6 +131,13 @@ fn extract_token(output: &str) -> Option { .map(str::to_owned) } +/// Canonical email address for a hive agent's Forgejo account. +/// Must match the `user.email` set by `meta::render_flake` so commits +/// by the agent link back to their Forgejo profile page. +fn agent_email(name: &str) -> String { + format!("{name}@hyperhive") +} + /// Ensure a forgejo user named `name` exists. Idempotent: forgejo /// returns a "user already exists" error which we treat as success. /// `admin` adds `--admin` (site admin) — used for the bootstrap @@ -143,7 +150,7 @@ async fn ensure_user_exists(name: &str, admin: bool) -> Result<()> { name, "--email", ]; - let email = format!("{name}@hive.local"); + let email = agent_email(name); args.push(&email); args.extend(["--random-password", "--must-change-password=false"]); if admin { @@ -171,6 +178,18 @@ async fn ensure_user_exists(name: &str, admin: bool) -> Result<()> { } } +/// Idempotently align the Forgejo account email to `agent_email(name)`. +/// Existing agents were created with `{name}@hive.local`; this corrects +/// that so git commits (which use `{name}@hyperhive`) link to profiles. +/// Best-effort: failures are warned, not propagated. +async fn ensure_user_email(name: &str) { + let email = agent_email(name); + match forge_admin(&["user", "edit", "--username", name, "--email", &email]).await { + Ok(_) => tracing::debug!(%name, %email, "forge: user email aligned"), + Err(e) => tracing::warn!(%name, error = %e, "forge: could not align user email"), + } +} + /// Mint a fresh access token for `name` and persist it to /// `/forge-token` (0600). Token name is suffixed with a /// monotonic clock so re-issuing doesn't collide with an existing @@ -496,6 +515,10 @@ pub async fn ensure_all() { if let Err(e) = ensure_user_for(&name).await { tracing::warn!(%name, error = ?e, "forge: ensure_user failed"); } + // Align email to match the git user.email set by meta::render_flake + // so commits link to the agent's Forgejo profile. Best-effort; + // also patches up agents created before this fix (old @hive.local). + ensure_user_email(&name).await; // Mirror the agent's applied config repo into agent-configs. // ensure_config_repo is idempotent; push_config catches any // drift since the last run — e.g. the startup migration just