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

@ -40,7 +40,6 @@ mod swarm_queue;
mod swarm_status;
#[cfg(test)]
mod test_env;
mod webhook_secret;
mod workers;
pub(crate) use agent_config::{capabilities, limits, resource_limits, tool_groups, topology};
@ -296,54 +295,6 @@ async fn cmd_serve(
// `workers::auto_update::submit_startup_sweep_nodes`), submitted
// unconditionally on every boot — moved off a bare `tokio::spawn` so it
// shows as real work on the dashboard.
// Webhook HMAC secret: load from state dir or generate on first run.
// Used by both the webhook handlers (verification) and the Forgejo
// hook registrations (so Forgejo signs deliveries with the same key).
let webhook_secret: Option<String> = match crate::webhook_secret::load_or_generate() {
Ok(s) => Some(s),
Err(e) => {
tracing::error!(
error = ?e,
"webhook secret load/generate failed; /webhook/* endpoints disabled and hooks not registered"
);
None
}
};
// Webhook setup: now a `NodeKind::WebhookRegister` DAG node (see
// `workers::auto_update::submit_startup_sweep_nodes`), registering both
// `internal/knowledge` (push → git pull) and the `agent-configs` org
// (pull_request → queue MergeConfigPr approval) hooks. Its executor
// re-derives the core token / hive domain / HMAC secret itself, mirroring
// the guard chain that used to live here — see `job_queue::exec::
// run_webhook_register`.
// Config-PR polling fallback: scan agent-configs org every 5 minutes
// for open PRs that have no pending MergeConfigPr approval. Catches
// anything the webhook missed (c0re was down when PR opened, delivery
// failed, etc.). First sweep fires immediately on startup.
let poll_coord = coord.clone();
let mut poll_shutdown = coord.shutdown_rx();
tokio::spawn(async move {
let interval = std::time::Duration::from_mins(5);
loop {
if let Some(token) = forge::core_token() {
let result = Box::pin(forge::config_pr_poll::poll_open_config_prs(
&token,
&poll_coord,
))
.await;
if let Err(e) = result {
tracing::debug!(error = ?e, "config-pr poll: sweep failed (forge may be absent)");
}
}
tokio::select! {
() = tokio::time::sleep(interval) => {}
_ = poll_shutdown.changed() => {
tracing::info!("config-pr poll: shutdown signal received");
break;
}
}
}
});
// Knowledge periodic pull: hourly fallback in case a knowledge event from
// the swarm is missed (e.g. hive-c0re was down when it was sent). Sleeps
// before its first pull: the boot `NodeKind::KnowledgePull` DAG node
@ -506,9 +457,8 @@ async fn cmd_serve(
// channel (used by `recv_blocking_batch`) stays untouched.
spawn_broker_to_dashboard_forwarder(coord.clone());
let dash_coord = coord.clone();
let dash_secret = webhook_secret.clone();
tokio::spawn(async move {
if let Err(e) = dashboard::serve(dashboard_port, dash_coord, dash_secret).await {
if let Err(e) = dashboard::serve(dashboard_port, dash_coord).await {
tracing::error!(error = ?e, "dashboard failed");
}
});