feat: add Docker first-start admin bootstrap
Rust CI / Test & Quality Checks (push) Canceled after 0s
Rust CI / Build Docker Image (push) Canceled after 0s

This commit is contained in:
thakares committed 2026-08-12 14:13:09 +05:30
1 parent 25577b4b83
commit 8e0bcbe580
9 files changed
+152 -6

No files matched your search

+53
View File
@@ -0,0 +1,53 @@
use crate::auth::hash_password;
use crate::config::Config;
use crate::db::Db;
use std::env;
use std::path::PathBuf;
use tracing::{error, info};
pub async fn run(
data_dir: Option<String>,
mut config: Config,
) -> Result<(), Box<dyn std::error::Error>> {
if let Some(d) = data_dir {
config.data_dir = PathBuf::from(d);
}
let db = Db::init(&config)?;
let conn = db.users.lock().unwrap();
let admin_count: i64 = conn.query_row(
"SELECT COUNT(*) FROM users WHERE account_type = 'admin';",
[],
|row| row.get(0),
)?;
if admin_count > 0 {
info!("Administrator already exists; initialization skipped.");
return Ok(());
}
let username = match env::var("ADMIN_USERNAME") {
Ok(u) if !u.trim().is_empty() => u.trim().to_string(),
_ => {
let msg = "No administrator exists.\nADMIN_USERNAME and ADMIN_PASSWORD are required for first-time initialization.";
error!("{}", msg);
return Err(msg.into());
}
};
let password = match env::var("ADMIN_PASSWORD") {
Ok(p) if !p.trim().is_empty() => p.trim().to_string(),
_ => {
let msg = "No administrator exists.\nADMIN_USERNAME and ADMIN_PASSWORD are required for first-time initialization.";
error!("{}", msg);
return Err(msg.into());
}
};
let hash = hash_password(&password).map_err(|e| e.to_string())?;
let u = crate::db::users::create_admin_user(&conn, &username, &hash)?;
db.init_user_databases(u.id)?;
info!("Administrator initialized successfully.");
Ok(())
}
+6
View File
@@ -11,6 +11,7 @@ pub mod disable_user;
pub mod doctor;
pub mod enable_user;
pub mod expand;
pub mod init_admin;
pub mod list_users;
pub mod migrate;
pub mod repair;
@@ -86,6 +87,11 @@ pub enum Commands {
#[arg(long)]
data_dir: Option<String>,
},
/// Initialize the first administrator for automated/container deployments
InitAdmin {
#[arg(long)]
data_dir: Option<String>,
},
/// Run database diagnostics and health checks
Doctor {
#[arg(long)]
+3
View File
@@ -44,6 +44,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
Commands::CreateAdmin { username, data_dir } => {
bzod::cli::create_admin::run(username, data_dir, config).await?;
}
Commands::InitAdmin { data_dir } => {
bzod::cli::init_admin::run(data_dir, config).await?;
}
Commands::Doctor { data_dir } => {
bzod::cli::doctor::run(data_dir, config).await?;
}