From 7e7d47f94cbaa31fe336e18c4c19b31feeebebf7 Mon Sep 17 00:00:00 2001 From: DaLaw2 Date: Sat, 18 Apr 2026 17:21:06 +0800 Subject: [PATCH] feat(soar): seed fusion-era default playbooks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Day 1 DB now ships with two playbooks that exercise the Fusion v1 condition vocabulary so a fresh install demonstrates multi-source agreement out of the box instead of requiring the operator to author a MultiSourceMin / SingleSourceHigh playbook before anything blocks. Both target `c2_beacon` — the canonical attack type where fusion carries the highest marginal value (Suricata trojan-activity + Beaconing CV + ML c2 class can all independently fire on the same C2 channel): - `fusion_c2_multi_source_block` — Condition: MultiSourceMin >= 2. Actions: block_ip 3600s + telegram + log. Requires agreement from two independent detection sources before blocking. - `fusion_c2_suricata_solo_high_block` — Condition: SingleSourceHigh for Suricata with min_confidence 0.95. Actions: block_ip 3600s + telegram + log. Escape hatch for high-certainty signature hits that shouldn't wait for a second source. Idempotent via the existing "seed only when playbooks table is empty" guard in `seed_default_playbooks`. Note: the pre-existing `default_block` (trigger "threat_detected") never matches any fused event — canonicalization in the orchestrator rewrites attack_type to one of the 13 canonical values before SOAR sees it. That cleanup is separate; this commit only adds the fusion defaults. clippy --package net-guardia -- -D warnings clean. 219 pass. Closes A-region F-5 seed. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../src/adapter/persistence/repository.rs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/net-guardia/src/adapter/persistence/repository.rs b/net-guardia/src/adapter/persistence/repository.rs index a908a4e..0d7b121 100644 --- a/net-guardia/src/adapter/persistence/repository.rs +++ b/net-guardia/src/adapter/persistence/repository.rs @@ -1565,6 +1565,28 @@ impl Database { self.insert_playbook_action(pb3, 2, "log", r#"{"level": "warn"}"#)?; self.insert_playbook_condition(pb3, "threshold", ">=", "0.7", None)?; + // 4. fusion_c2_multi_source_block — C2 beacon observed by ≥2 sources + // (e.g. Suricata trojan-activity + Beaconing CV + ML c2 class) is + // the highest-precision fusion signal we ship. Block for 1h and + // notify, no solo-source threshold so single-source C2 hits still + // require the solo playbook below to act. + let pb4 = self.insert_playbook("fusion_c2_multi_source_block", "c2_beacon", None, None, None, 600)?; + self.insert_playbook_action(pb4, 1, "block_ip", r#"{"ttl_secs": 3600}"#)?; + self.insert_playbook_action(pb4, 2, "send_telegram", "{}")?; + self.insert_playbook_action(pb4, 3, "log", r#"{"level": "warn"}"#)?; + self.insert_playbook_condition(pb4, "multi_source_min", ">=", "2", None)?; + + // 5. fusion_c2_suricata_solo_high_block — the escape hatch for + // Suricata signature hits with very high confidence (>=0.95). + // Lets known-good rules fire without waiting for agreement from a + // second source, matching how analysts intuitively treat a + // signature "dead-on" match. + let pb5 = self.insert_playbook("fusion_c2_suricata_solo_high_block", "c2_beacon", None, None, None, 600)?; + self.insert_playbook_action(pb5, 1, "block_ip", r#"{"ttl_secs": 3600}"#)?; + self.insert_playbook_action(pb5, 2, "send_telegram", "{}")?; + self.insert_playbook_action(pb5, 3, "log", r#"{"level": "warn"}"#)?; + self.insert_playbook_condition(pb5, "single_source_high", "==", "Suricata", Some("0.95"))?; + Ok(()) }