Send buffered events to configured webhook (async).
(&self)
| 131 | |
| 132 | /// Send buffered events to configured webhook (async). |
| 133 | pub async fn flush_webhook(&self) { |
| 134 | if self.config.webhook_url.is_empty() { |
| 135 | return; |
| 136 | } |
| 137 | |
| 138 | let audit_events = self.drain_audit(); |
| 139 | let auth_events = self.drain_auth(); |
| 140 | let all: Vec<AuditEntry> = audit_events.into_iter().chain(auth_events).collect(); |
| 141 | |
| 142 | if all.is_empty() { |
| 143 | return; |
| 144 | } |
| 145 | |
| 146 | let (body, signature) = self.build_webhook_payload(&all); |
| 147 | |
| 148 | let mut req = self |
| 149 | .client |
| 150 | .post(&self.config.webhook_url) |
| 151 | .header("Content-Type", "application/json") |
| 152 | .timeout(std::time::Duration::from_secs( |
| 153 | self.config.webhook_timeout_secs, |
| 154 | )) |
| 155 | .body(body); |
| 156 | |
| 157 | if !signature.is_empty() { |
| 158 | req = req.header("X-NodeDB-Signature", &signature); |
| 159 | } |
| 160 | |
| 161 | match req.send().await { |
| 162 | Ok(resp) if resp.status().is_success() => { |
| 163 | info!(events = all.len(), "SIEM webhook delivered"); |
| 164 | } |
| 165 | Ok(resp) => { |
| 166 | warn!(status = %resp.status(), "SIEM webhook delivery failed"); |
| 167 | } |
| 168 | Err(e) => { |
| 169 | warn!(error = %e, "SIEM webhook request failed"); |
| 170 | } |
| 171 | } |
| 172 | } |
| 173 | |
| 174 | /// Whether any export destinations are configured. |
| 175 | pub fn is_configured(&self) -> bool { |
nothing calls this directly
no test coverage detected