use anyhow::Result;
use cleanlib_client::config;
use crate::auth;
fn validate_api_key(api_key: &str) -> Result<()> {
if api_key.is_empty() {
anyhow::bail!(
"CLIENT_BEARER_EMPTY — API key must not be empty.\n\
Pass a non-empty value via `cleanlib login --api-key <KEY>` or\n\
set CLEANLIB_ENRICH_BEARER in your environment."
);
}
if api_key.trim().is_empty() {
anyhow::bail!(
"CLIENT_BEARER_WHITESPACE — API key must not be whitespace-only.\n\
Pass the literal API key value to `cleanlib login --api-key <KEY>`."
);
}
Ok(())
}
pub fn run(api_key: String, use_keyring: bool) -> Result<()> {
validate_api_key(&api_key)?;
if use_keyring {
auth::bearer::store_in_keyring(&api_key)?;
eprintln!(
"api key stored in keyring (service={}, user={})",
auth::KEYRING_SERVICE,
auth::KEYRING_USER
);
return Ok(());
}
let path = config::default_path()
.ok_or_else(|| anyhow::anyhow!("home directory not discoverable; cannot write config"))?;
let mut cfg = if path.exists() {
config::load(&path)?
} else {
config::Config::default()
};
cfg.auth.api_key = Some(api_key);
config::save(&cfg, &path)?;
eprintln!("api key stored in {}", path.display());
Ok(())
}
#[cfg(test)]
mod tests {
use super::validate_api_key;
#[test]
fn rejects_empty_api_key() {
let err = validate_api_key("").unwrap_err();
assert!(err.to_string().contains("CLIENT_BEARER_EMPTY"));
}
#[test]
fn rejects_whitespace_only_api_key() {
let err = validate_api_key(" ").unwrap_err();
assert!(err.to_string().contains("CLIENT_BEARER_WHITESPACE"));
}
#[test]
fn rejects_tab_and_newline_only() {
assert!(validate_api_key("\t").is_err());
assert!(validate_api_key("\n").is_err());
assert!(validate_api_key(" \t\n ").is_err());
}
#[test]
fn accepts_valid_tier_keyed_bearer_shape() {
assert!(validate_api_key("std_001").is_ok());
assert!(validate_api_key("clk_xyz_long_token_value_12345").is_ok());
}
}