(&self)
| 125 | |
| 126 | impl Command for Delegate { |
| 127 | fn run(&self) -> CliResult<()> { |
| 128 | let store = IdentityStore::open_default().map_err(|e| { |
| 129 | CliError::Internal(anyhow::anyhow!("Failed to open identity store: {e}")) |
| 130 | })?; |
| 131 | |
| 132 | let delegator = super::load_identity_or_default(&store, self.identity.as_deref())?; |
| 133 | if delegator.identity_type.is_delegated() || delegator.identity_type.is_agent() { |
| 134 | return Err(CliError::InvalidArgument { |
| 135 | message: format!("'{}' is an agent and cannot delegate", delegator.name), |
| 136 | }); |
| 137 | } |
| 138 | |
| 139 | // Resolve the delegate: either an identity in the local store, or the |
| 140 | // subject of a countersigned request. |
| 141 | let delegate = match (&self.request, &self.agent) { |
| 142 | (Some(path), _) => self.delegate_from_request(path)?, |
| 143 | (None, Some(name)) => store |
| 144 | .load_by_name(name) |
| 145 | .map_err(|_| CliError::IdentityNotFound(name.clone()))?, |
| 146 | (None, None) => { |
| 147 | return Err(CliError::InvalidArgument { |
| 148 | message: "name an agent identity, or pass --request <file> to countersign \ |
| 149 | a request" |
| 150 | .to_string(), |
| 151 | }) |
| 152 | } |
| 153 | }; |
| 154 | |
| 155 | let scope = self.build_scope()?; |
| 156 | let expires = self |
| 157 | .expires |
| 158 | .as_deref() |
| 159 | .map(parse_duration) |
| 160 | .transpose()? |
| 161 | .unwrap_or_else(|| chrono::Duration::days(DEFAULT_EXPIRY_DAYS)); |
| 162 | |
| 163 | let mut terms = Delegation::new(&delegator, &delegate, scope).expires_in(expires); |
| 164 | if let Some(agent_urn) = delegate |
| 165 | .metadata |
| 166 | .description |
| 167 | .as_deref() |
| 168 | .and_then(software_agent_from_description) |
| 169 | { |
| 170 | terms = terms.with_software_agent(agent_urn); |
| 171 | } |
| 172 | |
| 173 | let keypair = store.load_keypair(&delegator.id, None).map_err(|e| { |
| 174 | CliError::Internal(anyhow::anyhow!( |
| 175 | "Failed to load the signing key for '{}': {e}", |
| 176 | delegator.name |
| 177 | )) |
| 178 | })?; |
| 179 | let certificate = cert::mint(&delegator, &keypair, &terms); |
| 180 | let document = serde_json::to_string_pretty(&certificate).map_err(|e| { |
| 181 | CliError::Internal(anyhow::anyhow!("Failed to encode certificate: {e}")) |
| 182 | })?; |
| 183 | |
| 184 | // `--export` writes the wire form and nothing else, so the output is |
nothing calls this directly
no test coverage detected