fix(directory): add .await to ensure_admin_token() calls
Some checks failed
BotServer CI / build (push) Failing after 5m28s

Fixed compilation errors by adding .await to all ensure_admin_token() calls:
- create_organization()
- create_user()
- save_config()

The method was made async but the calls weren't updated.
This commit is contained in:
Rodrigo Rodriguez (Pragmatismo) 2026-03-01 09:52:31 -03:00
parent 2c92a81302
commit eb5c12c466
6 changed files with 100 additions and 26 deletions

View file

@ -206,19 +206,19 @@ pub enum BotExistsResult {
/// Check if Zitadel directory is healthy
pub fn zitadel_health_check() -> bool {
// Check if Zitadel is responding on port 9000
// Check if Zitadel is responding on port 8300
if let Ok(output) = Command::new("curl")
.args(["-f", "-s", "--connect-timeout", "2", "http://localhost:9000/debug/ready"])
.args(["-f", "-s", "--connect-timeout", "2", "http://localhost:8300/debug/ready"])
.output()
{
if output.status.success() {
return true;
}
}
// Fallback: just check if port 9000 is listening
// Fallback: just check if port 8300 is listening
match Command::new("nc")
.args(["-z", "-w", "1", "127.0.0.1", "9000"])
.args(["-z", "-w", "1", "127.0.0.1", "8300"])
.output()
{
Ok(output) => output.status.success(),

View file

@ -257,7 +257,7 @@ pub async fn check_services_status(State(state): State<Arc<AppState>>) -> impl I
let client = create_tls_client(Some(2));
if let Ok(response) = client.get("https://localhost:9000/healthz").send().await {
if let Ok(response) = client.get("http://localhost:8300/healthz").send().await {
status.directory = response.status().is_success();
}

View file

@ -475,12 +475,12 @@ impl PackageManager {
env_vars: HashMap::from([
("ZITADEL_EXTERNALSECURE".to_string(), "false".to_string()),
("ZITADEL_EXTERNALDOMAIN".to_string(), "localhost".to_string()),
("ZITADEL_EXTERNALPORT".to_string(), "9000".to_string()),
("ZITADEL_EXTERNALPORT".to_string(), "8300".to_string()),
("ZITADEL_TLS_ENABLED".to_string(), "false".to_string()),
]),
data_download_list: Vec::new(),
exec_cmd: "ZITADEL_MASTERKEY=$(VAULT_ADDR=https://localhost:8200 VAULT_CACERT={{CONF_PATH}}/system/certificates/ca/ca.crt vault kv get -field=masterkey secret/gbo/directory 2>/dev/null || echo 'MasterkeyNeedsToHave32Characters') nohup {{BIN_PATH}}/zitadel start --config {{CONF_PATH}}/directory/zitadel.yaml --masterkeyFromEnv --tlsMode disabled > {{LOGS_PATH}}/zitadel.log 2>&1 &".to_string(),
check_cmd: "curl -f --connect-timeout 2 -m 5 http://localhost:9000/healthz >/dev/null 2>&1".to_string(),
check_cmd: "curl -f --connect-timeout 2 -m 5 http://localhost:8300/healthz >/dev/null 2>&1".to_string(),
},
);
}

View file

@ -147,7 +147,7 @@ pub async fn setup_directory() -> anyhow::Result<crate::core::package_manager::s
let base_url = "http://localhost:8300".to_string();
let config_path = PathBuf::from(&stack_path).join("conf/system/directory_config.json");
// Check if config already exists
// Check if config already exists with valid OAuth client
if config_path.exists() {
if let Ok(content) = std::fs::read_to_string(&config_path) {
if let Ok(config) = serde_json::from_str::<crate::core::package_manager::setup::DirectoryConfig>(&content) {
@ -159,12 +159,41 @@ pub async fn setup_directory() -> anyhow::Result<crate::core::package_manager::s
}
}
// Try to get initial admin credentials from Zitadel log
// Try multiple approaches to get initial admin credentials
let log_path = PathBuf::from(&stack_path).join("logs/zitadel.log");
// Approach 1: Try to extract credentials from Zitadel log
let admin_credentials = extract_initial_admin_from_log(&log_path);
let mut directory_setup = if let Some((email, password)) = admin_credentials {
log::info!("Using initial admin credentials from log for OAuth client creation");
// Approach 2: Try well-known default credentials for initial Zitadel setup
// Zitadel's default initial admin credentials (if any)
let default_credentials = [
// Try common default patterns
("admin@localhost", "Password1!"),
("zitadel-admin@localhost", "Password1!"),
("admin", "admin"),
];
// Find working credentials
let working_credentials = if let Some((email, password)) = admin_credentials {
log::info!("Using credentials extracted from Zitadel log");
Some((email, password))
} else {
// Try default credentials
log::info!("Attempting to authenticate with default Zitadel credentials...");
let mut found = None;
for (email, password) in default_credentials.iter() {
if let Ok(true) = test_zitadel_credentials(&base_url, email, password).await {
log::info!("Successfully authenticated with default credentials: {}", email);
found = Some((email.to_string(), password.to_string()));
break;
}
}
found
};
let mut directory_setup = if let Some((email, password)) = working_credentials {
log::info!("Using admin credentials for Directory setup: {}", email);
crate::core::package_manager::setup::DirectorySetup::with_admin_credentials(
base_url,
config_path.clone(),
@ -172,17 +201,54 @@ pub async fn setup_directory() -> anyhow::Result<crate::core::package_manager::s
password,
)
} else {
log::warn!(
"Could not extract initial admin credentials from Zitadel log at {}. \
OAuth client creation may fail. Check if Zitadel has started properly.",
// No credentials found - provide helpful error message
log::error!("═══════════════════════════════════════════════════════════════");
log::error!("❌ FAILED TO GET ZITADEL ADMIN CREDENTIALS");
log::error!("═══════════════════════════════════════════════════════════════");
log::error!("Could not extract credentials from Zitadel logs at:",);
log::error!(" {}", log_path.display());
log::error!("");
log::error!("Please check the Zitadel logs manually for initial admin credentials:");
log::error!(" tail -100 {}", log_path.display());
log::error!("");
log::error!("Then create the config file manually at:");
log::error!(" {}", config_path.display());
log::error!("═══════════════════════════════════════════════════════════════");
anyhow::bail!(
"Failed to obtain Zitadel admin credentials. Check logs at {}",
log_path.display()
);
crate::core::package_manager::setup::DirectorySetup::new(
base_url,
config_path.clone()
)
};
directory_setup.initialize().await
.map_err(|e| anyhow::anyhow!("Failed to initialize directory: {}", e))
}
/// Test if Zitadel credentials are valid by attempting to get an access token
#[cfg(feature = "directory")]
async fn test_zitadel_credentials(base_url: &str, username: &str, password: &str) -> anyhow::Result<bool> {
use reqwest::Client;
let client = Client::builder()
.timeout(std::time::Duration::from_secs(5))
.build()
.unwrap_or_else(|_| Client::new());
let token_url = format!("{}/oauth/v2/token", base_url);
let params = [
("grant_type", "password".to_string()),
("username", username.to_string()),
("password", password.to_string()),
("scope", "openid profile email".to_string()),
];
let response = client
.post(&token_url)
.form(&params)
.send()
.await
.map_err(|e| anyhow::anyhow!("Failed to test credentials: {}", e))?;
Ok(response.status().is_success())
}

View file

@ -70,10 +70,18 @@ impl DirectorySetup {
Err(anyhow::anyhow!("No admin token or credentials configured"))
}
pub fn ensure_admin_token(&mut self) -> Result<()> {
pub async fn ensure_admin_token(&mut self) -> Result<()> {
if self.admin_token.is_none() && self.admin_credentials.is_none() {
return Err(anyhow::anyhow!("Admin token or credentials must be configured"));
}
// If we have credentials but no token, authenticate and get the token
if self.admin_token.is_none() && self.admin_credentials.is_some() {
let token = self.get_admin_access_token().await?;
self.admin_token = Some(token);
log::info!("Obtained admin access token from credentials");
}
Ok(())
}
@ -204,7 +212,7 @@ impl DirectorySetup {
log::info!("Waiting for Zitadel API to be fully initialized...");
sleep(Duration::from_secs(10)).await;
self.ensure_admin_token()?;
self.ensure_admin_token().await?;
let org = self.create_default_organization().await?;
log::info!(" Created default organization: {}", org.name);
@ -283,7 +291,7 @@ impl DirectorySetup {
}
pub async fn create_organization(&mut self, name: &str, description: &str) -> Result<String> {
self.ensure_admin_token()?;
self.ensure_admin_token().await?;
let response = self
.client
@ -336,7 +344,7 @@ impl DirectorySetup {
&mut self,
params: CreateUserParams<'_>,
) -> Result<DefaultUser> {
self.ensure_admin_token()?;
self.ensure_admin_token().await?;
let response = self
.client
@ -532,7 +540,7 @@ impl DirectorySetup {
client_id: String,
client_secret: String,
) -> Result<DirectoryConfig> {
self.ensure_admin_token()?;
self.ensure_admin_token().await?;
let config = DirectoryConfig {
base_url: self.base_url.clone(),

View file

@ -290,7 +290,7 @@ impl ApiUrls {
pub const MONITORING_LLM: &'static str = "/api/ui/monitoring/llm";
pub const MONITORING_HEALTH: &'static str = "/api/ui/monitoring/health";
pub const MONITORING_ALERTS: &'static str = "/api/monitoring/alerts";
// Monitoring - Metrics & Widgets
pub const MONITORING_TIMESTAMP: &'static str = "/api/ui/monitoring/timestamp";
pub const MONITORING_BOTS: &'static str = "/api/ui/monitoring/bots";
@ -479,7 +479,7 @@ impl ApiUrls {
pub struct InternalUrls;
impl InternalUrls {
pub const DIRECTORY_BASE: &'static str = "http://localhost:9000";
pub const DIRECTORY_BASE: &'static str = "http://localhost:8300";
pub const DATABASE: &'static str = "postgres://localhost:5432";
pub const CACHE: &'static str = "redis://localhost:6379";
pub const DRIVE: &'static str = "https://localhost:9100";