Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.

Each entry lists the date and the crate versions that were released.

## 2026-05-28 — mqdb-cli 0.8.6

### Fixed

- `mqdb agent start` (and `cluster start`) panicked at startup on every invocation in debug builds: `thread 'main' panicked ... Long option names must be unique ... '--' is in use by both 'passwd_data' and 'acl_data'`. Seventeen optional inline-content args (`passwd_data`, `acl_data`, `scram_data`, the `*_data`/`*_key`/`*_secret` variants in both agent and cluster) were declared `#[arg(long = "")]`, which clap registers as the empty long option `--`; the duplicates tripped clap's `debug_assert`, crashing every debug-build command before parsing (release builds skip the assert, so the flags were silently mis-defined and never parsed). Each now has a distinct hidden long name (`--passwd-data`, `--acl-data`, `--scram-data`, …), so debug builds run and the inline-content flags parse correctly while staying hidden from `--help`. Added a `Cli::command().debug_assert()` regression test so a future empty/duplicate long name fails CI instead of only crashing debug binaries.
- `mqdb agent start --memory-backend` no longer requires `--db`. The flag is now `required_unless_present = "memory_backend"`; in memory mode without a path it defaults to a temp directory, which the in-memory backend never touches. Callers no longer need to pass a dummy `--db`.

## 2026-05-28 — mqdb-core 0.7.1, mqdb-agent 0.8.5, mqdb-vault 0.1.1, mqdb-wasm 0.3.3, mqdb-cli 0.8.5

### Added
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/mqdb-cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mqdb-cli"
version = "0.8.5"
version = "0.8.6"
publish = false
edition.workspace = true
license = "AGPL-3.0-only"
Expand Down
27 changes: 16 additions & 11 deletions crates/mqdb-cli/src/cli_types/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,13 @@ pub(crate) struct AgentStartFields {
help = "Address to bind MQTT listener"
)]
pub(crate) bind: SocketAddr,
#[arg(long, env = "MQDB_DB", help = "Path to database directory")]
pub(crate) db: PathBuf,
#[arg(
long,
env = "MQDB_DB",
required_unless_present = "memory_backend",
help = "Path to database directory (optional with --memory-backend)"
)]
pub(crate) db: Option<PathBuf>,
#[arg(
long,
env = "MQDB_MEMORY_BACKEND",
Expand Down Expand Up @@ -79,15 +84,15 @@ pub(crate) struct AgentStartFields {
help = "Path to file containing encryption passphrase"
)]
pub(crate) passphrase_file: Option<PathBuf>,
#[arg(long = "", env = "MQDB_PASSPHRASE", hide = true)]
#[arg(long = "passphrase-data", env = "MQDB_PASSPHRASE", hide = true)]
pub(crate) passphrase_data: Option<String>,
#[arg(long, env = "MQDB_LICENSE_FILE", help = "Path to license key file")]
pub(crate) license: Option<PathBuf>,
#[arg(long = "", env = "MQDB_LICENSE", hide = true)]
#[arg(long = "license-data", env = "MQDB_LICENSE", hide = true)]
pub(crate) license_data: Option<String>,
#[arg(long = "", env = "MQDB_QUIC_CERT", hide = true)]
#[arg(long = "quic-cert-data", env = "MQDB_QUIC_CERT", hide = true)]
pub(crate) quic_cert_data: Option<String>,
#[arg(long = "", env = "MQDB_QUIC_KEY", hide = true)]
#[arg(long = "quic-key-data", env = "MQDB_QUIC_KEY", hide = true)]
pub(crate) quic_key_data: Option<String>,
#[arg(
long,
Expand Down Expand Up @@ -240,17 +245,17 @@ pub(crate) struct ClusterStartFields {
help = "Path to file containing encryption passphrase"
)]
pub(crate) passphrase_file: Option<PathBuf>,
#[arg(long = "", env = "MQDB_PASSPHRASE", hide = true)]
#[arg(long = "passphrase-data", env = "MQDB_PASSPHRASE", hide = true)]
pub(crate) passphrase_data: Option<String>,
#[arg(long, env = "MQDB_LICENSE_FILE", help = "Path to license key file")]
pub(crate) license: Option<PathBuf>,
#[arg(long = "", env = "MQDB_LICENSE", hide = true)]
#[arg(long = "license-data", env = "MQDB_LICENSE", hide = true)]
pub(crate) license_data: Option<String>,
#[arg(long = "", env = "MQDB_QUIC_CERT", hide = true)]
#[arg(long = "quic-cert-data", env = "MQDB_QUIC_CERT", hide = true)]
pub(crate) quic_cert_data: Option<String>,
#[arg(long = "", env = "MQDB_QUIC_KEY", hide = true)]
#[arg(long = "quic-key-data", env = "MQDB_QUIC_KEY", hide = true)]
pub(crate) quic_key_data: Option<String>,
#[arg(long = "", env = "MQDB_QUIC_CA", hide = true)]
#[arg(long = "quic-ca-data", env = "MQDB_QUIC_CA", hide = true)]
pub(crate) quic_ca_data: Option<String>,
}

Expand Down
24 changes: 16 additions & 8 deletions crates/mqdb-cli/src/cli_types/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ use super::base::JwtAlgorithmArg;
pub(crate) struct AuthArgs {
#[arg(long, env = "MQDB_PASSWD_FILE", help = "Path to password file")]
pub(crate) passwd: Option<PathBuf>,
#[arg(long = "", env = "MQDB_PASSWD", hide = true)]
#[arg(long = "passwd-data", env = "MQDB_PASSWD", hide = true)]
pub(crate) passwd_data: Option<String>,
#[arg(long, env = "MQDB_ACL_FILE", help = "Path to ACL file")]
pub(crate) acl: Option<PathBuf>,
#[arg(long = "", env = "MQDB_ACL", hide = true)]
#[arg(long = "acl-data", env = "MQDB_ACL", hide = true)]
pub(crate) acl_data: Option<String>,
#[cfg(feature = "dev-insecure")]
#[arg(long, help = "Allow anonymous connections (dev only)")]
Expand All @@ -26,7 +26,7 @@ pub(crate) struct AuthArgs {
help = "Path to SCRAM-SHA-256 credentials file"
)]
pub(crate) scram_file: Option<PathBuf>,
#[arg(long = "", env = "MQDB_SCRAM", hide = true)]
#[arg(long = "scram-data", env = "MQDB_SCRAM", hide = true)]
pub(crate) scram_data: Option<String>,
#[arg(
long,
Expand All @@ -41,7 +41,7 @@ pub(crate) struct AuthArgs {
help = "Path to JWT secret/key file"
)]
pub(crate) jwt_key: Option<PathBuf>,
#[arg(long = "", env = "MQDB_JWT_KEY", hide = true)]
#[arg(long = "jwt-key-data", env = "MQDB_JWT_KEY", hide = true)]
pub(crate) jwt_key_data: Option<String>,
#[arg(long, env = "MQDB_JWT_ISSUER", help = "JWT issuer claim")]
pub(crate) jwt_issuer: Option<String>,
Expand All @@ -56,15 +56,19 @@ pub(crate) struct AuthArgs {
pub(crate) jwt_clock_skew: u64,
#[arg(long, env = "MQDB_FEDERATED_JWT_CONFIG_FILE", conflicts_with_all = ["jwt_algorithm"], help = "Path to federated JWT config JSON")]
pub(crate) federated_jwt_config: Option<PathBuf>,
#[arg(long = "", env = "MQDB_FEDERATED_JWT_CONFIG", hide = true)]
#[arg(
long = "federated-jwt-config-data",
env = "MQDB_FEDERATED_JWT_CONFIG",
hide = true
)]
pub(crate) federated_jwt_config_data: Option<String>,
#[arg(
long,
env = "MQDB_CERT_AUTH_FILE",
help = "Path to certificate auth file"
)]
pub(crate) cert_auth_file: Option<PathBuf>,
#[arg(long = "", env = "MQDB_CERT_AUTH", hide = true)]
#[arg(long = "cert-auth-data", env = "MQDB_CERT_AUTH", hide = true)]
pub(crate) cert_auth_data: Option<String>,
#[arg(
long,
Expand Down Expand Up @@ -116,7 +120,11 @@ pub(crate) struct OAuthArgs {
help = "Path to file containing Google OAuth client secret"
)]
pub(crate) oauth_client_secret: Option<PathBuf>,
#[arg(long = "", env = "MQDB_OAUTH_CLIENT_SECRET", hide = true)]
#[arg(
long = "oauth-client-secret-data",
env = "MQDB_OAUTH_CLIENT_SECRET",
hide = true
)]
pub(crate) oauth_client_secret_data: Option<String>,
#[arg(
long,
Expand Down Expand Up @@ -168,7 +176,7 @@ pub(crate) struct OAuthArgs {
help = "Path to 32-byte identity encryption key file (auto-generated if omitted)"
)]
pub(crate) identity_key_file: Option<PathBuf>,
#[arg(long = "", env = "MQDB_IDENTITY_KEY", hide = true)]
#[arg(long = "identity-key-data", env = "MQDB_IDENTITY_KEY", hide = true)]
pub(crate) identity_key_data: Option<String>,
#[arg(
long,
Expand Down
25 changes: 24 additions & 1 deletion crates/mqdb-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,9 @@ async fn dispatch_agent(action: AgentAction) -> Result<(), Box<dyn std::error::E
AgentAction::Start(fields) => {
cmd_agent_start(AgentStartArgs {
bind: fields.bind,
db_path: fields.db,
db_path: fields
.db
.unwrap_or_else(|| std::env::temp_dir().join("mqdb-memory")),
memory_backend: fields.memory_backend,
auth: *fields.auth,
durability: fields.durability,
Expand Down Expand Up @@ -557,3 +559,24 @@ async fn dispatch_bench(action: BenchAction) -> Result<(), Box<dyn std::error::E
}
}
}

#[cfg(test)]
mod cli_tests {
use crate::cli_types::Cli;
use clap::{CommandFactory, Parser};

#[test]
fn cli_definition_is_valid() {
Cli::command().debug_assert();
}

#[test]
fn memory_backend_makes_db_optional() {
let parsed = Cli::try_parse_from(["mqdb", "agent", "start", "--memory-backend"]);
assert!(
parsed.is_ok(),
"--memory-backend should not require --db: {:?}",
parsed.err()
);
}
}
Loading