fix: Use SafeCommand directly for vault health check to avoid shell injection false positive
All checks were successful
BotServer CI/CD / build (push) Successful in 6m46s

- Replace safe_sh_command with SafeCommand::new("curl").args() in vault_health_check()
- The URL contains https:// which triggered '//' pattern detection in shell command
- Direct SafeCommand bypasses shell parsing, URL passed as single argument
- Add vault data directory existence check before recovery attempt
- Prevents 'Dangerous pattern // detected' errors during bootstrap
This commit is contained in:
Rodrigo Rodriguez (Pragmatismo) 2026-03-31 21:34:04 -03:00
parent 07a6c1edb3
commit 9919a8321c
2 changed files with 62 additions and 46 deletions

View file

@ -90,25 +90,30 @@ pub fn vault_health_check() -> bool {
let vault_addr =
std::env::var("VAULT_ADDR").unwrap_or_else(|_| "https://localhost:8200".to_string());
let cmd = format!(
"curl -f -s --connect-timeout 2 -k {}/v1/sys/health",
vault_addr
);
let health_url = format!("{}/v1/sys/health", vault_addr);
let output = safe_sh_command(&cmd);
if output.is_empty() {
return false;
}
if let Ok(json) = serde_json::from_str::<serde_json::Value>(&output) {
match SafeCommand::new("curl")
.and_then(|c| c.args(&["-f", "-s", "--connect-timeout", "2", "-k", &health_url]))
.and_then(|c| c.execute())
{
Ok(output) => {
if output.status.success() {
let stdout = String::from_utf8_lossy(&output.stdout);
if let Ok(json) = serde_json::from_str::<serde_json::Value>(&stdout) {
let sealed = json.get("sealed").and_then(|v| v.as_bool()).unwrap_or(true);
let initialized = json
.get("initialized")
.and_then(|v| v.as_bool())
.unwrap_or(false);
!sealed && initialized
} else {
false
return !sealed && initialized;
}
}
// Health endpoint returns 503 when sealed but initialized
let stderr = String::from_utf8_lossy(&output.stderr);
let stdout = String::from_utf8_lossy(&output.stdout);
stdout.contains("\"initialized\":true") || stderr.contains("\"initialized\":true")
}
Err(_) => false,
}
}

View file

@ -1387,6 +1387,15 @@ EOF"#.to_string(),
let vault_bin = bin_path.join("vault");
let vault_data = self.base_path.join("data/vault");
// Check if Vault data directory exists (real indicator of initialized state)
let vault_data_exists = vault_data.exists();
if !vault_data_exists {
info!("Vault data directory not found, will initialize fresh");
} else {
info!("Vault data directory found, checking health...");
}
// Wait for Vault to be ready
info!("Waiting for Vault to start...");
std::thread::sleep(std::time::Duration::from_secs(3));
@ -1395,6 +1404,8 @@ EOF"#.to_string(),
std::env::var("VAULT_ADDR").unwrap_or_else(|_| "https://localhost:8200".to_string());
let ca_cert = conf_path.join("system/certificates/ca/ca.crt");
// Only attempt recovery if data directory exists
if vault_data_exists {
// Check if Vault is already initialized via health endpoint
let health_cmd = format!(
"curl -f -s --connect-timeout 2 -k {}/v1/sys/health",
@ -1419,16 +1430,16 @@ EOF"#.to_string(),
let stdout = String::from_utf8_lossy(&output.stdout);
stdout.contains("\"initialized\":true")
|| stderr.contains("\"initialized\":true")
|| vault_data.exists()
}
} else {
vault_data.exists()
false
};
if already_initialized {
info!("Vault already initialized (detected via health/data), skipping init");
return self.recover_existing_vault();
}
}
// Initialize Vault
let init_cmd = format!(