auths_id/
agent_identity.rs1use std::path::PathBuf;
11
12use auths_core::storage::keychain::IdentityDID;
13
14#[derive(Debug, Clone)]
16pub enum AgentStorageMode {
17 Persistent {
20 repo_path: Option<PathBuf>,
22 },
23 InMemory,
26}
27
28#[derive(Debug, Clone)]
30pub struct AgentProvisioningConfig {
31 pub agent_name: String,
33 pub capabilities: Vec<auths_keri::Capability>,
35 pub expires_in: Option<u64>,
37 pub delegated_by: Option<IdentityDID>,
39 pub storage_mode: AgentStorageMode,
41}
42
43pub fn format_agent_toml(did: &str, key_alias: &str, config: &AgentProvisioningConfig) -> String {
55 let caps = config
56 .capabilities
57 .iter()
58 .map(|c| format!("\"{}\"", c))
59 .collect::<Vec<_>>()
60 .join(", ");
61
62 let mut out = format!(
63 "# Auths Agent Configuration\n\
64 # An agent is a KERI delegated identifier (dip) — create with `auths id agent add`\n\n\
65 [agent]\n\
66 name = \"{}\"\n\
67 did = \"{}\"\n\
68 key_alias = \"{}\"\n\
69 signer_type = \"Agent\"\n",
70 config.agent_name, did, key_alias,
71 );
72
73 if let Some(ref delegator) = config.delegated_by {
74 out.push_str(&format!("delegated_by = \"{}\"\n", delegator));
75 }
76
77 out.push_str(&format!("\n[capabilities]\ngranted = [{}]\n", caps));
78
79 if let Some(secs) = config.expires_in {
80 out.push_str(&format!("\n[expiry]\nexpires_in = {}\n", secs));
81 }
82
83 out
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 #[test]
91 fn format_agent_toml_with_all_fields() {
92 let config = AgentProvisioningConfig {
93 agent_name: "ci-bot".to_string(),
94 capabilities: vec![
95 auths_keri::Capability::sign_commit(),
96 auths_keri::Capability::parse("pr:create").unwrap(),
97 ],
98 expires_in: Some(86400),
99 delegated_by: Some(IdentityDID::parse("did:keri:Eabc123").unwrap()),
100 storage_mode: AgentStorageMode::Persistent { repo_path: None },
101 };
102 let toml = format_agent_toml("did:keri:Eagent", "agent-key", &config);
103 assert!(toml.contains("name = \"ci-bot\""));
104 assert!(toml.contains("did = \"did:keri:Eagent\""));
105 assert!(toml.contains("delegated_by = \"did:keri:Eabc123\""));
106 assert!(toml.contains("\"sign_commit\", \"pr:create\""));
107 assert!(toml.contains("expires_in = 86400"));
108 }
109
110 #[test]
111 fn format_agent_toml_minimal() {
112 let config = AgentProvisioningConfig {
113 agent_name: "solo".to_string(),
114 capabilities: vec![],
115 expires_in: None,
116 delegated_by: None,
117 storage_mode: AgentStorageMode::InMemory,
118 };
119 let toml = format_agent_toml("did:keri:E1", "k", &config);
120 assert!(!toml.contains("delegated_by"));
121 assert!(!toml.contains("[expiry]"));
122 }
123
124 #[test]
125 fn init_dryrun_shows_delegated_agent() {
126 let config = AgentProvisioningConfig {
130 agent_name: "deploy-bot".to_string(),
131 capabilities: vec![auths_keri::Capability::sign_commit()],
132 expires_in: None,
133 delegated_by: Some(IdentityDID::parse("did:keri:Eroot").unwrap()),
134 storage_mode: AgentStorageMode::Persistent { repo_path: None },
135 };
136 let toml = format_agent_toml("did:keri:E<pending>", "agent-key", &config);
137 assert!(
138 toml.contains("delegated identifier"),
139 "dry-run must frame the agent as a delegated identifier"
140 );
141 assert!(
142 toml.contains("delegated_by = \"did:keri:Eroot\""),
143 "dry-run must name the delegating root"
144 );
145 }
146}