refactor: Replace all hardcoded ./botserver-stack paths with get_stack_path()/get_work_path()
Some checks failed
BotServer CI/CD / build (push) Failing after 1m28s

- Adds get_stack_path() helper: returns /opt/gbo in production (.env without botserver-stack), ./botserver-stack in dev
- Adds get_work_path() helper: returns /opt/gbo/work in production, ./botserver-stack/data/system/work in dev
- Updated 35+ files to use dynamic path resolution
- Production system container no longer needs botserver-stack directory
- Work files go to /opt/gbo/work instead of /opt/gbo/bin/botserver-stack
This commit is contained in:
Rodrigo Rodriguez (Pragmatismo) 2026-04-04 09:24:44 -03:00
parent c05e40d35b
commit 7d8f141fc2
35 changed files with 201 additions and 145 deletions

View file

@ -863,7 +863,7 @@ Respond ONLY with valid JSON."#
.config .config
.as_ref() .as_ref()
.map(|c| c.site_path.clone()) .map(|c| c.site_path.clone())
.unwrap_or_else(|| "./botserver-stack/sites".to_string()) .unwrap_or_else(|| format!("{}/sites", crate::core::shared::utils::get_stack_path()))
} }
fn read_file( fn read_file(

View file

@ -1103,7 +1103,7 @@ END TRIGGER
.config .config
.as_ref() .as_ref()
.map(|c| c.site_path.clone()) .map(|c| c.site_path.clone())
.unwrap_or_else(|| "./botserver-stack/sites".to_string()); .unwrap_or_else(|| format!("{}/sites", crate::core::shared::utils::get_stack_path()));
let full_path = format!("{}/{}.gbai/{}", site_path, bot_id, path); let full_path = format!("{}/{}.gbai/{}", site_path, bot_id, path);

View file

@ -1,5 +1,6 @@
use crate::core::shared::get_content_type; use crate::core::shared::get_content_type;
use crate::core::shared::state::AppState; use crate::core::shared::state::AppState;
use crate::core::shared::utils::get_stack_path;
use axum::{ use axum::{
body::Body, body::Body,
extract::{Path, State}, extract::{Path, State},
@ -101,7 +102,7 @@ pub async fn serve_vendor_file(
let local_paths = [ let local_paths = [
format!("./botui/ui/suite/js/vendor/{}", file_path), format!("./botui/ui/suite/js/vendor/{}", file_path),
format!("../botui/ui/suite/js/vendor/{}", file_path), format!("../botui/ui/suite/js/vendor/{}", file_path),
format!("./botserver-stack/static/js/vendor/{}", file_path), format!("{}/static/js/vendor/{}", get_stack_path(), file_path),
]; ];
for local_path in &local_paths { for local_path in &local_paths {
@ -351,7 +352,7 @@ async fn serve_app_file_internal(state: &AppState, app_name: &str, file_path: &s
.config .config
.as_ref() .as_ref()
.map(|c| c.site_path.clone()) .map(|c| c.site_path.clone())
.unwrap_or_else(|| "./botserver-stack/sites".to_string()); .unwrap_or_else(|| format!("{}/sites", get_stack_path()));
let full_path = format!( let full_path = format!(
"{}/{}.gbai/{}.gbapp/{}/{}", "{}/{}.gbai/{}.gbapp/{}/{}",
@ -403,7 +404,7 @@ pub async fn list_all_apps(State(state): State<Arc<AppState>>) -> impl IntoRespo
.config .config
.as_ref() .as_ref()
.map(|c| c.site_path.clone()) .map(|c| c.site_path.clone())
.unwrap_or_else(|| "./botserver-stack/sites".to_string()); .unwrap_or_else(|| format!("{}/sites", get_stack_path()));
let mut apps = Vec::new(); let mut apps = Vec::new();

View file

@ -1,5 +1,6 @@
use crate::core::shared::models::UserSession; use crate::core::shared::models::UserSession;
use crate::core::shared::state::AppState; use crate::core::shared::state::AppState;
use crate::core::shared::utils::get_work_path;
use log::{error, trace}; use log::{error, trace};
use rhai::{Array, Dynamic, Engine, Map}; use rhai::{Array, Dynamic, Engine, Map};
use serde_json::Value; use serde_json::Value;
@ -237,7 +238,7 @@ fn resolve_file_path(
.config .config
.as_ref() .as_ref()
.map(|c| c.data_dir.as_str()) .map(|c| c.data_dir.as_str())
.unwrap_or("./botserver-stack/data"); .unwrap_or(&get_work_path());
let base_path = format!("{}/bots/{}/gbdrive", data_dir, user.bot_id); let base_path = format!("{}/bots/{}/gbdrive", data_dir, user.bot_id);
let full_path = format!("{}/{}", base_path, file_path); let full_path = format!("{}/{}", base_path, file_path);
@ -267,7 +268,7 @@ fn resolve_export_path(
.config .config
.as_ref() .as_ref()
.map(|c| c.data_dir.as_str()) .map(|c| c.data_dir.as_str())
.unwrap_or("./botserver-stack/data"); .unwrap_or(&get_work_path());
let base_path = format!("{}/bots/{}/gbdrive", data_dir, user.bot_id); let base_path = format!("{}/bots/{}/gbdrive", data_dir, user.bot_id);
std::fs::create_dir_all(&base_path)?; std::fs::create_dir_all(&base_path)?;

View file

@ -252,7 +252,7 @@ fn execute_qr_code_generation(
.config .config
.as_ref() .as_ref()
.map(|c| c.data_dir.as_str()) .map(|c| c.data_dir.as_str())
.unwrap_or("./botserver-stack/data"); .unwrap_or(&crate::core::shared::utils::get_work_path());
let final_path = match output_path { let final_path = match output_path {
Some(path) => { Some(path) => {

View file

@ -145,9 +145,8 @@ fn associate_tool_with_session(
// Check if tool's .mcp.json file exists in work directory // Check if tool's .mcp.json file exists in work directory
// Use relative path from botserver binary current directory // Use relative path from botserver binary current directory
let gb_dir = std::env::current_dir() let gb_dir =
.unwrap_or_else(|_| PathBuf::from(".")) std::path::PathBuf::from(crate::core::shared::utils::get_stack_path()).join("data/system");
.join("botserver-stack/data/system");
// Get bot name to construct the path // Get bot name to construct the path
let bot_name = get_bot_name_from_id(state, &user.bot_id)?; let bot_name = get_bot_name_from_id(state, &user.bot_id)?;

View file

@ -120,7 +120,7 @@ impl Default for WizardConfig {
organization: OrgConfig::default(), organization: OrgConfig::default(),
template: None, template: None,
install_mode: InstallMode::Development, install_mode: InstallMode::Development,
data_dir: PathBuf::from("./botserver-stack"), data_dir: PathBuf::from(crate::core::shared::utils::get_stack_path()),
} }
} }
} }
@ -839,7 +839,7 @@ pub fn load_wizard_config(path: &str) -> io::Result<WizardConfig> {
} }
pub fn should_run_wizard() -> bool { pub fn should_run_wizard() -> bool {
!std::path::Path::new("./botserver-stack").exists() !std::path::Path::new(&crate::core::shared::utils::get_stack_path()).exists()
&& !std::path::Path::new("/opt/gbo").exists() && !std::path::Path::new("/opt/gbo").exists()
} }

View file

@ -3,6 +3,7 @@ use crate::core::bootstrap::bootstrap_types::{BootstrapManager, BootstrapProgres
use crate::core::bootstrap::bootstrap_utils::{alm_ci_health_check, alm_health_check, cache_health_check, drive_health_check, safe_pkill, tables_health_check, vault_health_check, vector_db_health_check, zitadel_health_check}; use crate::core::bootstrap::bootstrap_utils::{alm_ci_health_check, alm_health_check, cache_health_check, drive_health_check, safe_pkill, tables_health_check, vault_health_check, vector_db_health_check, zitadel_health_check};
use crate::core::config::AppConfig; use crate::core::config::AppConfig;
use crate::core::package_manager::{InstallMode, PackageManager}; use crate::core::package_manager::{InstallMode, PackageManager};
use crate::core::shared::utils::get_stack_path;
use crate::security::command_guard::SafeCommand; use crate::security::command_guard::SafeCommand;
use log::{info, warn}; use log::{info, warn};
use std::path::PathBuf; use std::path::PathBuf;
@ -10,9 +11,7 @@ use tokio::time::{sleep, Duration};
impl BootstrapManager { impl BootstrapManager {
pub fn new(mode: InstallMode, tenant: Option<String>) -> Self { pub fn new(mode: InstallMode, tenant: Option<String>) -> Self {
let stack_path = std::env::var("BOTSERVER_STACK_PATH") let stack_path = PathBuf::from(get_stack_path());
.map(PathBuf::from)
.unwrap_or_else(|_| PathBuf::from("./botserver-stack"));
Self { Self {
install_mode: mode, install_mode: mode,
@ -28,7 +27,7 @@ impl BootstrapManager {
pub fn vault_bin(&self) -> String { pub fn vault_bin(&self) -> String {
self.stack_dir("bin/vault/vault") self.stack_dir("bin/vault/vault")
.to_str() .to_str()
.unwrap_or("./botserver-stack/bin/vault/vault") .unwrap_or(&get_stack_path())
.to_string() .to_string()
} }

View file

@ -1,23 +1,25 @@
// Bootstrap utility functions // Bootstrap utility functions
use crate::core::shared::utils::get_stack_path;
use crate::security::command_guard::SafeCommand; use crate::security::command_guard::SafeCommand;
use log::{debug, info, warn}; use log::{debug, info, warn};
/// Get list of processes to kill /// Get list of processes to kill (only used in dev with local botserver-stack)
pub fn get_processes_to_kill() -> Vec<(&'static str, Vec<&'static str>)> { pub fn get_processes_to_kill() -> Vec<(&'static str, Vec<&'static str>)> {
let stack = get_stack_path();
vec![ vec![
("botserver-stack/bin/vault", vec!["-9", "-f"]), (&format!("{}/bin/vault", stack), vec!["-9", "-f"]),
("botserver-stack/bin/tables", vec!["-9", "-f"]), (&format!("{}/bin/tables", stack), vec!["-9", "-f"]),
("botserver-stack/bin/drive", vec!["-9", "-f"]), (&format!("{}/bin/drive", stack), vec!["-9", "-f"]),
("botserver-stack/bin/cache", vec!["-9", "-f"]), (&format!("{}/bin/cache", stack), vec!["-9", "-f"]),
("botserver-stack/bin/directory", vec!["-9", "-f"]), (&format!("{}/bin/directory", stack), vec!["-9", "-f"]),
("botserver-stack/bin/llm", vec!["-9", "-f"]), (&format!("{}/bin/llm", stack), vec!["-9", "-f"]),
("botserver-stack/bin/email", vec!["-9", "-f"]), (&format!("{}/bin/email", stack), vec!["-9", "-f"]),
("botserver-stack/bin/proxy", vec!["-9", "-f"]), (&format!("{}/bin/proxy", stack), vec!["-9", "-f"]),
("botserver-stack/bin/dns", vec!["-9", "-f"]), (&format!("{}/bin/dns", stack), vec!["-9", "-f"]),
("botserver-stack/bin/meeting", vec!["-9", "-f"]), (&format!("{}/bin/meeting", stack), vec!["-9", "-f"]),
("botserver-stack/bin/vector_db", vec!["-9", "-f"]), (&format!("{}/bin/vector_db", stack), vec!["-9", "-f"]),
("botserver-stack/bin/zitadel", vec!["-9", "-f"]), (&format!("{}/bin/zitadel", stack), vec!["-9", "-f"]),
("botserver-stack/bin/alm", vec!["-9", "-f"]), (&format!("{}/bin/alm", stack), vec!["-9", "-f"]),
("forgejo", vec!["-9", "-f"]), ("forgejo", vec!["-9", "-f"]),
("caddy", vec!["-9", "-f"]), ("caddy", vec!["-9", "-f"]),
("postgres", vec!["-9", "-f"]), ("postgres", vec!["-9", "-f"]),
@ -130,7 +132,8 @@ pub fn cache_health_check() -> bool {
} }
} }
if let Ok(output) = SafeCommand::new("./botserver-stack/bin/cache/bin/valkey-cli") let stack_path = get_stack_path();
if let Ok(output) = SafeCommand::new(&format!("{}/bin/cache/bin/valkey-cli", stack_path))
.and_then(|c| c.args(&["ping"])) .and_then(|c| c.args(&["ping"]))
.and_then(|c| c.execute()) .and_then(|c| c.execute())
{ {
@ -265,8 +268,7 @@ pub fn tables_health_check() -> bool {
return output.status.success(); return output.status.success();
} }
let stack_path = let stack_path = get_stack_path();
std::env::var("BOTSERVER_STACK_PATH").unwrap_or_else(|_| "./botserver-stack".to_string());
let pg_isready = format!("{}/bin/tables/bin/pg_isready", stack_path); let pg_isready = format!("{}/bin/tables/bin/pg_isready", stack_path);
if let Ok(output) = SafeCommand::new(&pg_isready) if let Ok(output) = SafeCommand::new(&pg_isready)
.and_then(|c| c.args(&["-h", "127.0.0.1", "-p", "5432"])) .and_then(|c| c.args(&["-h", "127.0.0.1", "-p", "5432"]))

View file

@ -2,6 +2,7 @@
//! //!
//! Extracted from mod.rs //! Extracted from mod.rs
use crate::core::shared::utils::get_stack_path;
use crate::security::command_guard::SafeCommand; use crate::security::command_guard::SafeCommand;
use log::warn; use log::warn;
use std::fs; use std::fs;
@ -9,8 +10,7 @@ use std::path::PathBuf;
/// Check if another instance is already running /// Check if another instance is already running
pub fn check_single_instance() -> Result<bool, Box<dyn std::error::Error>> { pub fn check_single_instance() -> Result<bool, Box<dyn std::error::Error>> {
let stack_path = std::env::var("BOTSERVER_STACK_PATH") let stack_path = get_stack_path();
.unwrap_or_else(|_| "./botserver-stack".to_string());
let lock_file = PathBuf::from(&stack_path).join(".lock"); let lock_file = PathBuf::from(&stack_path).join(".lock");
if lock_file.exists() { if lock_file.exists() {
if let Ok(pid_str) = fs::read_to_string(&lock_file) { if let Ok(pid_str) = fs::read_to_string(&lock_file) {
@ -22,26 +22,28 @@ pub fn check_single_instance() -> Result<bool, Box<dyn std::error::Error>> {
.and_then(|cmd| cmd.execute().ok()) .and_then(|cmd| cmd.execute().ok())
{ {
if output.status.success() { if output.status.success() {
warn!("Another botserver process (PID {}) is already running on this stack", pid); warn!(
return Ok(false); "Another botserver process (PID {}) is already running on this stack",
} pid
);
return Ok(false);
} }
} }
} }
} }
}
let pid = std::process::id(); let pid = std::process::id();
if let Some(parent) = lock_file.parent() { if let Some(parent) = lock_file.parent() {
fs::create_dir_all(parent).ok(); fs::create_dir_all(parent).ok();
} }
fs::write(&lock_file, pid.to_string()).ok(); fs::write(&lock_file, pid.to_string()).ok();
Ok(true) Ok(true)
} }
/// Release the instance lock /// Release the instance lock
pub fn release_instance_lock() { pub fn release_instance_lock() {
let stack_path = std::env::var("BOTSERVER_STACK_PATH") let stack_path = get_stack_path();
.unwrap_or_else(|_| "./botserver-stack".to_string());
let lock_file = PathBuf::from(&stack_path).join(".lock"); let lock_file = PathBuf::from(&stack_path).join(".lock");
if lock_file.exists() { if lock_file.exists() {
fs::remove_file(&lock_file).ok(); fs::remove_file(&lock_file).ok();

View file

@ -60,10 +60,15 @@ pub fn safe_curl(args: &[&str]) -> Option<std::process::Output> {
/// Check Vault health status /// Check Vault health status
pub fn vault_health_check() -> bool { pub fn vault_health_check() -> bool {
let client_cert = let stack_path = crate::core::shared::utils::get_stack_path();
std::path::Path::new("./botserver-stack/conf/system/certificates/botserver/client.crt"); let client_cert = std::path::Path::new(&format!(
let client_key = "{}/conf/system/certificates/botserver/client.crt",
std::path::Path::new("./botserver-stack/conf/system/certificates/botserver/client.key"); stack_path
));
let client_key = std::path::Path::new(&format!(
"{}/conf/system/certificates/botserver/client.key",
stack_path
));
let certs_exist = client_cert.exists() && client_key.exists(); let certs_exist = client_cert.exists() && client_key.exists();
info!("Vault health check: certs_exist={}", certs_exist); info!("Vault health check: certs_exist={}", certs_exist);
@ -78,9 +83,15 @@ pub fn vault_health_check() -> bool {
"-m", "-m",
"5", "5",
"--cert", "--cert",
"./botserver-stack/conf/system/certificates/botserver/client.crt", &format!(
"{}/conf/system/certificates/botserver/client.crt",
stack_path
),
"--key", "--key",
"./botserver-stack/conf/system/certificates/botserver/client.key", &format!(
"{}/conf/system/certificates/botserver/client.key",
stack_path
),
"https://localhost:8200/v1/sys/health?standbyok=true&uninitcode=200&sealedcode=200", "https://localhost:8200/v1/sys/health?standbyok=true&uninitcode=200&sealedcode=200",
]) ])
} else { } else {
@ -138,8 +149,17 @@ pub fn dump_all_component_logs(log_dir: &Path) {
error!("========================================================================"); error!("========================================================================");
let components = vec![ let components = vec![
"vault", "tables", "drive", "cache", "directory", "llm", "vault",
"vector_db", "email", "proxy", "dns", "meeting" "tables",
"drive",
"cache",
"directory",
"llm",
"vector_db",
"email",
"proxy",
"dns",
"meeting",
]; ];
for component in components { for component in components {
@ -148,12 +168,21 @@ pub fn dump_all_component_logs(log_dir: &Path) {
continue; continue;
} }
let log_files = vec!["stdout.log", "stderr.log", "postgres.log", "vault.log", "minio.log"]; let log_files = vec![
"stdout.log",
"stderr.log",
"postgres.log",
"vault.log",
"minio.log",
];
for log_file in log_files { for log_file in log_files {
let log_path = component_log_dir.join(log_file); let log_path = component_log_dir.join(log_file);
if log_path.exists() { if log_path.exists() {
error!("-------------------- {} ({}) --------------------", component, log_file); error!(
"-------------------- {} ({}) --------------------",
component, log_file
);
match fs::read_to_string(&log_path) { match fs::read_to_string(&log_path) {
Ok(content) => { Ok(content) => {
let lines: Vec<&str> = content.lines().rev().take(30).collect(); let lines: Vec<&str> = content.lines().rev().take(30).collect();

View file

@ -2,6 +2,7 @@
//! //!
//! Extracted from mod.rs //! Extracted from mod.rs
use crate::core::shared::utils::get_stack_path;
use anyhow::Result; use anyhow::Result;
use log::info; use log::info;
use std::env; use std::env;
@ -10,8 +11,7 @@ use std::path::PathBuf;
/// Check if stack has been installed /// Check if stack has been installed
pub fn has_installed_stack() -> bool { pub fn has_installed_stack() -> bool {
let stack_path = env::var("BOTSERVER_STACK_PATH") let stack_path = get_stack_path();
.unwrap_or_else(|_| "./botserver-stack".to_string());
let stack_dir = PathBuf::from(&stack_path); let stack_dir = PathBuf::from(&stack_path);
if !stack_dir.exists() { if !stack_dir.exists() {
return false; return false;
@ -30,14 +30,15 @@ pub fn has_installed_stack() -> bool {
pub fn reset_vault_only() -> Result<()> { pub fn reset_vault_only() -> Result<()> {
if has_installed_stack() { if has_installed_stack() {
log::error!("REFUSING to reset Vault credentials - botserver-stack is installed!"); log::error!("REFUSING to reset Vault credentials - botserver-stack is installed!");
log::error!("If you need to re-initialize, manually delete botserver-stack directory first"); log::error!(
return Err(anyhow::anyhow!( "If you need to re-initialize, manually delete botserver-stack directory first"
"Cannot reset Vault - existing installation detected. Manual intervention required." );
)); return Err(anyhow::anyhow!(
"Cannot reset Vault - existing installation detected. Manual intervention required."
));
} }
let stack_path = env::var("BOTSERVER_STACK_PATH") let stack_path = get_stack_path();
.unwrap_or_else(|_| "./botserver-stack".to_string());
let vault_init = PathBuf::from(&stack_path).join("conf/vault/init.json"); let vault_init = PathBuf::from(&stack_path).join("conf/vault/init.json");
let env_file = PathBuf::from("./.env"); let env_file = PathBuf::from("./.env");
@ -58,10 +59,12 @@ pub fn reset_vault_only() -> Result<()> {
pub fn get_db_password_from_vault() -> Option<String> { pub fn get_db_password_from_vault() -> Option<String> {
use crate::core::bootstrap::bootstrap_utils::safe_sh_command; use crate::core::bootstrap::bootstrap_utils::safe_sh_command;
let vault_addr = env::var("VAULT_ADDR").unwrap_or_else(|_| "https://localhost:8200".to_string()); let vault_addr =
env::var("VAULT_ADDR").unwrap_or_else(|_| "https://localhost:8200".to_string());
let vault_token = env::var("VAULT_TOKEN").ok()?; let vault_token = env::var("VAULT_TOKEN").ok()?;
let vault_cacert = env::var("VAULT_CACERT").unwrap_or_else(|_| "./botserver-stack/conf/system/certificates/ca/ca.crt".to_string()); let vault_cacert = env::var("VAULT_CACERT")
let vault_bin = format!("{}/bin/vault/vault", env::var("BOTSERVER_STACK_PATH").unwrap_or_else(|_| "./botserver-stack".to_string())); .unwrap_or_else(|_| format!("{}/conf/system/certificates/ca/ca.crt", get_stack_path()));
let vault_bin = format!("{}/bin/vault/vault", get_stack_path());
let cmd = format!( let cmd = format!(
"VAULT_ADDR={} VAULT_TOKEN={} VAULT_CACERT={} {} kv get -field=password secret/gbo/tables 2>/dev/null", "VAULT_ADDR={} VAULT_TOKEN={} VAULT_CACERT={} {} kv get -field=password secret/gbo/tables 2>/dev/null",

View file

@ -957,7 +957,7 @@ TALK response
Err(e) => { Err(e) => {
warn!("Upload failed (mc not available): {}", e); warn!("Upload failed (mc not available): {}", e);
let fs_path = format!("./botserver-stack/minio/{}/{}", bucket, path); let fs_path = format!("{}/minio/{}/{}", crate::core::shared::utils::get_stack_path(), bucket, path);
if let Some(parent) = std::path::Path::new(&fs_path).parent() { if let Some(parent) = std::path::Path::new(&fs_path).parent() {
std::fs::create_dir_all(parent)?; std::fs::create_dir_all(parent)?;
} }

View file

@ -249,7 +249,7 @@ impl BotOrchestrator {
.config .config
.as_ref() .as_ref()
.map(|c| c.site_path.clone()) .map(|c| c.site_path.clone())
.unwrap_or_else(|| "./botserver-stack/sites".to_string()) .unwrap_or_else(|| format!("{}/sites", crate::core::shared::utils::get_stack_path()))
.into(), .into(),
"./templates".into(), "./templates".into(),
"../bottemplates".into(), "../bottemplates".into(),

View file

@ -37,9 +37,8 @@ pub fn get_session_tools(
// Build path to work/{bot_name}.gbai/{bot_name}.gbdialog directory // Build path to work/{bot_name}.gbai/{bot_name}.gbdialog directory
// Use relative path from botserver binary location // Use relative path from botserver binary location
let gb_dir = std::env::current_dir() let gb_dir =
.unwrap_or_else(|_| PathBuf::from(".")) std::path::PathBuf::from(crate::core::shared::utils::get_stack_path()).join("data/system");
.join("botserver-stack/data/system");
// Ensure work directory exists (create if not) // Ensure work directory exists (create if not)
let work_base = gb_dir.join("work"); let work_base = gb_dir.join("work");
@ -51,7 +50,12 @@ pub fn get_session_tools(
let work_path = work_base.join(format!("{}.gbai/{}.gbdialog", bot_name, bot_name)); let work_path = work_base.join(format!("{}.gbai/{}.gbdialog", bot_name, bot_name));
info!("Loading {} tools for session {} from {:?}", tool_names.len(), session_id, work_path); info!(
"Loading {} tools for session {} from {:?}",
tool_names.len(),
session_id,
work_path
);
let mut tools = Vec::new(); let mut tools = Vec::new();
@ -102,7 +106,7 @@ fn format_tool_for_openai(mcp_json: &Value, tool_name: &str) -> Option<Value> {
json!({ json!({
"type": param_type, "type": param_type,
"description": param_desc "description": param_desc
}) }),
); );
} }

View file

@ -37,9 +37,7 @@ pub struct ToolExecutor;
impl ToolExecutor { impl ToolExecutor {
/// Log tool execution errors to a dedicated log file /// Log tool execution errors to a dedicated log file
fn log_tool_error(bot_name: &str, tool_name: &str, error_msg: &str) { fn log_tool_error(bot_name: &str, tool_name: &str, error_msg: &str) {
let log_path = std::env::current_dir() let log_path = std::path::PathBuf::from(crate::core::shared::utils::get_work_path())
.unwrap_or_else(|_| std::path::PathBuf::from("."))
.join("botserver-stack/data/system/work")
.join(format!("{}_tool_errors.log", bot_name)); .join(format!("{}_tool_errors.log", bot_name));
// Create work directory if it doesn't exist // Create work directory if it doesn't exist
@ -353,10 +351,8 @@ impl ToolExecutor {
return source_path; return source_path;
} }
// Try compiled work directory (botserver-stack/data/system/work relative to current dir) // Try compiled work directory (work relative to stack path)
let work_path = std::env::current_dir() let work_path = std::path::PathBuf::from(crate::core::shared::utils::get_work_path())
.unwrap_or_else(|_| PathBuf::from("."))
.join("botserver-stack/data/system/work")
.join(format!("{}.gbai", bot_name)) .join(format!("{}.gbai", bot_name))
.join(format!("{}.gbdialog", bot_name)) .join(format!("{}.gbdialog", bot_name))
.join(format!("{}.bas", tool_name)); .join(format!("{}.bas", tool_name));

View file

@ -323,10 +323,10 @@ impl AppConfig {
ConfigManager::new(pool.clone()).get_config( ConfigManager::new(pool.clone()).get_config(
&Uuid::nil(), &Uuid::nil(),
"SITES_ROOT", "SITES_ROOT",
Some("./botserver-stack/sites"), Some(&format!("{}/sites", crate::core::shared::utils::get_stack_path())),
)? )?
}, },
data_dir: get_str("DATA_DIR", "./botserver-stack/data"), data_dir: get_str("DATA_DIR", &format!("{}/data", crate::core::shared::utils::get_stack_path())),
}) })
} }
pub fn from_env() -> Result<Self, anyhow::Error> { pub fn from_env() -> Result<Self, anyhow::Error> {
@ -371,8 +371,8 @@ impl AppConfig {
base_url: "http://localhost:8080".to_string(), base_url: "http://localhost:8080".to_string(),
}, },
site_path: "./botserver-stack/sites".to_string(), site_path: format!("{}/sites", crate::core::shared::utils::get_stack_path()),
data_dir: "./botserver-stack/data".to_string(), data_dir: format!("{}/data", crate::core::shared::utils::get_stack_path()),
}) })
} }
} }

View file

@ -34,7 +34,7 @@ impl Default for DnsConfig {
fn default() -> Self { fn default() -> Self {
Self { Self {
enabled: false, enabled: false,
zone_file_path: PathBuf::from("./botserver-stack/conf/dns/botserver.local.zone"), zone_file_path: PathBuf::from(&format!("{}/conf/dns/botserver.local.zone", crate::core::shared::utils::get_stack_path())),
domain: "botserver.local".to_string(), domain: "botserver.local".to_string(),
max_entries_per_ip: 5, max_entries_per_ip: 5,
ttl_seconds: 60, ttl_seconds: 60,

View file

@ -230,9 +230,7 @@ impl WebsiteCrawlerService {
let kb_name = format!("website_{}", sanitize_url_for_kb(&website.url)); let kb_name = format!("website_{}", sanitize_url_for_kb(&website.url));
let work_path = std::env::current_dir() let work_path = std::path::PathBuf::from(crate::core::shared::utils::get_work_path())
.unwrap_or_else(|_| std::path::PathBuf::from("."))
.join("botserver-stack/data/system/work")
.join(&bot_name) .join(&bot_name)
.join(format!("{}.gbkb", bot_name)) .join(format!("{}.gbkb", bot_name))
.join(&kb_name); .join(&kb_name);
@ -344,9 +342,7 @@ impl WebsiteCrawlerService {
trace!("Scanning .bas files for USE WEBSITE commands"); trace!("Scanning .bas files for USE WEBSITE commands");
// Use the correct work directory path instead of plain "work" // Use the correct work directory path instead of plain "work"
let work_dir = std::env::current_dir() let work_dir = std::path::PathBuf::from(crate::core::shared::utils::get_work_path());
.unwrap_or_else(|_| std::path::PathBuf::from("."))
.join("botserver-stack/data/system/work");
if !work_dir.exists() { if !work_dir.exists() {
return Ok(()); return Ok(());

View file

@ -2,10 +2,10 @@ use std::collections::HashMap;
use std::path::PathBuf; use std::path::PathBuf;
use log::{info, warn}; use log::{info, warn};
use super::generate_random_string; use super::generate_random_string;
use crate::core::shared::utils::get_stack_path;
pub async fn setup_alm() -> anyhow::Result<()> { pub async fn setup_alm() -> anyhow::Result<()> {
let stack_path_raw = std::env::var("BOTSERVER_STACK_PATH") let stack_path_raw = get_stack_path();
.unwrap_or_else(|_| "./botserver-stack".to_string());
let stack_path = std::fs::canonicalize(&stack_path_raw) let stack_path = std::fs::canonicalize(&stack_path_raw)
.unwrap_or_else(|_| PathBuf::from(&stack_path_raw)); .unwrap_or_else(|_| PathBuf::from(&stack_path_raw));

View file

@ -1,6 +1,7 @@
use crate::core::package_manager::component::ComponentConfig; use crate::core::package_manager::component::ComponentConfig;
use crate::core::package_manager::os::detect_os; use crate::core::package_manager::os::detect_os;
use crate::core::package_manager::{InstallMode, OsType}; use crate::core::package_manager::{InstallMode, OsType};
use crate::core::shared::utils::get_stack_path;
use crate::security::command_guard::SafeCommand; use crate::security::command_guard::SafeCommand;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use log::{error, info, trace, warn}; use log::{error, info, trace, warn};
@ -1011,7 +1012,7 @@ EOF"#.to_string(),
); );
env.insert( env.insert(
"VAULT_CACERT".to_string(), "VAULT_CACERT".to_string(),
"./botserver-stack/conf/system/certificates/ca/ca.crt".to_string(), format!("{}/conf/system/certificates/ca/ca.crt", get_stack_path()),
); );
env env
}, },

View file

@ -70,9 +70,9 @@ pub use alm_setup::setup_alm;
pub async fn setup_directory() -> anyhow::Result<crate::core::package_manager::setup::DirectoryConfig> { pub async fn setup_directory() -> anyhow::Result<crate::core::package_manager::setup::DirectoryConfig> {
use std::path::PathBuf; use std::path::PathBuf;
use std::collections::HashMap; use std::collections::HashMap;
use crate::core::shared::utils::get_stack_path;
let stack_path = std::env::var("BOTSERVER_STACK_PATH") let stack_path = get_stack_path();
.unwrap_or_else(|_| "./botserver-stack".to_string());
let base_url = "http://localhost:8300".to_string(); let base_url = "http://localhost:8300".to_string();
let config_path = PathBuf::from(&stack_path).join("conf/system/directory_config.json"); let config_path = PathBuf::from(&stack_path).join("conf/system/directory_config.json");

View file

@ -115,8 +115,7 @@ impl DirectorySetup {
/// The steps YAML configures FirstInstance.Org.PatPath which tells Zitadel to /// The steps YAML configures FirstInstance.Org.PatPath which tells Zitadel to
/// create a machine user with IAM_OWNER role and write its PAT to disk /// create a machine user with IAM_OWNER role and write its PAT to disk
fn load_pat_token(&mut self) -> Result<()> { fn load_pat_token(&mut self) -> Result<()> {
let stack_path = std::env::var("BOTSERVER_STACK_PATH") let stack_path = crate::core::shared::utils::get_stack_path();
.unwrap_or_else(|_| "./botserver-stack".to_string());
let pat_path = PathBuf::from(&stack_path).join("conf/directory/admin-pat.txt"); let pat_path = PathBuf::from(&stack_path).join("conf/directory/admin-pat.txt");
@ -139,7 +138,7 @@ impl DirectorySetup {
} }
// Also check the legacy location // Also check the legacy location
let legacy_pat_path = std::path::Path::new("./botserver-stack/conf/directory/admin-pat.txt"); let legacy_pat_path = std::path::Path::new(&format!("{}/conf/directory/admin-pat.txt", crate::core::shared::utils::get_stack_path()));
if legacy_pat_path.exists() { if legacy_pat_path.exists() {
let pat_token = std::fs::read_to_string(legacy_pat_path) let pat_token = std::fs::read_to_string(legacy_pat_path)
.map_err(|e| anyhow::anyhow!("Failed to read PAT file: {e}"))? .map_err(|e| anyhow::anyhow!("Failed to read PAT file: {e}"))?

View file

@ -1,3 +1,4 @@
use crate::core::shared::utils::get_stack_path;
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use diesel::PgConnection; use diesel::PgConnection;
use log::{debug, info, warn}; use log::{debug, info, warn};
@ -89,13 +90,14 @@ impl SecretsManager {
.and_then(|v| v.parse().ok()) .and_then(|v| v.parse().ok())
.unwrap_or(300); .unwrap_or(300);
let stack_path = get_stack_path();
let ca_cert = env::var("VAULT_CACERT") let ca_cert = env::var("VAULT_CACERT")
.unwrap_or_else(|_| "./botserver-stack/conf/system/certificates/ca/ca.crt".to_string()); .unwrap_or_else(|_| format!("{}/conf/system/certificates/ca/ca.crt", stack_path));
let client_cert = env::var("VAULT_CLIENT_CERT").unwrap_or_else(|_| { let client_cert = env::var("VAULT_CLIENT_CERT").unwrap_or_else(|_| {
"./botserver-stack/conf/system/certificates/botserver/client.crt".to_string() format!("{}/conf/system/certificates/botserver/client.crt", stack_path)
}); });
let client_key = env::var("VAULT_CLIENT_KEY").unwrap_or_else(|_| { let client_key = env::var("VAULT_CLIENT_KEY").unwrap_or_else(|_| {
"./botserver-stack/conf/system/certificates/botserver/client.key".to_string() format!("{}/conf/system/certificates/botserver/client.key", stack_path)
}); });
let enabled = !token.is_empty() && !addr.is_empty(); let enabled = !token.is_empty() && !addr.is_empty();

View file

@ -96,14 +96,40 @@ pub fn get_work_path() -> String {
.build(); .build();
let result = match rt { let result = match rt {
Ok(rt) => rt.block_on(sm.get_value("gbo/app", "work_path")) Ok(rt) => rt.block_on(sm.get_value("gbo/app", "work_path"))
.unwrap_or_else(|_| "./work".to_string()), .unwrap_or_else(|_| get_work_path_default()),
Err(_) => "./work".to_string(), Err(_) => get_work_path_default(),
}; };
let _ = tx.send(result); let _ = tx.send(result);
}); });
rx.recv().unwrap_or_else(|_| "./work".to_string()) rx.recv().unwrap_or_else(|_| get_work_path_default())
} else { } else {
"./work".to_string() get_work_path_default()
}
}
/// Returns the work directory path.
/// In production (system container with .env but no botserver-stack): /opt/gbo/work
/// In development (with botserver-stack directory): ./botserver-stack/data/system/work
fn get_work_path_default() -> String {
let has_stack = std::path::Path::new("./botserver-stack").exists();
let has_env = std::path::Path::new("./.env").exists();
if has_env && !has_stack {
"/opt/gbo/work".to_string()
} else {
"./botserver-stack/data/system/work".to_string()
}
}
/// Returns the stack base path.
/// In production (system container with .env but no botserver-stack): /opt/gbo
/// In development (with botserver-stack directory): ./botserver-stack
pub fn get_stack_path() -> String {
let has_stack = std::path::Path::new("./botserver-stack").exists();
let has_env = std::path::Path::new("./.env").exists();
if has_env && !has_stack {
"/opt/gbo".to_string()
} else {
"./botserver-stack".to_string()
} }
} }
@ -144,12 +170,13 @@ pub async fn create_s3_operator(
}; };
// Set CA cert for self-signed TLS (dev stack) // Set CA cert for self-signed TLS (dev stack)
if std::path::Path::new(CA_CERT_PATH).exists() { let ca_cert = ca_cert_path();
std::env::set_var("AWS_CA_BUNDLE", CA_CERT_PATH); if std::path::Path::new(&ca_cert).exists() {
std::env::set_var("SSL_CERT_FILE", CA_CERT_PATH); std::env::set_var("AWS_CA_BUNDLE", &ca_cert);
std::env::set_var("SSL_CERT_FILE", &ca_cert);
debug!( debug!(
"Set AWS_CA_BUNDLE and SSL_CERT_FILE to {} for S3 client", "Set AWS_CA_BUNDLE and SSL_CERT_FILE to {} for S3 client",
CA_CERT_PATH ca_cert
); );
} }
@ -445,8 +472,11 @@ pub fn sanitize_sql_value(value: &str) -> String {
value.replace('\'', "''") value.replace('\'', "''")
} }
/// Default path to the local CA certificate used for internal service TLS (dev stack) /// Returns the path to the local CA certificate used for internal service TLS (dev stack).
pub const CA_CERT_PATH: &str = "./botserver-stack/conf/system/certificates/ca/ca.crt"; /// In production this path may not exist, which is fine — the system CA store is used instead.
pub fn ca_cert_path() -> String {
format!("{}/conf/system/certificates/ca/ca.crt", get_stack_path())
}
/// Creates an HTTP client with proper TLS verification. /// Creates an HTTP client with proper TLS verification.
/// ///
@ -460,7 +490,7 @@ pub const CA_CERT_PATH: &str = "./botserver-stack/conf/system/certificates/ca/ca
/// # Returns /// # Returns
/// A reqwest::Client configured for TLS verification /// A reqwest::Client configured for TLS verification
pub fn create_tls_client(timeout_secs: Option<u64>) -> Client { pub fn create_tls_client(timeout_secs: Option<u64>) -> Client {
create_tls_client_with_ca(CA_CERT_PATH, timeout_secs) create_tls_client_with_ca(&ca_cert_path(), timeout_secs)
} }
/// Creates an HTTP client with a custom CA certificate path. /// Creates an HTTP client with a custom CA certificate path.

View file

@ -417,7 +417,7 @@ pub async fn apply_file_change(
.config .config
.as_ref() .as_ref()
.map(|c| c.site_path.clone()) .map(|c| c.site_path.clone())
.unwrap_or_else(|| "./botserver-stack/sites".to_string()); .unwrap_or_else(|| format!("{}/sites", crate::core::shared::utils::get_stack_path()));
let local_path = format!("{site_path}/{}.gbai/{}.gbapp/{app_name}/{file_name}", sanitized_name, sanitized_name); let local_path = format!("{site_path}/{}.gbai/{}.gbapp/{app_name}/{file_name}", sanitized_name, sanitized_name);
if let Some(parent) = std::path::Path::new(&local_path).parent() { if let Some(parent) = std::path::Path::new(&local_path).parent() {

View file

@ -8,6 +8,7 @@ use axum::{
use log::{error, info, warn}; use log::{error, info, warn};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
use crate::core::shared::utils::get_stack_path;
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::RwLock; use tokio::sync::RwLock;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
@ -148,7 +149,7 @@ pub async fn login(
})?; })?;
// Try to get admin token: first PAT file, then OAuth client credentials // Try to get admin token: first PAT file, then OAuth client credentials
let pat_path = std::path::Path::new("./botserver-stack/conf/directory/admin-pat.txt"); let pat_path = std::path::Path::new(&format!("{}/conf/directory/admin-pat.txt", get_stack_path()));
let admin_token = std::fs::read_to_string(pat_path) let admin_token = std::fs::read_to_string(pat_path)
.map(|s| s.trim().to_string()) .map(|s| s.trim().to_string())
.unwrap_or_default(); .unwrap_or_default();

View file

@ -3,6 +3,7 @@ use log::{error, info, warn};
use rand::Rng; use rand::Rng;
use std::fs; use std::fs;
use std::os::unix::fs::PermissionsExt; use std::os::unix::fs::PermissionsExt;
use crate::core::shared::utils::get_stack_path;
use uuid::Uuid; use uuid::Uuid;
use super::client::ZitadelClient; use super::client::ZitadelClient;
@ -299,7 +300,7 @@ fn save_setup_credentials(result: &BootstrapResult) {
fn save_admin_pat_token(pat_token: &str) { fn save_admin_pat_token(pat_token: &str) {
// Create directory if it doesn't exist // Create directory if it doesn't exist
let pat_dir = std::path::Path::new("./botserver-stack/conf/directory"); let pat_dir = std::path::Path::new(&format!("{}/conf/directory", get_stack_path()));
if let Err(e) = fs::create_dir_all(pat_dir) { if let Err(e) = fs::create_dir_all(pat_dir) {
error!("Failed to create PAT directory: {}", e); error!("Failed to create PAT directory: {}", e);
return; return;

View file

@ -1,6 +1,7 @@
use crate::basic::compiler::BasicCompiler; use crate::basic::compiler::BasicCompiler;
use crate::core::kb::{EmbeddingConfig, KnowledgeBaseManager}; use crate::core::kb::{EmbeddingConfig, KnowledgeBaseManager};
use crate::core::shared::state::AppState; use crate::core::shared::state::AppState;
use crate::core::shared::utils::get_work_path;
use diesel::prelude::*; use diesel::prelude::*;
use log::{debug, error, info, trace, warn}; use log::{debug, error, info, trace, warn};
use std::collections::HashMap; use std::collections::HashMap;
@ -43,12 +44,7 @@ pub struct LocalFileMonitor {
impl LocalFileMonitor { impl LocalFileMonitor {
pub fn new(state: Arc<AppState>) -> Self { pub fn new(state: Arc<AppState>) -> Self {
// Use botserver-stack/data/system/work as the work directory let work_root = PathBuf::from(get_work_path());
let work_root = std::env::current_dir()
.unwrap_or_else(|_| PathBuf::from("."))
.join("botserver-stack/data/system/work");
// Use /opt/gbo/data as the base directory for source files
let data_dir = PathBuf::from("/opt/gbo/data"); let data_dir = PathBuf::from("/opt/gbo/data");
#[cfg(any(feature = "research", feature = "llm"))] #[cfg(any(feature = "research", feature = "llm"))]

View file

@ -73,7 +73,7 @@ pub async fn ensure_llama_servers_running(
// Use default models when config is empty (no default.gbai/config.csv) // Use default models when config is empty (no default.gbai/config.csv)
let llm_server_path = if llm_server_path.is_empty() { let llm_server_path = if llm_server_path.is_empty() {
"./botserver-stack/bin/llm/build/bin".to_string() format!("{}/bin/llm/build/bin", crate::core::shared::utils::get_stack_path())
} else { } else {
llm_server_path llm_server_path
}; };
@ -94,7 +94,7 @@ pub async fn ensure_llama_servers_running(
// For llama-server startup, use path relative to botserver root // For llama-server startup, use path relative to botserver root
// The models are in <stack_path>/data/llm/ and the llama-server runs from botserver root // The models are in <stack_path>/data/llm/ and the llama-server runs from botserver root
let stack_path = std::env::var("BOTSERVER_STACK_PATH").unwrap_or_else(|_| "./botserver-stack".to_string()); let stack_path = crate::core::shared::utils::get_stack_path();
let llm_model_path = format!("{stack_path}/data/llm/{}", llm_model); let llm_model_path = format!("{stack_path}/data/llm/{}", llm_model);
let embedding_model_path = format!("{stack_path}/data/llm/{}", embedding_model); let embedding_model_path = format!("{stack_path}/data/llm/{}", embedding_model);
if !llm_server_enabled { if !llm_server_enabled {

View file

@ -206,7 +206,7 @@ async fn main() -> std::io::Result<()> {
dotenvy::dotenv().ok(); dotenvy::dotenv().ok();
let env_path_early = std::path::Path::new("./.env"); let env_path_early = std::path::Path::new("./.env");
let vault_init_path_early = std::path::Path::new("./botserver-stack/conf/vault/init.json"); let vault_init_path_early = std::path::Path::new(&format!("{}/conf/vault/init.json", crate::core::shared::utils::get_stack_path()));
let vault_addr = std::env::var("VAULT_ADDR").unwrap_or_default(); let vault_addr = std::env::var("VAULT_ADDR").unwrap_or_default();
let is_remote_vault = !vault_addr.is_empty() let is_remote_vault = !vault_addr.is_empty()
&& !vault_addr.contains("localhost") && !vault_addr.contains("localhost")

View file

@ -13,8 +13,7 @@ use crate::core::config::ConfigManager;
use crate::core::package_manager::InstallMode; use crate::core::package_manager::InstallMode;
use crate::core::session::SessionManager; use crate::core::session::SessionManager;
use crate::core::shared::state::AppState; use crate::core::shared::state::AppState;
use crate::core::shared::utils::create_conn; use crate::core::shared::utils::{create_conn, create_s3_operator, get_stack_path};
use crate::core::shared::utils::create_s3_operator;
use super::BootstrapProgress; use super::BootstrapProgress;
@ -88,8 +87,7 @@ pub async fn run_bootstrap(
trace!("Creating BootstrapManager..."); trace!("Creating BootstrapManager...");
let mut bootstrap = BootstrapManager::new(install_mode, tenant); let mut bootstrap = BootstrapManager::new(install_mode, tenant);
let stack_path = std::env::var("BOTSERVER_STACK_PATH") let stack_path = get_stack_path();
.unwrap_or_else(|_| "./botserver-stack".to_string());
let env_path = std::path::Path::new("./.env"); let env_path = std::path::Path::new("./.env");
let stack_env_path_str = format!("{}/.env", stack_path); let stack_env_path_str = format!("{}/.env", stack_path);
let vault_init_path_str = format!("{}/conf/vault/init.json", stack_path); let vault_init_path_str = format!("{}/conf/vault/init.json", stack_path);
@ -652,8 +650,7 @@ fn init_directory_service() -> Result<(Arc<Mutex<crate::directory::AuthService>>
let zitadel_config = { let zitadel_config = {
// Try to load from directory_config.json first // Try to load from directory_config.json first
// Use same path as DirectorySetup saves to (BOTSERVER_STACK_PATH/conf/system/directory_config.json) // Use same path as DirectorySetup saves to (BOTSERVER_STACK_PATH/conf/system/directory_config.json)
let stack_path = std::env::var("BOTSERVER_STACK_PATH") let stack_path = get_stack_path();
.unwrap_or_else(|_| "./botserver-stack".to_string());
let config_path = format!("{}/conf/system/directory_config.json", stack_path); let config_path = format!("{}/conf/system/directory_config.json", stack_path);
if let Ok(content) = std::fs::read_to_string(&config_path) { if let Ok(content) = std::fs::read_to_string(&config_path) {
if let Ok(json) = serde_json::from_str::<serde_json::Value>(&content) { if let Ok(json) = serde_json::from_str::<serde_json::Value>(&content) {
@ -718,7 +715,7 @@ fn default_zitadel_config() -> crate::directory::ZitadelConfig {
async fn bootstrap_directory_admin(zitadel_config: &crate::directory::ZitadelConfig) { async fn bootstrap_directory_admin(zitadel_config: &crate::directory::ZitadelConfig) {
use crate::directory::{bootstrap, ZitadelClient}; use crate::directory::{bootstrap, ZitadelClient};
let pat_path = std::path::Path::new("./botserver-stack/conf/directory/admin-pat.txt"); let pat_path = std::path::Path::new(&format!("{}/conf/directory/admin-pat.txt", get_stack_path()));
let bootstrap_client = if pat_path.exists() { let bootstrap_client = if pat_path.exists() {
match std::fs::read_to_string(pat_path) { match std::fs::read_to_string(pat_path) {
Ok(pat_token) => { Ok(pat_token) => {

View file

@ -402,7 +402,7 @@ pub async fn run_axum_server(
.config .config
.as_ref() .as_ref()
.map(|c| c.site_path.clone()) .map(|c| c.site_path.clone())
.unwrap_or_else(|| "./botserver-stack/sites".to_string()); .unwrap_or_else(|| format!("{}/sites", crate::core::shared::utils::get_stack_path()));
info!("Serving apps from: {}", site_path); info!("Serving apps from: {}", site_path);
@ -522,7 +522,7 @@ pub async fn run_axum_server(
.layer(cors) .layer(cors)
.layer(TraceLayer::new_for_http()); .layer(TraceLayer::new_for_http());
let cert_dir = std::path::Path::new("./botserver-stack/conf/system/certificates"); let cert_dir = std::path::Path::new(&format!("{}/conf/system/certificates", crate::core::shared::utils::get_stack_path()));
let cert_path = cert_dir.join("api/server.crt"); let cert_path = cert_dir.join("api/server.crt");
let key_path = cert_dir.join("api/server.key"); let key_path = cert_dir.join("api/server.key");

View file

@ -3,6 +3,7 @@ use std::collections::HashSet;
use std::path::PathBuf; use std::path::PathBuf;
use std::process::{Child, Output}; use std::process::{Child, Output};
use std::sync::LazyLock; use std::sync::LazyLock;
use crate::core::shared::utils::get_stack_path;
static ALLOWED_COMMANDS: LazyLock<HashSet<&'static str>> = LazyLock::new(|| { static ALLOWED_COMMANDS: LazyLock<HashSet<&'static str>> = LazyLock::new(|| {
HashSet::from([ HashSet::from([
@ -336,8 +337,7 @@ impl SafeCommand {
]; ];
// Add botserver-stack/bin/shared to PATH if it exists // Add botserver-stack/bin/shared to PATH if it exists
let stack_path = std::env::var("BOTSERVER_STACK_PATH") let stack_path = get_stack_path();
.unwrap_or_else(|_| "./botserver-stack".to_string());
let shared_bin = format!("{}/bin/shared", stack_path); let shared_bin = format!("{}/bin/shared", stack_path);
if std::path::Path::new(&shared_bin).exists() { if std::path::Path::new(&shared_bin).exists() {
path_entries.insert(0, shared_bin); path_entries.insert(0, shared_bin);
@ -390,8 +390,7 @@ impl SafeCommand {
]; ];
// Add botserver-stack/bin/shared to PATH if it exists // Add botserver-stack/bin/shared to PATH if it exists
let stack_path = std::env::var("BOTSERVER_STACK_PATH") let stack_path = get_stack_path();
.unwrap_or_else(|_| "./botserver-stack".to_string());
let shared_bin = format!("{}/bin/shared", stack_path); let shared_bin = format!("{}/bin/shared", stack_path);
if std::path::Path::new(&shared_bin).exists() { if std::path::Path::new(&shared_bin).exists() {
path_entries.insert(0, shared_bin); path_entries.insert(0, shared_bin);
@ -452,8 +451,7 @@ impl SafeCommand {
]; ];
// Add botserver-stack/bin/shared to PATH if it exists // Add botserver-stack/bin/shared to PATH if it exists
let stack_path = std::env::var("BOTSERVER_STACK_PATH") let stack_path = get_stack_path();
.unwrap_or_else(|_| "./botserver-stack".to_string());
let shared_bin = format!("{}/bin/shared", stack_path); let shared_bin = format!("{}/bin/shared", stack_path);
if std::path::Path::new(&shared_bin).exists() { if std::path::Path::new(&shared_bin).exists() {
path_entries.insert(0, shared_bin); path_entries.insert(0, shared_bin);
@ -506,8 +504,7 @@ impl SafeCommand {
]; ];
// Add botserver-stack/bin/shared to PATH if it exists // Add botserver-stack/bin/shared to PATH if it exists
let stack_path = std::env::var("BOTSERVER_STACK_PATH") let stack_path = get_stack_path();
.unwrap_or_else(|_| "./botserver-stack".to_string());
let shared_bin = format!("{}/bin/shared", stack_path); let shared_bin = format!("{}/bin/shared", stack_path);
if std::path::Path::new(&shared_bin).exists() { if std::path::Path::new(&shared_bin).exists() {
path_entries.insert(0, shared_bin); path_entries.insert(0, shared_bin);

View file

@ -287,7 +287,7 @@ impl SecurityManager {
if let Some(ref manager) = self.mtls_manager { if let Some(ref manager) = self.mtls_manager {
info!("Initializing mTLS for all services"); info!("Initializing mTLS for all services");
let base_path = PathBuf::from("./botserver-stack/conf/system"); let base_path = PathBuf::from(&format!("{}/conf/system", crate::core::shared::utils::get_stack_path()));
let ca_path = base_path.join("ca/ca.crt"); let ca_path = base_path.join("ca/ca.crt");
let cert_path = base_path.join("certs/api.crt"); let cert_path = base_path.join("certs/api.crt");