botserver/src/core/package_manager/mod.rs

149 lines
6.2 KiB
Rust
Raw Normal View History

pub mod cache;
2025-11-22 22:55:35 -03:00
pub mod component;
pub mod installer;
pub mod os;
pub mod setup;
pub mod alm_setup;
pub use cache::{CacheResult, DownloadCache};
2025-11-22 22:55:35 -03:00
pub use installer::PackageManager;
pub mod cli;
pub mod facade;
use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
2025-11-22 22:55:35 -03:00
pub enum InstallMode {
Local,
Container,
}
#[derive(Debug, Clone, PartialEq, Eq)]
2025-11-22 22:55:35 -03:00
pub enum OsType {
Linux,
MacOS,
Windows,
}
#[derive(Debug)]
pub struct ComponentInfo {
pub name: &'static str,
pub termination_command: &'static str,
}
pub fn get_all_components() -> Vec<ComponentInfo> {
vec![
ComponentInfo {
name: "tables",
termination_command: "postgres",
},
ComponentInfo {
name: "cache",
termination_command: "redis-server",
},
ComponentInfo {
name: "drive",
termination_command: "minio",
},
ComponentInfo {
name: "llm",
termination_command: "llama-server",
},
]
}
pub use alm_setup::setup_alm;
/// Initialize Directory (Zitadel) with default admin user and OAuth application
/// This should be called after Zitadel has started and is responding
#[cfg(feature = "directory")]
pub async fn setup_directory() -> anyhow::Result<crate::core::package_manager::setup::DirectoryConfig> {
use std::path::PathBuf;
use std::collections::HashMap;
let stack_path = std::env::var("BOTSERVER_STACK_PATH")
.unwrap_or_else(|_| "./botserver-stack".to_string());
let base_url = "http://localhost:8300".to_string();
let config_path = PathBuf::from(&stack_path).join("conf/system/directory_config.json");
// Check if config already exists in Vault first
if let Ok(secrets_manager) = crate::core::secrets::SecretsManager::from_env() {
if secrets_manager.is_enabled() {
if let Ok(secrets) = secrets_manager.get_secret(crate::core::secrets::SecretPaths::DIRECTORY).await {
if let (Some(client_id), Some(client_secret)) = (secrets.get("client_id"), secrets.get("client_secret")) {
// Validate that credentials are real, not placeholders
let is_valid = !client_id.is_empty()
&& !client_secret.is_empty()
&& client_secret != "..."
&& client_id.contains('@') // OAuth client IDs contain @
&& client_secret.len() > 10; // Real secrets are longer than placeholders
if is_valid {
log::info!("Directory already configured with OAuth client in Vault");
// Reconstruct config from Vault
let config = crate::core::package_manager::setup::DirectoryConfig {
base_url: base_url.clone(),
issuer_url: secrets.get("issuer_url").cloned().unwrap_or_else(|| base_url.clone()),
issuer: secrets.get("issuer").cloned().unwrap_or_else(|| base_url.clone()),
client_id: client_id.clone(),
client_secret: client_secret.clone(),
redirect_uri: secrets.get("redirect_uri").cloned().unwrap_or_else(|| "http://localhost:3000/auth/callback".to_string()),
project_id: secrets.get("project_id").cloned().unwrap_or_default(),
api_url: secrets.get("api_url").cloned().unwrap_or_else(|| base_url.clone()),
service_account_key: secrets.get("service_account_key").cloned(),
};
return Ok(config);
}
}
}
}
}
// Check if config already exists with valid OAuth client in file
if config_path.exists() {
if let Ok(content) = std::fs::read_to_string(&config_path) {
if let Ok(config) = serde_json::from_str::<crate::core::package_manager::setup::DirectoryConfig>(&content) {
// Validate that credentials are real, not placeholders
let is_valid = !config.client_id.is_empty()
&& !config.client_secret.is_empty()
&& config.client_secret != "..."
&& config.client_id.contains('@')
&& config.client_secret.len() > 10;
if is_valid {
log::info!("Directory already configured with OAuth client");
return Ok(config);
}
}
}
}
// Initialize directory with default credentials
let mut directory_setup = crate::core::package_manager::setup::DirectorySetup::new(base_url.clone(), config_path.clone());
let config = directory_setup.initialize().await
.map_err(|e| anyhow::anyhow!("Failed to initialize directory: {}", e))?;
// Store credentials in Vault
if let Ok(secrets_manager) = crate::core::secrets::SecretsManager::from_env() {
if secrets_manager.is_enabled() {
let mut secrets = HashMap::new();
secrets.insert("url".to_string(), config.base_url.clone());
secrets.insert("issuer_url".to_string(), config.issuer_url.clone());
secrets.insert("issuer".to_string(), config.issuer.clone());
secrets.insert("client_id".to_string(), config.client_id.clone());
secrets.insert("client_secret".to_string(), config.client_secret.clone());
secrets.insert("redirect_uri".to_string(), config.redirect_uri.clone());
secrets.insert("project_id".to_string(), config.project_id.clone());
secrets.insert("api_url".to_string(), config.api_url.clone());
if let Some(key) = &config.service_account_key {
secrets.insert("service_account_key".to_string(), key.clone());
}
match secrets_manager.put_secret(crate::core::secrets::SecretPaths::DIRECTORY, secrets).await {
Ok(_) => log::info!("Directory credentials stored in Vault"),
Err(e) => log::warn!("Failed to store directory credentials in Vault: {}", e),
}
}
}
Ok(config)
}