From c57796e2a45ca6e6e39aeed08b8f13b7fe30d322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabr=C3=ADcio=20Bracht?= Date: Fri, 22 May 2026 12:06:20 -0700 Subject: [PATCH 1/2] gate http server behind http-api feature in mqdb-agent --- CHANGELOG.md | 10 +++++++ Cargo.lock | 2 +- README.md | 26 +++++++++++++----- crates/mqdb-agent/Cargo.toml | 2 +- crates/mqdb-agent/src/agent/mod.rs | 41 +++++++++++++++++++++------- crates/mqdb-agent/src/agent/tasks.rs | 1 + docs/distributed-design.md | 2 +- docs/testing/01-setup.md | 11 +++++--- 8 files changed, 71 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49a2d1e..43f74fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,16 @@ 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-22 — mqdb-agent 0.8.1 + +### Fixed + +- `http-api` feature flag was effectively a lie: declared in `Cargo.toml` with `default = ["http-api"]`, but three pieces of `MqdbAgent` referenced `crate::http::*` unconditionally — the `http_config` field, the `with_http_config` builder, and the two call sites of `spawn_http_task` in `run` / `start`. `cargo check -p mqdb-agent --no-default-features` failed with five compile errors (`E0433` on the missing `crate::http`, `E0609` on the gated `identity_crypto` field, and an `E0282` inference failure cascading from those). Gated all three behind `#[cfg(feature = "http-api")]` so the flag now actually opts the HTTP server in or out. Default-feature consumers see no change. + +### Docs + +- Corrected stale feature-flag names in user-facing docs. `README.md`, `docs/distributed-design.md`, and `docs/testing/01-setup.md` all referenced `--features agent-only` and a `native` feature flag, neither of which exist in any `Cargo.toml`. The actual `mqdb` CLI features are `cluster` (default), `http-api` (default), `opentelemetry`, and `dev-insecure`; agent-only builds use `--no-default-features` (optionally adding `--features http-api`). Added a feature-flag reference table in `README.md` under "CLI Tool → Installation" documenting all four flags and their defaults — the `http-api` flag was previously undocumented anywhere outside its `Cargo.toml` declaration. + ## 2026-05-19 — mqdb-cluster 0.3.5 ### Removed diff --git a/Cargo.lock b/Cargo.lock index 1af7689..b7c70a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1349,7 +1349,7 @@ dependencies = [ [[package]] name = "mqdb-agent" -version = "0.8.0" +version = "0.8.1" dependencies = [ "arc-swap", "argon2", diff --git a/README.md b/README.md index bf8cba1..8ef7220 100644 --- a/README.md +++ b/README.md @@ -627,7 +627,7 @@ Any OTLP-compatible collector works: Jaeger, Grafana Tempo, Datadog, Honeycomb, ## Distributed Clustering (Native Edition) -> Clustering requires the `native` feature (commercial license). Agent-only builds (`--features agent-only`) do not include cluster code. +> Clustering requires the `cluster` feature on the `mqdb` CLI (enabled by default). To build without cluster code, use `--no-default-features` (and add `--features http-api` to keep the HTTP server). MQDB supports distributed clustering with automatic failover and partition rebalancing. The cluster distributes data across 256 fixed partitions with a configurable replication factor (RF=2 by default). Raft consensus manages cluster topology and partition ownership. All inter-node communication flows over QUIC streams with mTLS mutual authentication. @@ -740,13 +740,25 @@ The `mqdb` CLI provides command-line access to a running MQDB agent. ### Installation ```bash -# Agent-only (open-source edition) -cargo build --release --bin mqdb --features agent-only - -# Full build with clustering (commercial edition, default) +# Full build with clustering and HTTP API (default) cargo build --release --bin mqdb + +# Agent-only with HTTP API (no cluster code) +cargo build --release --bin mqdb --no-default-features --features http-api + +# Minimal agent (no cluster, no HTTP server) +cargo build --release --bin mqdb --no-default-features ``` +**CLI feature flags** (defined in `crates/mqdb-cli/Cargo.toml`): + +| Feature | Default | Effect | +|---------|---------|--------| +| `cluster` | yes | Enables `mqdb cluster *` commands and the distributed runtime. | +| `http-api` | yes | Enables the HTTP server used for OAuth, email/password auth, and the vault HTTP API. Without it, the `--http-bind` flag has no effect. | +| `opentelemetry` | no | Enables OTLP trace export (see [Observability](#observability)). | +| `dev-insecure` | no | Test-only shortcuts (anonymous mode, dev-login bypass). Never enable in production. | + ### Environment Variables Every CLI flag can be set via environment variable. This is the primary configuration method for Docker and ECS deployments. CLI flags take precedence over env vars when both are set. @@ -994,11 +1006,11 @@ Via MQTT, include `"projection"` in the request payload: ## Testing ```bash -# Run all tests (default features = native) +# Run all tests (default features: cluster + http-api) cargo test # Run agent-only tests (no cluster tests) -cargo test --features agent-only +cargo test --no-default-features --features http-api cargo test --test integration_test ``` diff --git a/crates/mqdb-agent/Cargo.toml b/crates/mqdb-agent/Cargo.toml index 603c2a5..38bd3a5 100644 --- a/crates/mqdb-agent/Cargo.toml +++ b/crates/mqdb-agent/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mqdb-agent" -version = "0.8.0" +version = "0.8.1" edition.workspace = true license = "Apache-2.0" authors.workspace = true diff --git a/crates/mqdb-agent/src/agent/mod.rs b/crates/mqdb-agent/src/agent/mod.rs index ab4d3c9..9f0a593 100644 --- a/crates/mqdb-agent/src/agent/mod.rs +++ b/crates/mqdb-agent/src/agent/mod.rs @@ -34,6 +34,7 @@ pub struct MqdbAgent { pub(super) quic_cert_file: Option, pub(super) quic_key_file: Option, pub(super) ws_bind_address: Option, + #[cfg(feature = "http-api")] pub(super) http_config: std::sync::Mutex>, pub(super) ownership_config: Arc, pub(super) scope_config: Arc, @@ -65,6 +66,7 @@ impl MqdbAgent { quic_cert_file: None, quic_key_file: None, ws_bind_address: None, + #[cfg(feature = "http-api")] http_config: std::sync::Mutex::new(None), ownership_config: Arc::new(mqdb_core::types::OwnershipConfig::default()), scope_config: Arc::new(mqdb_core::types::ScopeConfig::default()), @@ -218,6 +220,7 @@ impl MqdbAgent { Arc::clone(&self.vault_backend) } + #[cfg(feature = "http-api")] #[must_use] #[allow(clippy::missing_panics_doc)] pub fn with_http_config(mut self, config: crate::http::HttpServerConfig) -> Self { @@ -264,11 +267,20 @@ impl MqdbAgent { service_username.clone(), service_password.clone(), ); - let http_task = self.spawn_http_task( - bind_addr, - service_username.as_ref(), - service_password.as_ref(), - ); + let http_task: Option> = { + #[cfg(feature = "http-api")] + { + self.spawn_http_task( + bind_addr, + service_username.as_ref(), + service_password.as_ref(), + ) + } + #[cfg(not(feature = "http-api"))] + { + None + } + }; let license_task = self.spawn_license_check_task(); broker.run().await?; @@ -339,11 +351,20 @@ impl MqdbAgent { service_username.clone(), service_password.clone(), ); - let http_task = self.spawn_http_task( - bind_addr, - service_username.as_ref(), - service_password.as_ref(), - ); + let http_task: Option> = { + #[cfg(feature = "http-api")] + { + self.spawn_http_task( + bind_addr, + service_username.as_ref(), + service_password.as_ref(), + ) + } + #[cfg(not(feature = "http-api"))] + { + None + } + }; let license_task = self.spawn_license_check_task(); tokio::spawn(async move { diff --git a/crates/mqdb-agent/src/agent/tasks.rs b/crates/mqdb-agent/src/agent/tasks.rs index f6fbf54..110c06c 100644 --- a/crates/mqdb-agent/src/agent/tasks.rs +++ b/crates/mqdb-agent/src/agent/tasks.rs @@ -223,6 +223,7 @@ impl MqdbAgent { }) } + #[cfg(feature = "http-api")] pub(super) fn spawn_http_task( &self, bind_addr: SocketAddr, diff --git a/docs/distributed-design.md b/docs/distributed-design.md index f249391..bd23139 100644 --- a/docs/distributed-design.md +++ b/docs/distributed-design.md @@ -4,7 +4,7 @@ > Every claim has file:line references. When in doubt, verify against code. > Last verified: January 2026 (all milestones M1-M10 complete, Direct QUIC transport added) > -> **Note:** Clustering requires the `native` feature flag (commercial license). Agent-only builds (`--features agent-only`) exclude all cluster code. Shared types (partitions, IDs) live in `crates/mqdb-core/src/partition/` and compile unconditionally. +> **Note:** Clustering requires the `cluster` feature on the `mqdb` CLI (enabled by default; see `crates/mqdb-cli/Cargo.toml`). Builds with `--no-default-features` exclude all cluster code. Shared types (partitions, IDs) live in `crates/mqdb-core/src/partition/` and compile unconditionally. ## Overview diff --git a/docs/testing/01-setup.md b/docs/testing/01-setup.md index b1db061..08c5d6f 100644 --- a/docs/testing/01-setup.md +++ b/docs/testing/01-setup.md @@ -9,11 +9,14 @@ ```bash cd /path/to/mqdb -# Agent-only (open-source edition — no cluster commands) -cargo build --release --bin mqdb --features agent-only - -# Full build with clustering (commercial edition, default) +# Full build with clustering and HTTP API (default) cargo build --release + +# Agent-only with HTTP API (no cluster code) +cargo build --release --bin mqdb --no-default-features --features http-api + +# Minimal agent (no cluster, no HTTP server) +cargo build --release --bin mqdb --no-default-features ``` Binary location: `target/release/mqdb` From 68fc92c6f7f668699ae2a4ab03a50be5b5c22872 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabr=C3=ADcio=20Bracht?= Date: Fri, 22 May 2026 15:38:18 -0700 Subject: [PATCH 2/2] propagate http-api feature gate through cli, cluster, vault --- CHANGELOG.md | 6 +-- Cargo.lock | 4 +- Makefile.toml | 14 ++++++- README.md | 2 +- crates/mqdb-agent/src/agent/handlers.rs | 2 +- crates/mqdb-agent/src/agent/mod.rs | 2 +- crates/mqdb-agent/src/http/handlers.rs | 2 +- crates/mqdb-agent/src/http/mod.rs | 2 - crates/mqdb-agent/src/http/server.rs | 2 +- crates/mqdb-agent/src/lib.rs | 1 + .../mqdb-agent/src/{http => }/rate_limiter.rs | 0 crates/mqdb-cli/Cargo.toml | 6 +-- crates/mqdb-cli/src/commands/agent.rs | 42 +++++++++++++------ crates/mqdb-cli/src/commands/cluster.rs | 32 +++++++++----- crates/mqdb-cluster/Cargo.toml | 4 +- .../mqdb-cluster/src/cluster_agent/config.rs | 2 + .../src/cluster_agent/event_loop.rs | 3 ++ crates/mqdb-cluster/src/cluster_agent/init.rs | 3 ++ crates/mqdb-cluster/src/cluster_agent/mod.rs | 2 + crates/mqdb-vault/Cargo.toml | 2 +- crates/mqdb-vault/src/backend.rs | 2 +- 21 files changed, 92 insertions(+), 43 deletions(-) rename crates/mqdb-agent/src/{http => }/rate_limiter.rs (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43f74fc..38a4da6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,15 +4,15 @@ 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-22 — mqdb-agent 0.8.1 +## 2026-05-22 — mqdb-agent 0.8.1, mqdb-cluster 0.3.6, mqdb-cli 0.7.7 ### Fixed -- `http-api` feature flag was effectively a lie: declared in `Cargo.toml` with `default = ["http-api"]`, but three pieces of `MqdbAgent` referenced `crate::http::*` unconditionally — the `http_config` field, the `with_http_config` builder, and the two call sites of `spawn_http_task` in `run` / `start`. `cargo check -p mqdb-agent --no-default-features` failed with five compile errors (`E0433` on the missing `crate::http`, `E0609` on the gated `identity_crypto` field, and an `E0282` inference failure cascading from those). Gated all three behind `#[cfg(feature = "http-api")]` so the flag now actually opts the HTTP server in or out. Default-feature consumers see no change. +- `http-api` feature flag was effectively a lie at every layer: declared in `mqdb-agent`'s `Cargo.toml` with `default = ["http-api"]`, but three pieces of `MqdbAgent` referenced `crate::http::*` unconditionally — the `http_config` field, the `with_http_config` builder, and the two call sites of `spawn_http_task` in `run` / `start`. `cargo check -p mqdb-agent --no-default-features` failed with five compile errors (`E0433` on the missing `crate::http`, `E0609` on the gated `identity_crypto` field, and an `E0282` inference failure cascading from those). Even after gating those, the flag was still meaningless at the CLI level because `mqdb-cli`, `mqdb-cluster`, and `mqdb-vault` all depended on `mqdb-agent` without `default-features = false` — so the HTTP server was always compiled in regardless of what `mqdb-cli --features` said. Fixed by: (1) gating the three `mqdb-agent` items behind `#[cfg(feature = "http-api")]`; (2) extracting `RateLimiter` out of `mqdb_agent::http::rate_limiter` to a top-level `mqdb_agent::rate_limiter` module so `mqdb-vault` no longer needs `http-api`; (3) flipping `mqdb-cli`, `mqdb-cluster`, and `mqdb-vault` to `default-features = false` on their `mqdb-agent` dep; (4) feature-gating the HTTP wiring in `mqdb-cluster` (`http_config` fields, `with_http_config`, `spawn_http_task`) and `mqdb-cli` (`build_http_config`, `build_identity_crypto`, both `--http-bind` call sites). `cargo build --bin mqdb --no-default-features` now actually drops the HTTP server: `jsonwebtoken` symbols go from present to zero, and `hyper`-related code drops ~60% (residual `hyper`/`argon2` come from `mqtt5`, not our HTTP server). `--http-bind` without `http-api` logs a warning and is otherwise ignored. Added a `cargo make clippy-no-default` task wired into the default `clippy`/`ci` chain so this regression cannot reach `main` silently again. ### Docs -- Corrected stale feature-flag names in user-facing docs. `README.md`, `docs/distributed-design.md`, and `docs/testing/01-setup.md` all referenced `--features agent-only` and a `native` feature flag, neither of which exist in any `Cargo.toml`. The actual `mqdb` CLI features are `cluster` (default), `http-api` (default), `opentelemetry`, and `dev-insecure`; agent-only builds use `--no-default-features` (optionally adding `--features http-api`). Added a feature-flag reference table in `README.md` under "CLI Tool → Installation" documenting all four flags and their defaults — the `http-api` flag was previously undocumented anywhere outside its `Cargo.toml` declaration. +- Corrected stale feature-flag names in user-facing docs. `README.md`, `docs/distributed-design.md`, and `docs/testing/01-setup.md` all referenced `--features agent-only` and a `native` feature flag that don't exist on the `mqdb` CLI or `mqdb-agent`. (A `native` feature does exist in `mqdb-core/Cargo.toml`, but it gates `tokio` for non-native targets and is unrelated to the agent/cluster split the README described.) The actual `mqdb` CLI features are `cluster` (default), `http-api` (default), `opentelemetry`, and `dev-insecure`; agent-only builds use `--no-default-features` (optionally adding `--features http-api`). Added a feature-flag reference table in `README.md` under "CLI Tool → Installation" documenting all four flags and their defaults — the `http-api` flag was previously undocumented anywhere outside its `Cargo.toml` declaration. ## 2026-05-19 — mqdb-cluster 0.3.5 diff --git a/Cargo.lock b/Cargo.lock index b7c70a9..7c07747 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1384,7 +1384,7 @@ dependencies = [ [[package]] name = "mqdb-cli" -version = "0.7.6" +version = "0.7.7" dependencies = [ "base64", "bebytes", @@ -1411,7 +1411,7 @@ dependencies = [ [[package]] name = "mqdb-cluster" -version = "0.3.5" +version = "0.3.6" dependencies = [ "arc-swap", "bebytes", diff --git a/Makefile.toml b/Makefile.toml index b43409e..18298d8 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -97,7 +97,7 @@ args = ["install", "--path", "crates/mqdb-cli"] [tasks.clippy] description = "Lint all crates with pedantic warnings" -dependencies = ["clippy-native", "clippy-wasm"] +dependencies = ["clippy-native", "clippy-no-default", "clippy-wasm"] [tasks.clippy-native] description = "Lint native crate" @@ -110,6 +110,18 @@ args = [ "-W", "clippy::pedantic", ] +[tasks.clippy-no-default] +description = "Lint workspace with no default features (catches feature-gating regressions)" +command = "cargo" +args = [ + "clippy", + "--workspace", + "--no-default-features", + "--all-targets", + "--", + "-D", "warnings", +] + [tasks.clippy-wasm] description = "Lint WASM crate" command = "cargo" diff --git a/README.md b/README.md index 8ef7220..a463b6b 100644 --- a/README.md +++ b/README.md @@ -755,7 +755,7 @@ cargo build --release --bin mqdb --no-default-features | Feature | Default | Effect | |---------|---------|--------| | `cluster` | yes | Enables `mqdb cluster *` commands and the distributed runtime. | -| `http-api` | yes | Enables the HTTP server used for OAuth, email/password auth, and the vault HTTP API. Without it, the `--http-bind` flag has no effect. | +| `http-api` | yes | Enables the HTTP server used for OAuth, email/password auth, and the vault HTTP API. Without it, the HTTP server is not compiled in; `--http-bind` logs a warning and is ignored. | | `opentelemetry` | no | Enables OTLP trace export (see [Observability](#observability)). | | `dev-insecure` | no | Test-only shortcuts (anonymous mode, dev-login bypass). Never enable in production. | diff --git a/crates/mqdb-agent/src/agent/handlers.rs b/crates/mqdb-agent/src/agent/handlers.rs index 9739616..cdaa21b 100644 --- a/crates/mqdb-agent/src/agent/handlers.rs +++ b/crates/mqdb-agent/src/agent/handlers.rs @@ -19,7 +19,7 @@ use std::path::Path; use tracing::{error, info_span, warn}; #[cfg(feature = "http-api")] -use crate::http::rate_limiter::RateLimiter; +use crate::rate_limiter::RateLimiter; #[cfg(feature = "opentelemetry")] use mqtt5::telemetry::propagation; diff --git a/crates/mqdb-agent/src/agent/mod.rs b/crates/mqdb-agent/src/agent/mod.rs index 9f0a593..910517c 100644 --- a/crates/mqdb-agent/src/agent/mod.rs +++ b/crates/mqdb-agent/src/agent/mod.rs @@ -17,7 +17,7 @@ use tokio::sync::{broadcast, oneshot, watch}; use tracing::info; #[cfg(feature = "http-api")] -use crate::http::rate_limiter::RateLimiter; +use crate::rate_limiter::RateLimiter; pub use mqdb_core::protocol::{ AdminOperation, DbOperation, build_request, parse_admin_topic, parse_db_topic, diff --git a/crates/mqdb-agent/src/http/handlers.rs b/crates/mqdb-agent/src/http/handlers.rs index f5f2fa1..a29a1fa 100644 --- a/crates/mqdb-agent/src/http/handlers.rs +++ b/crates/mqdb-agent/src/http/handlers.rs @@ -7,8 +7,8 @@ use super::identity_crypto::IdentityCrypto; use super::jwt_signer::{JwtSigningConfig, sign_jwt, verify_jwt_ignore_expiry}; use super::pkce::PkceCache; use super::providers::{ProviderIdentity, ProviderRegistry}; -use super::rate_limiter::RateLimiter; use super::session_store::{JtiRevocationStore, NewSession, SessionStore}; +use crate::rate_limiter::RateLimiter; use crate::vault_backend::{DbAccess, VaultBackend, VaultError}; use base64::Engine; use base64::engine::general_purpose::URL_SAFE_NO_PAD; diff --git a/crates/mqdb-agent/src/http/mod.rs b/crates/mqdb-agent/src/http/mod.rs index 0427cbb..16bd117 100644 --- a/crates/mqdb-agent/src/http/mod.rs +++ b/crates/mqdb-agent/src/http/mod.rs @@ -9,7 +9,6 @@ pub mod identity_crypto; mod jwt_signer; mod pkce; pub mod providers; -pub mod rate_limiter; mod server; mod session_store; @@ -17,6 +16,5 @@ pub use identity_crypto::IdentityCrypto; pub use jwt_signer::{JwtSigningAlgorithm, JwtSigningConfig}; pub use providers::google::GoogleProvider; pub use providers::{Provider, ProviderConfig, ProviderRegistry}; -pub use rate_limiter::RateLimiter; pub use server::{HttpServer, HttpServerConfig}; pub use session_store::SessionStore; diff --git a/crates/mqdb-agent/src/http/server.rs b/crates/mqdb-agent/src/http/server.rs index ccd1852..1c97b12 100644 --- a/crates/mqdb-agent/src/http/server.rs +++ b/crates/mqdb-agent/src/http/server.rs @@ -6,8 +6,8 @@ use super::identity_crypto::IdentityCrypto; use super::jwt_signer::JwtSigningConfig; use super::pkce::PkceCache; use super::providers::ProviderRegistry; -use super::rate_limiter::RateLimiter; use super::session_store::{JtiRevocationStore, SessionStore}; +use crate::rate_limiter::RateLimiter; use crate::vault_backend::{DbAccess, NoopVaultBackend, VaultBackend}; use http_body_util::BodyExt; use http_body_util::Full; diff --git a/crates/mqdb-agent/src/lib.rs b/crates/mqdb-agent/src/lib.rs index 9836289..04a0eb4 100644 --- a/crates/mqdb-agent/src/lib.rs +++ b/crates/mqdb-agent/src/lib.rs @@ -11,6 +11,7 @@ pub mod db_helpers; pub mod dedup; pub mod dispatcher; pub mod outbox_processor; +pub mod rate_limiter; pub mod runtime; pub mod session; pub mod subscription_registry; diff --git a/crates/mqdb-agent/src/http/rate_limiter.rs b/crates/mqdb-agent/src/rate_limiter.rs similarity index 100% rename from crates/mqdb-agent/src/http/rate_limiter.rs rename to crates/mqdb-agent/src/rate_limiter.rs diff --git a/crates/mqdb-cli/Cargo.toml b/crates/mqdb-cli/Cargo.toml index 022f579..0483943 100644 --- a/crates/mqdb-cli/Cargo.toml +++ b/crates/mqdb-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mqdb-cli" -version = "0.7.6" +version = "0.7.7" publish = false edition.workspace = true license = "AGPL-3.0-only" @@ -14,7 +14,7 @@ path = "src/main.rs" [dependencies] mqdb-core = { path = "../mqdb-core", features = ["fjall-backend"] } -mqdb-agent = { path = "../mqdb-agent" } +mqdb-agent = { path = "../mqdb-agent", default-features = false } mqdb-cluster = { path = "../mqdb-cluster", optional = true } serde.workspace = true @@ -39,7 +39,7 @@ mqdb-vault = { version = "0.1.0", path = "../mqdb-vault" } [features] default = ["cluster", "http-api"] cluster = ["dep:mqdb-cluster", "dep:rustls"] -http-api = ["mqdb-agent/http-api"] +http-api = ["mqdb-agent/http-api", "mqdb-cluster?/http-api"] dev-insecure = ["mqdb-agent/dev-insecure", "mqdb-cluster?/dev-insecure"] opentelemetry = ["mqdb-agent/opentelemetry"] diff --git a/crates/mqdb-cli/src/commands/agent.rs b/crates/mqdb-cli/src/commands/agent.rs index b8f189e..38ce68d 100644 --- a/crates/mqdb-cli/src/commands/agent.rs +++ b/crates/mqdb-cli/src/commands/agent.rs @@ -2,7 +2,9 @@ // SPDX-License-Identifier: AGPL-3.0-only use std::net::SocketAddr; -use std::path::{Path, PathBuf}; +#[cfg(feature = "http-api")] +use std::path::Path; +use std::path::PathBuf; use std::sync::Arc; use mqdb_agent::{Database, MqdbAgent}; @@ -164,21 +166,31 @@ pub(crate) async fn cmd_agent_start( } if let Some(http_bind) = args.oauth.http_bind { - let ownership_for_http = agent.ownership_config_arc(); - let http_config = build_http_config( - http_bind, - &args.auth, - &args.oauth, - federated_content.as_deref(), - ownership_for_http, - &args.db_path, - )?; - if !http_config.cookie_secure { + #[cfg(feature = "http-api")] + { + let ownership_for_http = agent.ownership_config_arc(); + let http_config = build_http_config( + http_bind, + &args.auth, + &args.oauth, + federated_content.as_deref(), + ownership_for_http, + &args.db_path, + )?; + if !http_config.cookie_secure { + tracing::warn!( + "session cookies will be sent without Secure flag — use --cookie-secure in production" + ); + } + agent = agent.with_http_config(http_config); + } + #[cfg(not(feature = "http-api"))] + { + let _ = http_bind; tracing::warn!( - "session cookies will be sent without Secure flag — use --cookie-secure in production" + "--http-bind ignored: build with --features http-api to enable the HTTP server" ); } - agent = agent.with_http_config(http_config); } let agent = Arc::new(agent); @@ -302,6 +314,7 @@ pub(crate) fn build_auth_setup_config( }) } +#[cfg(feature = "http-api")] pub(crate) fn build_http_config( http_bind: SocketAddr, auth: &AuthArgs, @@ -410,6 +423,7 @@ pub(crate) fn build_http_config( }) } +#[cfg(feature = "http-api")] fn build_identity_crypto( oauth: &OAuthArgs, db_path: &Path, @@ -499,6 +513,7 @@ fn verify_and_log_license( } } +#[cfg(feature = "http-api")] fn serialize_key_material(salt: &[u8], wrapped_key: &[u8]) -> Vec { let salt_len: u32 = salt.len().try_into().expect("salt length fits in u32"); let mut out = Vec::with_capacity(4 + salt.len() + wrapped_key.len()); @@ -508,6 +523,7 @@ fn serialize_key_material(salt: &[u8], wrapped_key: &[u8]) -> Vec { out } +#[cfg(feature = "http-api")] fn deserialize_key_material(data: &[u8]) -> Result<(&[u8], &[u8]), String> { if data.len() < 4 { return Err("identity key file too short".into()); diff --git a/crates/mqdb-cli/src/commands/cluster.rs b/crates/mqdb-cli/src/commands/cluster.rs index cdcad08..69ea2f7 100644 --- a/crates/mqdb-cli/src/commands/cluster.rs +++ b/crates/mqdb-cli/src/commands/cluster.rs @@ -8,7 +8,9 @@ use std::path::PathBuf; use mqdb_cluster::{ClusterConfig, ClusteredAgent, PeerConfig}; use serde_json::json; -use super::agent::{build_auth_setup_config, build_http_config}; +use super::agent::build_auth_setup_config; +#[cfg(feature = "http-api")] +use super::agent::build_http_config; use crate::cli_types::{AuthArgs, ConnectionArgs, DurabilityArg, OAuthArgs, OutputFormat}; use crate::commands::env_secret::{ resolve_federated_jwt_content, resolve_passphrase, resolve_path_or_data, @@ -176,15 +178,25 @@ pub(crate) async fn cmd_cluster_start( std::sync::Arc::new(mqdb_core::types::OwnershipConfig::default()) }; if let Some(http_bind) = args.oauth.http_bind { - let http_config = build_http_config( - http_bind, - &args.auth, - &args.oauth, - federated_content.as_deref(), - ownership_arc.clone(), - &db_path, - )?; - config = config.with_http_config(http_config); + #[cfg(feature = "http-api")] + { + let http_config = build_http_config( + http_bind, + &args.auth, + &args.oauth, + federated_content.as_deref(), + ownership_arc.clone(), + &db_path, + )?; + config = config.with_http_config(http_config); + } + #[cfg(not(feature = "http-api"))] + { + let _ = http_bind; + tracing::warn!( + "--http-bind ignored: build with --features http-api to enable the HTTP server" + ); + } } if args.ownership.is_some() { config = config.with_ownership((*ownership_arc).clone()); diff --git a/crates/mqdb-cluster/Cargo.toml b/crates/mqdb-cluster/Cargo.toml index 9c7f375..a03c05b 100644 --- a/crates/mqdb-cluster/Cargo.toml +++ b/crates/mqdb-cluster/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mqdb-cluster" -version = "0.3.5" +version = "0.3.6" publish = false edition.workspace = true license = "AGPL-3.0-only" @@ -10,7 +10,7 @@ description = "Distributed clustering, Raft consensus, and QUIC transport for MQ [dependencies] mqdb-core = { path = "../mqdb-core", features = ["fjall-backend"] } -mqdb-agent = { path = "../mqdb-agent" } +mqdb-agent = { path = "../mqdb-agent", default-features = false } serde.workspace = true serde_json.workspace = true diff --git a/crates/mqdb-cluster/src/cluster_agent/config.rs b/crates/mqdb-cluster/src/cluster_agent/config.rs index 043cf8f..8238b34 100644 --- a/crates/mqdb-cluster/src/cluster_agent/config.rs +++ b/crates/mqdb-cluster/src/cluster_agent/config.rs @@ -33,6 +33,7 @@ impl ClusterConfig { }, bridge_out_only: false, ws_bind_address: None, + #[cfg(feature = "http-api")] http_config: None, ownership: mqdb_core::types::OwnershipConfig::default(), scope_config: mqdb_core::types::ScopeConfig::default(), @@ -180,6 +181,7 @@ impl ClusterConfig { self } + #[cfg(feature = "http-api")] #[must_use] pub fn with_http_config(mut self, config: mqdb_agent::http::HttpServerConfig) -> Self { self.http_config = Some(config); diff --git a/crates/mqdb-cluster/src/cluster_agent/event_loop.rs b/crates/mqdb-cluster/src/cluster_agent/event_loop.rs index e1e7f15..6fd52e6 100644 --- a/crates/mqdb-cluster/src/cluster_agent/event_loop.rs +++ b/crates/mqdb-cluster/src/cluster_agent/event_loop.rs @@ -108,7 +108,10 @@ impl ClusteredAgent { None }; + #[cfg(feature = "http-api")] let _http_task = self.spawn_http_task(service_username, service_password); + #[cfg(not(feature = "http-api"))] + let _ = (service_username, service_password); self.recover_pending_lwts().await; self.recover_pending_outbox().await; diff --git a/crates/mqdb-cluster/src/cluster_agent/init.rs b/crates/mqdb-cluster/src/cluster_agent/init.rs index 901cb92..099f895 100644 --- a/crates/mqdb-cluster/src/cluster_agent/init.rs +++ b/crates/mqdb-cluster/src/cluster_agent/init.rs @@ -129,6 +129,7 @@ impl ClusteredAgent { /// # Errors /// If node initialization fails: invalid node ID, storage backend, or Raft setup. + #[allow(clippy::too_many_lines)] pub fn new(config: ClusterConfig) -> Result { let node_id = NodeId::validated(config.node_id) .ok_or(ClusterInitError::InvalidNodeId(config.node_id))?; @@ -231,6 +232,7 @@ impl ClusteredAgent { rx_main_queue: Some(rx_main_queue), rx_batch: Some(rx_batch), ws_bind_address: config.ws_bind_address, + #[cfg(feature = "http-api")] http_config: config.http_config, ownership: ownership_arc, scope_config: Arc::new(config.scope_config), @@ -303,6 +305,7 @@ impl ClusteredAgent { Ok(()) } + #[cfg(feature = "http-api")] pub(super) fn spawn_http_task( &mut self, service_username: Option<&String>, diff --git a/crates/mqdb-cluster/src/cluster_agent/mod.rs b/crates/mqdb-cluster/src/cluster_agent/mod.rs index b960ab0..8dbcceb 100644 --- a/crates/mqdb-cluster/src/cluster_agent/mod.rs +++ b/crates/mqdb-cluster/src/cluster_agent/mod.rs @@ -118,6 +118,7 @@ pub struct ClusterConfig { pub quic: QuicConfig, pub bridge_out_only: bool, pub ws_bind_address: Option, + #[cfg(feature = "http-api")] pub http_config: Option, pub ownership: mqdb_core::types::OwnershipConfig, pub scope_config: mqdb_core::types::ScopeConfig, @@ -158,6 +159,7 @@ pub struct ClusteredAgent { rx_main_queue: Option>, rx_batch: Option>, ws_bind_address: Option, + #[cfg(feature = "http-api")] http_config: Option, ownership: Arc, scope_config: Arc, diff --git a/crates/mqdb-vault/Cargo.toml b/crates/mqdb-vault/Cargo.toml index 26e1b7a..d3787a0 100644 --- a/crates/mqdb-vault/Cargo.toml +++ b/crates/mqdb-vault/Cargo.toml @@ -10,7 +10,7 @@ description = "Vault transparent encryption for MQDB (AGPL, Pro/Enterprise featu [dependencies] base64.workspace = true -mqdb-agent = { version = "0.8.0", path = "../mqdb-agent" } +mqdb-agent = { version = "0.8.0", path = "../mqdb-agent", default-features = false } mqdb-core = { version = "0.7.0", path = "../mqdb-core" } mqtt5.workspace = true ring.workspace = true diff --git a/crates/mqdb-vault/src/backend.rs b/crates/mqdb-vault/src/backend.rs index e75bab1..bca5929 100644 --- a/crates/mqdb-vault/src/backend.rs +++ b/crates/mqdb-vault/src/backend.rs @@ -11,7 +11,7 @@ use crate::transform::{ use base64::Engine; use base64::engine::general_purpose::STANDARD as BASE64; use mqdb_agent::Database; -use mqdb_agent::http::rate_limiter::RateLimiter; +use mqdb_agent::rate_limiter::RateLimiter; use mqdb_agent::vault_backend::{ DbAccess, EncryptRequestOutput, VaultAdminOutcome, VaultBackend, VaultError, VaultFuture, VaultResult,