zen-ai-pentest 2.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 (75) hide show
  1. agents/__init__.py +28 -0
  2. agents/agent_base.py +239 -0
  3. agents/agent_orchestrator.py +346 -0
  4. agents/analysis_agent.py +225 -0
  5. agents/cli.py +258 -0
  6. agents/exploit_agent.py +224 -0
  7. agents/integration.py +211 -0
  8. agents/post_scan_agent.py +937 -0
  9. agents/react_agent.py +384 -0
  10. agents/react_agent_enhanced.py +616 -0
  11. agents/react_agent_vm.py +298 -0
  12. agents/research_agent.py +176 -0
  13. api/__init__.py +11 -0
  14. api/auth.py +123 -0
  15. api/main.py +1027 -0
  16. api/schemas.py +357 -0
  17. api/websocket.py +97 -0
  18. autonomous/__init__.py +122 -0
  19. autonomous/agent.py +253 -0
  20. autonomous/agent_loop.py +1370 -0
  21. autonomous/exploit_validator.py +1537 -0
  22. autonomous/memory.py +448 -0
  23. autonomous/react.py +339 -0
  24. autonomous/tool_executor.py +488 -0
  25. backends/__init__.py +16 -0
  26. backends/chatgpt_direct.py +133 -0
  27. backends/claude_direct.py +130 -0
  28. backends/duckduckgo.py +138 -0
  29. backends/openrouter.py +120 -0
  30. benchmarks/__init__.py +149 -0
  31. benchmarks/benchmark_engine.py +904 -0
  32. benchmarks/ci_benchmark.py +785 -0
  33. benchmarks/comparison.py +729 -0
  34. benchmarks/metrics.py +553 -0
  35. benchmarks/run_benchmarks.py +809 -0
  36. ci_cd/__init__.py +2 -0
  37. core/__init__.py +17 -0
  38. core/async_pool.py +282 -0
  39. core/asyncio_fix.py +222 -0
  40. core/cache.py +472 -0
  41. core/container.py +277 -0
  42. core/database.py +114 -0
  43. core/input_validator.py +353 -0
  44. core/models.py +288 -0
  45. core/orchestrator.py +611 -0
  46. core/plugin_manager.py +571 -0
  47. core/rate_limiter.py +405 -0
  48. core/secure_config.py +328 -0
  49. core/shield_integration.py +296 -0
  50. modules/__init__.py +46 -0
  51. modules/cve_database.py +362 -0
  52. modules/exploit_assist.py +330 -0
  53. modules/nuclei_integration.py +480 -0
  54. modules/osint.py +604 -0
  55. modules/protonvpn.py +554 -0
  56. modules/recon.py +165 -0
  57. modules/sql_injection_db.py +826 -0
  58. modules/tool_orchestrator.py +498 -0
  59. modules/vuln_scanner.py +292 -0
  60. modules/wordlist_generator.py +566 -0
  61. risk_engine/__init__.py +99 -0
  62. risk_engine/business_impact.py +267 -0
  63. risk_engine/business_impact_calculator.py +563 -0
  64. risk_engine/cvss.py +156 -0
  65. risk_engine/epss.py +190 -0
  66. risk_engine/example_usage.py +294 -0
  67. risk_engine/false_positive_engine.py +1073 -0
  68. risk_engine/scorer.py +304 -0
  69. web_ui/backend/main.py +471 -0
  70. zen_ai_pentest-2.0.0.dist-info/METADATA +795 -0
  71. zen_ai_pentest-2.0.0.dist-info/RECORD +75 -0
  72. zen_ai_pentest-2.0.0.dist-info/WHEEL +5 -0
  73. zen_ai_pentest-2.0.0.dist-info/entry_points.txt +2 -0
  74. zen_ai_pentest-2.0.0.dist-info/licenses/LICENSE +21 -0
  75. zen_ai_pentest-2.0.0.dist-info/top_level.txt +10 -0
agents/__init__.py ADDED
@@ -0,0 +1,28 @@
1
+ """
2
+ Multi-Agent Collaboration System for Zen AI Pentest
3
+ Inspired by Clawed/Moltbot architecture
4
+ Agents can communicate, share context, and coordinate research
5
+ Author: SHAdd0WTAka
6
+ """
7
+
8
+ from .agent_base import AgentMessage, AgentRole, BaseAgent
9
+ from .agent_orchestrator import AgentOrchestrator
10
+ from .analysis_agent import AnalysisAgent
11
+ from .exploit_agent import ExploitAgent
12
+ from .post_scan_agent import (PentestLoot, PostScanAgent, VerifiedFinding,
13
+ run_post_scan_workflow)
14
+ from .research_agent import ResearchAgent
15
+
16
+ __all__ = [
17
+ "BaseAgent",
18
+ "AgentRole",
19
+ "AgentMessage",
20
+ "AgentOrchestrator",
21
+ "ResearchAgent",
22
+ "ExploitAgent",
23
+ "AnalysisAgent",
24
+ "PostScanAgent",
25
+ "run_post_scan_workflow",
26
+ "VerifiedFinding",
27
+ "PentestLoot",
28
+ ]
agents/agent_base.py ADDED
@@ -0,0 +1,239 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Base Agent Class for Multi-Agent System
4
+ Provides messaging, context sharing, and role-based capabilities
5
+ Author: SHAdd0WTAka
6
+ """
7
+
8
+ import asyncio
9
+ import logging
10
+ import uuid
11
+ from abc import ABC, abstractmethod
12
+ from dataclasses import dataclass, field
13
+ from datetime import datetime
14
+ from enum import Enum
15
+ from typing import Any, Callable, Dict, List, Optional
16
+
17
+ logger = logging.getLogger("ZenAI.Agents")
18
+
19
+
20
+ class AgentRole(Enum):
21
+ """Agent roles for specialization"""
22
+
23
+ RESEARCHER = "researcher" # Gathers information, reconnaissance
24
+ ANALYST = "analyst" # Analyzes data, finds patterns
25
+ EXPLOIT = "exploit" # Develops exploits, payloads
26
+ COORDINATOR = "coordinator" # Manages workflow between agents
27
+ REPORTER = "reporter" # Generates reports, summaries
28
+ POST_EXPLOITATION = (
29
+ "post_exploit" # Post-scan workflow: verification, evidence, cleanup
30
+ )
31
+
32
+
33
+ class AgentState(Enum):
34
+ """Operational states for agents"""
35
+
36
+ IDLE = "idle"
37
+ BUSY = "busy"
38
+ WAITING = "waiting"
39
+ COMPLETED = "completed"
40
+ FAILED = "failed"
41
+ STOPPED = "stopped"
42
+
43
+
44
+
45
+ @dataclass
46
+ class AgentMessage:
47
+ """Message format for inter-agent communication"""
48
+
49
+ id: str = field(default_factory=lambda: str(uuid.uuid4())[:8])
50
+ sender: str = ""
51
+ recipient: str = "" # "all" for broadcast, specific ID for direct
52
+ msg_type: str = "chat" # chat, task, result, request, response
53
+ content: str = ""
54
+ context: Dict[str, Any] = field(default_factory=dict)
55
+ timestamp: str = field(default_factory=lambda: datetime.now().isoformat())
56
+ priority: int = 1 # 1=low, 2=medium, 3=high, 4=critical
57
+ requires_response: bool = False
58
+
59
+ def to_dict(self) -> Dict:
60
+ return {
61
+ "id": self.id,
62
+ "sender": self.sender,
63
+ "recipient": self.recipient,
64
+ "type": self.msg_type,
65
+ "content": self.content,
66
+ "context": self.context,
67
+ "timestamp": self.timestamp,
68
+ "priority": self.priority,
69
+ "requires_response": self.requires_response,
70
+ }
71
+
72
+
73
+ class BaseAgent(ABC):
74
+ """
75
+ Base class for all agents in the system
76
+ Provides messaging, context management, and coordination capabilities
77
+ """
78
+
79
+ def __init__(self, name: str, role: AgentRole, orchestrator=None):
80
+ self.id = str(uuid.uuid4())[:8]
81
+ self.name = name
82
+ self.role = role
83
+ self.orchestrator = orchestrator
84
+ self.message_queue: asyncio.Queue = asyncio.Queue()
85
+ self.inbox: List[AgentMessage] = []
86
+ self.context: Dict[str, Any] = {} # Shared workspace
87
+ self.memory: List[Dict] = [] # Agent's memory of interactions
88
+ self.handlers: Dict[str, Callable] = {}
89
+ self.running = False
90
+ self.task: Optional[asyncio.Task] = None
91
+
92
+ logger.info(f"[Agent] Initialized {self.name} ({self.role.value}) [{self.id}]")
93
+
94
+ def register_handler(self, msg_type: str, handler: Callable):
95
+ """Register a handler for specific message types"""
96
+ self.handlers[msg_type] = handler
97
+
98
+ async def send_message(
99
+ self,
100
+ content: str,
101
+ recipient: str = "all",
102
+ msg_type: str = "chat",
103
+ priority: int = 1,
104
+ requires_response: bool = False,
105
+ context: Dict = None,
106
+ ) -> str:
107
+ """
108
+ Send a message to another agent or broadcast
109
+ Returns message ID for tracking
110
+ """
111
+ msg = AgentMessage(
112
+ sender=f"{self.name}[{self.id}]",
113
+ recipient=recipient,
114
+ msg_type=msg_type,
115
+ content=content,
116
+ priority=priority,
117
+ requires_response=requires_response,
118
+ context=context or {},
119
+ )
120
+
121
+ if self.orchestrator:
122
+ await self.orchestrator.route_message(msg)
123
+ logger.debug(f"[Agent:{self.name}] Sent {msg_type} to {recipient}")
124
+ else:
125
+ # Direct send if no orchestrator
126
+ await self.message_queue.put(msg)
127
+
128
+ return msg.id
129
+
130
+ async def receive_message(self, msg: AgentMessage):
131
+ """Receive a message into the queue"""
132
+ await self.message_queue.put(msg)
133
+ self.inbox.append(msg)
134
+
135
+ # Store in memory
136
+ self.memory.append(
137
+ {"type": "received", "message": msg.to_dict(), "processed": False}
138
+ )
139
+
140
+ logger.debug(f"[Agent:{self.name}] Received message from {msg.sender}")
141
+
142
+ async def process_messages(self):
143
+ """Main message processing loop"""
144
+ self.running = True
145
+
146
+ while self.running:
147
+ try:
148
+ # Get message with timeout to allow checking running flag
149
+ msg = await asyncio.wait_for(self.message_queue.get(), timeout=1.0)
150
+
151
+ # Process based on type
152
+ if msg.msg_type in self.handlers:
153
+ await self.handlers[msg.msg_type](msg)
154
+ else:
155
+ await self.handle_message(msg)
156
+
157
+ # Mark as processed in memory
158
+ for mem in self.memory:
159
+ if mem["type"] == "received" and mem["message"]["id"] == msg.id:
160
+ mem["processed"] = True
161
+
162
+ except asyncio.TimeoutError:
163
+ continue
164
+ except Exception as e:
165
+ logger.error(f"[Agent:{self.name}] Error processing message: {e}")
166
+
167
+ async def handle_message(self, msg: AgentMessage):
168
+ """Default message handler - override in subclasses"""
169
+ logger.info(f"[Agent:{self.name}] Handling {msg.msg_type} from {msg.sender}")
170
+
171
+ # Default chat response
172
+ if msg.msg_type == "chat":
173
+ response = f"Acknowledged: {msg.content[:50]}..."
174
+ if msg.requires_response:
175
+ await self.send_message(
176
+ content=response, recipient=msg.sender, msg_type="response"
177
+ )
178
+
179
+ def update_context(self, key: str, value: Any, share: bool = False):
180
+ """
181
+ Update agent's local context
182
+ If share=True, broadcast to all agents via orchestrator
183
+ """
184
+ self.context[key] = value
185
+
186
+ if share and self.orchestrator:
187
+ asyncio.create_task(
188
+ self.orchestrator.update_shared_context(key, value, self.id)
189
+ )
190
+
191
+ def get_context(self, key: str) -> Any:
192
+ """Get value from context"""
193
+ return self.context.get(key)
194
+
195
+ def share_findings(self, findings: Dict):
196
+ """Share findings with all agents"""
197
+ if self.orchestrator:
198
+ asyncio.create_task(
199
+ self.send_message(
200
+ content=f"Sharing {len(findings)} findings",
201
+ msg_type="findings",
202
+ context={"findings": findings},
203
+ priority=2,
204
+ )
205
+ )
206
+
207
+ @abstractmethod
208
+ async def execute_task(self, task: Dict) -> Dict:
209
+ """Execute a specific task - must be implemented by subclasses"""
210
+ pass
211
+
212
+ async def start(self):
213
+ """Start the agent's message processing loop"""
214
+ self.task = asyncio.create_task(self.process_messages())
215
+ logger.info(f"[Agent:{self.name}] Started")
216
+
217
+ async def stop(self):
218
+ """Stop the agent gracefully"""
219
+ self.running = False
220
+ if self.task:
221
+ self.task.cancel()
222
+ try:
223
+ await self.task
224
+ except asyncio.CancelledError:
225
+ pass
226
+ logger.info(f"[Agent:{self.name}] Stopped")
227
+
228
+ def get_status(self) -> Dict:
229
+ """Get agent status"""
230
+ return {
231
+ "id": self.id,
232
+ "name": self.name,
233
+ "role": self.role.value,
234
+ "running": self.running,
235
+ "queue_size": self.message_queue.qsize(),
236
+ "inbox_count": len(self.inbox),
237
+ "memory_entries": len(self.memory),
238
+ "context_keys": list(self.context.keys()),
239
+ }
@@ -0,0 +1,346 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Agent Orchestrator
4
+ Manages multiple agents, routes messages, coordinates research
5
+ Like Clawed/Moltbot but for penetration testing
6
+ Author: SHAdd0WTAka
7
+ """
8
+
9
+ import asyncio
10
+ import logging
11
+ from datetime import datetime
12
+ from typing import Any, Dict, List, Optional
13
+
14
+ from .agent_base import AgentMessage, AgentRole, BaseAgent
15
+
16
+ logger = logging.getLogger("ZenAI.Agents")
17
+
18
+
19
+ class AgentOrchestrator:
20
+ """
21
+ Central coordinator for multi-agent system
22
+ Manages agent lifecycle, message routing, and context sharing
23
+ """
24
+
25
+ def __init__(self, zen_orchestrator=None):
26
+ self.agents: Dict[str, BaseAgent] = {}
27
+ self.agent_by_role: Dict[AgentRole, List[BaseAgent]] = {}
28
+ self.shared_context: Dict[str, Any] = {}
29
+ self.message_history: List[AgentMessage] = []
30
+ self.conversation_threads: Dict[str, List[str]] = {} # thread_id -> message_ids
31
+ self.zen_orchestrator = zen_orchestrator # Link to LLM orchestrator
32
+ self.running = False
33
+ self.research_coordination: Dict[str, Any] = {}
34
+
35
+ def register_agent(self, agent: BaseAgent):
36
+ """Register an agent with the orchestrator"""
37
+ self.agents[agent.id] = agent
38
+ agent.orchestrator = self
39
+
40
+ # Index by role
41
+ if agent.role not in self.agent_by_role:
42
+ self.agent_by_role[agent.role] = []
43
+ self.agent_by_role[agent.role].append(agent)
44
+
45
+ logger.info(
46
+ f"[Orchestrator] Registered agent {agent.name} ({agent.role.value})"
47
+ )
48
+
49
+ def unregister_agent(self, agent_id: str):
50
+ """Remove an agent from the system"""
51
+ if agent_id in self.agents:
52
+ agent = self.agents[agent_id]
53
+
54
+ # Remove from role index
55
+ if agent.role in self.agent_by_role:
56
+ self.agent_by_role[agent.role] = [
57
+ a for a in self.agent_by_role[agent.role] if a.id != agent_id
58
+ ]
59
+
60
+ del self.agents[agent_id]
61
+ logger.info(f"[Orchestrator] Unregistered agent {agent_id}")
62
+
63
+ async def route_message(self, msg: AgentMessage):
64
+ """Route a message to the appropriate recipient(s)"""
65
+ self.message_history.append(msg)
66
+
67
+ if msg.recipient == "all":
68
+ # Broadcast to all agents except sender
69
+ for agent_id, agent in self.agents.items():
70
+ if f"[{agent_id}]" not in msg.sender:
71
+ await agent.receive_message(msg)
72
+
73
+ elif msg.recipient.startswith("role:"):
74
+ # Send to all agents of a specific role
75
+ role_str = msg.recipient.split(":")[1]
76
+ try:
77
+ role = AgentRole(role_str)
78
+ for agent in self.agent_by_role.get(role, []):
79
+ if f"[{agent.id}]" not in msg.sender:
80
+ await agent.receive_message(msg)
81
+ except ValueError:
82
+ logger.error(f"[Orchestrator] Invalid role: {role_str}")
83
+
84
+ else:
85
+ # Direct message to specific agent
86
+ # Parse agent ID from recipient string like "AgentName[ID]"
87
+ if "[" in msg.recipient and "]" in msg.recipient:
88
+ agent_id = msg.recipient.split("[")[1].split("]")[0]
89
+ if agent_id in self.agents:
90
+ await self.agents[agent_id].receive_message(msg)
91
+
92
+ async def update_shared_context(self, key: str, value: Any, source_agent_id: str):
93
+ """Update shared context and notify all agents"""
94
+ self.shared_context[key] = {
95
+ "value": value,
96
+ "updated_by": source_agent_id,
97
+ "timestamp": datetime.now().isoformat(),
98
+ }
99
+
100
+ # Notify all agents of context update
101
+ for agent_id, agent in self.agents.items():
102
+ if agent_id != source_agent_id:
103
+ await agent.receive_message(
104
+ AgentMessage(
105
+ sender="orchestrator",
106
+ recipient=f"{agent.name}[{agent.id}]",
107
+ msg_type="context_update",
108
+ content=f"Context updated: {key}",
109
+ context={"key": key, "value": value},
110
+ )
111
+ )
112
+
113
+ def get_shared_context(self, key: str = None) -> Any:
114
+ """Get value from shared context"""
115
+ if key:
116
+ return self.shared_context.get(key, {}).get("value")
117
+ return self.shared_context
118
+
119
+ async def start_research_coordination(
120
+ self, topic: str, pentest_context: Dict
121
+ ) -> str:
122
+ """
123
+ Coordinate multi-agent research on a topic
124
+ Returns thread ID for tracking
125
+ """
126
+ thread_id = f"research_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
127
+
128
+ self.research_coordination[thread_id] = {
129
+ "topic": topic,
130
+ "context": pentest_context,
131
+ "started": datetime.now().isoformat(),
132
+ "agents_involved": [],
133
+ "findings": [],
134
+ "status": "active",
135
+ }
136
+
137
+ # Notify all research agents
138
+ for agent in self.agent_by_role.get(AgentRole.RESEARCHER, []):
139
+ await agent.receive_message(
140
+ AgentMessage(
141
+ sender="orchestrator",
142
+ recipient=f"{agent.name}[{agent.id}]",
143
+ msg_type="research_task",
144
+ content=f"Research coordination started: {topic}",
145
+ context={
146
+ "thread_id": thread_id,
147
+ "pentest_context": pentest_context,
148
+ "shared_context": self.shared_context,
149
+ },
150
+ priority=3,
151
+ )
152
+ )
153
+ self.research_coordination[thread_id]["agents_involved"].append(agent.id)
154
+
155
+ logger.info(f"[Orchestrator] Started research coordination: {thread_id}")
156
+ return thread_id
157
+
158
+ async def coordinate_agents(self, task_type: str, context: Dict) -> Dict:
159
+ """
160
+ Coordinate multiple agents for a complex task
161
+ Agents will communicate and share findings
162
+ """
163
+ results = {
164
+ "task_type": task_type,
165
+ "started": datetime.now().isoformat(),
166
+ "agent_responses": {},
167
+ }
168
+
169
+ # Determine which agents to involve based on task
170
+ involved_roles = []
171
+
172
+ if task_type == "reconnaissance":
173
+ involved_roles = [AgentRole.RESEARCHER, AgentRole.ANALYST]
174
+ elif task_type == "vulnerability_analysis":
175
+ involved_roles = [AgentRole.ANALYST, AgentRole.EXPLOIT]
176
+ elif task_type == "exploit_development":
177
+ involved_roles = [AgentRole.EXPLOIT, AgentRole.ANALYST]
178
+ elif task_type == "full_assessment":
179
+ involved_roles = [
180
+ AgentRole.RESEARCHER,
181
+ AgentRole.ANALYST,
182
+ AgentRole.EXPLOIT,
183
+ ]
184
+
185
+ # Start all involved agents
186
+ tasks = []
187
+ for role in involved_roles:
188
+ for agent in self.agent_by_role.get(role, []):
189
+ agent_task = asyncio.create_task(
190
+ agent.execute_task(
191
+ {
192
+ "type": task_type,
193
+ "context": context,
194
+ "shared_context": self.shared_context,
195
+ }
196
+ )
197
+ )
198
+ tasks.append((agent.id, agent_task))
199
+
200
+ # Wait for all agents to complete
201
+ for agent_id, task in tasks:
202
+ try:
203
+ result = await asyncio.wait_for(task, timeout=300)
204
+ results["agent_responses"][agent_id] = result
205
+ except asyncio.TimeoutError:
206
+ results["agent_responses"][agent_id] = {"error": "timeout"}
207
+
208
+ # Agents should have communicated with each other during execution
209
+ # Collect their findings from shared context
210
+ results["shared_findings"] = self.shared_context
211
+ results["completed"] = datetime.now().isoformat()
212
+
213
+ return results
214
+
215
+ async def facilitate_conversation(
216
+ self, topic: str, participants: List[str], rounds: int = 3
217
+ ) -> List[AgentMessage]:
218
+ """
219
+ Facilitate a multi-round conversation between agents
220
+ Similar to Clawed/Moltbot group discussions
221
+ """
222
+ conversation = []
223
+
224
+ for round_num in range(rounds):
225
+ logger.info(f"[Orchestrator] Conversation round {round_num + 1}/{rounds}")
226
+
227
+ for participant_id in participants:
228
+ if participant_id in self.agents:
229
+ agent = self.agents[participant_id]
230
+
231
+ # Request agent's thoughts on topic
232
+ msg = AgentMessage(
233
+ sender="orchestrator",
234
+ recipient=f"{agent.name}[{agent.id}]",
235
+ msg_type="conversation_round",
236
+ content=f"Round {round_num + 1}: Share your thoughts on {topic}",
237
+ context={
238
+ "round": round_num + 1,
239
+ "topic": topic,
240
+ "conversation_so_far": [m.to_dict() for m in conversation],
241
+ "shared_context": self.shared_context,
242
+ },
243
+ requires_response=True,
244
+ )
245
+
246
+ await agent.receive_message(msg)
247
+
248
+ return conversation
249
+
250
+ async def start_all(self):
251
+ """Start all registered agents"""
252
+ self.running = True
253
+ for agent in self.agents.values():
254
+ await agent.start()
255
+
256
+ async def stop_all(self):
257
+ """Stop all agents gracefully"""
258
+ self.running = False
259
+ for agent in self.agents.values():
260
+ await agent.stop()
261
+
262
+ async def execute_post_scan_workflow(
263
+ self, target: str, scan_results: Dict[str, Any]
264
+ ) -> Dict[str, Any]:
265
+ """
266
+ Execute the complete post-scan pentester workflow
267
+ This runs automatically after every scan to ensure professional standards
268
+
269
+ Phases:
270
+ 1. Manual Verification (false positive elimination)
271
+ 2. Vulnerability Validation
272
+ 3. Exploitation Attempts
273
+ 4. Post-Exploitation (privilege escalation, lateral movement)
274
+ 5. Evidence Collection
275
+ 6. Loot Documentation
276
+ 7. Cleanup & Restoration
277
+ 8. Report Preparation
278
+ """
279
+ from .post_scan_agent import PostScanAgent
280
+
281
+ logger.info(f"[Orchestrator] Starting post-scan workflow for {target}")
282
+ print(f"\n[Post-Scan Workflow] Initiating professional pentest follow-up...")
283
+
284
+ # Create and run post-scan agent
285
+ post_scan_agent = PostScanAgent()
286
+
287
+ # Extract findings from scan results
288
+ findings = scan_results.get("findings", [])
289
+ if not findings:
290
+ # Create sample findings if none exist
291
+ findings = self._generate_sample_findings(target)
292
+
293
+ # Execute the workflow
294
+ results = await post_scan_agent.run(target, findings)
295
+
296
+ # Store in shared context
297
+ await self.update_shared_context(f"post_scan_{target}", results, "orchestrator")
298
+
299
+ logger.info(f"[Orchestrator] Post-scan workflow complete for {target}")
300
+ return results
301
+
302
+ def _generate_sample_findings(self, target: str) -> List[Dict]:
303
+ """Generate sample findings for demonstration"""
304
+ return [
305
+ {
306
+ "id": "CVE-2021-44228",
307
+ "title": "Log4j Remote Code Execution",
308
+ "severity": "critical",
309
+ "cvss_score": 10.0,
310
+ "description": "Log4Shell vulnerability allows RCE",
311
+ "port": 8080,
312
+ "service": "http",
313
+ },
314
+ {
315
+ "id": "WEAK_SSH",
316
+ "title": "SSH Weak Cipher Suites",
317
+ "severity": "medium",
318
+ "cvss_score": 5.3,
319
+ "description": "SSH supports weak ciphers",
320
+ "port": 22,
321
+ "service": "ssh",
322
+ },
323
+ {
324
+ "id": "DEFAULT_CREDS",
325
+ "title": "Default Credentials Detected",
326
+ "severity": "high",
327
+ "cvss_score": 8.1,
328
+ "description": "Default admin/admin credentials work",
329
+ "port": 80,
330
+ "service": "http",
331
+ },
332
+ ]
333
+
334
+ def get_system_status(self) -> Dict:
335
+ """Get status of entire multi-agent system"""
336
+ return {
337
+ "agents": {
338
+ agent_id: agent.get_status() for agent_id, agent in self.agents.items()
339
+ },
340
+ "shared_context_keys": list(self.shared_context.keys()),
341
+ "message_count": len(self.message_history),
342
+ "active_research": list(self.research_coordination.keys()),
343
+ "role_distribution": {
344
+ role.value: len(agents) for role, agents in self.agent_by_role.items()
345
+ },
346
+ }