config PRs: an operator's Forgejo merge deploys the merged rev
A config PR merged in the Forgejo UI changed nothing on the hive: the hive's webhook ignores `closed`, its poll then cancels the dashboard card, and `applied/main` stays where it was. swarm-controller reads `merged`/`merge_commit_sha` off the `pull_request` delivery it already receives for `agent-configs`, finds the hive placing the agent by scanning every hive's wanted state (the scan `declarations_elsewhere` already ran, factored out), and queues a `TriggerDeploy` carrying the rev. Zero or several claimants deploy nothing and log the claimants. `DeployRequest` gains `rev: Option<String>` with `serde(default)`, so rev-less payloads from either side keep decoding. hive-c0re, given a rev for an agent it runs: a no-op when `applied/main` already is the rev (a dashboard merge deploys its own PR); otherwise it fetches the forge `main` with the core token, requires the rev to descend from `applied/main` (the ancestry gate, factored out of `run_deploy_merge_verify`), fast-forwards by CAS and queues the usual relocking rebuild. No eval-verify on this path, per mara (#4850 c90075). A refusal is commented on the PR that merged the rev, found by commit. swarm-controller's forge-objects pass converges every config repo's `main` rule to merge whitelist `operators` + `core` and approval whitelist `operators`. The hive's boot PATCH stops forcing `enable_approvals_whitelist` off, so the two do not fight. Refs #4850
This commit is contained in:
parent
9224c0bd15
commit
f1c695c212
11 changed files with 732 additions and 76 deletions
|
|
@ -223,17 +223,23 @@ const DEPLOY_SUBJECT_PREFIX: &str = "$SWARM.deploy";
|
|||
|
||||
/// What a [`deploy_subject`] message carries.
|
||||
///
|
||||
/// Only the agent: the subject already names the hive, and repeating it here
|
||||
/// would be two places stating one fact, free to disagree.
|
||||
/// No hive: the subject already names it, and repeating it here would be two
|
||||
/// places stating one fact, free to disagree.
|
||||
///
|
||||
/// ⚠️ **A trigger, not the config.** The hive already tracks the agent's
|
||||
/// config repo; putting desired state on the wire would make this message a
|
||||
/// second source of truth for something git already owns, and a hive that
|
||||
/// missed a message would then be wrong rather than merely late.
|
||||
/// With [`Self::rev`] set it names the commit of the agent's config repo to
|
||||
/// deploy. The config itself stays in git: the hive fetches that commit from
|
||||
/// the forge, so a hive that misses a message is behind, never wrong.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct DeployRequest {
|
||||
/// The agent to rebuild, as the swarm knows it.
|
||||
pub agent: String,
|
||||
/// The commit on the agent's config repo `main` to deploy. `None`
|
||||
/// rebuilds whatever the hive already has applied.
|
||||
///
|
||||
/// `serde(default)` so a payload without the field still decodes: the
|
||||
/// controller and the hives are deployed independently.
|
||||
#[serde(default)]
|
||||
pub rev: Option<String>,
|
||||
}
|
||||
|
||||
/// The hive-notices stream, shared by the hive that publishes and
|
||||
|
|
@ -1053,6 +1059,26 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_deploy_request_without_a_rev_decodes() {
|
||||
let request: super::DeployRequest =
|
||||
serde_json::from_str(r#"{"agent":"damocles"}"#).expect("a rev-less payload decodes");
|
||||
assert_eq!(
|
||||
request,
|
||||
super::DeployRequest {
|
||||
agent: "damocles".to_owned(),
|
||||
rev: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_deploy_request_carries_its_rev() {
|
||||
let request: super::DeployRequest =
|
||||
serde_json::from_str(r#"{"agent":"damocles","rev":"abc123"}"#).expect("decodes");
|
||||
assert_eq!(request.rev.as_deref(), Some("abc123"));
|
||||
}
|
||||
|
||||
/// The bug behind the log store's 401: a client REGISTERED for
|
||||
/// `authelia.bearer.authz` still receives a token carrying no scope
|
||||
/// unless the request asks, and authelia's authz endpoint refuses that.
|
||||
|
|
|
|||
Loading…
Reference in a new issue