Ver Código Fonte

fix: pretty-print IRIS alert_note as indented JSON with nulls stripped

Replace plain-text sectioned format with json.dumps(indent=2) so the
Alert Note field in IRIS renders as readable indented JSON. Null values
are recursively removed to keep the output clean. IOC verdict fields
(vt_stats, abuseipdb_score/reports, reason) are flattened into the
verdicts array for easy scanning.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
tum 1 dia atrás
pai
commit
012e088454
1 arquivos alterados com 33 adições e 63 exclusões
  1. 33 63
      soc-integrator/app/services/mvp_service.py

+ 33 - 63
soc-integrator/app/services/mvp_service.py

@@ -656,71 +656,41 @@ class MvpService:
656 656
         severity_str = (event.get("severity") or "medium").lower()
657 657
         severity_id = _IRIS_SEVERITY_ID.get(severity_str, 3)
658 658
 
659
-        note_lines: list[str] = []
660
-
661
-        # Asset
662
-        asset = event.get("asset") or {}
663
-        if any(asset.get(k) for k in ("hostname", "user", "agent_id")):
664
-            note_lines.append("## Asset")
665
-            if asset.get("hostname"):
666
-                note_lines.append(f"  Hostname : {asset['hostname']}")
667
-            if asset.get("user"):
668
-                note_lines.append(f"  User     : {asset['user']}")
669
-            if asset.get("agent_id"):
670
-                note_lines.append(f"  Agent ID : {asset['agent_id']}")
671
-
672
-        # Network
673
-        network = event.get("network") or {}
674
-        net_fields = {k: network.get(k) for k in ("src_ip", "dst_ip", "dst_port", "dst_host", "proto") if network.get(k)}
675
-        if net_fields:
676
-            note_lines.append("\n## Network")
677
-            for k, v in net_fields.items():
678
-                note_lines.append(f"  {k:<12}: {v}")
679
-
680
-        # IOC verdicts
659
+        def _strip_nulls(obj: Any) -> Any:
660
+            """Recursively remove None values to keep the JSON compact."""
661
+            if isinstance(obj, dict):
662
+                return {k: _strip_nulls(v) for k, v in obj.items() if v is not None}
663
+            if isinstance(obj, list):
664
+                return [_strip_nulls(i) for i in obj]
665
+            return obj
666
+
681 667
         raw = event.get("raw") or {}
682
-        verdicts: list[dict[str, Any]] = raw.get("verdicts") or []
683
-        if verdicts:
684
-            note_lines.append("\n## IOC Verdicts")
668
+        note_data: dict[str, Any] = {
669
+            "asset": event.get("asset") or {},
670
+            "network": event.get("network") or {},
671
+            "tags": event.get("tags") or [],
672
+        }
673
+        if raw.get("verdicts"):
685 674
             ioc_payload = raw.get("payload") or {}
686
-            if ioc_payload.get("ioc_value"):
687
-                note_lines.append(f"  IOC      : {ioc_payload.get('ioc_type','?')} / {ioc_payload['ioc_value']}")
688
-            for v in verdicts:
689
-                provider = v.get("provider", "?")
690
-                matched = v.get("matched", False)
691
-                conf = v.get("confidence", 0.0)
692
-                sev = v.get("severity", "?")
693
-                result = v.get("result") or {}
694
-                note_lines.append(f"\n  [{provider.upper()}]")
695
-                note_lines.append(f"    Matched    : {'YES' if matched else 'no'}")
696
-                note_lines.append(f"    Confidence : {conf:.0%}")
697
-                note_lines.append(f"    Severity   : {sev}")
698
-                # Provider-specific detail
699
-                providers_detail = (result.get("providers") or {})
700
-                vt = providers_detail.get("virustotal", {})
701
-                if vt.get("stats"):
702
-                    s = vt["stats"]
703
-                    note_lines.append(
704
-                        f"    VT Stats   : malicious={s.get('malicious',0)} "
705
-                        f"suspicious={s.get('suspicious',0)} "
706
-                        f"harmless={s.get('harmless',0)} "
707
-                        f"undetected={s.get('undetected',0)}"
708
-                    )
709
-                ab = providers_detail.get("abuseipdb", {})
710
-                if ab:
711
-                    note_lines.append(
712
-                        f"    AbuseIPDB  : score={ab.get('score',0)} "
713
-                        f"reports={ab.get('totalReports',0)}"
714
-                    )
715
-                if result.get("reason"):
716
-                    note_lines.append(f"    Reason     : {result['reason']}")
717
-
718
-        # Tags
719
-        tags = event.get("tags") or []
720
-        if tags:
721
-            note_lines.append(f"\n## Tags\n  {', '.join(str(t) for t in tags)}")
722
-
723
-        alert_note = "\n".join(note_lines).strip()
675
+            note_data["ioc"] = {
676
+                "type": ioc_payload.get("ioc_type"),
677
+                "value": ioc_payload.get("ioc_value"),
678
+                "verdicts": [
679
+                    {
680
+                        "provider": v.get("provider"),
681
+                        "matched": v.get("matched"),
682
+                        "confidence": round(float(v.get("confidence") or 0), 4),
683
+                        "severity": v.get("severity"),
684
+                        "reason": (v.get("result") or {}).get("reason"),
685
+                        "vt_stats": ((v.get("result") or {}).get("providers") or {}).get("virustotal", {}).get("stats"),
686
+                        "abuseipdb_score": ((v.get("result") or {}).get("providers") or {}).get("abuseipdb", {}).get("score"),
687
+                        "abuseipdb_reports": ((v.get("result") or {}).get("providers") or {}).get("abuseipdb", {}).get("totalReports"),
688
+                    }
689
+                    for v in raw["verdicts"]
690
+                ],
691
+            }
692
+
693
+        alert_note = json.dumps(_strip_nulls(note_data), indent=2, ensure_ascii=False)
724 694
 
725 695
         payload: dict[str, Any] = {
726 696
             "alert_title": event.get("title") or f"Wazuh alert {event_id}",