From 3e5aff39eb04e365bc53823014b1d63edfa4a0ad Mon Sep 17 00:00:00 2001 From: damocles Date: Sat, 11 Jul 2026 10:58:35 +0200 Subject: [PATCH] =?UTF-8?q?fix(#1970):=20address=20argus=20review=20?= =?UTF-8?q?=E2=80=94=20#=20Errors=20doc,=20regen=20hivectl-cli.md,=20GET?= =?UTF-8?q?=20/api/github-account=20status?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/tools/hivectl-cli.md | 32 ++++++++++++++++++++++ hive-c0re/src/dashboard/matrix_accounts.rs | 28 +++++++++++++++++++ hive-c0re/src/dashboard/mod.rs | 2 +- hive-c0re/src/priv_client.rs | 6 ++++ 4 files changed, 67 insertions(+), 1 deletion(-) diff --git a/docs/tools/hivectl-cli.md b/docs/tools/hivectl-cli.md index 4e685019..d46f5bfd 100644 --- a/docs/tools/hivectl-cli.md +++ b/docs/tools/hivectl-cli.md @@ -13,6 +13,8 @@ This document contains the help content for the `hivectl` command-line program. * [`hivectl matrix promote-user`↴](#hivectl-matrix-promote-user) * [`hivectl matrix reset-password`↴](#hivectl-matrix-reset-password) * [`hivectl matrix invite`↴](#hivectl-matrix-invite) +* [`hivectl github`↴](#hivectl-github) +* [`hivectl github set-token`↴](#hivectl-github-set-token) * [`hivectl gateway`↴](#hivectl-gateway) * [`hivectl gateway create-user`↴](#hivectl-gateway-create-user) * [`hivectl gateway delete-user`↴](#hivectl-gateway-delete-user) @@ -49,6 +51,7 @@ Sibling to the `hive-c0re` daemon binary. Covers host-side admin operations that * `forge` — Forgejo user provisioning. Manual entry point to the same idempotent flow c0re runs automatically at boot (`forge::ensure_all`) — useful for recovery, ad-hoc reprovisioning, or single-agent fixes without bouncing the daemon * `matrix` — matrix-tuwunel user provisioning. Manual entry point to the same idempotent flow c0re runs automatically at boot (`matrix::ensure_all`) — useful when the boot-time sweep skipped an agent (e.g. matrix container wasn't up yet) or to re-register after wiping a token file +* `github` — GitHub account provisioning: write an operator-supplied personal access token (PAT) into an agent's `hyperhive.githubAccount` token file so its `gh` wrapper + git credential helper can authenticate. Unlike forge/matrix there is no account creation — the operator supplies a PAT for an existing GitHub account * `gateway` — Gateway htpasswd user management. Add, remove, or list users in an htpasswd file used by the gateway's HTTP Basic auth (`services.hyperhive.gateway.auth`). Credentials are stored as `BCrypt` hashes — no extra service or PAM required * `agents` — Agent container management. Requires the hive-c0re daemon to be running (connects to the host admin socket) * `wg` — WireGuard inter-hive mesh setup helpers (`services.hyperhive.swarm`) @@ -194,6 +197,35 @@ Invite a matrix user to the hive Space (default) or a specific room. Uses the hi +## `hivectl github` + +GitHub account provisioning: write an operator-supplied personal access token (PAT) into an agent's `hyperhive.githubAccount` token file so its `gh` wrapper + git credential helper can authenticate. Unlike forge/matrix there is no account creation — the operator supplies a PAT for an existing GitHub account + +**Usage:** `hivectl github ` + +###### **Subcommands:** + +* `set-token` — Write a GitHub PAT into ``'s state dir (`github-token`, 0600, agent-owned) via hive-priv. The agent must declare `hyperhive.githubAccount` (its `tokenFile` pointing at this path) for the `gh` wrapper + git credential helper to pick it up. The token is read live at invocation, so no rebuild/restart is needed. Prefer `--token-stdin`: an inline `--token` is visible in shell history + process listings + + + +## `hivectl github set-token` + +Write a GitHub PAT into ``'s state dir (`github-token`, 0600, agent-owned) via hive-priv. The agent must declare `hyperhive.githubAccount` (its `tokenFile` pointing at this path) for the `gh` wrapper + git credential helper to pick it up. The token is read live at invocation, so no rebuild/restart is needed. Prefer `--token-stdin`: an inline `--token` is visible in shell history + process listings + +**Usage:** `hivectl github set-token [OPTIONS] ` + +###### **Arguments:** + +* `` — Logical agent name (the container/agent name) + +###### **Options:** + +* `--token ` — The PAT value inline. Mutually exclusive with `--token-stdin` +* `--token-stdin` — Read the PAT from stdin (trailing newline stripped). Mutually exclusive with `--token` + + + ## `hivectl gateway` Gateway htpasswd user management. Add, remove, or list users in an htpasswd file used by the gateway's HTTP Basic auth (`services.hyperhive.gateway.auth`). Credentials are stored as `BCrypt` hashes — no extra service or PAM required diff --git a/hive-c0re/src/dashboard/matrix_accounts.rs b/hive-c0re/src/dashboard/matrix_accounts.rs index e526d7fd..4f5f5c52 100644 --- a/hive-c0re/src/dashboard/matrix_accounts.rs +++ b/hive-c0re/src/dashboard/matrix_accounts.rs @@ -301,6 +301,34 @@ pub(super) async fn post_github_account(Form(f): Form) -> Res axum::Json(GithubAccountResult { ok: true }).into_response() } +#[derive(Deserialize)] +pub(super) struct GithubAccountQuery { + agent: String, +} + +#[derive(Serialize)] +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, +} + +/// `GET /api/github-account?agent=` — 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. +pub(super) async fn get_github_account(Query(q): Query) -> Response { + let agent = q.agent.trim(); + if !is_plain_ident(agent) { + 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() +} + /// POST `m.login.password` to `/_matrix/client/v3/login`. /// Returns `(access_token, user_id)`. async fn matrix_password_login( diff --git a/hive-c0re/src/dashboard/mod.rs b/hive-c0re/src/dashboard/mod.rs index b3909047..60facd1f 100644 --- a/hive-c0re/src/dashboard/mod.rs +++ b/hive-c0re/src/dashboard/mod.rs @@ -190,7 +190,7 @@ pub async fn serve(port: u16, coord: Arc) -> Result<()> { ) .route( "/api/github-account", - post(matrix_accounts::post_github_account), + post(matrix_accounts::post_github_account).get(matrix_accounts::get_github_account), ) .route( "/api/cancel-reminder/{id}", diff --git a/hive-c0re/src/priv_client.rs b/hive-c0re/src/priv_client.rs index 4f2d8b31..bd7fb1f1 100644 --- a/hive-c0re/src/priv_client.rs +++ b/hive-c0re/src/priv_client.rs @@ -286,6 +286,12 @@ pub async fn write_agent_matrix_token( /// user so the `gh` wrapper / git credential helper can read it from inside the /// container. Single account per agent — no account suffix. The token value is /// operator-supplied (for the agent's `hyperhive.githubAccount`). +/// +/// # Errors +/// +/// Returns an error if the hive-priv call fails — the socket is unreachable, +/// `agent_name` is rejected by the root-side validation, or the file +/// write/chown fails. pub async fn write_agent_github_token(agent_name: &str, token: &str) -> Result<()> { ok(call(&PrivRequest::WriteAgentGithubToken { agent_name: agent_name.to_owned(),