hyperhive/hivectl/src/github.rs

48 lines
1.7 KiB
Rust

//! `hivectl github set-token <agent>` — write an operator-supplied GitHub PAT
//! into an agent's `github-token` state file via the daemon's privileged
//! helper, so the agent's `gh` wrapper + git credential helper authenticate.
use std::path::Path;
use anyhow::{Result, bail};
use crate::util::daemon_request;
/// `hivectl github set-token <agent>`: write an operator-supplied GitHub PAT
/// into the agent's `github-token` state file (0600, agent-owned) via
/// hive-priv, so the agent's `gh` wrapper + git credential helper can
/// authenticate. Read live at invocation, so no rebuild/restart is needed.
pub(crate) async fn github_set_token(
socket: &Path,
agent: &str,
token: Option<String>,
token_stdin: bool,
) -> Result<()> {
// Resolve + validate the token client-side (inline flag or stdin read);
// the daemon never touches this process's stdin. Persistence happens
// daemon-side via the privileged helper.
let token = match (token, token_stdin) {
(Some(t), _) => t,
(None, true) => {
let mut s = String::new();
std::io::Read::read_to_string(&mut std::io::stdin(), &mut s)?;
s.trim_end_matches(['\n', '\r']).to_owned()
}
(None, false) => bail!(
"provide the PAT via --token <pat> or --token-stdin (stdin preferred — \
an inline token is visible in shell history + process listings)"
),
};
if token.is_empty() {
bail!("refusing to write an empty GitHub token for agent '{agent}'");
}
daemon_request(
socket,
hive_host_sock::HostRequest::SetAgentGithubToken {
agent: crate::util::parse_ident(agent)?,
token,
},
"github",
)
.await
}