Watch
0
0
Fork
You've already forked hyperhive
0

remove the create_repo agent tool

mara ruled on #4849 (c88934): "remove create_repo tool". The tool ran in
hive-c0re with the hive's core token, so it only ever worked for agents
on the hive that runs the forge.

Removed:

- the create_repo MCP tool and CreateRepoArgs (hive-agent-mcp)
- wire variants Request::CreateRepo and Response::RepoCreated
  (hive-core-agent-sock)
- hive-c0re's handle_create_repo, its valid_repo_name check and the
  dispatch arm
- forge::create_agent_repo and apply_operator_branch_protection, which
  had no other caller, plus AGENTS_ORG and OPERATORS_TEAM, whose only
  users they were
- the tool's docs (docs/tools/forge.md repo management, docs/turn-loop/
  mcp.md, the conventions tool-group table) and the doc comments that
  named it (hive-sock-client's response timeout, ensure_repo_creation_
  disabled, the security doc's merge-gate bullet)

ToolGroup::Forge is kept with no tools, the same way b88a5b24 kept
Lifecycle, so existing meta/capabilities.json grants still parse.

Forge state is untouched: existing agents/* repos keep their collaborators
and operators-team branch protection. The swarm-controller's own
create_repo (config-org repos) is a different path and is unchanged.

Closes #4849
This commit is contained in:
atlas 2026-09-30 23:42:15 +02:00 • committed by mara
commit 7d217f8267
14 changed files with 43 additions and 230 deletions

View file

@ -18,8 +18,8 @@ use reqwest::StatusCode;
use crate::coordinator::Coordinator;
use super::{
AGENTS_ORG, CONFIG_ORG, OPERATORS_TEAM, SHARED_DOCS_REPO, SHARED_ORG, api, core_auth_header,
core_token, forge_git_url, forge_http_base, is_present,
CONFIG_ORG, SHARED_DOCS_REPO, SHARED_ORG, api, core_auth_header, core_token, forge_git_url,
forge_http_base, is_present,
};
/// Creation options for an empty repo defaulting to `main`.
@ -659,52 +659,6 @@ fn main_branch_protection_option() -> CreateBranchProtectionOption {
}
}
/// Apply the operator merge-gate branch protection to `repo`'s default
/// branch: only [`OPERATORS_TEAM`] members can merge, and an
/// approving review from that team is required — so the author (a write-level
/// agent, not in the team) cannot merge its own PR.
///
/// Idempotent, but **verify-don't-trust**: a create failure is ambiguous —
/// "rule already exists" (success) OR a silent rejection that created NO rule
/// (e.g. a 422 where `OPERATORS_TEAM` doesn't exist in `AGENTS_ORG`). The old
/// code folded 200/409/422 into `Ok` and left the repo unprotected with no
/// error — a fail-open merge gate. So on any create error, GET the `main` rule
/// and only treat it as success if the rule is actually present (the exact fix
/// already applied to [`apply_config_repo_branch_protection`]).
async fn apply_operator_branch_protection(repo: &str, token: &str) -> Result<()> {
let client = api(token)?;
let mut rule = main_branch_protection_option();
rule.enable_merge_whitelist = Some(true);
rule.merge_whitelist_teams = Some(vec![OPERATORS_TEAM.to_owned()]);
rule.enable_approvals_whitelist = Some(true);
rule.approvals_whitelist_teams = Some(vec![OPERATORS_TEAM.to_owned()]);
rule.required_approvals = Some(1);
rule.block_on_official_review_requests = Some(true);
let Err(create_err) = client
.repo_create_branch_protection(AGENTS_ORG, repo, rule)
.await
else {
tracing::info!(%repo, "forge: applied operator branch protection");
return Ok(());
};
match client
.repo_get_branch_protection(AGENTS_ORG, repo, "main")
.await
{
Ok(_) => {
tracing::debug!(
%repo, create_error = %create_err,
"forge: operator branch protection already present"
);
Ok(())
}
Err(check_err) => anyhow::bail!(
"branch protection for {AGENTS_ORG}/{repo} not applied: create failed \
({create_err}); GET main rule failed ({check_err}), no `main` rule present"
),
}
}
/// Apply branch protection to an `agent-configs/<name>` repo's `main` so it
/// can serve as the agent-editable, PR-merge config surface:
/// - **`main` is never directly pushable** — no push is enabled on the
@ -809,24 +763,3 @@ fn config_repo_protection_edit() -> EditBranchProtectionOption {
unprotected_file_patterns: None,
}
}
/// Create a repo for `agent` in the c0re-owned [`AGENTS_ORG`] and wire the
/// perms: the org owns it (perms stay c0re-managed), the agent is added
/// as a **write** collaborator (not owner — can push + open PRs but can't
/// bypass branch protection), and the default branch gets the operator
/// merge gate. This is the sanctioned create path now that agents can't
/// create repos directly (`max_repo_creation = 0`). Idempotent.
pub async fn create_agent_repo(agent: &str, repo: &str, core_token: &str) -> Result<String> {
ensure_org_repo(AGENTS_ORG, repo, core_token).await?;
add_collaborator(
AGENTS_ORG,
repo,
agent,
AddCollaboratorOptionPermission::Write,
core_token,
)
.await?;
apply_operator_branch_protection(repo, core_token).await?;
tracing::info!(%agent, %repo, "forge: created agent repo in {AGENTS_ORG} with operator merge gate");
Ok(format!("{AGENTS_ORG}/{repo}"))
}