Watch
0
0
Fork
You've already forked hyperhive
0
hyperhive/hive-c0re/src/dashboard/matrix_accounts.rs
atlas 6a1d85c24f hive-dashboard: remove the MATRIX credentials tab and its login route
The CR3D3NTIALS page's MATRIX tab was the only caller of
`POST /api/matrix-account-login` (provision/log in an external matrix
account through the hive) and `GET /api/matrix-accounts` (its account
list). External matrix accounts are linked from the swarm UI now
(`LinkMatrixAccountForm` -> swarm-controller), so the hive-side UI and
both routes go. `priv_client::restart_matrix_daemon` had no other caller
and goes with them.

Already-provisioned credentials keep working: the `matrix-token-<name>`
files and `matrix-account-<name>.json` sidecars the old route wrote are
still discovered by hive-matrix-mcp (`accounts::configured` ->
`discover_token_accounts`), the `matrix-token*` path unit still re-fires
the daemon, and `WriteAgentMatrixToken` stays for the swarm credential
worker. Removing that usage waits on moving the existing creds to
swarm level.

The GITHUB tab is the credentials page's default tab now.

Refs #4348
2026-09-29 13:54:18 +02:00

100 lines
3.7 KiB
Rust

//! Per-agent GitHub PAT provisioning for the dashboard's GITHUB tab:
//! `POST /api/github-account` stores it, `GET /api/github-account` reports
//! whether one is stored.
use axum::extract::{Form, Query};
use axum::response::{IntoResponse, Response};
use serde::{Deserialize, Serialize};
use utoipa::{IntoParams, ToSchema};
use super::{Ident, error_response};
use crate::coordinator::Coordinator;
/// Form body for `POST /api/github-account` (urlencoded, the dashboard's
/// mutation convention). Writes the operator-supplied PAT to the agent's
/// `github-token` file. No account creation and no login modes — the
/// operator pastes a PAT for an existing account.
#[derive(Deserialize, ToSchema)]
pub(super) struct GithubAccountForm {
agent: String,
token: String,
}
#[derive(Serialize, ToSchema)]
struct GithubAccountResult {
ok: bool,
}
/// Provision (or refresh) an agent's GitHub PAT from the dashboard
/// credentials tab.
///
/// Validates the agent name, then writes the PAT to
/// `<state>/github-token` (`0600`, agent-owned) via hive-priv. No account
/// creation and no daemon to kick — the agent's `gh` wrapper / git credential
/// helper read the file live, so the new token takes effect immediately.
/// Operator-authenticated (dashboard). Never echoes the token back — only
/// `{ ok: true }`.
#[utoipa::path(
post,
path = "/api/github-account",
request_body(content = GithubAccountForm, content_type = "application/x-www-form-urlencoded"),
responses(
(status = 200, description = "PAT provisioned", body = GithubAccountResult),
(status = 500, description = "invalid agent name, empty token, or the write failed"),
),
tag = "matrix_accounts"
)]
pub(super) async fn post_github_account(Form(f): Form<GithubAccountForm>) -> Response {
let agent = f.agent.trim();
let token = f.token.trim();
let Ok(agent) = Ident::parse(agent) else {
return error_response(&format!("github-account: invalid agent {agent:?}"));
};
if token.is_empty() {
return error_response("github-account: token is required");
}
if let Err(e) = crate::priv_client::write_agent_github_token(agent.as_str(), token).await {
return error_response(&format!("github-account: write token failed: {e:#}"));
}
tracing::info!(%agent, "github-account: provisioned github PAT");
axum::Json(GithubAccountResult { ok: true }).into_response()
}
#[derive(Deserialize, IntoParams)]
pub(super) struct GithubAccountQuery {
agent: String,
}
#[derive(Serialize, ToSchema)]
struct GithubAccountStatus {
/// A `github-token` file exists in the agent's state dir (a PAT has been
/// provisioned). A static PAT has no live/heartbeat concept, so this is
/// the only status the credentials tab needs.
present: bool,
}
/// Whether the agent has a GitHub
/// PAT provisioned (its `github-token` file exists).
///
/// Lets the credentials tab show "token stored" vs "not set" instead of a
/// black-hole paste field. Never returns the token itself.
#[utoipa::path(
get,
path = "/api/github-account",
params(GithubAccountQuery),
responses(
(status = 200, description = "whether a github PAT is provisioned", body = GithubAccountStatus),
(status = 500, description = "invalid agent name"),
),
tag = "matrix_accounts"
)]
pub(super) async fn get_github_account(Query(q): Query<GithubAccountQuery>) -> Response {
let agent = q.agent.trim();
let Ok(agent) = Ident::parse(agent) else {
return error_response(&format!("github-account: invalid agent {agent:?}"));
};
let present = Coordinator::agent_notes_dir(&agent)
.join("github-token")
.exists();
axum::Json(GithubAccountStatus { present }).into_response()
}