hivectl: print token to stdout for non-agent users (#662)
This commit is contained in:
parent
a9114342e4
commit
18253bf2f5
3 changed files with 121 additions and 40 deletions
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
use anyhow::{Context as _, Result, bail};
|
||||
use clap::{Parser, Subcommand};
|
||||
use hive_c0re::coordinator::Coordinator;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(
|
||||
|
|
@ -58,13 +59,21 @@ enum Cmd {
|
|||
#[derive(Subcommand)]
|
||||
enum ForgeCmd {
|
||||
/// Create or refresh the Forgejo account + token for `<name>`.
|
||||
/// Idempotent: skips user creation when the account exists,
|
||||
/// skips token mint when the token file is already populated.
|
||||
/// To force re-minting, delete the token file at
|
||||
/// `/var/lib/hyperhive/agents/<name>/state/forge-token`.
|
||||
///
|
||||
/// When `<name>` matches an existing agent (i.e. it has a state
|
||||
/// dir under `/var/lib/hyperhive/agents/`), persists the token to
|
||||
/// `<state>/forge-token` (idempotent: re-mints + rewrites every
|
||||
/// call so the on-disk scope matches the current
|
||||
/// `forge::TOKEN_SCOPES`).
|
||||
///
|
||||
/// When `<name>` is **not** an agent (a human or any other
|
||||
/// non-container account), creates the forgejo user and prints the
|
||||
/// freshly-minted token to stdout — no `/var/lib/hyperhive/agents/`
|
||||
/// directory is created for the user (#662).
|
||||
CreateUser {
|
||||
/// Container/agent name (the `<name>` in `h-<name>`; manager
|
||||
/// agent uses the literal `manager`).
|
||||
/// Forgejo username. For agents: the container/agent name
|
||||
/// (`<n>` in `h-<n>`; manager uses the literal `manager`).
|
||||
/// For humans: any forgejo username — `mara`, `damocles`, etc.
|
||||
name: String,
|
||||
},
|
||||
}
|
||||
|
|
@ -72,11 +81,20 @@ enum ForgeCmd {
|
|||
#[derive(Subcommand)]
|
||||
enum MatrixCmd {
|
||||
/// Create or refresh the matrix account + access token for `<name>`.
|
||||
/// Idempotent: skips registration entirely when the token file is
|
||||
/// already populated. To force re-registration, delete the token
|
||||
/// file at `/var/lib/hyperhive/agents/<name>/state/matrix-token`.
|
||||
///
|
||||
/// When `<name>` matches an existing agent (i.e. it has a state
|
||||
/// dir under `/var/lib/hyperhive/agents/`), persists the token to
|
||||
/// `<state>/matrix-token`. Skips registration when the file is
|
||||
/// already populated; delete it to force re-registration.
|
||||
///
|
||||
/// When `<name>` is **not** an agent (a human or any other
|
||||
/// non-container account), registers the matrix user and prints
|
||||
/// the freshly-minted access token to stdout — no
|
||||
/// `/var/lib/hyperhive/agents/` directory is created for the user
|
||||
/// (#662).
|
||||
CreateUser {
|
||||
/// Container/agent name.
|
||||
/// Matrix localpart. For agents: the container/agent name.
|
||||
/// For humans: any matrix localpart — `mara`, `damocles`, etc.
|
||||
name: String,
|
||||
},
|
||||
}
|
||||
|
|
@ -100,16 +118,35 @@ async fn main() -> Result<()> {
|
|||
}
|
||||
}
|
||||
|
||||
/// True when `name` matches an existing hyperhive agent — i.e. it has a
|
||||
/// persistent state dir under `/var/lib/hyperhive/agents/`. We use the
|
||||
/// state dir (not the live container list) so kept-state tombstones
|
||||
/// still resolve as agents — re-provisioning a destroyed-but-kept agent
|
||||
/// should still drop its token in the existing state tree.
|
||||
fn is_agent(name: &str) -> bool {
|
||||
Coordinator::agent_state_root(name).exists()
|
||||
}
|
||||
|
||||
async fn forge_create_user(name: &str) -> Result<()> {
|
||||
if !hive_c0re::forge::is_present().await {
|
||||
bail!(
|
||||
"hive-forge container not running — start it (services.hyperhive.forge.enable = true) before provisioning forge users"
|
||||
);
|
||||
}
|
||||
hive_c0re::forge::ensure_user_for(name)
|
||||
.await
|
||||
.with_context(|| format!("forge create-user {name}"))?;
|
||||
println!("forge: provisioned user '{name}' (idempotent)");
|
||||
if is_agent(name) {
|
||||
hive_c0re::forge::ensure_user_for(name)
|
||||
.await
|
||||
.with_context(|| format!("forge create-user {name}"))?;
|
||||
let path = Coordinator::agent_notes_dir(name).join("forge-token");
|
||||
println!("forge: provisioned agent user '{name}'");
|
||||
println!("token persisted at: {}", path.display());
|
||||
} else {
|
||||
let token = hive_c0re::forge::provision_user_token(name)
|
||||
.await
|
||||
.with_context(|| format!("forge create-user {name}"))?;
|
||||
println!("forge: provisioned user '{name}' (not an agent — token not persisted)");
|
||||
println!("token: {token}");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -125,9 +162,19 @@ async fn matrix_create_user(name: &str) -> Result<()> {
|
|||
.timeout(std::time::Duration::from_secs(30))
|
||||
.build()
|
||||
.context("build reqwest client")?;
|
||||
hive_c0re::matrix::ensure_user_for(&client, name, ®ister_token)
|
||||
.await
|
||||
.with_context(|| format!("matrix create-user {name}"))?;
|
||||
println!("matrix: provisioned user '{name}' (idempotent)");
|
||||
if is_agent(name) {
|
||||
hive_c0re::matrix::ensure_user_for(&client, name, ®ister_token)
|
||||
.await
|
||||
.with_context(|| format!("matrix create-user {name}"))?;
|
||||
let path = Coordinator::agent_notes_dir(name).join("matrix-token");
|
||||
println!("matrix: provisioned agent user '{name}'");
|
||||
println!("token persisted at: {}", path.display());
|
||||
} else {
|
||||
let token = hive_c0re::matrix::provision_user_token(&client, name, ®ister_token)
|
||||
.await
|
||||
.with_context(|| format!("matrix create-user {name}"))?;
|
||||
println!("matrix: provisioned user '{name}' (not an agent — token not persisted)");
|
||||
println!("token: {token}");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue