elasticctl-api 0.9.4

Typed detection-rule model and endpoint wrappers for Elastic Security.
Documentation
use crate::alerts::{self, AlertHit};
use elasticctl_core::{Error, ErrorKind, Result, Transport};
use serde_json::json;
#[derive(Debug)]
pub struct AlertActivity {
    pub window: String,
    pub total: u64,
    pub open: u64,
    pub acknowledged: u64,
    pub closed: u64,
    pub other: u64,
    pub recent: Vec<AlertHit>,
}
pub fn validate_since(value: &str) -> Result<()> {
    let b = value.as_bytes();
    if !(2..=5).contains(&b.len())
        || b[0] == b'0'
        || !b[..b.len() - 1].iter().all(u8::is_ascii_digit)
        || !matches!(b[b.len() - 1], b's' | b'm' | b'h' | b'd' | b'w')
    {
        return Err(Error::new(ErrorKind::Error, "invalid since"));
    }
    Ok(())
}
pub async fn alert_activity(
    t: &Transport,
    rule_id: &str,
    since: &str,
    recent: usize,
) -> Result<AlertActivity> {
    validate_since(since)?;
    let size = recent.min(super::RECENT_ALERTS);
    let body = json!({"query":{"bool":{"filter":[{"term":{"kibana.alert.rule.rule_id":rule_id}},{"range":{"@timestamp":{"gte":format!("now-{since}")}}}]}},"sort":[{"@timestamp":{"order":"desc"}},{"kibana.alert.uuid":{"order":"asc"}}],"size":size,"track_total_hits":true,"aggs":{"status":{"terms":{"field":"kibana.alert.workflow_status","size":8}}}});
    let page = alerts::search_activity(t, &body).await?;
    let mut out = AlertActivity {
        window: since.into(),
        total: page.total,
        open: 0,
        acknowledged: 0,
        closed: 0,
        other: page.other,
        recent: page.hits.into_iter().take(size).collect(),
    };
    for (key, n) in page.buckets {
        let counter = match key.as_str() {
            "open" => &mut out.open,
            "acknowledged" => &mut out.acknowledged,
            "closed" => &mut out.closed,
            _ => &mut out.other,
        };
        *counter = counter
            .checked_add(n)
            .ok_or_else(|| Error::new(ErrorKind::Http, "activity count overflow"))?;
    }
    Ok(out)
}