drop the hive's push of the legacy core/meta repo
Nothing reads core/meta: builds come from internal/meta. Remove push_meta, ensure_meta_remote, meta_read_access, ensure_repo, the per-agent forge sync that only served them, and the git commit path in meta.rs; remove_permission_files now just deletes the seed files.
This commit is contained in:
parent
dd2f0d3ece
commit
b6b568e97e
1 changed files with 81 additions and 518 deletions
|
|
@ -1,6 +1,5 @@
|
|||
//! Optional Forgejo wiring — the legacy `core/meta` repo (the hive's old
|
||||
//! permission-seed repo, which `meta::remove_permission_files` still commits
|
||||
//! to) and its read-access grants. Those writes, as `core`, run only beside a local `hive-forge`
|
||||
//! Optional Forgejo wiring — the `core` admin user and token and its avatar.
|
||||
//! Those writes, as `core`, run only beside a local `hive-forge`
|
||||
//! container; reads of the forge go through [`reader_token`] on every hive.
|
||||
//! The swarm-wide orgs, teams and repos, and each agent's read grant on
|
||||
//! `internal/docs`, are swarm-controller's. Full design:
|
||||
|
|
@ -15,10 +14,7 @@ mod users;
|
|||
pub(crate) use internal_meta::internal_meta_source;
|
||||
pub use reader::reader_token;
|
||||
pub use reconcile::{fetch_forge_main, reconcile_config_apply, reconcile_config_status};
|
||||
pub use repos::{
|
||||
clone_config_into_proposed, ensure_meta_remote, ensure_repo, fetch_config_main_into_applied,
|
||||
meta_read_access, push_meta,
|
||||
};
|
||||
pub use repos::{clone_config_into_proposed, fetch_config_main_into_applied};
|
||||
pub use users::core_token;
|
||||
|
||||
use std::future::IntoFuture;
|
||||
|
|
@ -74,13 +70,13 @@ pub(crate) fn validate_env() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Git remote for `repo` (e.g. `"core/meta"`) — **credential-free**.
|
||||
/// Git remote for `repo` (e.g. `"hyperhive/hyperhive"`) — **credential-free**.
|
||||
///
|
||||
/// The token does not go here. A URL is a process argument, and `argv` is
|
||||
/// world-readable through `/proc/<pid>/cmdline` for as long as the git child
|
||||
/// lives, so a credentialed remote publishes the core admin token to every
|
||||
/// local user on the host. Credentials travel in the environment instead, via
|
||||
/// [`core_auth_header`] and [`crate::lifecycle::git_command_authed`] —
|
||||
/// [`basic_auth_header`] and [`crate::lifecycle::git_command_authed`] —
|
||||
/// `/proc/<pid>/environ` is owner-only.
|
||||
pub(crate) fn forge_git_url(repo: &str) -> String {
|
||||
git_url_with_base(forge_http_base(), repo)
|
||||
|
|
@ -92,11 +88,6 @@ fn git_url_with_base(base: &str, repo: &str) -> String {
|
|||
format!("{base}/{repo}.git")
|
||||
}
|
||||
|
||||
/// The `http.extraHeader` value authenticating as the forge core user.
|
||||
pub(crate) fn core_auth_header(token: &str) -> String {
|
||||
basic_auth_header("core", token)
|
||||
}
|
||||
|
||||
/// The `http.extraHeader` value carrying `token`. Forgejo takes the account
|
||||
/// from the token, so `login` only labels the request.
|
||||
///
|
||||
|
|
@ -120,16 +111,6 @@ fn basic_auth_header(login: &str, token: &str) -> String {
|
|||
/// still can't reach *another* agent's config. hive-c0re only reads from it.
|
||||
pub(crate) const CONFIG_ORG: &str = "agent-configs";
|
||||
|
||||
/// Leak `s` to get a `&'static str` warning `kind` for the small, bounded
|
||||
/// set of boot warnings in [`ensure_all`] keyed by a runtime name (at
|
||||
/// most a handful per process). [`crate::warnings::set_boot_warning`]
|
||||
/// requires a `'static` kind so distinct orgs/repos don't clobber each
|
||||
/// other's warning entry; leaking a few short strings once per boot is
|
||||
/// cheap and bounded, unlike a per-request or per-loop-iteration leak.
|
||||
fn static_kind(s: String) -> &'static str {
|
||||
Box::leak(s.into_boxed_str())
|
||||
}
|
||||
|
||||
/// Probe whether `hive-forge` exists as a nixos-container. Cheap —
|
||||
/// `nixos-container list` is just a directory scan in /etc. Routed
|
||||
/// through hive-priv: `nixos-container` needs root, and hive-c0re runs
|
||||
|
|
@ -216,42 +197,7 @@ where
|
|||
.map_err(|_| anyhow::anyhow!("{op}: no answer from the forge within {API_TIMEOUT:?}"))
|
||||
}
|
||||
|
||||
/// Per-agent forge sync: grant read access to the legacy `core/meta`, and wire
|
||||
/// the `meta` remote in its proposed repo. All operations are idempotent;
|
||||
/// failures are logged as warnings but don't abort the caller.
|
||||
///
|
||||
/// `core_token` is `core_token()` — passed in so callers that already
|
||||
/// fetched it don't re-read the file. Pass `None` to skip the
|
||||
/// `meta_read_access` step (safe: the access grant is best-effort).
|
||||
///
|
||||
/// Called by both `ensure_all()` (startup sweep) and `rebuild_agent`
|
||||
/// (per-rebuild) so the two paths stay equivalent.
|
||||
/// Returns `true` if all steps succeeded, `false` if any step failed. The
|
||||
/// caller can use the return value to aggregate per-agent failures into a
|
||||
/// dashboard warning (see [`ensure_all`]); the rebuild path ignores it and
|
||||
/// relies on the journal `warn!` lines alone (a rebuild is its own retry).
|
||||
pub async fn sync_agent(name: &str, core_token: Option<&str>) -> bool {
|
||||
// The agent's forge account, token and `agent-configs/<name>` repo are
|
||||
// swarm-controller's; this hive creates none of them and pushes nothing
|
||||
// to the repo.
|
||||
let mut ok = true;
|
||||
// Grant read-only access to the legacy core/meta and wire the `meta`
|
||||
// remote into the proposed repo. Agents build from `internal/meta`, not
|
||||
// from this repo.
|
||||
if let Some(token) = core_token
|
||||
&& let Err(e) = meta_read_access(name, token).await
|
||||
{
|
||||
tracing::warn!(%name, error = ?e, "forge: ensure_meta_read_access failed");
|
||||
ok = false;
|
||||
}
|
||||
if let Err(e) = ensure_meta_remote(name).await {
|
||||
tracing::warn!(%name, error = ?e, "forge: ensure_meta_remote failed");
|
||||
ok = false;
|
||||
}
|
||||
ok
|
||||
}
|
||||
|
||||
/// The `core_token.is_some()` half of [`ensure_all`]: the legacy meta repo, the
|
||||
/// The `core_token.is_some()` half of [`ensure_all`]: the
|
||||
/// core avatar, and removing this hive's own config-PR hook —
|
||||
/// every step that needs an authenticated forge client. The swarm-wide
|
||||
/// objects (orgs, the `operators` team, mirrors, `internal/docs`,
|
||||
|
|
@ -260,17 +206,6 @@ pub async fn sync_agent(name: &str, core_token: Option<&str>) -> bool {
|
|||
/// `ensure_all` under clippy's function-length limit; not meant to be called
|
||||
/// from anywhere else.
|
||||
async fn ensure_all_orgs_and_repos(token: &str) {
|
||||
// The legacy meta repo lives at core/meta. The only push to it is
|
||||
// `meta::remove_permission_files`' commit; make sure the repo exists
|
||||
// before that push hits a 404.
|
||||
if let Err(e) = ensure_repo("meta", token).await {
|
||||
tracing::warn!(error = ?e, "forge: ensure_repo core/meta failed");
|
||||
crate::warnings::set_boot_warning(
|
||||
"forge_ensure_meta_repo",
|
||||
"crit",
|
||||
format!("forge: core/meta repo provisioning failed: {e}"),
|
||||
);
|
||||
}
|
||||
if let Err(e) = ensure_core_avatar(token).await {
|
||||
tracing::warn!(error = ?e, "forge: ensure_core_avatar failed");
|
||||
crate::warnings::set_boot_warning(
|
||||
|
|
@ -382,11 +317,10 @@ async fn wait_until_ready() -> bool {
|
|||
}
|
||||
|
||||
/// Sweep the forge at startup: seed the `core` admin user (hive-c0re's own
|
||||
/// identity for pushing the legacy meta repo + driving the API) and its token, the
|
||||
/// `core/meta` repo and the local knowledge clone, then run [`sync_agent`]
|
||||
/// over every existing container (manager + sub-agents). Agent accounts,
|
||||
/// identity for driving the API, and the one nix's git reads as) and its token,
|
||||
/// then its avatar. Agent accounts,
|
||||
/// tokens and `agent-configs/<name>` repos are the swarm-controller's, as is
|
||||
/// the `agent-configs` org; this sweep pushes nothing to them.
|
||||
/// the `agent-configs` org; this sweep touches none of them.
|
||||
/// Called once at hive-c0re startup. Per-step failures are logged
|
||||
/// but don't abort the sweep.
|
||||
pub async fn ensure_all() {
|
||||
|
|
@ -413,37 +347,6 @@ pub async fn ensure_all() {
|
|||
if let Some(token) = core_token.as_deref() {
|
||||
ensure_all_orgs_and_repos(token).await;
|
||||
}
|
||||
let Ok(containers) = crate::lifecycle::list().await else {
|
||||
tracing::warn!("forge: nixos-container list failed; skipping user sweep");
|
||||
crate::warnings::set_boot_warning(
|
||||
"forge_container_list",
|
||||
"crit",
|
||||
"forge: nixos-container list failed; per-agent forge sync skipped this boot",
|
||||
);
|
||||
return;
|
||||
};
|
||||
let mut sync_failed: Vec<String> = Vec::new();
|
||||
for c in containers {
|
||||
let Some(name) = c.strip_prefix(crate::lifecycle::AGENT_PREFIX) else {
|
||||
continue;
|
||||
};
|
||||
if !sync_agent(name, core_token.as_deref()).await {
|
||||
sync_failed.push(name.to_owned());
|
||||
}
|
||||
}
|
||||
if !sync_failed.is_empty() {
|
||||
// Use static_kind to mint a `&'static str` key from the failed-agent
|
||||
// list (bounded leak: one per hive-c0re boot, not per request).
|
||||
let key = static_kind(format!("forge_sync_agent_{}", sync_failed.join("_")));
|
||||
crate::warnings::set_boot_warning(
|
||||
key,
|
||||
"warn",
|
||||
format!(
|
||||
"forge: per-agent sync failed for: {} (see journal for per-step detail)",
|
||||
sync_failed.join(", ")
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
@ -526,9 +429,9 @@ mod tests {
|
|||
/// back to `core:<token>`, so the swap is genuinely equivalent auth and
|
||||
/// not a silent downgrade to anonymous.
|
||||
#[test]
|
||||
fn core_auth_header_is_basic_core_token() {
|
||||
fn basic_auth_header_is_basic_core_token() {
|
||||
use base64::Engine as _;
|
||||
let header = super::core_auth_header("s3cret");
|
||||
let header = super::basic_auth_header("core", "s3cret");
|
||||
let b64 = header
|
||||
.strip_prefix("Authorization: Basic ")
|
||||
.expect("basic auth header");
|
||||
|
|
|
|||
Loading…
Reference in a new issue