Watch
0
0
Fork
You've already forked hyperhive
0

config PRs: remove the hive's config-PR webhook, poll and core merge

An operator's merge on the forge deploys a config PR through
swarm-controller's DeployRequest{rev}. The hive-side path that queued a
MergeConfigPr approval and merged the PR as `core` goes:

- the `/webhook/config-pr` receiver, its HMAC secret, the WebhookRegister
  boot node and the org-hook registration; the hive vhost's `/webhook/`
  location
- the 5-minute config-PR poll
- ApprovalKind::MergeConfigPr, its dashboard card, and the deploy DAG it
  drove (DeployWindow, MergeVerify, DeployApply, FinalizeDeploy,
  DeployTail), with verify_commit, the two-phase meta deploy, rollback
  refs, the PR-failure comment and forge/pr_merge.rs
- `fetched_sha`, `sha_short`/`pr_number` on approval events, and
  `sha`/`tag` on HelperEvent::ApprovalResolved: only the merge path set
  them

`config_repo`, `merged_pr_for_commit` and `post_pr_comment` move to
forge/pr_comment.rs for the merged-rev deploy's refusal comment.
Approvals v5 drops stored `merge_config_pr` rows; a test reopens a v4
database holding them.

Closes #4850
This commit is contained in:
atlas 2026-10-02 22:32:17 +02:00
commit efbfec6d01
39 changed files with 286 additions and 3199 deletions

View file

@ -603,10 +603,7 @@ impl Client {
}
/// Every agent in [`CONFIG_ORG`] with an open config PR, keyed by agent
/// name. Mirrors `hive-c0re::forge::config_pr_poll::poll_open_config_prs`'s
/// scan shape (list repos in the org, list open PRs per repo) but returns
/// data instead of side-effecting an approval queue — this daemon has no
/// approval system of its own; it exists so `GET
/// name: list repos in the org, then open PRs per repo. It exists so `GET
/// /api/agents/{name}/config-pr` has something to answer from,
/// independent of any one hive being up.
///
@ -649,9 +646,7 @@ impl Client {
}
};
// Only the first open PR matters for the panel — a config repo
// is meant to carry at most one live proposal at a time (the
// same assumption `hive-c0re`'s poller and the `MergeConfigPr`
// approval flow both make).
// is meant to carry at most one live proposal at a time.
if let Some(pr) = prs.into_iter().next() {
let Some(pr_number) = pr.number.and_then(|n| u64::try_from(n).ok()) else {
continue;
@ -900,19 +895,9 @@ impl Client {
/// forge event reaches [`crate::webhook`] instead of the endpoint only
/// being reachable by hand.
///
/// **These are registered ALONGSIDE the per-hive hooks, not instead of
/// them.** Every hive keeps receiving and acting on its own deliveries
/// exactly as today; the controller receives a copy and (for now) logs
/// it. Taking the hive-side registration away is a later step, and it
/// has to be later: fan-out swarm→hive does not exist yet, so a hook
/// moved now would point at a receiver that forwards nowhere — silent on
/// both sides, indistinguishable from no activity.
///
/// ⛔ **No stale-hook deletion arm, unlike the two per-hive registrars
/// this otherwise mirrors.** Their arm deletes hooks matching their own
/// path with a foreign base; copying it here would delete the hives'
/// live hooks, which are not stale — they are the path still in
/// production. The controller only ever adds its own.
/// Adds its own hooks only. A hive's `/webhook/config-pr` hook left on
/// the `agent-configs` org by an older release stays registered and
/// delivers to a route no hive serves.
///
/// Idempotent: an existing hook with the same `target_url` is left
/// alone, so this is safe on every boot.
@ -921,8 +906,7 @@ impl Client {
///
/// Returns the first failure. A listing failure is not fatal — it falls
/// through to the create attempt, which is idempotent server-side by way
/// of the already-exists fold, the same best-effort shape `hive-c0re`
/// uses.
/// of the already-exists fold.
pub async fn ensure_swarm_webhooks(&self, public_base: &str, secret: &str) -> Result<()> {
for kind in DeliveryKind::ALL {
let target_url = kind.target_url(public_base);
@ -989,7 +973,7 @@ impl Client {
);
}
Err(e) => {
// Best-effort, same as the per-hive registrars: a forge that
// Best-effort: a forge that
// cannot be listed may still accept a create, and a
// duplicate create is folded into success below. `warn!`
// because that fold is an assumption about the forge, not a
@ -1054,8 +1038,7 @@ fn transitive_reach(start: i64, adj: &HashMap<i64, Vec<i64>>) -> usize {
}
/// Where a hook lives. The knowledge hook is repo-scoped and the config-PR
/// hook is org-scoped, mirroring exactly where the per-hive registrars put
/// theirs — a hook on the wrong scope would never fire, and forgejo would
/// hook is org-scoped — a hook on the wrong scope would never fire, and forgejo would
/// report that as a perfectly healthy hook with no deliveries.
enum HookScope<'a> {
Repo {