fix(audit): prevent state transition when no targets exist (#854)

Avoid setting AuditSystemState::Starting when target list is empty.
Now checks target availability before state transition, keeping the
system in Stopped state if no enabled targets are found.

- Check targets.is_empty() before setting Starting state
- Return early with Ok(()) when no targets exist
- Maintain consistent state machine behavior
- Prevent transient "Starting" state with no actual targets

Resolves issue where audit system would incorrectly enter Starting
state even when configuration contained no enabled targets.
This commit is contained in:
houseme
2025-11-14 20:23:21 +08:00
committed by GitHub
parent 3cf565e847
commit 55e3a1f7e0
5 changed files with 19 additions and 9 deletions

4
Cargo.lock generated
View File

@@ -9789,9 +9789,9 @@ dependencies = [
[[package]]
name = "wildmatch"
version = "2.6.0"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d654e41fe05169e03e27b97e0c23716535da037c1652a31fd99c6b2fad84059"
checksum = "29333c3ea1ba8b17211763463ff24ee84e41c78224c16b001cd907e663a38c68"
dependencies = [
"serde",
]

View File

@@ -252,7 +252,7 @@ urlencoding = "2.1.3"
uuid = { version = "1.18.1", features = ["v4", "fast-rng", "macro-diagnostics"] }
vaultrs = { version = "0.7.4" }
walkdir = "2.5.0"
wildmatch = { version = "2.6.0", features = ["serde"] }
wildmatch = { version = "2.6.1", features = ["serde"] }
winapi = { version = "0.3.9" }
xxhash-rust = { version = "0.8.15", features = ["xxh64", "xxh3"] }
zip = "6.0.0"

View File

@@ -15,7 +15,7 @@
use crate::{AuditEntry, AuditResult, AuditSystem};
use rustfs_ecstore::config::Config;
use std::sync::{Arc, OnceLock};
use tracing::{error, trace, warn};
use tracing::{debug, error, trace, warn};
/// Global audit system instance
static AUDIT_SYSTEM: OnceLock<Arc<AuditSystem>> = OnceLock::new();
@@ -78,7 +78,7 @@ pub async fn dispatch_audit_log(entry: Arc<AuditEntry>) -> AuditResult<()> {
} else {
// The system is not initialized at all. This is a more important state.
// It might be better to return an error or log a warning.
warn!("Audit system not initialized, dropping audit entry.");
debug!("Audit system not initialized, dropping audit entry.");
// If this should be a hard failure, you can return Err(AuditError::NotInitialized("..."))
Ok(())
}

View File

@@ -59,7 +59,7 @@ impl AuditSystem {
/// Starts the audit system with the given configuration
pub async fn start(&self, config: Config) -> AuditResult<()> {
let mut state = self.state.write().await;
let state = self.state.write().await;
match *state {
AuditSystemState::Running => {
@@ -72,7 +72,6 @@ impl AuditSystem {
_ => {}
}
*state = AuditSystemState::Starting;
drop(state);
info!("Starting audit system");
@@ -90,6 +89,17 @@ impl AuditSystem {
let mut registry = self.registry.lock().await;
match registry.create_targets_from_config(&config).await {
Ok(targets) => {
if targets.is_empty() {
info!("No enabled audit targets found, keeping audit system stopped");
drop(registry);
return Ok(());
}
{
let mut state = self.state.write().await;
*state = AuditSystemState::Starting;
}
info!(target_count = targets.len(), "Created audit targets successfully");
// Initialize all targets

View File

@@ -16,7 +16,7 @@ use rustfs_audit::system::AuditSystemState;
use rustfs_audit::{AuditError, AuditResult, audit_system, init_audit_system};
use rustfs_config::DEFAULT_DELIMITER;
use rustfs_ecstore::config::GLOBAL_SERVER_CONFIG;
use tracing::{error, info, warn};
use tracing::{info, warn};
/// Start the audit system.
/// This function checks if the audit subsystem is configured in the global server configuration.
@@ -89,7 +89,7 @@ pub(crate) async fn start_audit_system() -> AuditResult<()> {
Ok(())
}
Err(e) => {
error!(
warn!(
target: "rustfs::main::start_audit_system",
"Audit system startup failed: {:?}",
e