elasticctl-api 0.10.0

Typed detection-rule model and endpoint wrappers for Elastic Security.
Documentation
use super::*;
use crate::value_lists::{Container, LocalPair, ValueListType};
use serde_json::json;

#[test]
fn pull_collects_every_value_rule_and_exception_collision_before_writing() {
    for existing in [false, true] {
        let parent = tempfile::tempdir().unwrap();
        let root = parent.path().join("mirror");
        if existing {
            std::fs::create_dir(&root).unwrap();
            std::fs::write(root.join("sentinel"), "unchanged").unwrap();
        }
        let lock = acquire_pull(&root).unwrap();
        let rules = ["rule/a", "rule?a", "rule:a"].map(|id| {
            Rule::from_value(json!({"rule_id": id, "name": id, "type": "query"})).unwrap()
        });
        let exceptions = ["exception/a", "exception?a", "exception:a"]
            .map(|id| {
                let list = ExceptionList::from_value(json!({
                    "list_id": id, "name": id, "type": "detection", "namespace_type": "single"
                }))
                .unwrap();
                (list.key().unwrap(), (list, vec![]))
            })
            .into();
        let values = ["A", "a-559aead08264"].map(|id| LocalPair {
            stem: crate::value_lists::file_stem(id),
            container: Container {
                id: id.into(),
                name: id.into(),
                description: "Synthetic".into(),
                list_type: ValueListType::Keyword,
                meta: None,
            },
            values: ["value".into()].into(),
        });
        let error = write_mirror(&lock, &rules, &exceptions, &values, Format::Yaml).unwrap_err();
        assert_eq!(error.kind, ErrorKind::Conflict);
        for pair in [
            "\"A\" and \"a-559aead08264\"",
            "\"rule/a\" and \"rule?a\"",
            "\"rule/a\" and \"rule:a\"",
            "\"rule?a\" and \"rule:a\"",
            "\"exception/a (single)\" and \"exception:a (single)\"",
            "\"exception/a (single)\" and \"exception?a (single)\"",
            "\"exception:a (single)\" and \"exception?a (single)\"",
        ] {
            assert!(
                error.message.contains(pair),
                "missing {pair}: {}",
                error.message
            );
        }
        assert!(error.message.starts_with("7 filename collision(s)"));
        if existing {
            assert_eq!(
                std::fs::read_to_string(root.join("sentinel")).unwrap(),
                "unchanged"
            );
            assert_eq!(std::fs::read_dir(&root).unwrap().count(), 1);
        } else {
            assert!(!root.exists());
        }
    }
}