development
rs 44 lines 1.82 KB
Raw
1 //! Credential resolution from the environment.
2
3 use smbcloud_ascapi_core::ApiKey;
4 use smbcloud_ascapi_core::Error;
5
6 /// Resolve an App Store Connect API key from the environment.
7 ///
8 /// Deliberately per-call rather than at startup: an MCP server that
9 /// refuses to start without credentials cannot answer `tools/list`, which
10 /// is the first thing every client asks and the only way a user discovers
11 /// what configuration is missing. Unconfigured servers should list their
12 /// tools and fail with a useful message when one is called.
13 pub fn api_key_from_env() -> Result<ApiKey, String> {
14 let key_id = std::env::var("ASC_API_KEY")
15 .map_err(|_| "ASC_API_KEY is not set (App Store Connect API key ID)".to_string())?;
16 let issuer_id = std::env::var("ASC_ISSUER_ID")
17 .map_err(|_| "ASC_ISSUER_ID is not set (App Store Connect issuer ID)".to_string())?;
18
19 let path = match std::env::var("ASC_PRIVATE_KEY_PATH") {
20 Ok(path) => std::path::PathBuf::from(path),
21 Err(_) => {
22 let home = std::env::var("HOME").map_err(|_| {
23 "neither ASC_PRIVATE_KEY_PATH nor HOME is set, so the .p8 key cannot be located"
24 .to_string()
25 })?;
26 std::path::PathBuf::from(home)
27 .join(".appstoreconnect")
28 .join("private_keys")
29 .join(format!("AuthKey_{key_id}.p8"))
30 }
31 };
32
33 ApiKey::from_p8_file(&key_id, &issuer_id, &path).map_err(|error| match error {
34 // The most common misconfiguration by a wide margin, and the
35 // default-path message needs to name the path it guessed.
36 Error::PrivateKeyRead { .. } => {
37 format!(
38 "could not read the App Store Connect private key at {}",
39 path.display()
40 )
41 }
42 other => other.to_string(),
43 })
44 }