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
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:
parent
c05e40d35b
commit
7d8f141fc2
35 changed files with 201 additions and 145 deletions
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)?;
|
||||||
|
|
|
||||||
|
|
@ -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) => {
|
||||||
|
|
|
||||||
|
|
@ -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)?;
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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"]))
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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)?;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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(),
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
|
|
|
||||||
|
|
@ -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()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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(());
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -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");
|
||||||
|
|
|
||||||
|
|
@ -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}"))?
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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"))]
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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) => {
|
||||||
|
|
|
||||||
|
|
@ -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");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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");
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue