//! `hivectl github set-token ` — 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 `: 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, 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 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 }