auths_sdk/domains/identity/types.rs
1use auths_core::storage::keychain::{IdentityDID, KeyAlias};
2use auths_verifier::Capability;
3use auths_verifier::types::CanonicalDid;
4use std::path::PathBuf;
5
6use crate::domains::ci::types::{CiEnvironment, CiIdentityConfig};
7
8/// Policy for handling an existing identity during developer setup.
9///
10/// Replaces interactive CLI prompts with a typed enum that headless consumers
11/// can set programmatically.
12///
13/// Usage:
14/// ```ignore
15/// let config = CreateDeveloperIdentityConfig::builder("my-key")
16/// .with_conflict_policy(IdentityConflictPolicy::ReuseExisting)
17/// .build();
18/// ```
19#[derive(Debug, Clone, Default)]
20pub enum IdentityConflictPolicy {
21 /// Return an error if an identity already exists (default).
22 #[default]
23 Error,
24 /// Reuse the existing identity silently.
25 ReuseExisting,
26 /// Overwrite the existing identity with a new one.
27 ForceNew,
28}
29
30/// Configuration for provisioning a new developer identity.
31///
32/// Use [`CreateDeveloperIdentityConfigBuilder`] to construct this with optional fields.
33/// The registry backend is injected via [`crate::context::AuthsContext`] — this
34/// struct carries only serializable configuration values.
35///
36/// Args:
37/// * `key_alias`: Human-readable name for the key (e.g. "work-laptop").
38///
39/// Usage:
40/// ```ignore
41/// let config = CreateDeveloperIdentityConfig::builder("work-laptop")
42/// .with_platform(crate::types::PlatformVerification::GitHub { access_token: "ghp_abc".into() })
43/// .with_git_signing_scope(crate::types::GitSigningScope::Global)
44/// .build();
45/// ```
46#[derive(Debug)]
47pub struct CreateDeveloperIdentityConfig {
48 /// Human-readable name for the key (e.g. "work-laptop").
49 pub key_alias: KeyAlias,
50 /// Optional platform verification configuration.
51 pub platform: Option<crate::types::PlatformVerification>,
52 /// How to configure git commit signing.
53 pub git_signing_scope: crate::types::GitSigningScope,
54 /// Whether to register the identity on a remote registry.
55 pub register_on_registry: bool,
56 /// Remote registry URL, if registration is enabled.
57 pub registry_url: Option<String>,
58 /// What to do if an identity already exists.
59 pub conflict_policy: IdentityConflictPolicy,
60 /// Optional KERI witness configuration for the inception event.
61 pub witness_config: Option<auths_id::witness_config::WitnessConfig>,
62 /// Optional JSON metadata to attach to the identity.
63 pub metadata: Option<serde_json::Value>,
64 /// Path to the `auths-sign` binary, required when git signing is configured.
65 /// The CLI resolves this via `which::which("auths-sign")`.
66 pub sign_binary_path: Option<PathBuf>,
67 /// Override the default curve for key generation. Defaults to `CurveType::default()` (P-256).
68 pub curve: auths_crypto::CurveType,
69}
70
71impl CreateDeveloperIdentityConfig {
72 /// Creates a builder with the required key alias.
73 ///
74 /// Args:
75 /// * `key_alias`: Human-readable name for the key.
76 ///
77 /// Usage:
78 /// ```ignore
79 /// let builder = CreateDeveloperIdentityConfig::builder("my-key");
80 /// ```
81 pub fn builder(key_alias: KeyAlias) -> CreateDeveloperIdentityConfigBuilder {
82 CreateDeveloperIdentityConfigBuilder {
83 key_alias,
84 platform: None,
85 git_signing_scope: crate::types::GitSigningScope::Global,
86 register_on_registry: false,
87 registry_url: None,
88 conflict_policy: IdentityConflictPolicy::Error,
89 witness_config: None,
90 metadata: None,
91 sign_binary_path: None,
92 curve: auths_crypto::CurveType::default(),
93 }
94 }
95}
96
97/// Builder for [`CreateDeveloperIdentityConfig`].
98#[derive(Debug)]
99pub struct CreateDeveloperIdentityConfigBuilder {
100 key_alias: KeyAlias,
101 platform: Option<crate::types::PlatformVerification>,
102 git_signing_scope: crate::types::GitSigningScope,
103 register_on_registry: bool,
104 registry_url: Option<String>,
105 conflict_policy: IdentityConflictPolicy,
106 witness_config: Option<auths_id::witness_config::WitnessConfig>,
107 metadata: Option<serde_json::Value>,
108 sign_binary_path: Option<PathBuf>,
109 curve: auths_crypto::CurveType,
110}
111
112impl CreateDeveloperIdentityConfigBuilder {
113 /// Configures platform identity verification for the new identity.
114 ///
115 /// The SDK never opens a browser or runs OAuth flows. The caller must
116 /// obtain the access token beforehand and pass it here.
117 ///
118 /// Args:
119 /// * `platform`: The platform and access token to verify against.
120 ///
121 /// Usage:
122 /// ```ignore
123 /// let config = CreateDeveloperIdentityConfig::builder("my-key")
124 /// .with_platform(crate::types::PlatformVerification::GitHub {
125 /// access_token: "ghp_abc123".into(),
126 /// })
127 /// .build();
128 /// ```
129 pub fn with_platform(mut self, platform: crate::types::PlatformVerification) -> Self {
130 self.platform = Some(platform);
131 self
132 }
133
134 /// Sets the Git signing scope (local, global, or skip).
135 ///
136 /// Args:
137 /// * `scope`: How to configure `git config` for commit signing.
138 ///
139 /// Usage:
140 /// ```ignore
141 /// let config = CreateDeveloperIdentityConfig::builder("my-key")
142 /// .with_git_signing_scope(crate::types::GitSigningScope::Local {
143 /// repo_path: PathBuf::from("/path/to/repo"),
144 /// })
145 /// .build();
146 /// ```
147 pub fn with_git_signing_scope(mut self, scope: crate::types::GitSigningScope) -> Self {
148 self.git_signing_scope = scope;
149 self
150 }
151
152 /// Enables registration on a remote auths registry after identity creation.
153 ///
154 /// Args:
155 /// * `url`: The registry URL to register with.
156 ///
157 /// Usage:
158 /// ```ignore
159 /// let config = CreateDeveloperIdentityConfig::builder("my-key")
160 /// .with_registration("https://registry.auths.dev")
161 /// .build();
162 /// ```
163 pub fn with_registration(mut self, url: impl Into<String>) -> Self {
164 self.register_on_registry = true;
165 self.registry_url = Some(url.into());
166 self
167 }
168
169 /// Sets the policy for handling an existing identity at the registry path.
170 ///
171 /// Args:
172 /// * `policy`: What to do if an identity already exists.
173 ///
174 /// Usage:
175 /// ```ignore
176 /// let config = CreateDeveloperIdentityConfig::builder("my-key")
177 /// .with_conflict_policy(IdentityConflictPolicy::ReuseExisting)
178 /// .build();
179 /// ```
180 pub fn with_conflict_policy(mut self, policy: IdentityConflictPolicy) -> Self {
181 self.conflict_policy = policy;
182 self
183 }
184
185 /// Sets the witness configuration for the KERI inception event.
186 ///
187 /// Args:
188 /// * `config`: Witness endpoints and thresholds.
189 ///
190 /// Usage:
191 /// ```ignore
192 /// let config = CreateDeveloperIdentityConfig::builder("my-key")
193 /// .with_witness_config(witness_cfg)
194 /// .build();
195 /// ```
196 pub fn with_witness_config(mut self, config: auths_id::witness_config::WitnessConfig) -> Self {
197 self.witness_config = Some(config);
198 self
199 }
200
201 /// Attaches custom metadata to the identity (e.g. `created_at`, `setup_profile`).
202 ///
203 /// Args:
204 /// * `metadata`: Arbitrary JSON metadata.
205 ///
206 /// Usage:
207 /// ```ignore
208 /// let config = CreateDeveloperIdentityConfig::builder("my-key")
209 /// .with_metadata(serde_json::json!({"team": "platform"}))
210 /// .build();
211 /// ```
212 pub fn with_metadata(mut self, metadata: serde_json::Value) -> Self {
213 self.metadata = Some(metadata);
214 self
215 }
216
217 /// Sets the path to the `auths-sign` binary used for git signing configuration.
218 ///
219 /// Required when `git_signing_scope` is not `Skip`. The CLI resolves this via
220 /// `which::which("auths-sign")`.
221 ///
222 /// Args:
223 /// * `path`: Absolute path to the `auths-sign` binary.
224 ///
225 /// Usage:
226 /// ```ignore
227 /// let config = CreateDeveloperIdentityConfig::builder("my-key")
228 /// .with_sign_binary_path(PathBuf::from("/usr/local/bin/auths-sign"))
229 /// .build();
230 /// ```
231 pub fn with_sign_binary_path(mut self, path: PathBuf) -> Self {
232 self.sign_binary_path = Some(path);
233 self
234 }
235
236 /// Override the curve for key generation (default: P-256).
237 pub fn with_curve(mut self, curve: auths_crypto::CurveType) -> Self {
238 self.curve = curve;
239 self
240 }
241
242 /// Builds the final [`CreateDeveloperIdentityConfig`].
243 ///
244 /// Usage:
245 /// ```ignore
246 /// let config = CreateDeveloperIdentityConfig::builder("my-key").build();
247 /// ```
248 pub fn build(self) -> CreateDeveloperIdentityConfig {
249 CreateDeveloperIdentityConfig {
250 key_alias: self.key_alias,
251 platform: self.platform,
252 git_signing_scope: self.git_signing_scope,
253 register_on_registry: self.register_on_registry,
254 registry_url: self.registry_url,
255 conflict_policy: self.conflict_policy,
256 witness_config: self.witness_config,
257 metadata: self.metadata,
258 sign_binary_path: self.sign_binary_path,
259 curve: self.curve,
260 }
261 }
262}
263
264/// Selects which identity persona to provision via [`crate::setup::initialize`].
265///
266/// Usage:
267/// ```ignore
268/// // Developer preset (platform keychain, git signing):
269/// let config = IdentityConfig::developer(KeyAlias::new_unchecked("work-laptop"));
270///
271/// // CI preset (memory keychain, ephemeral):
272/// let config = IdentityConfig::ci(PathBuf::from("/tmp/.auths-ci"));
273///
274/// // Agent preset (minimal capabilities, long-lived):
275/// let config = IdentityConfig::agent(KeyAlias::new_unchecked("deploy-bot"), registry_path);
276///
277/// // Custom configuration:
278/// let config = IdentityConfig::Developer(
279/// CreateDeveloperIdentityConfig::builder(alias)
280/// .with_platform(crate::types::PlatformVerification::GitHub { access_token: token })
281/// .build()
282/// );
283/// ```
284#[derive(Debug)]
285pub enum IdentityConfig {
286 /// Full local developer setup: platform keychain, git signing, passphrase.
287 Developer(CreateDeveloperIdentityConfig),
288 /// Ephemeral CI setup: memory keychain, no git signing.
289 Ci(CiIdentityConfig),
290 /// Agent setup: file keychain, scoped capabilities, long-lived.
291 Agent(CreateAgentIdentityConfig),
292}
293
294impl IdentityConfig {
295 /// Create a developer identity config with sensible defaults.
296 ///
297 /// Args:
298 /// * `alias`: Human-readable key alias (e.g. `"work-laptop"`).
299 ///
300 /// Usage:
301 /// ```ignore
302 /// let config = IdentityConfig::developer(KeyAlias::new_unchecked("work-laptop"));
303 /// ```
304 pub fn developer(alias: KeyAlias) -> Self {
305 Self::Developer(CreateDeveloperIdentityConfig::builder(alias).build())
306 }
307
308 /// Create a CI/ephemeral identity config.
309 ///
310 /// Args:
311 /// * `registry_path`: Path to the ephemeral auths registry directory.
312 ///
313 /// Usage:
314 /// ```ignore
315 /// let config = IdentityConfig::ci(PathBuf::from("/tmp/.auths-ci"));
316 /// ```
317 pub fn ci(registry_path: impl Into<PathBuf>) -> Self {
318 let registry_path = registry_path.into();
319 let keychain_file = registry_path.join("keys.enc");
320 Self::Ci(CiIdentityConfig {
321 ci_environment: CiEnvironment::Unknown,
322 registry_path,
323 keychain_file,
324 passphrase: crate::domains::ci::types::DEFAULT_CI_PASSPHRASE.to_string(),
325 })
326 }
327
328 /// Create an agent identity config with sensible defaults.
329 ///
330 /// Args:
331 /// * `alias`: Human-readable agent name.
332 /// * `registry_path`: Path to the auths registry directory.
333 ///
334 /// Usage:
335 /// ```ignore
336 /// let config = IdentityConfig::agent(KeyAlias::new_unchecked("deploy-bot"), registry_path);
337 /// ```
338 pub fn agent(alias: KeyAlias, registry_path: impl Into<PathBuf>) -> Self {
339 Self::Agent(CreateAgentIdentityConfig::builder(alias, registry_path).build())
340 }
341}
342
343/// Configuration for agent identity.
344///
345/// Use [`CreateAgentIdentityConfigBuilder`] to construct this with optional fields.
346///
347/// Args:
348/// * `alias`: Human-readable name for the agent.
349/// * `parent_identity_did`: The DID of the identity that owns this agent.
350/// * `registry_path`: Path to the auths registry.
351///
352/// Usage:
353/// ```ignore
354/// let config = CreateAgentIdentityConfig::builder("deploy-bot", "did:keri:abc123", path)
355/// .with_capabilities(vec!["sign-commit".into()])
356/// .build();
357/// ```
358#[derive(Debug)]
359pub struct CreateAgentIdentityConfig {
360 /// Human-readable name for the agent.
361 pub alias: KeyAlias,
362 /// Capabilities granted to the agent.
363 pub capabilities: Vec<Capability>,
364 /// DID of the parent identity that delegates authority.
365 pub parent_identity_did: Option<String>,
366 /// Path to the auths registry directory.
367 pub registry_path: PathBuf,
368 /// Duration in seconds until expiration (per RFC 6749).
369 pub expires_in: Option<u64>,
370 /// If true, construct state without persisting.
371 pub dry_run: bool,
372}
373
374impl CreateAgentIdentityConfig {
375 /// Creates a builder with alias and registry path.
376 ///
377 /// Args:
378 /// * `alias`: Human-readable name for the agent.
379 /// * `registry_path`: Path to the auths registry directory.
380 ///
381 /// Usage:
382 /// ```ignore
383 /// let builder = CreateAgentIdentityConfig::builder("deploy-bot", path);
384 /// ```
385 pub fn builder(
386 alias: KeyAlias,
387 registry_path: impl Into<PathBuf>,
388 ) -> CreateAgentIdentityConfigBuilder {
389 CreateAgentIdentityConfigBuilder {
390 alias,
391 capabilities: Vec::new(),
392 parent_identity_did: None,
393 registry_path: registry_path.into(),
394 expires_in: None,
395 dry_run: false,
396 }
397 }
398}
399
400/// Builder for [`CreateAgentIdentityConfig`].
401#[derive(Debug)]
402pub struct CreateAgentIdentityConfigBuilder {
403 alias: KeyAlias,
404 capabilities: Vec<Capability>,
405 parent_identity_did: Option<String>,
406 registry_path: PathBuf,
407 expires_in: Option<u64>,
408 dry_run: bool,
409}
410
411impl CreateAgentIdentityConfigBuilder {
412 /// Sets the parent identity DID that delegates authority to this agent.
413 ///
414 /// Args:
415 /// * `did`: The DID of the owning identity.
416 ///
417 /// Usage:
418 /// ```ignore
419 /// let config = CreateAgentIdentityConfig::builder("bot", path)
420 /// .with_parent_did("did:keri:abc123")
421 /// .build();
422 /// ```
423 pub fn with_parent_did(mut self, did: impl Into<String>) -> Self {
424 self.parent_identity_did = Some(did.into());
425 self
426 }
427
428 /// Sets the capabilities granted to the agent.
429 ///
430 /// Args:
431 /// * `capabilities`: List of capabilities.
432 ///
433 /// Usage:
434 /// ```ignore
435 /// let config = CreateAgentIdentityConfig::builder("bot", path)
436 /// .with_capabilities(vec![Capability::sign_commit()])
437 /// .build();
438 /// ```
439 pub fn with_capabilities(mut self, capabilities: Vec<Capability>) -> Self {
440 self.capabilities = capabilities;
441 self
442 }
443
444 /// Sets the agent key expiration time in seconds.
445 ///
446 /// Args:
447 /// * `secs`: Seconds until the agent identity expires.
448 ///
449 /// Usage:
450 /// ```ignore
451 /// let config = CreateAgentIdentityConfig::builder("bot", path)
452 /// .with_expiry(86400) // 24 hours
453 /// .build();
454 /// ```
455 pub fn with_expiry(mut self, secs: u64) -> Self {
456 self.expires_in = Some(secs);
457 self
458 }
459
460 /// Enables dry-run mode (constructs state without persisting).
461 ///
462 /// Usage:
463 /// ```ignore
464 /// let config = CreateAgentIdentityConfig::builder("bot", path)
465 /// .dry_run(true)
466 /// .build();
467 /// ```
468 pub fn dry_run(mut self, enabled: bool) -> Self {
469 self.dry_run = enabled;
470 self
471 }
472
473 /// Builds the final [`CreateAgentIdentityConfig`].
474 ///
475 /// Usage:
476 /// ```ignore
477 /// let config = CreateAgentIdentityConfig::builder("bot", path).build();
478 /// ```
479 pub fn build(self) -> CreateAgentIdentityConfig {
480 CreateAgentIdentityConfig {
481 alias: self.alias,
482 capabilities: self.capabilities,
483 parent_identity_did: self.parent_identity_did,
484 registry_path: self.registry_path,
485 expires_in: self.expires_in,
486 dry_run: self.dry_run,
487 }
488 }
489}
490
491/// Configuration for rotating an identity's signing keys.
492///
493/// Args:
494/// * `repo_path`: Path to the auths registry (typically `~/.auths`).
495/// * `identity_key_alias`: Keychain alias of the current signing key.
496/// If `None`, the first non-next alias for the identity is used.
497/// * `next_key_alias`: Keychain alias to store the new key under.
498/// Defaults to `<identity_key_alias>-rotated-<timestamp>`.
499///
500/// Usage:
501/// ```ignore
502/// let config = IdentityRotationConfig {
503/// repo_path: PathBuf::from("/home/user/.auths"),
504/// identity_key_alias: Some("main".into()),
505/// next_key_alias: None,
506/// };
507/// ```
508#[derive(Debug)]
509pub struct IdentityRotationConfig {
510 /// Path to the auths registry (typically `~/.auths`).
511 pub repo_path: PathBuf,
512 /// Keychain alias of the current signing key (auto-detected if `None`).
513 pub identity_key_alias: Option<KeyAlias>,
514 /// Keychain alias for the new rotated key (auto-generated if `None`).
515 pub next_key_alias: Option<KeyAlias>,
516}
517
518// Result types for identity operations
519
520/// Outcome of a successful developer identity setup.
521///
522/// Usage:
523/// ```ignore
524/// let result = initialize(IdentityConfig::developer(alias), &ctx, keychain, &signer, &provider, git_cfg)?;
525/// if let InitializeResult::Developer(r) = result {
526/// println!("Created identity: {}", r.identity_did);
527/// }
528/// ```
529#[derive(Debug, Clone)]
530pub struct DeveloperIdentityResult {
531 /// The controller DID of the created identity.
532 pub identity_did: IdentityDID,
533 /// The device DID bound to this identity.
534 pub device_did: CanonicalDid,
535 /// The keychain alias used for the signing key.
536 pub key_alias: KeyAlias,
537 /// Result of platform verification, if performed.
538 pub platform_claim: Option<crate::result::PlatformClaimResult>,
539 /// Whether git commit signing was configured.
540 pub git_signing_configured: bool,
541 /// Result of registry registration, if performed.
542 pub registered: Option<RegistrationOutcome>,
543}
544
545/// Outcome of a successful CI/ephemeral identity setup.
546///
547/// Usage:
548/// ```ignore
549/// let result = initialize(IdentityConfig::ci(registry_path), &ctx, keychain, &signer, &provider, None)?;
550/// if let InitializeResult::Ci(r) = result {
551/// for line in &r.env_block { println!("{line}"); }
552/// }
553/// ```
554#[derive(Debug, Clone)]
555pub struct CiIdentityResult {
556 /// The controller DID of the CI identity.
557 pub identity_did: IdentityDID,
558 /// The device DID bound to this CI identity.
559 pub device_did: CanonicalDid,
560 /// Shell `export` lines for configuring CI environment variables.
561 pub env_block: Vec<String>,
562}
563
564/// Outcome of a successful agent identity setup.
565///
566/// Usage:
567/// ```ignore
568/// let result = initialize(IdentityConfig::agent(alias, path), &ctx, keychain, &signer, &provider, None)?;
569/// if let InitializeResult::Agent(r) = result {
570/// println!("Agent {:?} delegated by {:?}", r.agent_did, r.parent_did);
571/// }
572/// ```
573#[derive(Debug, Clone)]
574pub struct AgentIdentityResult {
575 /// The DID of the newly created agent identity (None for dry-run proposals).
576 pub agent_did: Option<IdentityDID>,
577 /// The DID of the parent identity that delegated authority (None if no parent).
578 pub parent_did: Option<IdentityDID>,
579 /// The capabilities granted to the agent.
580 pub capabilities: Vec<Capability>,
581}
582
583/// Outcome of [`crate::setup::initialize`] — one variant per identity persona.
584///
585/// Usage:
586/// ```ignore
587/// match initialize(config, &ctx, keychain, &signer, &provider, git_cfg)? {
588/// InitializeResult::Developer(r) => display_developer_result(r),
589/// InitializeResult::Ci(r) => display_ci_result(r),
590/// InitializeResult::Agent(r) => display_agent_result(r),
591/// }
592/// ```
593#[derive(Debug, Clone)]
594pub enum InitializeResult {
595 /// Developer identity result.
596 Developer(DeveloperIdentityResult),
597 /// CI/ephemeral identity result.
598 Ci(CiIdentityResult),
599 /// Agent identity result.
600 Agent(AgentIdentityResult),
601}
602
603/// Outcome of a successful identity rotation.
604///
605/// Usage:
606/// ```ignore
607/// let result: IdentityRotationResult = rotate_identity(config, provider)?;
608/// println!("Rotated DID: {}", result.controller_did);
609/// println!("New key: {}...", result.new_key_fingerprint);
610/// println!("Old key: {}...", result.previous_key_fingerprint);
611/// ```
612#[derive(Debug, Clone)]
613pub struct IdentityRotationResult {
614 /// The controller DID of the rotated identity.
615 pub controller_did: IdentityDID,
616 /// Hex-encoded fingerprint of the new signing key.
617 pub new_key_fingerprint: String,
618 /// Hex-encoded fingerprint of the previous signing key.
619 pub previous_key_fingerprint: String,
620 /// KERI sequence number after this rotation event.
621 pub sequence: u128,
622 /// The alias the rotated-in signing key is stored under. Stays equal to the
623 /// pre-rotation alias by default (stable alias); differs only when the
624 /// caller passed an explicit `next_key_alias`.
625 pub new_key_alias: String,
626}
627
628/// Outcome of a successful registry registration.
629///
630/// Usage:
631/// ```ignore
632/// if let Some(reg) = result.registered {
633/// println!("Registered {} at {}", reg.did, reg.registry);
634/// }
635/// ```
636#[derive(Debug, Clone)]
637pub struct RegistrationOutcome {
638 /// The DID returned by the registry (e.g. `did:keri:EABC...`).
639 pub did: IdentityDID,
640 /// The registry URL where the identity was registered.
641 pub registry: String,
642 /// Number of platform claims indexed by the registry.
643 pub platform_claims_indexed: usize,
644}