refactor(config): require explicit BZOD data directory
This commit is contained in:
1 parent
d398341f01
commit
c2e138f823
55 files changed
+471
-119
No files matched your search
+3
-1
@@ -1,7 +1,9 @@
|
|||||||
# BZOD Platform Configuration
|
# BZOD Platform Configuration
|
||||||
HOST=0.0.0.0
|
HOST=0.0.0.0
|
||||||
PORT=8080
|
PORT=8080
|
||||||
DATA_DIR=./data
|
# Physical BZOD data root.
|
||||||
|
# REQUIRED: Set this explicitly; there is no implicit ./data fallback.
|
||||||
|
NX9_BZOD_DATA_DIR=/var/lib/bzod/data
|
||||||
|
|
||||||
# Security Settings
|
# Security Settings
|
||||||
COOKIE_SECURE=false
|
COOKIE_SECURE=false
|
||||||
|
|||||||
+1
-1
@@ -73,7 +73,7 @@ RUN mkdir -p \
|
|||||||
/usr/local/bin/docker-entrypoint.sh
|
/usr/local/bin/docker-entrypoint.sh
|
||||||
|
|
||||||
# Runtime configuration
|
# Runtime configuration
|
||||||
ENV DATA_DIR=/app/data \
|
ENV NX9_BZOD_DATA_DIR=/app/data \
|
||||||
CONFIG_DIR=/app/config \
|
CONFIG_DIR=/app/config \
|
||||||
IMAGES_DIR=/app/images \
|
IMAGES_DIR=/app/images \
|
||||||
PORT=8654 \
|
PORT=8654 \
|
||||||
|
|||||||
@@ -168,9 +168,10 @@ services:
|
|||||||
- "8654:8654"
|
- "8654:8654"
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./data:/app/data
|
- /var/lib/bzod/data:/app/data
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
|
- NX9_BZOD_DATA_DIR=/app/data
|
||||||
- RUST_LOG=info
|
- RUST_LOG=info
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -182,6 +183,28 @@ docker compose up -d
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
# Data Directory & Configuration Precedence
|
||||||
|
|
||||||
|
BZOD requires an explicit physical data root. There is **no implicit `./data` fallback**.
|
||||||
|
|
||||||
|
Precedence:
|
||||||
|
1. **CLI `--data-dir`** (Highest)
|
||||||
|
2. **`NX9_BZOD_DATA_DIR`** environment variable
|
||||||
|
3. **`config.toml` / `bzod.toml` `data_dir`** setting
|
||||||
|
4. **Configuration Error** if no data directory is configured.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Via environment variable
|
||||||
|
NX9_BZOD_DATA_DIR=/var/lib/bzod/data bzod serve
|
||||||
|
|
||||||
|
# Via CLI argument
|
||||||
|
bzod migrate --data-dir=/var/lib/bzod/data --dry-run
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
# Native Installation
|
# Native Installation
|
||||||
|
|
||||||
Download the latest release.
|
Download the latest release.
|
||||||
@@ -202,16 +225,16 @@ bzod --help
|
|||||||
|
|
||||||
# Initialize
|
# Initialize
|
||||||
|
|
||||||
Create the administrator.
|
Create the administrator (specifying `--data-dir` or `NX9_BZOD_DATA_DIR`):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bzod create-admin
|
NX9_BZOD_DATA_DIR=/var/lib/bzod/data bzod create-admin
|
||||||
```
|
```
|
||||||
|
|
||||||
Start the server.
|
Start the server:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bzod serve
|
NX9_BZOD_DATA_DIR=/var/lib/bzod/data bzod serve
|
||||||
```
|
```
|
||||||
|
|
||||||
Default server:
|
Default server:
|
||||||
@@ -234,6 +257,7 @@ After=network.target
|
|||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
|
|
||||||
|
Environment=NX9_BZOD_DATA_DIR=/var/lib/bzod/data
|
||||||
ExecStart=/usr/local/bin/bzod serve
|
ExecStart=/usr/local/bin/bzod serve
|
||||||
|
|
||||||
Restart=always
|
Restart=always
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ BZOD_IMAGE=${BZOD_IMAGE}
|
|||||||
HOST=0.0.0.0
|
HOST=0.0.0.0
|
||||||
PORT=8654
|
PORT=8654
|
||||||
|
|
||||||
DATA_DIR=/app/data
|
NX9_BZOD_DATA_DIR=/app/data
|
||||||
CONFIG_DIR=/app/config
|
CONFIG_DIR=/app/config
|
||||||
IMAGES_DIR=/app/images
|
IMAGES_DIR=/app/images
|
||||||
|
|
||||||
@@ -238,7 +238,7 @@ services:
|
|||||||
HOST: "${HOST:-0.0.0.0}"
|
HOST: "${HOST:-0.0.0.0}"
|
||||||
PORT: "${PORT:-8654}"
|
PORT: "${PORT:-8654}"
|
||||||
|
|
||||||
DATA_DIR: "/app/data"
|
NX9_BZOD_DATA_DIR: "/app/data"
|
||||||
CONFIG_DIR: "/app/config"
|
CONFIG_DIR: "/app/config"
|
||||||
IMAGES_DIR: "/app/images"
|
IMAGES_DIR: "/app/images"
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@ services:
|
|||||||
- ADMIN_USERNAME=${ADMIN_USERNAME}
|
- ADMIN_USERNAME=${ADMIN_USERNAME}
|
||||||
- CONFIG_DIR=/app/config
|
- CONFIG_DIR=/app/config
|
||||||
- COOKIE_SECURE=false
|
- COOKIE_SECURE=false
|
||||||
- DATA_DIR=/app/data
|
- NX9_BZOD_DATA_DIR=/app/data
|
||||||
- HOST=0.0.0.0
|
- HOST=0.0.0.0
|
||||||
- IMAGES_DIR=/app/images
|
- IMAGES_DIR=/app/images
|
||||||
- PORT=8654
|
- PORT=8654
|
||||||
|
|||||||
+24
@@ -284,3 +284,27 @@ bzod doctor
|
|||||||
* SECURITY.md
|
* SECURITY.md
|
||||||
* API.md
|
* API.md
|
||||||
* ARCHITECTURE.md
|
* ARCHITECTURE.md
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Data Directory Configuration
|
||||||
|
|
||||||
|
BZOD requires an explicit physical data directory root. There is **no implicit `./data` fallback**.
|
||||||
|
|
||||||
|
### Configuration Precedence
|
||||||
|
|
||||||
|
1. **CLI `--data-dir`** (Highest priority)
|
||||||
|
```bash
|
||||||
|
bzod serve --data-dir /var/lib/bzod/data
|
||||||
|
bzod migrate --data-dir=/var/lib/bzod/data --dry-run
|
||||||
|
```
|
||||||
|
2. **Environment Variable `NX9_BZOD_DATA_DIR`**
|
||||||
|
```bash
|
||||||
|
export NX9_BZOD_DATA_DIR=/var/lib/bzod/data
|
||||||
|
bzod serve
|
||||||
|
```
|
||||||
|
3. **Configuration File (`bzod.toml` / `config.toml`)**
|
||||||
|
```toml
|
||||||
|
data_dir = "/var/lib/bzod/data"
|
||||||
|
```
|
||||||
|
4. **Error**: If no data directory is provided via CLI, `NX9_BZOD_DATA_DIR`, or config file, BZOD terminates with an actionable error.
|
||||||
@@ -100,7 +100,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
HOST: 0.0.0.0
|
HOST: 0.0.0.0
|
||||||
PORT: 8654
|
PORT: 8654
|
||||||
DATA_DIR: /app/data
|
NX9_BZOD_DATA_DIR: /app/data
|
||||||
COOKIE_SECURE: "false"
|
COOKIE_SECURE: "false"
|
||||||
|
|
||||||
healthcheck:
|
healthcheck:
|
||||||
@@ -205,10 +205,10 @@ BZOD Docker Container
|
|||||||
# Environment Variables
|
# Environment Variables
|
||||||
|
|
||||||
| Variable | Description | Default |
|
| Variable | Description | Default |
|
||||||
| ------------- | ------------------ | --------- |
|
| ----------------- | ------------------ | ------------- |
|
||||||
| HOST | Bind address | 0.0.0.0 |
|
| HOST | Bind address | 0.0.0.0 |
|
||||||
| PORT | Listen port | 8654 |
|
| PORT | Listen port | 8654 |
|
||||||
| DATA_DIR | Database directory | /app/data |
|
| NX9_BZOD_DATA_DIR | Database directory | (required) |
|
||||||
| COOKIE_SECURE | Secure cookies | false |
|
| COOKIE_SECURE | Secure cookies | false |
|
||||||
| RUST_LOG | Logging level | info |
|
| RUST_LOG | Logging level | info |
|
||||||
|
|
||||||
|
|||||||
@@ -213,3 +213,34 @@ pub enum RepairCommands {
|
|||||||
data_dir: Option<String>,
|
data_dir: Option<String>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Commands {
|
||||||
|
pub fn data_dir(&self) -> Option<&str> {
|
||||||
|
match self {
|
||||||
|
Commands::Serve { data_dir, .. } => data_dir.as_deref(),
|
||||||
|
Commands::Backup { data_dir, .. } => data_dir.as_deref(),
|
||||||
|
Commands::Restore { data_dir, .. } => data_dir.as_deref(),
|
||||||
|
Commands::Migrate { data_dir, .. } => data_dir.as_deref(),
|
||||||
|
Commands::Stats { data_dir, .. } => data_dir.as_deref(),
|
||||||
|
Commands::Validate { data_dir, .. } => data_dir.as_deref(),
|
||||||
|
Commands::AuditDestinations { data_dir, .. } => data_dir.as_deref(),
|
||||||
|
Commands::CreateAdmin { data_dir, .. } => data_dir.as_deref(),
|
||||||
|
Commands::InitAdmin { data_dir, .. } => data_dir.as_deref(),
|
||||||
|
Commands::Doctor { data_dir, .. } => data_dir.as_deref(),
|
||||||
|
Commands::Shorten { data_dir, .. } => data_dir.as_deref(),
|
||||||
|
Commands::Expand { data_dir, .. } => data_dir.as_deref(),
|
||||||
|
Commands::CreateUser { data_dir, .. } => data_dir.as_deref(),
|
||||||
|
Commands::DeleteUser { data_dir, .. } => data_dir.as_deref(),
|
||||||
|
Commands::DisableUser { data_dir, .. } => data_dir.as_deref(),
|
||||||
|
Commands::EnableUser { data_dir, .. } => data_dir.as_deref(),
|
||||||
|
Commands::ResetPassword { data_dir, .. } => data_dir.as_deref(),
|
||||||
|
Commands::ListUsers { data_dir, .. } => data_dir.as_deref(),
|
||||||
|
Commands::BackupUser { data_dir, .. } => data_dir.as_deref(),
|
||||||
|
Commands::RestoreUser { data_dir, .. } => data_dir.as_deref(),
|
||||||
|
Commands::AdminMigrate { data_dir, .. } => data_dir.as_deref(),
|
||||||
|
Commands::Repair { command } => match command {
|
||||||
|
RepairCommands::Registry { data_dir, .. } => data_dir.as_deref(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-2
@@ -277,8 +277,7 @@ pub fn perform_restore(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 5. Run validation on the normalized temp_dir
|
// 5. Run validation on the normalized temp_dir
|
||||||
let mut temp_config = Config::load();
|
let temp_config = Config::load_with_cli(Some(&temp_dir))?;
|
||||||
temp_config.data_dir = temp_dir.clone();
|
|
||||||
|
|
||||||
// Namespace audit
|
// Namespace audit
|
||||||
match crate::db::users::audit_slug_namespace(&temp_config) {
|
match crate::db::users::audit_slug_namespace(&temp_config) {
|
||||||
|
|||||||
+101
-15
@@ -3,6 +3,45 @@ use std::env;
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
pub const NX9_BZOD_DATA_DIR_ENV: &str = "NX9_BZOD_DATA_DIR";
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum ConfigError {
|
||||||
|
MissingDataDir,
|
||||||
|
InvalidConfig(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for ConfigError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::MissingDataDir => write!(
|
||||||
|
f,
|
||||||
|
"data directory is not configured; set NX9_BZOD_DATA_DIR or use --data-dir=<path>"
|
||||||
|
),
|
||||||
|
Self::InvalidConfig(msg) => write!(f, "configuration error: {msg}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for ConfigError {}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum DataDirSource {
|
||||||
|
Cli,
|
||||||
|
Env,
|
||||||
|
ConfigFile,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for DataDirSource {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Cli => write!(f, "CLI"),
|
||||||
|
Self::Env => write!(f, "NX9_BZOD_DATA_DIR"),
|
||||||
|
Self::ConfigFile => write!(f, "config.toml"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub host: String,
|
pub host: String,
|
||||||
@@ -45,11 +84,23 @@ struct TomlBackupConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn load() -> Self {
|
pub fn load() -> Result<Self, ConfigError> {
|
||||||
// 1. Built-in defaults
|
Self::load_with_cli(None::<&std::path::Path>)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_with_cli<P: AsRef<std::path::Path>>(
|
||||||
|
cli_data_dir: Option<P>,
|
||||||
|
) -> Result<Self, ConfigError> {
|
||||||
|
Self::load_from_sources(cli_data_dir, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_from_sources<P: AsRef<std::path::Path>>(
|
||||||
|
cli_data_dir: Option<P>,
|
||||||
|
load_dotenv: bool,
|
||||||
|
) -> Result<Self, ConfigError> {
|
||||||
|
// 1. Built-in defaults (no implicit data_dir default)
|
||||||
let mut host = "0.0.0.0".to_string();
|
let mut host = "0.0.0.0".to_string();
|
||||||
let mut port = 8080u16;
|
let mut port = 8080u16;
|
||||||
let mut data_dir = PathBuf::from("./data");
|
|
||||||
let mut admin_username = "admin".to_string();
|
let mut admin_username = "admin".to_string();
|
||||||
let mut bootstrap_password_sha256 = "".to_string();
|
let mut bootstrap_password_sha256 = "".to_string();
|
||||||
let mut session_secret =
|
let mut session_secret =
|
||||||
@@ -63,12 +114,18 @@ impl Config {
|
|||||||
let mut backup_dir = PathBuf::from("./backups");
|
let mut backup_dir = PathBuf::from("./backups");
|
||||||
let mut base_url = None;
|
let mut base_url = None;
|
||||||
|
|
||||||
// 2. Load bzod.toml if it exists
|
let mut resolved_data_dir: Option<PathBuf> = None;
|
||||||
let mut toml_path = "bzod.toml".to_string();
|
let mut data_dir_source: Option<DataDirSource> = None;
|
||||||
if fs::metadata("bzod.toml").is_err() && fs::metadata("config/bzod.toml").is_ok() {
|
|
||||||
toml_path = "config/bzod.toml".to_string();
|
// 2. Load bzod.toml / config.toml if it exists
|
||||||
}
|
let possible_tomls = [
|
||||||
if let Ok(toml_content) = fs::read_to_string(&toml_path) {
|
"bzod.toml",
|
||||||
|
"config/bzod.toml",
|
||||||
|
"config.toml",
|
||||||
|
"config/config.toml",
|
||||||
|
];
|
||||||
|
for toml_path in possible_tomls {
|
||||||
|
if let Ok(toml_content) = fs::read_to_string(toml_path) {
|
||||||
if let Ok(toml_config) = toml::from_str::<TomlConfig>(&toml_content) {
|
if let Ok(toml_config) = toml::from_str::<TomlConfig>(&toml_content) {
|
||||||
if let Some(h) = toml_config.host {
|
if let Some(h) = toml_config.host {
|
||||||
host = h;
|
host = h;
|
||||||
@@ -77,7 +134,10 @@ impl Config {
|
|||||||
port = p;
|
port = p;
|
||||||
}
|
}
|
||||||
if let Some(d) = toml_config.data_dir {
|
if let Some(d) = toml_config.data_dir {
|
||||||
data_dir = PathBuf::from(d);
|
if !d.trim().is_empty() {
|
||||||
|
resolved_data_dir = Some(PathBuf::from(d));
|
||||||
|
data_dir_source = Some(DataDirSource::ConfigFile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if let Some(u) = toml_config.admin_username {
|
if let Some(u) = toml_config.admin_username {
|
||||||
admin_username = u;
|
admin_username = u;
|
||||||
@@ -118,16 +178,20 @@ impl Config {
|
|||||||
if let Some(bu) = toml_config.base_url {
|
if let Some(bu) = toml_config.base_url {
|
||||||
base_url = Some(bu);
|
base_url = Some(bu);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Load .env if present
|
// 3. Load .env if present
|
||||||
|
if load_dotenv {
|
||||||
let _ = dotenvy::dotenv();
|
let _ = dotenvy::dotenv();
|
||||||
if fs::metadata("config/.env").is_ok() {
|
if fs::metadata("config/.env").is_ok() {
|
||||||
let _ = dotenvy::from_path("config/.env");
|
let _ = dotenvy::from_path("config/.env");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 4. Load from Environment Variables (taking highest precedence)
|
// 4. Load from Environment Variables (taking precedence over config file)
|
||||||
if let Ok(h) = env::var("HOST") {
|
if let Ok(h) = env::var("HOST") {
|
||||||
host = h;
|
host = h;
|
||||||
}
|
}
|
||||||
@@ -136,8 +200,11 @@ impl Config {
|
|||||||
port = p;
|
port = p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Ok(d_str) = env::var("DATA_DIR") {
|
if let Ok(d_str) = env::var(NX9_BZOD_DATA_DIR_ENV) {
|
||||||
data_dir = PathBuf::from(d_str);
|
if !d_str.trim().is_empty() {
|
||||||
|
resolved_data_dir = Some(PathBuf::from(d_str));
|
||||||
|
data_dir_source = Some(DataDirSource::Env);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if let Ok(u) = env::var("ADMIN_USERNAME") {
|
if let Ok(u) = env::var("ADMIN_USERNAME") {
|
||||||
admin_username = u;
|
admin_username = u;
|
||||||
@@ -187,7 +254,26 @@ impl Config {
|
|||||||
base_url = Some(bu);
|
base_url = Some(bu);
|
||||||
}
|
}
|
||||||
|
|
||||||
Self {
|
// 5. CLI override (highest precedence)
|
||||||
|
if let Some(cli_dir) = cli_data_dir {
|
||||||
|
let path_ref = cli_dir.as_ref();
|
||||||
|
if !path_ref.as_os_str().is_empty() {
|
||||||
|
resolved_data_dir = Some(path_ref.to_path_buf());
|
||||||
|
data_dir_source = Some(DataDirSource::Cli);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let data_dir = match resolved_data_dir {
|
||||||
|
Some(dir) => dir,
|
||||||
|
None => return Err(ConfigError::MissingDataDir),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(source) = data_dir_source {
|
||||||
|
tracing::info!("Data directory: {}", data_dir.display());
|
||||||
|
tracing::info!("Data directory source: {}", source);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
host,
|
host,
|
||||||
port,
|
port,
|
||||||
data_dir,
|
data_dir,
|
||||||
@@ -202,6 +288,6 @@ impl Config {
|
|||||||
backup_interval_mins,
|
backup_interval_mins,
|
||||||
backup_dir,
|
backup_dir,
|
||||||
base_url,
|
base_url,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
-3
@@ -392,12 +392,11 @@ mod db_init_tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_db_init() {
|
fn test_db_init() {
|
||||||
let temp_dir = PathBuf::from("./temp_test_db_dir");
|
let temp_dir = std::env::temp_dir().join(format!("test_db_init_{}", uuid::Uuid::new_v4()));
|
||||||
if temp_dir.exists() {
|
if temp_dir.exists() {
|
||||||
let _ = std::fs::remove_dir_all(&temp_dir);
|
let _ = std::fs::remove_dir_all(&temp_dir);
|
||||||
}
|
}
|
||||||
let mut config = Config::load();
|
let config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
let db = Db::init(&config);
|
let db = Db::init(&config);
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@
|
|||||||
//! └── extensions/<extension>/<extension>.db
|
//! └── extensions/<extension>/<extension>.db
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! `<data_dir>` is `Config.data_dir` (env `DATA_DIR`, default `./data`).
|
//! `<data_dir>` is `Config.data_dir` (CLI `--data-dir`, env `NX9_BZOD_DATA_DIR`, or config file).
|
||||||
//! It is not renamed to `database/`. Production Docker, CasaOS, and
|
//! It is not renamed to `database/`. Production Docker, CasaOS, and
|
||||||
//! `deploy.sh` bind this physical root.
|
//! `deploy.sh` bind this physical root.
|
||||||
|
|
||||||
|
|||||||
+7
-1
@@ -13,7 +13,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
.init();
|
.init();
|
||||||
|
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
let config = Config::load();
|
let config = match Config::load_with_cli(cli.command.data_dir()) {
|
||||||
|
Ok(config) => config,
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("Error: {err}");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
match cli.command {
|
match cli.command {
|
||||||
Commands::Serve {
|
Commands::Serve {
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ use std::fs;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.base_url = Some("http://bzo.in".to_string());
|
config.base_url = Some("http://bzo.in".to_string());
|
||||||
config
|
config
|
||||||
|
|||||||
@@ -19,10 +19,9 @@ use bzod::web::admin::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.base_url = Some("http://localhost:8080".to_string());
|
config.base_url = Some("http://bzo.in".to_string());
|
||||||
config
|
config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,8 +18,7 @@ fn compute_sha256(value: &str) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.admin_username = "admin".to_string();
|
config.admin_username = "admin".to_string();
|
||||||
config.base_url = Some("http://localhost:8080".to_string());
|
config.base_url = Some("http://localhost:8080".to_string());
|
||||||
|
|||||||
@@ -21,8 +21,7 @@ use bzod::db::Db;
|
|||||||
use bzod::web::admin::{dashboard_get, login_post, LoginForm};
|
use bzod::web::admin::{dashboard_get, login_post, LoginForm};
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.admin_username = "admin".to_string();
|
config.admin_username = "admin".to_string();
|
||||||
config.base_url = Some("http://localhost:8080".to_string());
|
config.base_url = Some("http://localhost:8080".to_string());
|
||||||
|
|||||||
+1
-2
@@ -7,8 +7,7 @@ use std::fs;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.base_url = Some("http://bzo.in".to_string());
|
config.base_url = Some("http://bzo.in".to_string());
|
||||||
config
|
config
|
||||||
|
|||||||
@@ -7,8 +7,7 @@ use tar::Archive;
|
|||||||
use zstd::Decoder;
|
use zstd::Decoder;
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.base_url = Some("http://bzo.in".to_string());
|
config.base_url = Some("http://bzo.in".to_string());
|
||||||
config
|
config
|
||||||
@@ -200,8 +199,7 @@ async fn test_restore_slug_collision_rejection() {
|
|||||||
));
|
));
|
||||||
fs::create_dir_all(&temp_dir).unwrap();
|
fs::create_dir_all(&temp_dir).unwrap();
|
||||||
|
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.join("backups");
|
config.backup_dir = temp_dir.join("backups");
|
||||||
fs::create_dir_all(&config.backup_dir).unwrap();
|
fs::create_dir_all(&config.backup_dir).unwrap();
|
||||||
|
|
||||||
|
|||||||
@@ -18,8 +18,7 @@ fn compute_sha256(value: &str) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.admin_username = "admin".to_string();
|
config.admin_username = "admin".to_string();
|
||||||
config.base_url = Some("http://localhost:8080".to_string());
|
config.base_url = Some("http://localhost:8080".to_string());
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ use std::sync::Arc;
|
|||||||
use tokio::sync::Barrier;
|
use tokio::sync::Barrier;
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.base_url = Some("http://bzo.in".to_string());
|
config.base_url = Some("http://bzo.in".to_string());
|
||||||
config
|
config
|
||||||
|
|||||||
@@ -0,0 +1,222 @@
|
|||||||
|
use bzod::config::{Config, ConfigError, NX9_BZOD_DATA_DIR_ENV};
|
||||||
|
use bzod::db::topology::Topology;
|
||||||
|
use bzod::identity::TenantId;
|
||||||
|
use std::env;
|
||||||
|
use std::fs;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
// Global lock to prevent race conditions during env-var testing
|
||||||
|
static ENV_LOCK: Mutex<()> = Mutex::new(());
|
||||||
|
|
||||||
|
struct EnvGuard {
|
||||||
|
key: &'static str,
|
||||||
|
original_val: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EnvGuard {
|
||||||
|
fn set(key: &'static str, val: &str) -> Self {
|
||||||
|
let original_val = env::var(key).ok();
|
||||||
|
env::set_var(key, val);
|
||||||
|
Self { key, original_val }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unset(key: &'static str) -> Self {
|
||||||
|
let original_val = env::var(key).ok();
|
||||||
|
env::remove_var(key);
|
||||||
|
Self { key, original_val }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for EnvGuard {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if let Some(ref val) = self.original_val {
|
||||||
|
env::set_var(self.key, val);
|
||||||
|
} else {
|
||||||
|
env::remove_var(self.key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_no_configuration_returns_missing_data_dir_error() {
|
||||||
|
let _lock = ENV_LOCK.lock().unwrap();
|
||||||
|
let _guard = EnvGuard::unset(NX9_BZOD_DATA_DIR_ENV);
|
||||||
|
|
||||||
|
// Call load_from_sources with no CLI and load_dotenv=false in an isolated context
|
||||||
|
let res = Config::load_from_sources(None::<&Path>, false);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
res.is_err(),
|
||||||
|
"Expected error when no data directory is configured"
|
||||||
|
);
|
||||||
|
match res.err().unwrap() {
|
||||||
|
ConfigError::MissingDataDir => {}
|
||||||
|
other => panic!("Expected ConfigError::MissingDataDir, got {:?}", other),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_environment_variable_resolves_data_dir() {
|
||||||
|
let _lock = ENV_LOCK.lock().unwrap();
|
||||||
|
let test_path = "/tmp/nx9-env-test-data";
|
||||||
|
let _guard = EnvGuard::set(NX9_BZOD_DATA_DIR_ENV, test_path);
|
||||||
|
|
||||||
|
let config = Config::load_from_sources(None::<&Path>, false)
|
||||||
|
.expect("Config should load with NX9_BZOD_DATA_DIR set");
|
||||||
|
|
||||||
|
assert_eq!(config.data_dir, PathBuf::from(test_path));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_config_file_resolves_data_dir() {
|
||||||
|
let _lock = ENV_LOCK.lock().unwrap();
|
||||||
|
let _guard = EnvGuard::unset(NX9_BZOD_DATA_DIR_ENV);
|
||||||
|
|
||||||
|
let temp_dir = std::env::temp_dir().join(format!("bzod_cfg_test_{}", uuid::Uuid::new_v4()));
|
||||||
|
fs::create_dir_all(&temp_dir).unwrap();
|
||||||
|
|
||||||
|
let toml_file = temp_dir.join("bzod.toml");
|
||||||
|
let target_data_dir = "/tmp/config-file-data";
|
||||||
|
fs::write(&toml_file, format!("data_dir = \"{}\"\n", target_data_dir)).unwrap();
|
||||||
|
|
||||||
|
// Change current directory temporarily for config file reading
|
||||||
|
let original_cwd = env::current_dir().unwrap();
|
||||||
|
env::set_current_dir(&temp_dir).unwrap();
|
||||||
|
|
||||||
|
let config_res = Config::load_from_sources(None::<&Path>, false);
|
||||||
|
|
||||||
|
// Restore cwd
|
||||||
|
env::set_current_dir(original_cwd).unwrap();
|
||||||
|
let _ = fs::remove_dir_all(&temp_dir);
|
||||||
|
|
||||||
|
let config = config_res.expect("Config should load from bzod.toml");
|
||||||
|
assert_eq!(config.data_dir, PathBuf::from(target_data_dir));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_environment_overrides_config_file() {
|
||||||
|
let _lock = ENV_LOCK.lock().unwrap();
|
||||||
|
let env_data_dir = "/tmp/env-override-data";
|
||||||
|
let _guard = EnvGuard::set(NX9_BZOD_DATA_DIR_ENV, env_data_dir);
|
||||||
|
|
||||||
|
let temp_dir = std::env::temp_dir().join(format!("bzod_cfg_test_{}", uuid::Uuid::new_v4()));
|
||||||
|
fs::create_dir_all(&temp_dir).unwrap();
|
||||||
|
|
||||||
|
let toml_file = temp_dir.join("bzod.toml");
|
||||||
|
let config_data_dir = "/tmp/config-file-data";
|
||||||
|
fs::write(&toml_file, format!("data_dir = \"{}\"\n", config_data_dir)).unwrap();
|
||||||
|
|
||||||
|
let original_cwd = env::current_dir().unwrap();
|
||||||
|
env::set_current_dir(&temp_dir).unwrap();
|
||||||
|
|
||||||
|
let config_res = Config::load_from_sources(None::<&Path>, false);
|
||||||
|
|
||||||
|
env::set_current_dir(original_cwd).unwrap();
|
||||||
|
let _ = fs::remove_dir_all(&temp_dir);
|
||||||
|
|
||||||
|
let config = config_res.expect("Config should load");
|
||||||
|
assert_eq!(config.data_dir, PathBuf::from(env_data_dir));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cli_overrides_environment() {
|
||||||
|
let _lock = ENV_LOCK.lock().unwrap();
|
||||||
|
let env_data_dir = "/tmp/env-data";
|
||||||
|
let _guard = EnvGuard::set(NX9_BZOD_DATA_DIR_ENV, env_data_dir);
|
||||||
|
|
||||||
|
let cli_data_dir = "/tmp/cli-override-data";
|
||||||
|
let config = Config::load_from_sources(Some(cli_data_dir), false)
|
||||||
|
.expect("Config should load with CLI override");
|
||||||
|
|
||||||
|
assert_eq!(config.data_dir, PathBuf::from(cli_data_dir));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cli_overrides_config_file() {
|
||||||
|
let _lock = ENV_LOCK.lock().unwrap();
|
||||||
|
let _guard = EnvGuard::unset(NX9_BZOD_DATA_DIR_ENV);
|
||||||
|
|
||||||
|
let temp_dir = std::env::temp_dir().join(format!("bzod_cfg_test_{}", uuid::Uuid::new_v4()));
|
||||||
|
fs::create_dir_all(&temp_dir).unwrap();
|
||||||
|
|
||||||
|
let toml_file = temp_dir.join("bzod.toml");
|
||||||
|
let config_data_dir = "/tmp/config-file-data";
|
||||||
|
fs::write(&toml_file, format!("data_dir = \"{}\"\n", config_data_dir)).unwrap();
|
||||||
|
|
||||||
|
let original_cwd = env::current_dir().unwrap();
|
||||||
|
env::set_current_dir(&temp_dir).unwrap();
|
||||||
|
|
||||||
|
let cli_data_dir = "/tmp/cli-data-highest";
|
||||||
|
let config_res = Config::load_from_sources(Some(cli_data_dir), false);
|
||||||
|
|
||||||
|
env::set_current_dir(original_cwd).unwrap();
|
||||||
|
let _ = fs::remove_dir_all(&temp_dir);
|
||||||
|
|
||||||
|
let config = config_res.expect("Config should load with CLI override");
|
||||||
|
assert_eq!(config.data_dir, PathBuf::from(cli_data_dir));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_relative_path_semantics_preserved() {
|
||||||
|
let _lock = ENV_LOCK.lock().unwrap();
|
||||||
|
let relative_path = "custom_relative/data";
|
||||||
|
let config = Config::load_from_sources(Some(relative_path), false)
|
||||||
|
.expect("Relative path in CLI should be accepted as-is without forced canonicalization");
|
||||||
|
|
||||||
|
assert_eq!(config.data_dir, PathBuf::from(relative_path));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_topology_resolves_all_databases_relative_to_configured_root() {
|
||||||
|
let custom_root = PathBuf::from("/var/lib/bzod/custom_root");
|
||||||
|
let topology = Topology::new(&custom_root);
|
||||||
|
|
||||||
|
assert_eq!(topology.root(), &custom_root);
|
||||||
|
assert_eq!(topology.admin_dir(), custom_root.join("admin"));
|
||||||
|
assert_eq!(topology.slugs_dir(), custom_root.join("slugs"));
|
||||||
|
assert_eq!(topology.users_dir(), custom_root.join("users"));
|
||||||
|
|
||||||
|
// Core databases
|
||||||
|
assert_eq!(topology.admin_db(), custom_root.join("admin/admin.db"));
|
||||||
|
assert_eq!(topology.system_db(), custom_root.join("admin/system.db"));
|
||||||
|
assert_eq!(
|
||||||
|
topology.users_registry_db(),
|
||||||
|
custom_root.join("admin/users.db")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
topology.global_urls_db(),
|
||||||
|
custom_root.join("slugs/global_urls.db")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
topology.global_landing_pages_db(),
|
||||||
|
custom_root.join("slugs/global_landing_pages.db")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
topology.reserved_db(),
|
||||||
|
custom_root.join("slugs/reserved.db")
|
||||||
|
);
|
||||||
|
|
||||||
|
// Tenant databases
|
||||||
|
let tenant_id = TenantId::parse("a1b2c3d4e5f6").unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
topology.tenant_dir(tenant_id),
|
||||||
|
custom_root.join("users/a1b2c3d4e5f6")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
topology.tenant_content_db(tenant_id),
|
||||||
|
custom_root.join("users/a1b2c3d4e5f6/content.db")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
topology.tenant_analytics_db(tenant_id),
|
||||||
|
custom_root.join("users/a1b2c3d4e5f6/analytics.db")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
topology.tenant_profile_db(tenant_id),
|
||||||
|
custom_root.join("users/a1b2c3d4e5f6/profile.db")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
topology.extension_db("a1b2c3d4e5f6", "cv").unwrap(),
|
||||||
|
custom_root.join("users/a1b2c3d4e5f6/extensions/cv/cv.db")
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -4,8 +4,7 @@ use std::fs;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.base_url = Some("http://bzo.in".to_string());
|
config.base_url = Some("http://bzo.in".to_string());
|
||||||
config
|
config
|
||||||
|
|||||||
@@ -18,8 +18,7 @@ fn compute_sha256(value: &str) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.admin_username = "admin".to_string();
|
config.admin_username = "admin".to_string();
|
||||||
config.base_url = Some("http://localhost:8080".to_string());
|
config.base_url = Some("http://localhost:8080".to_string());
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ use std::fs;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.base_url = Some("http://bzo.in".to_string());
|
config.base_url = Some("http://bzo.in".to_string());
|
||||||
config
|
config
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ use std::fs;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.base_url = Some("http://bzo.in".to_string());
|
config.base_url = Some("http://bzo.in".to_string());
|
||||||
config
|
config
|
||||||
|
|||||||
@@ -21,8 +21,7 @@ use std::path::PathBuf;
|
|||||||
use tar::Builder;
|
use tar::Builder;
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.base_url = Some("http://bzo.in".to_string());
|
config.base_url = Some("http://bzo.in".to_string());
|
||||||
config
|
config
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ use std::fs;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.base_url = Some("http://bzo.in".to_string());
|
config.base_url = Some("http://bzo.in".to_string());
|
||||||
config
|
config
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ use std::path::PathBuf;
|
|||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.base_url = Some("http://bzo.in".to_string());
|
config.base_url = Some("http://bzo.in".to_string());
|
||||||
config
|
config
|
||||||
|
|||||||
@@ -34,8 +34,7 @@ fn test_custom_slug_validation() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.base_url = Some("http://bzo.in".to_string());
|
config.base_url = Some("http://bzo.in".to_string());
|
||||||
config
|
config
|
||||||
|
|||||||
@@ -18,8 +18,7 @@ fn compute_sha256(value: &str) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.admin_username = "admin".to_string();
|
config.admin_username = "admin".to_string();
|
||||||
config.base_url = Some("http://localhost:8080".to_string());
|
config.base_url = Some("http://localhost:8080".to_string());
|
||||||
|
|||||||
@@ -18,8 +18,7 @@ fn compute_sha256(value: &str) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.admin_username = "admin".to_string();
|
config.admin_username = "admin".to_string();
|
||||||
config.base_url = Some("http://localhost:8080".to_string());
|
config.base_url = Some("http://localhost:8080".to_string());
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ use std::fs;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.base_url = Some("http://bzo.in".to_string());
|
config.base_url = Some("http://bzo.in".to_string());
|
||||||
config
|
config
|
||||||
|
|||||||
@@ -29,8 +29,7 @@ fn compute_sha256(value: &str) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.admin_username = "admin".to_string();
|
config.admin_username = "admin".to_string();
|
||||||
config.base_url = Some("http://localhost:8080".to_string());
|
config.base_url = Some("http://localhost:8080".to_string());
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ use std::fs;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.base_url = Some("http://bzo.in".to_string());
|
config.base_url = Some("http://bzo.in".to_string());
|
||||||
config
|
config
|
||||||
|
|||||||
@@ -11,8 +11,7 @@ use std::path::PathBuf;
|
|||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.base_url = Some("http://bzo.in".to_string());
|
config.base_url = Some("http://bzo.in".to_string());
|
||||||
config
|
config
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ use std::fs;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.base_url = Some("http://bzo.in".to_string());
|
config.base_url = Some("http://bzo.in".to_string());
|
||||||
config
|
config
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ use std::fs;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.base_url = Some("http://bzo.in".to_string());
|
config.base_url = Some("http://bzo.in".to_string());
|
||||||
config
|
config
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ use std::fs;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.base_url = Some("http://bzo.in".to_string());
|
config.base_url = Some("http://bzo.in".to_string());
|
||||||
config
|
config
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ use std::fs;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.base_url = Some("http://bzo.in".to_string());
|
config.base_url = Some("http://bzo.in".to_string());
|
||||||
config
|
config
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ use std::fs;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.base_url = Some("http://bzo.in".to_string());
|
config.base_url = Some("http://bzo.in".to_string());
|
||||||
config
|
config
|
||||||
|
|||||||
@@ -19,8 +19,7 @@ fn compute_sha256(value: &str) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.admin_username = "admin".to_string();
|
config.admin_username = "admin".to_string();
|
||||||
config.base_url = Some("http://localhost:8080".to_string());
|
config.base_url = Some("http://localhost:8080".to_string());
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ use std::fs;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.base_url = Some("http://bzo.in".to_string());
|
config.base_url = Some("http://bzo.in".to_string());
|
||||||
config
|
config
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ use std::fs;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.base_url = Some("http://bzo.in".to_string());
|
config.base_url = Some("http://bzo.in".to_string());
|
||||||
config
|
config
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ use std::fs;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.base_url = Some("http://bzo.in".to_string());
|
config.base_url = Some("http://bzo.in".to_string());
|
||||||
config
|
config
|
||||||
|
|||||||
@@ -50,8 +50,7 @@ impl TestHarness {
|
|||||||
let temp_dir =
|
let temp_dir =
|
||||||
std::env::temp_dir().join(format!("bzod_admin_boundary_{}", uuid::Uuid::new_v4()));
|
std::env::temp_dir().join(format!("bzod_admin_boundary_{}", uuid::Uuid::new_v4()));
|
||||||
fs::create_dir_all(&temp_dir).unwrap();
|
fs::create_dir_all(&temp_dir).unwrap();
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.join("backups");
|
config.backup_dir = temp_dir.join("backups");
|
||||||
config.base_url = Some("http://localhost:8080".to_string());
|
config.base_url = Some("http://localhost:8080".to_string());
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ use bzod::state::AppState;
|
|||||||
use bzod::web::create_router;
|
use bzod::web::create_router;
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.join("backups");
|
config.backup_dir = temp_dir.join("backups");
|
||||||
config.base_url = Some("http://localhost:8080".to_string());
|
config.base_url = Some("http://localhost:8080".to_string());
|
||||||
config
|
config
|
||||||
|
|||||||
@@ -55,8 +55,7 @@ impl TestHarness {
|
|||||||
let temp_dir =
|
let temp_dir =
|
||||||
std::env::temp_dir().join(format!("bzod_user_boundary_{}", uuid::Uuid::new_v4()));
|
std::env::temp_dir().join(format!("bzod_user_boundary_{}", uuid::Uuid::new_v4()));
|
||||||
fs::create_dir_all(&temp_dir).unwrap();
|
fs::create_dir_all(&temp_dir).unwrap();
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.join("backups");
|
config.backup_dir = temp_dir.join("backups");
|
||||||
config.base_url = Some("http://localhost:8080".to_string());
|
config.base_url = Some("http://localhost:8080".to_string());
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,7 @@ use std::path::PathBuf;
|
|||||||
fn temp_config() -> (PathBuf, Config) {
|
fn temp_config() -> (PathBuf, Config) {
|
||||||
let temp_dir = std::env::temp_dir().join(format!("bzod_v08_topology_{}", uuid::Uuid::new_v4()));
|
let temp_dir = std::env::temp_dir().join(format!("bzod_v08_topology_{}", uuid::Uuid::new_v4()));
|
||||||
fs::create_dir_all(&temp_dir).unwrap();
|
fs::create_dir_all(&temp_dir).unwrap();
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.join("backups");
|
config.backup_dir = temp_dir.join("backups");
|
||||||
(temp_dir, config)
|
(temp_dir, config)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,8 +25,7 @@ fn temp_config() -> (PathBuf, Config) {
|
|||||||
let temp_dir =
|
let temp_dir =
|
||||||
std::env::temp_dir().join(format!("bzod_v08_id_migrate_{}", uuid::Uuid::new_v4()));
|
std::env::temp_dir().join(format!("bzod_v08_id_migrate_{}", uuid::Uuid::new_v4()));
|
||||||
fs::create_dir_all(&temp_dir).unwrap();
|
fs::create_dir_all(&temp_dir).unwrap();
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.join("backups");
|
config.backup_dir = temp_dir.join("backups");
|
||||||
(temp_dir, config)
|
(temp_dir, config)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,7 @@ use uuid::Uuid;
|
|||||||
fn create_test_config() -> (PathBuf, Config) {
|
fn create_test_config() -> (PathBuf, Config) {
|
||||||
let temp_dir = std::env::temp_dir().join(format!("bzod_p6a_test_{}", Uuid::new_v4()));
|
let temp_dir = std::env::temp_dir().join(format!("bzod_p6a_test_{}", Uuid::new_v4()));
|
||||||
fs::create_dir_all(&temp_dir).unwrap();
|
fs::create_dir_all(&temp_dir).unwrap();
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.join("backups");
|
config.backup_dir = temp_dir.join("backups");
|
||||||
config.base_url = Some("http://localhost:8080".to_string());
|
config.base_url = Some("http://localhost:8080".to_string());
|
||||||
(temp_dir, config)
|
(temp_dir, config)
|
||||||
|
|||||||
@@ -25,8 +25,7 @@ fn temp_config() -> (PathBuf, Config) {
|
|||||||
let temp_dir =
|
let temp_dir =
|
||||||
std::env::temp_dir().join(format!("bzod_v08_slug_migrate_{}", uuid::Uuid::new_v4()));
|
std::env::temp_dir().join(format!("bzod_v08_slug_migrate_{}", uuid::Uuid::new_v4()));
|
||||||
fs::create_dir_all(&temp_dir).unwrap();
|
fs::create_dir_all(&temp_dir).unwrap();
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.join("backups");
|
config.backup_dir = temp_dir.join("backups");
|
||||||
(temp_dir, config)
|
(temp_dir, config)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,7 @@ use std::time::Instant;
|
|||||||
fn temp_config() -> (PathBuf, Config) {
|
fn temp_config() -> (PathBuf, Config) {
|
||||||
let temp_dir = std::env::temp_dir().join(format!("bzod_v08_boundary_{}", uuid::Uuid::new_v4()));
|
let temp_dir = std::env::temp_dir().join(format!("bzod_v08_boundary_{}", uuid::Uuid::new_v4()));
|
||||||
fs::create_dir_all(&temp_dir).unwrap();
|
fs::create_dir_all(&temp_dir).unwrap();
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.join("backups");
|
config.backup_dir = temp_dir.join("backups");
|
||||||
(temp_dir, config)
|
(temp_dir, config)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ use std::fs;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
fn create_temp_config(temp_dir: PathBuf) -> Config {
|
||||||
let mut config = Config::load();
|
let mut config = Config::load_with_cli(Some(&temp_dir)).unwrap();
|
||||||
config.data_dir = temp_dir.clone();
|
|
||||||
config.backup_dir = temp_dir.clone();
|
config.backup_dir = temp_dir.clone();
|
||||||
config.base_url = Some("http://bzo.in".to_string());
|
config.base_url = Some("http://bzo.in".to_string());
|
||||||
config
|
config
|
||||||
|
|||||||
+1
-1
@@ -121,7 +121,7 @@ if [ ! -f "${ENV_FILE}" ]; then
|
|||||||
cat <<EOF > "${ENV_FILE}"
|
cat <<EOF > "${ENV_FILE}"
|
||||||
HOST=0.0.0.0
|
HOST=0.0.0.0
|
||||||
PORT=8654
|
PORT=8654
|
||||||
DATA_DIR=${DATA_DIR}
|
NX9_BZOD_DATA_DIR=${DATA_DIR}
|
||||||
COOKIE_SECURE=true
|
COOKIE_SECURE=true
|
||||||
RUST_LOG=info
|
RUST_LOG=info
|
||||||
SESSION_SECRET=$(openssl rand -hex 32)
|
SESSION_SECRET=$(openssl rand -hex 32)
|
||||||
|
|||||||
Reference in new issue
Block a user