Watch
0
0
Fork
You've already forked hyperhive
0

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:
atlas 2026-10-02 18:45:18 +02:00
commit f1c695c212
11 changed files with 732 additions and 76 deletions

View file

@ -667,14 +667,14 @@ fn main_branch_protection_option() -> CreateBranchProtectionOption {
/// node (`actions::run_deploy_apply`), which fast-forward-*merges* the reviewed
/// head through the forge merge API (`Do=fast-forward-only`,
/// `head_commit_id` pinned to the reviewed sha).
/// - **merge is whitelisted to `core`** — only hive-c0re can merge a config PR;
/// the agent can push feature branches + open PRs but can't land them.
/// - **the operator's dashboard approval is the gate** — approval happens on
/// the `MergeConfigPr` card and hive-c0re only merges an approved PR. There's
/// deliberately no Forgejo `required_approvals` review requirement: the flow
/// never does an in-forge review, so requiring one would only dead-block the
/// `core` merge. The dashboard approval + the `core`-only merge whitelist are
/// the real gate.
/// - **merge is whitelisted to `core`** — the agent can push feature branches +
/// open PRs but can't land them. swarm-controller adds the `operators` team
/// to the whitelist, so an operator can also merge in the forge UI.
/// - **the operator's dashboard approval is the gate for `core`** — approval
/// happens on the `MergeConfigPr` card and hive-c0re only merges an approved
/// PR. There's deliberately no Forgejo `required_approvals` review
/// requirement: that flow never does an in-forge review, so requiring one
/// would only dead-block the `core` merge.
/// - **fast-forward-only** — `main` only ever advances by fast-forward; a raced
/// non-ff `main` is refused by the merge API rather than force-moved.
///
@ -736,6 +736,11 @@ async fn apply_config_repo_branch_protection(repo: &str, token: &str) -> Result<
/// left `None`, so a repo carrying an older push-based or approval-gated rule is
/// actually *converged* rather than merely re-asserted — a PATCH leaves unset
/// fields untouched. Every field unrelated to this policy stays `None`.
///
/// The approval and merge whitelists' **teams** stay `None` too, and so does
/// `enable_approvals_whitelist`: swarm-controller puts the `operators` team on
/// both, so operators can merge config PRs in the forge UI, and this PATCH
/// runs on every boot.
fn config_repo_protection_edit() -> EditBranchProtectionOption {
EditBranchProtectionOption {
apply_to_admins: None,
@ -745,7 +750,7 @@ fn config_repo_protection_edit() -> EditBranchProtectionOption {
block_on_outdated_branch: None,
block_on_rejected_reviews: None,
dismiss_stale_approvals: None,
enable_approvals_whitelist: Some(false),
enable_approvals_whitelist: None,
enable_merge_whitelist: Some(true),
enable_push: Some(false),
enable_push_whitelist: Some(false),