iflow-mcp-m507_ai-soc-agent 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. iflow_mcp_m507_ai_soc_agent-1.0.0.dist-info/METADATA +410 -0
  2. iflow_mcp_m507_ai_soc_agent-1.0.0.dist-info/RECORD +85 -0
  3. iflow_mcp_m507_ai_soc_agent-1.0.0.dist-info/WHEEL +5 -0
  4. iflow_mcp_m507_ai_soc_agent-1.0.0.dist-info/entry_points.txt +2 -0
  5. iflow_mcp_m507_ai_soc_agent-1.0.0.dist-info/licenses/LICENSE +21 -0
  6. iflow_mcp_m507_ai_soc_agent-1.0.0.dist-info/top_level.txt +1 -0
  7. src/__init__.py +8 -0
  8. src/ai_controller/README.md +139 -0
  9. src/ai_controller/__init__.py +12 -0
  10. src/ai_controller/agent_executor.py +596 -0
  11. src/ai_controller/cli/__init__.py +2 -0
  12. src/ai_controller/cli/main.py +243 -0
  13. src/ai_controller/session_manager.py +409 -0
  14. src/ai_controller/web/__init__.py +2 -0
  15. src/ai_controller/web/server.py +1181 -0
  16. src/ai_controller/web/static/css/README.md +102 -0
  17. src/api/__init__.py +13 -0
  18. src/api/case_management.py +271 -0
  19. src/api/edr.py +187 -0
  20. src/api/kb.py +136 -0
  21. src/api/siem.py +308 -0
  22. src/core/__init__.py +10 -0
  23. src/core/config.py +242 -0
  24. src/core/config_storage.py +684 -0
  25. src/core/dto.py +50 -0
  26. src/core/errors.py +36 -0
  27. src/core/logging.py +128 -0
  28. src/integrations/__init__.py +8 -0
  29. src/integrations/case_management/__init__.py +5 -0
  30. src/integrations/case_management/iris/__init__.py +11 -0
  31. src/integrations/case_management/iris/iris_client.py +885 -0
  32. src/integrations/case_management/iris/iris_http.py +274 -0
  33. src/integrations/case_management/iris/iris_mapper.py +263 -0
  34. src/integrations/case_management/iris/iris_models.py +128 -0
  35. src/integrations/case_management/thehive/__init__.py +8 -0
  36. src/integrations/case_management/thehive/thehive_client.py +193 -0
  37. src/integrations/case_management/thehive/thehive_http.py +147 -0
  38. src/integrations/case_management/thehive/thehive_mapper.py +190 -0
  39. src/integrations/case_management/thehive/thehive_models.py +125 -0
  40. src/integrations/cti/__init__.py +6 -0
  41. src/integrations/cti/local_tip/__init__.py +10 -0
  42. src/integrations/cti/local_tip/local_tip_client.py +90 -0
  43. src/integrations/cti/local_tip/local_tip_http.py +110 -0
  44. src/integrations/cti/opencti/__init__.py +10 -0
  45. src/integrations/cti/opencti/opencti_client.py +101 -0
  46. src/integrations/cti/opencti/opencti_http.py +418 -0
  47. src/integrations/edr/__init__.py +6 -0
  48. src/integrations/edr/elastic_defend/__init__.py +6 -0
  49. src/integrations/edr/elastic_defend/elastic_defend_client.py +351 -0
  50. src/integrations/edr/elastic_defend/elastic_defend_http.py +162 -0
  51. src/integrations/eng/__init__.py +10 -0
  52. src/integrations/eng/clickup/__init__.py +8 -0
  53. src/integrations/eng/clickup/clickup_client.py +513 -0
  54. src/integrations/eng/clickup/clickup_http.py +156 -0
  55. src/integrations/eng/github/__init__.py +8 -0
  56. src/integrations/eng/github/github_client.py +169 -0
  57. src/integrations/eng/github/github_http.py +158 -0
  58. src/integrations/eng/trello/__init__.py +8 -0
  59. src/integrations/eng/trello/trello_client.py +207 -0
  60. src/integrations/eng/trello/trello_http.py +162 -0
  61. src/integrations/kb/__init__.py +12 -0
  62. src/integrations/kb/fs_kb_client.py +313 -0
  63. src/integrations/siem/__init__.py +6 -0
  64. src/integrations/siem/elastic/__init__.py +6 -0
  65. src/integrations/siem/elastic/elastic_client.py +3319 -0
  66. src/integrations/siem/elastic/elastic_http.py +165 -0
  67. src/mcp/README.md +183 -0
  68. src/mcp/TOOLS.md +2827 -0
  69. src/mcp/__init__.py +13 -0
  70. src/mcp/__main__.py +18 -0
  71. src/mcp/agent_profiles.py +408 -0
  72. src/mcp/flow_agent_profiles.py +424 -0
  73. src/mcp/mcp_server.py +4086 -0
  74. src/mcp/rules_engine.py +487 -0
  75. src/mcp/runbook_manager.py +264 -0
  76. src/orchestrator/__init__.py +11 -0
  77. src/orchestrator/incident_workflow.py +244 -0
  78. src/orchestrator/tools_case.py +1085 -0
  79. src/orchestrator/tools_cti.py +359 -0
  80. src/orchestrator/tools_edr.py +315 -0
  81. src/orchestrator/tools_eng.py +378 -0
  82. src/orchestrator/tools_kb.py +156 -0
  83. src/orchestrator/tools_siem.py +1709 -0
  84. src/web/__init__.py +8 -0
  85. src/web/config_server.py +511 -0
src/mcp/__init__.py ADDED
@@ -0,0 +1,13 @@
1
+ """
2
+ MCP (Model Context Protocol) server and rules engine for SamiGPT.
3
+
4
+ This package contains:
5
+ - mcp_server.py: MCP server implementation that exposes SamiGPT skills as tools
6
+ - rules_engine.py: Rules/workflow engine for automated investigations
7
+ """
8
+
9
+ from .mcp_server import SamiGPTMCPServer, configure_mcp_logging
10
+ from .rules_engine import RulesEngine
11
+
12
+ __all__ = ["SamiGPTMCPServer", "configure_mcp_logging", "RulesEngine"]
13
+
src/mcp/__main__.py ADDED
@@ -0,0 +1,18 @@
1
+ """Entry point for the MCP server."""
2
+
3
+ import asyncio
4
+ import sys
5
+
6
+ from .mcp_server import main
7
+
8
+
9
+ def cli():
10
+ """Synchronous entry point for the MCP server."""
11
+ try:
12
+ asyncio.run(main())
13
+ except KeyboardInterrupt:
14
+ sys.exit(0)
15
+
16
+
17
+ if __name__ == "__main__":
18
+ cli()
@@ -0,0 +1,408 @@
1
+ """
2
+ Agent Profile Manager for SOC tier-based agent configuration.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ import json
8
+ import os
9
+ from dataclasses import dataclass
10
+ from typing import Any, Dict, List, Optional
11
+
12
+ from ..core.errors import IntegrationError
13
+
14
+
15
+ @dataclass
16
+ class DecisionAuthority:
17
+ """Decision authority for an agent."""
18
+ close_false_positives: bool = False
19
+ close_benign_true_positives: bool = False
20
+ escalate_to_soc2: bool = False
21
+ escalate_to_soc3: bool = False
22
+ containment_actions: bool = False
23
+ forensic_collection: bool = False
24
+
25
+
26
+ @dataclass
27
+ class AgentProfile:
28
+ """Represents an agent profile configuration."""
29
+ name: str
30
+ tier: str # "soc1", "soc2", "soc3"
31
+ description: str
32
+ capabilities: List[str]
33
+ runbooks: List[str]
34
+ decision_authority: DecisionAuthority
35
+ auto_select_runbook: bool = True
36
+ max_concurrent_cases: int = 10
37
+
38
+ def get_starting_runbook(self) -> Optional[str]:
39
+ """
40
+ Get the starting runbook for this agent profile.
41
+
42
+ Returns:
43
+ Starting runbook path, or None if not defined
44
+ """
45
+ # Starting runbooks are the first/main runbook for each tier
46
+ starting_runbooks = {
47
+ "soc1": "soc1/triage/initial_alert_triage",
48
+ "soc2": "soc2/investigation/case_analysis",
49
+ # SOC3 doesn't have a single starting runbook - it's action-based
50
+ }
51
+
52
+ if self.tier in starting_runbooks:
53
+ return starting_runbooks[self.tier]
54
+
55
+ # For SOC3 or other tiers, return first runbook if available
56
+ if self.runbooks:
57
+ return self.runbooks[0]
58
+
59
+ return None
60
+
61
+ def can_execute_runbook(self, runbook_name: str) -> bool:
62
+ """Check if agent can execute a runbook."""
63
+ # Check if runbook is in agent's runbook list
64
+ if runbook_name in self.runbooks:
65
+ return True
66
+
67
+ # Check if runbook matches agent's tier (includes case-specific runbooks like soc2/cases/malware_deep_analysis)
68
+ if f"/{self.tier}/" in runbook_name:
69
+ return True
70
+
71
+ # Check case-specific runbooks (e.g., soc2/cases/malware_deep_analysis)
72
+ # Case-specific runbooks are sub-runbooks that can be executed by the same tier
73
+ if f"/{self.tier}/cases/" in runbook_name:
74
+ return True
75
+
76
+ return False
77
+
78
+ def select_runbook_for_alert(self, alert_type: str, alert_details: Dict[str, Any]) -> Optional[str]:
79
+ """
80
+ Auto-select appropriate runbook based on alert type.
81
+
82
+ For SOC1 and SOC2, returns the starting runbook.
83
+ For SOC3, selects based on required action.
84
+ """
85
+ if not self.auto_select_runbook:
86
+ return None
87
+
88
+ # For SOC1 and SOC2, use the starting runbook
89
+ if self.tier in ["soc1", "soc2"]:
90
+ return self.get_starting_runbook()
91
+
92
+ # For SOC3 - select based on required action
93
+ if self.tier == "soc3":
94
+ recommended_actions = alert_details.get("recommended_actions", [])
95
+ if isinstance(recommended_actions, str):
96
+ recommended_actions = [recommended_actions]
97
+
98
+ if any("isolate" in str(action).lower() for action in recommended_actions):
99
+ return "soc3/response/endpoint_isolation"
100
+ elif any("terminate" in str(action).lower() for action in recommended_actions):
101
+ return "soc3/response/process_termination"
102
+ elif any("forensic" in str(action).lower() for action in recommended_actions):
103
+ return "soc3/forensics/artifact_collection"
104
+
105
+ # Default: return starting runbook (first runbook)
106
+ return self.get_starting_runbook()
107
+
108
+ return None
109
+
110
+
111
+ class AgentProfileManager:
112
+ """Manages agent profiles and routing."""
113
+
114
+ def __init__(self, config_path: Optional[str] = None):
115
+ """
116
+ Initialize agent profile manager.
117
+
118
+ Args:
119
+ config_path: Path to agent profiles config file.
120
+ """
121
+ if config_path is None:
122
+ # Default to config/agent_profiles.json relative to project root
123
+ project_root = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
124
+ config_path = os.path.join(project_root, "config", "agent_profiles.json")
125
+
126
+ self.config_path = config_path
127
+ self.profiles: Dict[str, AgentProfile] = {}
128
+ self.routing_rules: Dict[str, str] = {}
129
+ self._load_profiles()
130
+
131
+ def _load_profiles(self) -> None:
132
+ """Load agent profiles from config file."""
133
+ if not os.path.exists(self.config_path):
134
+ # Create default profiles
135
+ self._create_default_profiles()
136
+ # Save default config
137
+ self._save_default_config()
138
+ return
139
+
140
+ try:
141
+ with open(self.config_path, "r") as f:
142
+ config = json.load(f)
143
+ except Exception as e:
144
+ raise IntegrationError(f"Failed to load agent profiles config: {e}")
145
+
146
+ # Load agent profiles
147
+ for agent_id, agent_config in config.get("agents", {}).items():
148
+ decision_auth = DecisionAuthority(
149
+ **agent_config.get("decision_authority", {})
150
+ )
151
+
152
+ profile = AgentProfile(
153
+ name=agent_config["name"],
154
+ tier=agent_config["tier"],
155
+ description=agent_config.get("description", ""),
156
+ capabilities=agent_config.get("capabilities", []),
157
+ runbooks=agent_config.get("runbooks", []),
158
+ decision_authority=decision_auth,
159
+ auto_select_runbook=agent_config.get("auto_select_runbook", True),
160
+ max_concurrent_cases=agent_config.get("max_concurrent_cases", 10)
161
+ )
162
+
163
+ self.profiles[agent_id] = profile
164
+
165
+ # Load routing rules
166
+ self.routing_rules = config.get("routing_rules", {})
167
+
168
+ def _create_default_profiles(self) -> None:
169
+ """Create default agent profiles."""
170
+ # SOC1 Profile
171
+ soc1_profile = AgentProfile(
172
+ name="SOC1 Triage Agent",
173
+ tier="soc1",
174
+ description="Handles initial alert triage and false positive identification",
175
+ capabilities=["initial_triage", "basic_enrichment", "false_positive_identification"],
176
+ runbooks=[
177
+ "soc1/triage/initial_alert_triage",
178
+ "soc1/enrichment/ioc_enrichment",
179
+ "soc1/remediation/close_false_positive"
180
+ ],
181
+ decision_authority=DecisionAuthority(
182
+ close_false_positives=True,
183
+ close_benign_true_positives=True,
184
+ escalate_to_soc2=True,
185
+ escalate_to_soc3=False,
186
+ containment_actions=False,
187
+ forensic_collection=False
188
+ ),
189
+ auto_select_runbook=True,
190
+ max_concurrent_cases=10
191
+ )
192
+ self.profiles["soc1_triage_agent"] = soc1_profile
193
+
194
+ # SOC2 Profile
195
+ soc2_profile = AgentProfile(
196
+ name="SOC2 Investigation Agent",
197
+ tier="soc2",
198
+ description="Performs deep investigation and correlation analysis",
199
+ capabilities=["deep_investigation", "correlation_analysis", "threat_hunting", "containment_recommendations"],
200
+ runbooks=[
201
+ "soc2/investigation/case_analysis"
202
+ ],
203
+ decision_authority=DecisionAuthority(
204
+ close_false_positives=True,
205
+ close_benign_true_positives=True,
206
+ escalate_to_soc2=False,
207
+ escalate_to_soc3=True,
208
+ containment_actions=False,
209
+ forensic_collection=False
210
+ ),
211
+ auto_select_runbook=True,
212
+ max_concurrent_cases=5
213
+ )
214
+ self.profiles["soc2_investigation_agent"] = soc2_profile
215
+
216
+ # SOC3 Profile
217
+ soc3_profile = AgentProfile(
218
+ name="SOC3 Response Agent",
219
+ tier="soc3",
220
+ description="Executes incident response and containment actions",
221
+ capabilities=["incident_response", "containment_execution", "forensic_collection"],
222
+ runbooks=[
223
+ "soc3/response/endpoint_isolation",
224
+ "soc3/response/process_termination",
225
+ "soc3/forensics/artifact_collection"
226
+ ],
227
+ decision_authority=DecisionAuthority(
228
+ close_false_positives=True,
229
+ close_benign_true_positives=True,
230
+ escalate_to_soc2=False,
231
+ escalate_to_soc3=False,
232
+ containment_actions=True,
233
+ forensic_collection=True
234
+ ),
235
+ auto_select_runbook=True,
236
+ max_concurrent_cases=3
237
+ )
238
+ self.profiles["soc3_response_agent"] = soc3_profile
239
+
240
+ def _save_default_config(self) -> None:
241
+ """Save default configuration to file."""
242
+ config = {
243
+ "agents": {
244
+ "soc1_triage_agent": {
245
+ "name": "SOC1 Triage Agent",
246
+ "tier": "soc1",
247
+ "description": "Handles initial alert triage and false positive identification",
248
+ "capabilities": ["initial_triage", "basic_enrichment", "false_positive_identification"],
249
+ "runbooks": [
250
+ "soc1/triage/initial_alert_triage",
251
+ "soc1/enrichment/ioc_enrichment",
252
+ "soc1/remediation/close_false_positive"
253
+ ],
254
+ "case_runbooks": [
255
+ "soc1/cases/suspicious_login_triage",
256
+ "soc1/cases/malware_initial_triage"
257
+ ],
258
+ "decision_authority": {
259
+ "close_false_positives": True,
260
+ "close_benign_true_positives": True,
261
+ "escalate_to_soc2": True,
262
+ "escalate_to_soc3": False,
263
+ "containment_actions": False,
264
+ "forensic_collection": False
265
+ },
266
+ "auto_select_runbook": True,
267
+ "max_concurrent_cases": 10
268
+ },
269
+ "soc2_investigation_agent": {
270
+ "name": "SOC2 Investigation Agent",
271
+ "tier": "soc2",
272
+ "description": "Performs deep investigation and correlation analysis",
273
+ "capabilities": ["deep_investigation", "correlation_analysis", "threat_hunting", "containment_recommendations"],
274
+ "runbooks": [
275
+ "soc2/investigation/case_analysis"
276
+ ],
277
+ "case_runbooks": [
278
+ "soc2/cases/malware_deep_analysis",
279
+ "soc2/cases/suspicious_login_investigation"
280
+ ],
281
+ "decision_authority": {
282
+ "close_false_positives": True,
283
+ "close_benign_true_positives": True,
284
+ "escalate_to_soc2": False,
285
+ "escalate_to_soc3": True,
286
+ "containment_actions": False,
287
+ "forensic_collection": False
288
+ },
289
+ "auto_select_runbook": True,
290
+ "max_concurrent_cases": 5
291
+ },
292
+ "soc3_response_agent": {
293
+ "name": "SOC3 Response Agent",
294
+ "tier": "soc3",
295
+ "description": "Executes incident response and containment actions",
296
+ "capabilities": ["incident_response", "containment_execution", "forensic_collection"],
297
+ "runbooks": [
298
+ "soc3/response/endpoint_isolation",
299
+ "soc3/response/process_termination",
300
+ "soc3/forensics/artifact_collection"
301
+ ],
302
+ "decision_authority": {
303
+ "close_false_positives": True,
304
+ "close_benign_true_positives": True,
305
+ "escalate_to_soc2": False,
306
+ "escalate_to_soc3": False,
307
+ "containment_actions": True,
308
+ "forensic_collection": True
309
+ },
310
+ "auto_select_runbook": True,
311
+ "max_concurrent_cases": 3
312
+ }
313
+ },
314
+ "routing_rules": {
315
+ "new_alert": "soc1_triage_agent",
316
+ "review_cases": "soc2_investigation_agent",
317
+ "requires_containment": "soc3_response_agent",
318
+ "forensic_collection": "soc3_response_agent"
319
+ }
320
+ }
321
+
322
+ # Ensure config directory exists
323
+ os.makedirs(os.path.dirname(self.config_path), exist_ok=True)
324
+
325
+ with open(self.config_path, "w") as f:
326
+ json.dump(config, f, indent=2)
327
+
328
+ def get_profile(self, agent_id: str) -> Optional[AgentProfile]:
329
+ """Get agent profile by ID."""
330
+ return self.profiles.get(agent_id)
331
+
332
+ def list_profiles(self) -> List[Dict[str, Any]]:
333
+ """List all agent profiles."""
334
+ return [
335
+ {
336
+ "agent_id": agent_id,
337
+ "name": profile.name,
338
+ "tier": profile.tier,
339
+ "description": profile.description,
340
+ "capabilities": profile.capabilities,
341
+ "runbook_count": len(profile.runbooks),
342
+ "decision_authority": {
343
+ "close_false_positives": profile.decision_authority.close_false_positives,
344
+ "escalate_to_soc2": profile.decision_authority.escalate_to_soc2,
345
+ "escalate_to_soc3": profile.decision_authority.escalate_to_soc3,
346
+ "containment_actions": profile.decision_authority.containment_actions,
347
+ "forensic_collection": profile.decision_authority.forensic_collection
348
+ }
349
+ }
350
+ for agent_id, profile in self.profiles.items()
351
+ ]
352
+
353
+ def route_to_agent(
354
+ self,
355
+ case_id: Optional[str] = None,
356
+ alert_id: Optional[str] = None,
357
+ alert_type: Optional[str] = None,
358
+ case_status: Optional[str] = None
359
+ ) -> Optional[str]:
360
+ """
361
+ Route a case/alert to appropriate agent.
362
+
363
+ Args:
364
+ case_id: Case ID
365
+ alert_id: Alert ID
366
+ alert_type: Type of alert
367
+ case_status: Current case status
368
+
369
+ Returns:
370
+ Agent ID to handle the case/alert
371
+ """
372
+ # Check routing rules
373
+ # Priority 1: Response actions (SOC3) - containment and forensic collection
374
+ if case_status and "containment" in case_status.lower():
375
+ return self.routing_rules.get("requires_containment", "soc3_response_agent")
376
+
377
+ if case_status and "forensic" in case_status.lower():
378
+ return self.routing_rules.get("forensic_collection", "soc3_response_agent")
379
+
380
+ # Priority 2: Case review (SOC2) - SOC2 always starts by reviewing cases
381
+ if case_id:
382
+ return self.routing_rules.get("review_cases", "soc2_investigation_agent")
383
+
384
+ # Priority 3: New alerts (SOC1) - default for new alerts without cases
385
+ return self.routing_rules.get("new_alert", "soc1_triage_agent")
386
+
387
+ def get_agent_for_tier(self, tier: str) -> Optional[AgentProfile]:
388
+ """Get agent profile for a specific SOC tier."""
389
+ for profile in self.profiles.values():
390
+ if profile.tier == tier:
391
+ return profile
392
+ return None
393
+
394
+ def get_starting_runbook_for_tier(self, tier: str) -> Optional[str]:
395
+ """
396
+ Get the starting runbook for a specific SOC tier.
397
+
398
+ Args:
399
+ tier: SOC tier (soc1, soc2, soc3)
400
+
401
+ Returns:
402
+ Starting runbook path, or None if not found
403
+ """
404
+ profile = self.get_agent_for_tier(tier)
405
+ if profile:
406
+ return profile.get_starting_runbook()
407
+ return None
408
+