use std::path::PathBuf;
use auths_core::storage::keychain::IdentityDID;
#[derive(Debug, Clone)]
pub enum AgentStorageMode {
Persistent {
repo_path: Option<PathBuf>,
},
InMemory,
}
#[derive(Debug, Clone)]
pub struct AgentProvisioningConfig {
pub agent_name: String,
pub capabilities: Vec<String>,
pub expires_in: Option<u64>,
pub delegated_by: Option<IdentityDID>,
pub storage_mode: AgentStorageMode,
}
pub fn format_agent_toml(did: &str, key_alias: &str, config: &AgentProvisioningConfig) -> String {
let caps = config
.capabilities
.iter()
.map(|c| format!("\"{}\"", c))
.collect::<Vec<_>>()
.join(", ");
let mut out = format!(
"# Auths Agent Configuration\n\
# An agent is a KERI delegated identifier (dip) — create with `auths id agent add`\n\n\
[agent]\n\
name = \"{}\"\n\
did = \"{}\"\n\
key_alias = \"{}\"\n\
signer_type = \"Agent\"\n",
config.agent_name, did, key_alias,
);
if let Some(ref delegator) = config.delegated_by {
out.push_str(&format!("delegated_by = \"{}\"\n", delegator));
}
out.push_str(&format!("\n[capabilities]\ngranted = [{}]\n", caps));
if let Some(secs) = config.expires_in {
out.push_str(&format!("\n[expiry]\nexpires_in = {}\n", secs));
}
out
}
#[cfg(test)]
#[allow(clippy::disallowed_methods)] mod tests {
use super::*;
#[test]
fn format_agent_toml_with_all_fields() {
let config = AgentProvisioningConfig {
agent_name: "ci-bot".to_string(),
capabilities: vec!["sign_commit".to_string(), "pr:create".to_string()],
expires_in: Some(86400),
delegated_by: Some(IdentityDID::new_unchecked("did:keri:Eabc123")),
storage_mode: AgentStorageMode::Persistent { repo_path: None },
};
let toml = format_agent_toml("did:keri:Eagent", "agent-key", &config);
assert!(toml.contains("name = \"ci-bot\""));
assert!(toml.contains("did = \"did:keri:Eagent\""));
assert!(toml.contains("delegated_by = \"did:keri:Eabc123\""));
assert!(toml.contains("\"sign_commit\", \"pr:create\""));
assert!(toml.contains("expires_in = 86400"));
}
#[test]
fn format_agent_toml_minimal() {
let config = AgentProvisioningConfig {
agent_name: "solo".to_string(),
capabilities: vec![],
expires_in: None,
delegated_by: None,
storage_mode: AgentStorageMode::InMemory,
};
let toml = format_agent_toml("did:keri:E1", "k", &config);
assert!(!toml.contains("delegated_by"));
assert!(!toml.contains("[expiry]"));
}
#[test]
fn init_dryrun_shows_delegated_agent() {
let config = AgentProvisioningConfig {
agent_name: "deploy-bot".to_string(),
capabilities: vec!["sign_commit".to_string()],
expires_in: None,
delegated_by: Some(IdentityDID::new_unchecked("did:keri:Eroot")),
storage_mode: AgentStorageMode::Persistent { repo_path: None },
};
let toml = format_agent_toml("did:keri:E<pending>", "agent-key", &config);
assert!(
toml.contains("delegated identifier"),
"dry-run must frame the agent as a delegated identifier"
);
assert!(
toml.contains("delegated_by = \"did:keri:Eroot\""),
"dry-run must name the delegating root"
);
}
}