swarm-controller: own the swarm-wide forge objects; hive-c0re stops creating them
The orgs agent-configs/internal/agents (plus mirror owners), the operators team in agents and agent-configs, the pull-mirrors, internal/docs, internal/knowledge (public, README-seeded) and the agent-configs org avatar are one set per forge. hive-c0re ensured them in its boot sweep, as the core admin, and only on the hive co-located with the forge container. swarm-controller now reconciles them at start and every 5 minutes (forge/objects.rs: observe -> pure plan -> apply). A failed object logs a warn line plus a pass summary and is retried next tick. create_repo ensures the agent-configs org and its operators team first, so a config repo's merge gate never depends on the periodic pass having run. hive-c0re drops ensure_org, SEEDED_ORGS, ensure_mirrors/ensure_mirror_repo, ensure_operators_team, ensure_shared_docs_repo, ensure_knowledge_repo/ set_repo_public, seed_readme, ensure_config_org_avatar and the one-shot knowledge::remove_webhook cleanup, with their now-unused helpers. nix: the mirror list moves from the hive-c0re unit (HYPERHIVE_FORGE_MIRRORS) to the swarm-controller unit (SWARM_CONTROLLER_FORGE_MIRRORS), with an eval warning when mirrors are declared on a host that runs no controller. c0re.orgAvatarPng is renamed to deploy.swarm-controller.configOrgAvatarPng. Refs #3782
This commit is contained in:
parent
85ba45b2de
commit
20419ccd41
18 changed files with 1456 additions and 822 deletions
|
|
@ -12,7 +12,7 @@ use forgejo_api::structs::{EditUserOption, UpdateUserAvatarOption};
|
|||
use forgejo_api::{ApiErrorKind, ForgejoError};
|
||||
use reqwest::StatusCode;
|
||||
|
||||
use super::{CONFIG_ORG, api, forge_admin};
|
||||
use super::{api, forge_admin};
|
||||
|
||||
const TOKEN_NAME_PREFIX: &str = "hyperhive";
|
||||
// Where the host-side `core` admin token lives. Used by hive-c0re itself
|
||||
|
|
@ -20,21 +20,18 @@ const TOKEN_NAME_PREFIX: &str = "hyperhive";
|
|||
// in `crate::paths`; aliased here under the long-standing name.
|
||||
use crate::paths::FORGE_CORE_TOKEN as CORE_TOKEN_PATH;
|
||||
// Forge provisioning markers (`forge/core-avatar-set`,
|
||||
// `forge/agent-configs-avatar-set`, `forge/email-aligned-<name>`) live
|
||||
// in `crate::paths` — one-shot guards: the upload/align runs once, the
|
||||
// marker is written, subsequent startups skip. Delete one to force its
|
||||
// step to re-run.
|
||||
// Avatar PNG paths are resolved by `core_avatar_png_path` /
|
||||
// `config_org_avatar_png_path` below — only-used-here, so they live
|
||||
// in this module rather than the shared `hive_sh4re::assets` helpers
|
||||
// (which now hold only `prompt_template`, the one asset path every
|
||||
// crate needs — the agent icon, the last other one, moved off the
|
||||
// `forge/email-aligned-<name>`) live in `crate::paths` — one-shot guards:
|
||||
// the upload/align runs once, the marker is written, subsequent startups
|
||||
// skip. Delete one to force its step to re-run.
|
||||
// The avatar PNG path is resolved by `core_avatar_png_path` below —
|
||||
// only-used-here, so it lives in this module rather than the shared
|
||||
// `hive_sh4re::assets` helpers (which now hold only `prompt_template`, the
|
||||
// one asset path every crate needs — the agent icon, the last other one, moved off the
|
||||
// shared-asset model entirely; see `hive-agent::web_ui::screen`).
|
||||
|
||||
/// `$HIVE_ASSETS_DIR/branding/hyperhive.png` — the core mark,
|
||||
/// rasterised. Not independently configurable (unlike the org avatar
|
||||
/// below) — override the whole `services.hyperhive.c0re.assets`
|
||||
/// package to change it.
|
||||
/// rasterised. Not independently configurable — override the whole
|
||||
/// `services.hyperhive.c0re.assets` package to change it.
|
||||
fn core_avatar_png_path() -> std::path::PathBuf {
|
||||
let dir = std::env::var("HIVE_ASSETS_DIR").expect(
|
||||
"HIVE_ASSETS_DIR is unset — the hyperhive NixOS module sets it from \
|
||||
|
|
@ -44,21 +41,6 @@ fn core_avatar_png_path() -> std::path::PathBuf {
|
|||
std::path::PathBuf::from(dir).join("branding/hyperhive.png")
|
||||
}
|
||||
|
||||
/// Path to the `agent-configs` org's avatar PNG. Independently
|
||||
/// configurable via `services.hyperhive.c0re.orgAvatarPng` — the nix
|
||||
/// module resolves `HIVE_ORG_AVATAR_PNG` to that option's value, or
|
||||
/// the bundled `agent-configs.png` from `assets` when unset, so an
|
||||
/// operator can override just this image without replacing the whole
|
||||
/// `assets` package.
|
||||
fn config_org_avatar_png_path() -> std::path::PathBuf {
|
||||
std::path::PathBuf::from(std::env::var("HIVE_ORG_AVATAR_PNG").expect(
|
||||
"HIVE_ORG_AVATAR_PNG is unset — the hyperhive NixOS module sets it \
|
||||
unconditionally on the hive-c0re unit (from \
|
||||
services.hyperhive.c0re.orgAvatarPng or the bundled default), so \
|
||||
this process was started outside that unit",
|
||||
))
|
||||
}
|
||||
|
||||
/// Bootstrap `core` token scopes — adds `read:admin,write:admin` on
|
||||
/// top of the agent scopes (swarm-controller's `AGENT_TOKEN_SCOPES`)
|
||||
/// so the host daemon can drive `/api/v1/admin/*`. Site-admin
|
||||
|
|
@ -369,39 +351,6 @@ pub(super) async fn ensure_core_avatar(token: &str) -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Set the `agent-configs` org's Forgejo avatar to the
|
||||
/// configs-stack glyph once. Sibling to `ensure_core_avatar`:
|
||||
/// one-shot, marker-guarded, best-effort. Uses `org_update_avatar`
|
||||
/// (`POST /api/v1/orgs/{org}/avatar`, base64-PNG payload).
|
||||
pub(super) async fn ensure_config_org_avatar(token: &str) -> Result<()> {
|
||||
let marker = crate::paths::forge_config_org_avatar_marker();
|
||||
if marker.exists() {
|
||||
return Ok(());
|
||||
}
|
||||
let png_path = config_org_avatar_png_path();
|
||||
let png_bytes = tokio::fs::read(&png_path)
|
||||
.await
|
||||
.with_context(|| format!("read {CONFIG_ORG} avatar PNG from {}", png_path.display()))?;
|
||||
api(token)?
|
||||
.org_update_avatar(
|
||||
CONFIG_ORG,
|
||||
UpdateUserAvatarOption {
|
||||
image: Some(base64::engine::general_purpose::STANDARD.encode(&png_bytes)),
|
||||
},
|
||||
)
|
||||
.await
|
||||
.with_context(|| format!("set {CONFIG_ORG} avatar"))?;
|
||||
if let Some(parent) = marker.parent() {
|
||||
std::fs::create_dir_all(parent).ok();
|
||||
}
|
||||
std::fs::write(marker, "").ok();
|
||||
tracing::info!(
|
||||
org = CONFIG_ORG,
|
||||
"forge: set org avatar to configs-stack logo"
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Outcome of probing whether the persisted core token still works
|
||||
/// against the *current* forge. Existence on disk is not validity: a
|
||||
/// token minted before a forge rebuild / re-provision is unknown to the
|
||||
|
|
|
|||
Loading…
Reference in a new issue