Skip to main content

aster_server/routes/
utils.rs

1use aster::config::declarative_providers::load_provider;
2use aster::config::Config;
3use aster::providers::base::{ConfigKey, ProviderMetadata, ProviderType};
4use serde::{Deserialize, Serialize};
5use std::env;
6use std::error::Error;
7
8#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
9pub enum KeyLocation {
10    Environment,
11    ConfigFile,
12    Keychain,
13    NotFound,
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct KeyInfo {
18    pub name: String,
19    pub is_set: bool,
20    pub location: KeyLocation,
21    pub is_secret: bool,
22    pub value: Option<String>, // Only populated for non-secret keys that are set
23}
24
25/// Inspects a configuration key to determine if it's set, its location, and value (for non-secret keys)
26#[allow(dead_code)]
27pub fn inspect_key(key_name: &str, is_secret: bool) -> Result<KeyInfo, Box<dyn Error>> {
28    let config = Config::global();
29
30    // Check environment variable first
31    let env_value = env::var(key_name).ok();
32
33    if let Some(value) = env_value {
34        return Ok(KeyInfo {
35            name: key_name.to_string(),
36            is_set: true,
37            location: KeyLocation::Environment,
38            is_secret,
39            // Only include value for non-secret keys
40            value: if !is_secret { Some(value) } else { None },
41        });
42    }
43
44    // Check config store
45    let config_result = if is_secret {
46        config.get_secret(key_name).map(|v| (v, true))
47    } else {
48        config.get_param(key_name).map(|v| (v, false))
49    };
50
51    match config_result {
52        Ok((value, is_secret_actual)) => {
53            // Determine location based on whether it's a secret value
54            let location = if is_secret_actual {
55                KeyLocation::Keychain
56            } else {
57                KeyLocation::ConfigFile
58            };
59
60            Ok(KeyInfo {
61                name: key_name.to_string(),
62                is_set: true,
63                location,
64                is_secret: is_secret_actual,
65                // Only include value for non-secret keys
66                value: if !is_secret_actual { Some(value) } else { None },
67            })
68        }
69        Err(_) => Ok(KeyInfo {
70            name: key_name.to_string(),
71            is_set: false,
72            location: KeyLocation::NotFound,
73            is_secret,
74            value: None,
75        }),
76    }
77}
78
79/// Inspects multiple keys at once
80#[allow(dead_code)]
81pub fn inspect_keys(
82    keys: &[(String, bool)], // (name, is_secret) pairs
83) -> Result<Vec<KeyInfo>, Box<dyn Error>> {
84    let mut results = Vec::new();
85
86    for (key_name, is_secret) in keys {
87        let info = inspect_key(key_name, *is_secret)?;
88        results.push(info);
89    }
90
91    Ok(results)
92}
93
94pub fn check_provider_configured(metadata: &ProviderMetadata, provider_type: ProviderType) -> bool {
95    let config = Config::global();
96
97    if provider_type == ProviderType::Custom || provider_type == ProviderType::Declarative {
98        if let Ok(loaded_provider) = load_provider(metadata.name.as_str()) {
99            return config
100                .get_secret::<String>(&loaded_provider.config.api_key_env)
101                .is_ok();
102        }
103    }
104    // Special case: Zero-config providers (no config keys)
105    if metadata.config_keys.is_empty() {
106        // Check if the provider has been explicitly configured via the UI
107        let configured_marker = format!("{}_configured", metadata.name);
108        return config.get_param::<bool>(&configured_marker).is_ok();
109    }
110
111    // Get all required keys
112    let required_keys: Vec<&ConfigKey> = metadata
113        .config_keys
114        .iter()
115        .filter(|key| key.required)
116        .collect();
117
118    // Special case: If a provider has exactly one required key and that key
119    // has a default value, check if it's explicitly set
120    if required_keys.len() == 1 && required_keys[0].default.is_some() {
121        let key = &required_keys[0];
122
123        // Check if the key is explicitly set (either in env or config)
124        let is_set_in_env = env::var(&key.name).is_ok();
125        let is_set_in_config = config.get(&key.name, key.secret).is_ok();
126
127        return is_set_in_env || is_set_in_config;
128    }
129
130    // Special case: If a provider has only optional keys with defaults,
131    // check if a configuration marker exists
132    if required_keys.is_empty() && !metadata.config_keys.is_empty() {
133        let all_optional_with_defaults = metadata
134            .config_keys
135            .iter()
136            .all(|key| !key.required && key.default.is_some());
137
138        if all_optional_with_defaults {
139            // Check if the provider has been explicitly configured via the UI
140            let configured_marker = format!("{}_configured", metadata.name);
141            return config.get_param::<bool>(&configured_marker).is_ok();
142        }
143    }
144
145    // For providers with multiple keys or keys without defaults:
146    // Find required keys that don't have default values
147    let required_non_default_keys: Vec<&ConfigKey> = required_keys
148        .iter()
149        .filter(|key| key.default.is_none())
150        .cloned()
151        .collect();
152
153    // If there are no non-default keys, this provider needs at least one key explicitly set
154    if required_non_default_keys.is_empty() {
155        return required_keys.iter().any(|key| {
156            let is_set_in_env = env::var(&key.name).is_ok();
157            let is_set_in_config = config.get(&key.name, key.secret).is_ok();
158
159            is_set_in_env || is_set_in_config
160        });
161    }
162
163    // Otherwise, all non-default keys must be set
164    required_non_default_keys.iter().all(|key| {
165        let is_set_in_env = env::var(&key.name).is_ok();
166        let is_set_in_config = config.get(&key.name, key.secret).is_ok();
167
168        is_set_in_env || is_set_in_config
169    })
170}