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
core/plugin_manager.py ADDED
@@ -0,0 +1,571 @@
1
+ """
2
+ Plugin Manager - Dynamic Plugin System for Zen AI Pentest
3
+
4
+ Features:
5
+ - Dynamic plugin loading/unloading
6
+ - Hook system for extensibility
7
+ - Plugin configuration management
8
+ - Sandboxed execution
9
+ - Dependency checking
10
+
11
+ Author: SHAdd0WTAka + Kimi AI
12
+ """
13
+
14
+ import importlib
15
+ import importlib.util
16
+ import json
17
+ import logging
18
+ import os
19
+ import pkgutil
20
+ import sys
21
+ from abc import ABC, abstractmethod
22
+ from dataclasses import dataclass, field
23
+ from enum import Enum
24
+ from pathlib import Path
25
+ from typing import Any, Callable, Dict, List, Optional, Type
26
+
27
+ logger = logging.getLogger("ZenAI.Plugins")
28
+
29
+
30
+ class PluginType(Enum):
31
+ """Types of plugins"""
32
+ SCANNER = "scanner" # Vulnerability scanners
33
+ EXPLOIT = "exploit" # Exploit modules
34
+ REPORT = "report" # Report generators
35
+ OSINT = "osint" # OSINT sources
36
+ POST_EXPLOITATION = "post" # Post-exploitation
37
+ TOOL = "tool" # External tools integration
38
+ NOTIFIER = "notifier" # Notification services
39
+ AUTH = "auth" # Authentication providers
40
+
41
+
42
+ class PluginStatus(Enum):
43
+ """Plugin loading status"""
44
+ UNLOADED = "unloaded"
45
+ LOADING = "loading"
46
+ LOADED = "loaded"
47
+ ERROR = "error"
48
+ DISABLED = "disabled"
49
+
50
+
51
+ @dataclass
52
+ class PluginInfo:
53
+ """Plugin metadata"""
54
+ name: str
55
+ version: str
56
+ description: str
57
+ author: str
58
+ plugin_type: PluginType
59
+ dependencies: List[str] = field(default_factory=list)
60
+ hooks: List[str] = field(default_factory=list)
61
+ config_schema: Dict[str, Any] = field(default_factory=dict)
62
+
63
+ # Runtime info
64
+ status: PluginStatus = PluginStatus.UNLOADED
65
+ path: Optional[str] = None
66
+ error_message: Optional[str] = None
67
+ loaded_at: Optional[str] = None
68
+
69
+
70
+ class BasePlugin(ABC):
71
+ """
72
+ Base class for all plugins
73
+
74
+ All plugins must inherit from this class and implement required methods.
75
+ """
76
+
77
+ # Plugin metadata (must be overridden)
78
+ NAME: str = ""
79
+ VERSION: str = "1.0.0"
80
+ DESCRIPTION: str = ""
81
+ AUTHOR: str = ""
82
+ PLUGIN_TYPE: PluginType = PluginType.TOOL
83
+
84
+ def __init__(self, config: Optional[Dict] = None):
85
+ self.config = config or {}
86
+ self.enabled = True
87
+ self.logger = logging.getLogger(f"ZenAI.Plugin.{self.NAME}")
88
+
89
+ @abstractmethod
90
+ async def initialize(self) -> bool:
91
+ """
92
+ Initialize the plugin.
93
+ Called once when plugin is loaded.
94
+
95
+ Returns:
96
+ True if initialization successful
97
+ """
98
+ pass
99
+
100
+ @abstractmethod
101
+ async def execute(self, **kwargs) -> Any:
102
+ """
103
+ Execute plugin functionality.
104
+ Main entry point for the plugin.
105
+
106
+ Args:
107
+ **kwargs: Plugin-specific parameters
108
+
109
+ Returns:
110
+ Plugin result
111
+ """
112
+ pass
113
+
114
+ async def shutdown(self):
115
+ """
116
+ Cleanup when plugin is unloaded.
117
+ Override to perform cleanup.
118
+ """
119
+ pass
120
+
121
+ def get_config(self, key: str, default: Any = None) -> Any:
122
+ """Get configuration value"""
123
+ return self.config.get(key, default)
124
+
125
+ def set_config(self, key: str, value: Any):
126
+ """Set configuration value"""
127
+ self.config[key] = value
128
+
129
+ def validate_config(self) -> bool:
130
+ """
131
+ Validate plugin configuration.
132
+ Override to implement custom validation.
133
+
134
+ Returns:
135
+ True if configuration is valid
136
+ """
137
+ return True
138
+
139
+ def get_info(self) -> PluginInfo:
140
+ """Get plugin information"""
141
+ return PluginInfo(
142
+ name=self.NAME,
143
+ version=self.VERSION,
144
+ description=self.DESCRIPTION,
145
+ author=self.AUTHOR,
146
+ plugin_type=self.PLUGIN_TYPE
147
+ )
148
+
149
+
150
+ class HookManager:
151
+ """
152
+ Hook system for plugin intercommunication.
153
+ Allows plugins to register callbacks for specific events.
154
+ """
155
+
156
+ def __init__(self):
157
+ self._hooks: Dict[str, List[Callable]] = {}
158
+ self._filters: Dict[str, List[Callable]] = {}
159
+
160
+ def register_hook(self, hook_name: str, callback: Callable, priority: int = 10):
161
+ """
162
+ Register a hook callback.
163
+
164
+ Args:
165
+ hook_name: Name of the hook
166
+ callback: Function to call
167
+ priority: Lower number = higher priority (default 10)
168
+ """
169
+ if hook_name not in self._hooks:
170
+ self._hooks[hook_name] = []
171
+
172
+ self._hooks[hook_name].append({
173
+ "callback": callback,
174
+ "priority": priority
175
+ })
176
+
177
+ # Sort by priority
178
+ self._hooks[hook_name].sort(key=lambda x: x["priority"])
179
+ logger.debug(f"Registered hook '{hook_name}' with priority {priority}")
180
+
181
+ def unregister_hook(self, hook_name: str, callback: Callable):
182
+ """Unregister a hook callback"""
183
+ if hook_name in self._hooks:
184
+ self._hooks[hook_name] = [
185
+ h for h in self._hooks[hook_name]
186
+ if h["callback"] != callback
187
+ ]
188
+
189
+ async def execute_hook(self, hook_name: str, *args, **kwargs) -> List[Any]:
190
+ """
191
+ Execute all callbacks for a hook.
192
+
193
+ Args:
194
+ hook_name: Name of the hook to execute
195
+ *args, **kwargs: Arguments to pass to callbacks
196
+
197
+ Returns:
198
+ List of results from all callbacks
199
+ """
200
+ results = []
201
+
202
+ if hook_name in self._hooks:
203
+ for hook in self._hooks[hook_name]:
204
+ try:
205
+ result = await hook["callback"](*args, **kwargs)
206
+ results.append(result)
207
+ except Exception as e:
208
+ logger.error(f"Hook '{hook_name}' callback failed: {e}")
209
+
210
+ return results
211
+
212
+ def register_filter(self, filter_name: str, callback: Callable, priority: int = 10):
213
+ """
214
+ Register a filter callback.
215
+ Filters modify data passed through them.
216
+ """
217
+ if filter_name not in self._filters:
218
+ self._filters[filter_name] = []
219
+
220
+ self._filters[filter_name].append({
221
+ "callback": callback,
222
+ "priority": priority
223
+ })
224
+
225
+ self._filters[filter_name].sort(key=lambda x: x["priority"])
226
+
227
+ async def apply_filter(self, filter_name: str, data: Any, **kwargs) -> Any:
228
+ """
229
+ Apply all filters to data.
230
+
231
+ Args:
232
+ filter_name: Name of the filter chain
233
+ data: Data to filter
234
+ **kwargs: Additional arguments
235
+
236
+ Returns:
237
+ Filtered data
238
+ """
239
+ if filter_name not in self._filters:
240
+ return data
241
+
242
+ for filter_hook in self._filters[filter_name]:
243
+ try:
244
+ data = await filter_hook["callback"](data, **kwargs)
245
+ except Exception as e:
246
+ logger.error(f"Filter '{filter_name}' callback failed: {e}")
247
+
248
+ return data
249
+
250
+
251
+ class PluginManager:
252
+ """
253
+ Central plugin manager for Zen AI Pentest.
254
+ Handles loading, unloading, and managing plugins.
255
+ """
256
+
257
+ def __init__(self, plugin_dirs: Optional[List[str]] = None):
258
+ self.plugin_dirs = plugin_dirs or ["plugins", "custom_plugins"]
259
+ self.plugins: Dict[str, BasePlugin] = {}
260
+ self.plugin_info: Dict[str, PluginInfo] = {}
261
+ self.hooks = HookManager()
262
+ self._loaded_modules: Dict[str, Any] = {}
263
+
264
+ # Ensure plugin directories exist
265
+ for plugin_dir in self.plugin_dirs:
266
+ Path(plugin_dir).mkdir(parents=True, exist_ok=True)
267
+
268
+ def discover_plugins(self) -> List[PluginInfo]:
269
+ """
270
+ Discover available plugins in plugin directories.
271
+
272
+ Returns:
273
+ List of discovered plugin information
274
+ """
275
+ discovered = []
276
+
277
+ for plugin_dir in self.plugin_dirs:
278
+ if not os.path.exists(plugin_dir):
279
+ continue
280
+
281
+ # Look for plugin directories or files
282
+ for item in os.listdir(plugin_dir):
283
+ item_path = os.path.join(plugin_dir, item)
284
+
285
+ # Check for plugin.json manifest
286
+ manifest_path = os.path.join(item_path, "plugin.json")
287
+ if os.path.isfile(manifest_path):
288
+ try:
289
+ with open(manifest_path) as f:
290
+ manifest = json.load(f)
291
+
292
+ info = PluginInfo(
293
+ name=manifest.get("name", item),
294
+ version=manifest.get("version", "1.0.0"),
295
+ description=manifest.get("description", ""),
296
+ author=manifest.get("author", "Unknown"),
297
+ plugin_type=PluginType(manifest.get("type", "tool")),
298
+ dependencies=manifest.get("dependencies", []),
299
+ hooks=manifest.get("hooks", []),
300
+ path=item_path
301
+ )
302
+ discovered.append(info)
303
+
304
+ except Exception as e:
305
+ logger.error(f"Failed to load plugin manifest {manifest_path}: {e}")
306
+
307
+ # Check for Python module
308
+ elif os.path.isfile(os.path.join(item_path, "__init__.py")):
309
+ # Try to import and get metadata
310
+ try:
311
+ info = self._get_plugin_info_from_module(item_path)
312
+ if info:
313
+ discovered.append(info)
314
+ except Exception as e:
315
+ logger.error(f"Failed to inspect plugin {item_path}: {e}")
316
+
317
+ return discovered
318
+
319
+ def _get_plugin_info_from_module(self, path: str) -> Optional[PluginInfo]:
320
+ """Extract plugin info from Python module"""
321
+ # Add to path temporarily
322
+ parent_dir = os.path.dirname(path)
323
+ if parent_dir not in sys.path:
324
+ sys.path.insert(0, parent_dir)
325
+
326
+ try:
327
+ module_name = os.path.basename(path)
328
+ spec = importlib.util.spec_from_file_location(
329
+ module_name,
330
+ os.path.join(path, "__init__.py")
331
+ )
332
+
333
+ if spec and spec.loader:
334
+ module = importlib.util.module_from_spec(spec)
335
+ spec.loader.exec_module(module)
336
+
337
+ # Look for plugin class
338
+ for attr_name in dir(module):
339
+ attr = getattr(module, attr_name)
340
+ if (isinstance(attr, type) and
341
+ issubclass(attr, BasePlugin) and
342
+ attr != BasePlugin and
343
+ hasattr(attr, 'NAME')):
344
+
345
+ return PluginInfo(
346
+ name=attr.NAME,
347
+ version=getattr(attr, 'VERSION', '1.0.0'),
348
+ description=getattr(attr, 'DESCRIPTION', ''),
349
+ author=getattr(attr, 'AUTHOR', 'Unknown'),
350
+ plugin_type=getattr(attr, 'PLUGIN_TYPE', PluginType.TOOL),
351
+ path=path
352
+ )
353
+ finally:
354
+ if parent_dir in sys.path:
355
+ sys.path.remove(parent_dir)
356
+
357
+ return None
358
+
359
+ async def load_plugin(self, plugin_name: str, config: Optional[Dict] = None) -> bool:
360
+ """
361
+ Load a plugin by name.
362
+
363
+ Args:
364
+ plugin_name: Name of the plugin to load
365
+ config: Optional configuration dictionary
366
+
367
+ Returns:
368
+ True if plugin loaded successfully
369
+ """
370
+ if plugin_name in self.plugins:
371
+ logger.warning(f"Plugin '{plugin_name}' is already loaded")
372
+ return True
373
+
374
+ # Find plugin
375
+ discovered = self.discover_plugins()
376
+ plugin_info = next((p for p in discovered if p.name == plugin_name), None)
377
+
378
+ if not plugin_info:
379
+ logger.error(f"Plugin '{plugin_name}' not found")
380
+ return False
381
+
382
+ plugin_info.status = PluginStatus.LOADING
383
+
384
+ try:
385
+ # Check dependencies
386
+ for dep in plugin_info.dependencies:
387
+ if dep not in self.plugins:
388
+ logger.error(f"Plugin '{plugin_name}' requires '{dep}' which is not loaded")
389
+ plugin_info.status = PluginStatus.ERROR
390
+ plugin_info.error_message = f"Missing dependency: {dep}"
391
+ return False
392
+
393
+ # Load the plugin
394
+ plugin = await self._load_plugin_class(plugin_info, config)
395
+
396
+ if not plugin:
397
+ raise Exception("Failed to instantiate plugin")
398
+
399
+ # Validate config
400
+ if not plugin.validate_config():
401
+ raise Exception("Plugin configuration validation failed")
402
+
403
+ # Initialize
404
+ if not await plugin.initialize():
405
+ raise Exception("Plugin initialization failed")
406
+
407
+ # Register hooks
408
+ for hook_name in plugin_info.hooks:
409
+ if hasattr(plugin, f"on_{hook_name}"):
410
+ callback = getattr(plugin, f"on_{hook_name}")
411
+ self.hooks.register_hook(hook_name, callback)
412
+
413
+ # Store plugin
414
+ self.plugins[plugin_name] = plugin
415
+ self.plugin_info[plugin_name] = plugin_info
416
+ plugin_info.status = PluginStatus.LOADED
417
+
418
+ logger.info(f"Plugin '{plugin_name}' v{plugin_info.version} loaded successfully")
419
+ return True
420
+
421
+ except Exception as e:
422
+ logger.error(f"Failed to load plugin '{plugin_name}': {e}")
423
+ plugin_info.status = PluginStatus.ERROR
424
+ plugin_info.error_message = str(e)
425
+ return False
426
+
427
+ async def _load_plugin_class(self, info: PluginInfo, config: Optional[Dict]) -> Optional[BasePlugin]:
428
+ """Load and instantiate plugin class"""
429
+ if not info.path:
430
+ return None
431
+
432
+ parent_dir = os.path.dirname(info.path)
433
+ if parent_dir not in sys.path:
434
+ sys.path.insert(0, parent_dir)
435
+
436
+ try:
437
+ module_name = os.path.basename(info.path)
438
+ spec = importlib.util.spec_from_file_location(
439
+ module_name,
440
+ os.path.join(info.path, "__init__.py")
441
+ )
442
+
443
+ if spec and spec.loader:
444
+ module = importlib.util.module_from_spec(spec)
445
+ spec.loader.exec_module(module)
446
+
447
+ # Find plugin class
448
+ for attr_name in dir(module):
449
+ attr = getattr(module, attr_name)
450
+ if (isinstance(attr, type) and
451
+ issubclass(attr, BasePlugin) and
452
+ attr != BasePlugin and
453
+ attr.NAME == info.name):
454
+
455
+ return attr(config)
456
+
457
+ finally:
458
+ if parent_dir in sys.path:
459
+ sys.path.remove(parent_dir)
460
+
461
+ return None
462
+
463
+ async def unload_plugin(self, plugin_name: str) -> bool:
464
+ """
465
+ Unload a plugin.
466
+
467
+ Args:
468
+ plugin_name: Name of the plugin to unload
469
+
470
+ Returns:
471
+ True if plugin unloaded successfully
472
+ """
473
+ if plugin_name not in self.plugins:
474
+ logger.warning(f"Plugin '{plugin_name}' is not loaded")
475
+ return False
476
+
477
+ plugin = self.plugins[plugin_name]
478
+ info = self.plugin_info[plugin_name]
479
+
480
+ try:
481
+ # Shutdown plugin
482
+ await plugin.shutdown()
483
+
484
+ # Unregister hooks
485
+ for hook_name in info.hooks:
486
+ if hasattr(plugin, f"on_{hook_name}"):
487
+ callback = getattr(plugin, f"on_{hook_name}")
488
+ self.hooks.unregister_hook(hook_name, callback)
489
+
490
+ # Remove from registry
491
+ del self.plugins[plugin_name]
492
+ info.status = PluginStatus.UNLOADED
493
+
494
+ logger.info(f"Plugin '{plugin_name}' unloaded")
495
+ return True
496
+
497
+ except Exception as e:
498
+ logger.error(f"Error unloading plugin '{plugin_name}': {e}")
499
+ return False
500
+
501
+ async def reload_plugin(self, plugin_name: str) -> bool:
502
+ """Reload a plugin (unload and load again)"""
503
+ config = None
504
+ if plugin_name in self.plugins:
505
+ config = self.plugins[plugin_name].config
506
+ await self.unload_plugin(plugin_name)
507
+
508
+ return await self.load_plugin(plugin_name, config)
509
+
510
+ def get_plugin(self, name: str) -> Optional[BasePlugin]:
511
+ """Get loaded plugin by name"""
512
+ return self.plugins.get(name)
513
+
514
+ def get_all_plugins(self) -> Dict[str, PluginInfo]:
515
+ """Get information about all plugins"""
516
+ # Include discovered but not loaded plugins
517
+ discovered = {p.name: p for p in self.discover_plugins()}
518
+ discovered.update(self.plugin_info)
519
+ return discovered
520
+
521
+ def get_plugins_by_type(self, plugin_type: PluginType) -> List[BasePlugin]:
522
+ """Get all plugins of a specific type"""
523
+ return [
524
+ p for p in self.plugins.values()
525
+ if p.PLUGIN_TYPE == plugin_type
526
+ ]
527
+
528
+ async def execute_plugin(self, name: str, **kwargs) -> Any:
529
+ """
530
+ Execute a plugin by name.
531
+
532
+ Args:
533
+ name: Plugin name
534
+ **kwargs: Arguments to pass to plugin
535
+
536
+ Returns:
537
+ Plugin execution result
538
+ """
539
+ plugin = self.get_plugin(name)
540
+ if not plugin:
541
+ raise ValueError(f"Plugin '{name}' not found or not loaded")
542
+
543
+ return await plugin.execute(**kwargs)
544
+
545
+ async def load_all_plugins(self):
546
+ """Load all discovered plugins"""
547
+ discovered = self.discover_plugins()
548
+
549
+ for info in discovered:
550
+ if info.name not in self.plugins:
551
+ await self.load_plugin(info.name)
552
+
553
+
554
+ # Global plugin manager instance
555
+ plugin_manager = PluginManager()
556
+
557
+
558
+ # Convenience functions
559
+ def register_hook(hook_name: str, callback: Callable, priority: int = 10):
560
+ """Register a hook callback"""
561
+ plugin_manager.hooks.register_hook(hook_name, callback, priority)
562
+
563
+
564
+ def apply_filter(filter_name: str, data: Any, **kwargs):
565
+ """Apply filters to data"""
566
+ return plugin_manager.hooks.apply_filter(filter_name, data, **kwargs)
567
+
568
+
569
+ async def execute_hook(hook_name: str, *args, **kwargs):
570
+ """Execute a hook"""
571
+ return await plugin_manager.hooks.execute_hook(hook_name, *args, **kwargs)