use std::path::PathBuf;
use tracing::warn;
use tracing_subscriber::EnvFilter;
pub fn init_logging(level: &str) {
let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(level));
tracing_subscriber::fmt()
.with_env_filter(filter)
.without_time()
.compact()
.init();
}
fn fallback_dir() -> PathBuf {
crate::platform::config::fallback_data_dir()
}
pub fn resolve_data_path(configured: &str) -> PathBuf {
let path = PathBuf::from(configured);
if can_write_dir(&path) {
return path;
}
let fallback = fallback_dir().join("db");
warn!(
primary = %path.display(),
fallback = %fallback.display(),
"db path not writable, using fallback"
);
let _ = std::fs::create_dir_all(&fallback);
fallback
}
pub fn resolve_age_key_path(cfg: &crate::platform::config::SecretsConfig) -> PathBuf {
let path = PathBuf::from(
cfg.age_key_path
.as_deref()
.unwrap_or("/etc/rustploy/age.key"),
);
if path.exists() {
return path;
}
let parent = path.parent().unwrap_or(&path);
if can_write_dir(parent) {
return path;
}
let fallback = fallback_dir().join("age.key");
warn!(
primary = %path.display(),
fallback = %fallback.display(),
"age key directory not writable, using fallback"
);
let _ = std::fs::create_dir_all(fallback.parent().unwrap());
fallback
}
fn can_write_dir(dir: &std::path::Path) -> bool {
if std::fs::create_dir_all(dir).is_err() {
return false;
}
let probe = dir.join(".rustploy_write_probe");
if std::fs::write(&probe, b"").is_err() {
return false;
}
let _ = std::fs::remove_file(probe);
true
}
#[cfg(test)]
mod age_key_tests {
use super::*;
use crate::platform::config::SecretsConfig;
fn parse(toml_text: &str) -> SecretsConfig {
#[derive(serde::Deserialize)]
struct W {
secrets: SecretsConfig,
}
toml::from_str::<W>(toml_text).unwrap().secrets
}
#[test]
fn config_sem_age_key_path_parseia_e_usa_o_padrao() {
let c = parse("[secrets]\nrecovery_recipient = \"age1x\"\n");
assert!(c.age_key_path.is_none());
assert_eq!(resolve_age_key_path(&c).file_name().unwrap(), "age.key");
}
#[test]
fn age_key_path_explicito_tem_prioridade() {
let d = tempfile::tempdir().unwrap();
let c = parse(&format!(
"[secrets]\nage_key_path = \"{}/k.key\"\n",
d.path().display()
));
assert_eq!(resolve_age_key_path(&c), d.path().join("k.key"));
}
}