add meta read access and remote for agents on forge
This commit is contained in:
parent
4bc5237bea
commit
bbe4cdb872
3 changed files with 109 additions and 7 deletions
|
|
@ -8,10 +8,10 @@
|
|||
//!
|
||||
//! It also mirrors each agent's hive-c0re-owned *applied* config repo
|
||||
//! into the private `agent-configs` org (`push_config`), so every
|
||||
//! deploy / approval tag core plants is visible on the forge. Core is
|
||||
//! the only principal with access — agents are not org members and
|
||||
//! the repos are private, so an agent can't reach a config repo
|
||||
//! (not even its own) through the forge.
|
||||
//! deploy / approval tag core plants is visible on the forge. Each
|
||||
//! agent is a read-only collaborator on `core/meta` (the meta flake)
|
||||
//! so they can fetch their deployment context; the `agent-configs`
|
||||
//! repos remain core-only.
|
||||
//!
|
||||
//! No-op when `hive-forge` isn't enabled (detected via
|
||||
//! `nixos-container list`), so operators who don't run the bundled
|
||||
|
|
@ -381,6 +381,75 @@ pub async fn ensure_config_repo(name: &str) -> Result<()> {
|
|||
ensure_org_repo(CONFIG_ORG, name, &token).await
|
||||
}
|
||||
|
||||
/// Grant agent `name` read-only collaborator access to `core/meta` on
|
||||
/// the forge so the agent can clone/fetch the meta flake. Idempotent:
|
||||
/// HTTP 204 (already a collaborator) is treated as success.
|
||||
pub async fn meta_read_access(name: &str, core_token: &str) -> Result<()> {
|
||||
let url = format!("{FORGE_HTTP}/api/v1/repos/core/meta/collaborators/{name}");
|
||||
let body = r#"{"permission":"read"}"#;
|
||||
let out = Command::new("curl")
|
||||
.args([
|
||||
"-sS",
|
||||
"-o",
|
||||
"/dev/null",
|
||||
"-w",
|
||||
"%{http_code}",
|
||||
"-X",
|
||||
"PUT",
|
||||
"-H",
|
||||
"Content-Type: application/json",
|
||||
"-H",
|
||||
&format!("Authorization: token {core_token}"),
|
||||
"-d",
|
||||
body,
|
||||
&url,
|
||||
])
|
||||
.output()
|
||||
.await
|
||||
.context("invoke curl PUT core/meta/collaborators")?;
|
||||
let code = String::from_utf8_lossy(&out.stdout).trim().to_owned();
|
||||
match code.as_str() {
|
||||
"204" => {
|
||||
tracing::info!(%name, "forge: granted meta read access");
|
||||
Ok(())
|
||||
}
|
||||
other => anyhow::bail!(
|
||||
"PUT core/meta/collaborators/{name} returned HTTP {other}"
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Add `http://localhost:3000/core/meta.git` as the `meta` remote in
|
||||
/// the agent's proposed config repo so the agent (and the manager) can
|
||||
/// fetch the meta flake from the forge. Idempotent: no-op when the
|
||||
/// remote already points at the right URL, or when the proposed repo
|
||||
/// does not exist yet. No-op when the forge is not running.
|
||||
pub async fn ensure_meta_remote(name: &str) -> Result<()> {
|
||||
if !is_present().await {
|
||||
return Ok(());
|
||||
}
|
||||
let proposed_dir = Coordinator::agent_proposed_dir(name);
|
||||
if !proposed_dir.join(".git").exists() {
|
||||
return Ok(());
|
||||
}
|
||||
let want = format!("{FORGE_HTTP}/core/meta.git");
|
||||
let existing = crate::lifecycle::git_command()
|
||||
.current_dir(&proposed_dir)
|
||||
.args(["remote", "get-url", "meta"])
|
||||
.output()
|
||||
.await
|
||||
.context("git remote get-url meta")?;
|
||||
if existing.status.success() {
|
||||
let current = String::from_utf8_lossy(&existing.stdout).trim().to_owned();
|
||||
if current == want {
|
||||
return Ok(());
|
||||
}
|
||||
crate::lifecycle::git(&proposed_dir, &["remote", "set-url", "meta", &want]).await
|
||||
} else {
|
||||
crate::lifecycle::git(&proposed_dir, &["remote", "add", "meta", &want]).await
|
||||
}
|
||||
}
|
||||
|
||||
/// Mirror agent `name`'s applied config repo — `main` plus every tag
|
||||
/// (`proposal` / `approved` / `building` / `deployed` / `failed` /
|
||||
/// `denied`) — to `agent-configs/<name>` on the local forge.
|
||||
|
|
@ -531,5 +600,15 @@ pub async fn ensure_all() {
|
|||
if let Err(e) = push_config(&name).await {
|
||||
tracing::warn!(%name, error = ?e, "forge: push_config failed");
|
||||
}
|
||||
// Grant read-only access to core/meta and wire the `meta` remote
|
||||
// into the proposed repo so agents can fetch their deployment context.
|
||||
if let Some(token) = core_token.as_deref() {
|
||||
if let Err(e) = meta_read_access(&name, token).await {
|
||||
tracing::warn!(%name, error = ?e, "forge: ensure_meta_read_access failed");
|
||||
}
|
||||
}
|
||||
if let Err(e) = ensure_meta_remote(&name).await {
|
||||
tracing::warn!(%name, error = ?e, "forge: ensure_meta_remote failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue