Skip to main content

canic_host/icp/
identity.rs

1//! Module: icp::identity
2//!
3//! Responsibility: resolve the Principal of the active ICP CLI identity.
4//! Does not own: identity selection, authentication policy, or controller authorization.
5//! Boundary: callers compare the returned text with their own typed authority.
6
7use super::{error::IcpCommandError, model::IcpCli, run::run_output};
8
9impl IcpCli {
10    /// Return the Principal text for the identity that will execute ICP commands.
11    pub fn identity_principal_text(&self) -> Result<String, IcpCommandError> {
12        let mut command = self.identity_principal_command();
13        run_output(&mut command)
14    }
15
16    /// Return the selected identity's exact default account in the requested ledger format.
17    pub fn identity_account_id_text(
18        &self,
19        format: IcpIdentityAccountFormat,
20    ) -> Result<String, IcpCommandError> {
21        let mut command = self.identity_account_id_command(format);
22        run_output(&mut command)
23    }
24
25    fn identity_principal_command(&self) -> std::process::Command {
26        let mut command = self.command();
27        command.args(["identity", "principal"]);
28        command
29    }
30
31    fn identity_account_id_command(
32        &self,
33        format: IcpIdentityAccountFormat,
34    ) -> std::process::Command {
35        let mut command = self.command();
36        command.args(["identity", "account-id", "--format", format.label()]);
37        command
38    }
39}
40
41///
42/// IcpIdentityAccountFormat
43///
44/// Ledger account representation selected for one ICP CLI identity observation.
45///
46#[derive(Clone, Copy, Debug, Eq, PartialEq)]
47pub enum IcpIdentityAccountFormat {
48    IcpLedger,
49    Icrc1,
50}
51
52impl IcpIdentityAccountFormat {
53    const fn label(self) -> &'static str {
54        match self {
55            Self::IcpLedger => "ledger",
56            Self::Icrc1 => "icrc1",
57        }
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64    use crate::icp::command::command_display;
65
66    #[test]
67    fn identity_resolution_uses_the_active_identity_without_network_selection() {
68        let icp = IcpCli::new("icp", Some("ic".to_string())).with_cwd("/workspace/app");
69
70        assert_eq!(
71            command_display(&icp.identity_principal_command()),
72            "icp --project-root-override /workspace/app identity principal"
73        );
74    }
75
76    #[test]
77    fn account_resolution_selects_the_exact_ledger_representation() {
78        let icp = IcpCli::new("icp", Some("ic".to_string())).with_cwd("/workspace/app");
79
80        assert_eq!(
81            command_display(&icp.identity_account_id_command(IcpIdentityAccountFormat::Icrc1)),
82            "icp --project-root-override /workspace/app identity account-id --format icrc1"
83        );
84        assert_eq!(
85            command_display(&icp.identity_account_id_command(IcpIdentityAccountFormat::IcpLedger)),
86            "icp --project-root-override /workspace/app identity account-id --format ledger"
87        );
88    }
89}