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.
- agents/__init__.py +28 -0
- agents/agent_base.py +239 -0
- agents/agent_orchestrator.py +346 -0
- agents/analysis_agent.py +225 -0
- agents/cli.py +258 -0
- agents/exploit_agent.py +224 -0
- agents/integration.py +211 -0
- agents/post_scan_agent.py +937 -0
- agents/react_agent.py +384 -0
- agents/react_agent_enhanced.py +616 -0
- agents/react_agent_vm.py +298 -0
- agents/research_agent.py +176 -0
- api/__init__.py +11 -0
- api/auth.py +123 -0
- api/main.py +1027 -0
- api/schemas.py +357 -0
- api/websocket.py +97 -0
- autonomous/__init__.py +122 -0
- autonomous/agent.py +253 -0
- autonomous/agent_loop.py +1370 -0
- autonomous/exploit_validator.py +1537 -0
- autonomous/memory.py +448 -0
- autonomous/react.py +339 -0
- autonomous/tool_executor.py +488 -0
- backends/__init__.py +16 -0
- backends/chatgpt_direct.py +133 -0
- backends/claude_direct.py +130 -0
- backends/duckduckgo.py +138 -0
- backends/openrouter.py +120 -0
- benchmarks/__init__.py +149 -0
- benchmarks/benchmark_engine.py +904 -0
- benchmarks/ci_benchmark.py +785 -0
- benchmarks/comparison.py +729 -0
- benchmarks/metrics.py +553 -0
- benchmarks/run_benchmarks.py +809 -0
- ci_cd/__init__.py +2 -0
- core/__init__.py +17 -0
- core/async_pool.py +282 -0
- core/asyncio_fix.py +222 -0
- core/cache.py +472 -0
- core/container.py +277 -0
- core/database.py +114 -0
- core/input_validator.py +353 -0
- core/models.py +288 -0
- core/orchestrator.py +611 -0
- core/plugin_manager.py +571 -0
- core/rate_limiter.py +405 -0
- core/secure_config.py +328 -0
- core/shield_integration.py +296 -0
- modules/__init__.py +46 -0
- modules/cve_database.py +362 -0
- modules/exploit_assist.py +330 -0
- modules/nuclei_integration.py +480 -0
- modules/osint.py +604 -0
- modules/protonvpn.py +554 -0
- modules/recon.py +165 -0
- modules/sql_injection_db.py +826 -0
- modules/tool_orchestrator.py +498 -0
- modules/vuln_scanner.py +292 -0
- modules/wordlist_generator.py +566 -0
- risk_engine/__init__.py +99 -0
- risk_engine/business_impact.py +267 -0
- risk_engine/business_impact_calculator.py +563 -0
- risk_engine/cvss.py +156 -0
- risk_engine/epss.py +190 -0
- risk_engine/example_usage.py +294 -0
- risk_engine/false_positive_engine.py +1073 -0
- risk_engine/scorer.py +304 -0
- web_ui/backend/main.py +471 -0
- zen_ai_pentest-2.0.0.dist-info/METADATA +795 -0
- zen_ai_pentest-2.0.0.dist-info/RECORD +75 -0
- zen_ai_pentest-2.0.0.dist-info/WHEEL +5 -0
- zen_ai_pentest-2.0.0.dist-info/entry_points.txt +2 -0
- zen_ai_pentest-2.0.0.dist-info/licenses/LICENSE +21 -0
- zen_ai_pentest-2.0.0.dist-info/top_level.txt +10 -0
core/container.py
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Dependency Injection Container
|
|
3
|
+
Provides loose coupling and testability
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import inspect
|
|
7
|
+
import logging
|
|
8
|
+
from functools import wraps
|
|
9
|
+
from typing import Any, Callable, Optional, Type, TypeVar
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
T = TypeVar("T")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Provider:
|
|
17
|
+
"""Base provider class"""
|
|
18
|
+
|
|
19
|
+
def __init__(self, factory: Callable, *args, **kwargs):
|
|
20
|
+
self.factory = factory
|
|
21
|
+
self.args = args
|
|
22
|
+
self.kwargs = kwargs
|
|
23
|
+
self._instance: Optional[Any] = None
|
|
24
|
+
|
|
25
|
+
def get(self, container: "Container") -> Any:
|
|
26
|
+
"""Get instance from provider"""
|
|
27
|
+
raise NotImplementedError()
|
|
28
|
+
|
|
29
|
+
def _resolve_dependencies(self, container: "Container") -> tuple:
|
|
30
|
+
"""Resolve positional and keyword dependencies"""
|
|
31
|
+
resolved_args = []
|
|
32
|
+
for arg in self.args:
|
|
33
|
+
if isinstance(arg, Provider):
|
|
34
|
+
resolved_args.append(arg.get(container))
|
|
35
|
+
elif isinstance(arg, str) and arg.startswith("@"):
|
|
36
|
+
# Reference to another provider
|
|
37
|
+
ref_name = arg[1:]
|
|
38
|
+
resolved_args.append(container.get(ref_name))
|
|
39
|
+
else:
|
|
40
|
+
resolved_args.append(arg)
|
|
41
|
+
|
|
42
|
+
resolved_kwargs = {}
|
|
43
|
+
for key, value in self.kwargs.items():
|
|
44
|
+
if isinstance(value, Provider):
|
|
45
|
+
resolved_kwargs[key] = value.get(container)
|
|
46
|
+
elif isinstance(value, str) and value.startswith("@"):
|
|
47
|
+
ref_name = value[1:]
|
|
48
|
+
resolved_kwargs[key] = container.get(ref_name)
|
|
49
|
+
else:
|
|
50
|
+
resolved_kwargs[key] = value
|
|
51
|
+
|
|
52
|
+
return resolved_args, resolved_kwargs
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class Singleton(Provider):
|
|
56
|
+
"""Singleton provider - creates instance once"""
|
|
57
|
+
|
|
58
|
+
def get(self, container: "Container") -> Any:
|
|
59
|
+
if self._instance is None:
|
|
60
|
+
args, kwargs = self._resolve_dependencies(container)
|
|
61
|
+
self._instance = self.factory(*args, **kwargs)
|
|
62
|
+
return self._instance
|
|
63
|
+
|
|
64
|
+
def reset(self):
|
|
65
|
+
"""Reset singleton instance (useful for testing)"""
|
|
66
|
+
self._instance = None
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class Factory(Provider):
|
|
70
|
+
"""Factory provider - creates new instance each time"""
|
|
71
|
+
|
|
72
|
+
def get(self, container: "Container") -> Any:
|
|
73
|
+
args, kwargs = self._resolve_dependencies(container)
|
|
74
|
+
return self.factory(*args, **kwargs)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class Value(Provider):
|
|
78
|
+
"""Value provider - returns constant value"""
|
|
79
|
+
|
|
80
|
+
def __init__(self, value: Any):
|
|
81
|
+
self._value = value
|
|
82
|
+
|
|
83
|
+
def get(self, container: "Container") -> Any:
|
|
84
|
+
return self._value
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class Container:
|
|
88
|
+
"""
|
|
89
|
+
Dependency Injection Container
|
|
90
|
+
|
|
91
|
+
Usage:
|
|
92
|
+
container = Container()
|
|
93
|
+
container.register('config', Value({'debug': True}))
|
|
94
|
+
container.register('db', Singleton(Database, config='@config'))
|
|
95
|
+
|
|
96
|
+
db = container.get('db')
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
def __init__(self):
|
|
100
|
+
self._providers: dict[str, Provider] = {}
|
|
101
|
+
self._cache: dict[str, Any] = {}
|
|
102
|
+
|
|
103
|
+
def register(self, name: str, provider: Provider) -> "Container":
|
|
104
|
+
"""Register a provider"""
|
|
105
|
+
self._providers[name] = provider
|
|
106
|
+
return self
|
|
107
|
+
|
|
108
|
+
def register_singleton(
|
|
109
|
+
self, name: str, factory: Callable, *args, **kwargs
|
|
110
|
+
) -> "Container":
|
|
111
|
+
"""Register a singleton provider"""
|
|
112
|
+
return self.register(name, Singleton(factory, *args, **kwargs))
|
|
113
|
+
|
|
114
|
+
def register_factory(
|
|
115
|
+
self, name: str, factory: Callable, *args, **kwargs
|
|
116
|
+
) -> "Container":
|
|
117
|
+
"""Register a factory provider"""
|
|
118
|
+
return self.register(name, Factory(factory, *args, **kwargs))
|
|
119
|
+
|
|
120
|
+
def register_value(self, name: str, value: Any) -> "Container":
|
|
121
|
+
"""Register a constant value"""
|
|
122
|
+
return self.register(name, Value(value))
|
|
123
|
+
|
|
124
|
+
def get(self, name: str) -> Any:
|
|
125
|
+
"""Get instance from container"""
|
|
126
|
+
if name not in self._providers:
|
|
127
|
+
raise KeyError(f"No provider registered for '{name}'")
|
|
128
|
+
|
|
129
|
+
provider = self._providers[name]
|
|
130
|
+
return provider.get(self)
|
|
131
|
+
|
|
132
|
+
def has(self, name: str) -> bool:
|
|
133
|
+
"""Check if provider exists"""
|
|
134
|
+
return name in self._providers
|
|
135
|
+
|
|
136
|
+
def remove(self, name: str) -> "Container":
|
|
137
|
+
"""Remove a provider"""
|
|
138
|
+
if name in self._providers:
|
|
139
|
+
del self._providers[name]
|
|
140
|
+
if name in self._cache:
|
|
141
|
+
del self._cache[name]
|
|
142
|
+
return self
|
|
143
|
+
|
|
144
|
+
def reset(self) -> "Container":
|
|
145
|
+
"""Reset all singletons"""
|
|
146
|
+
for provider in self._providers.values():
|
|
147
|
+
if isinstance(provider, Singleton):
|
|
148
|
+
provider.reset()
|
|
149
|
+
self._cache.clear()
|
|
150
|
+
return self
|
|
151
|
+
|
|
152
|
+
def inject(self, func: Callable) -> Callable:
|
|
153
|
+
"""
|
|
154
|
+
Decorator to inject dependencies based on type hints
|
|
155
|
+
|
|
156
|
+
@container.inject
|
|
157
|
+
def my_function(db: Database = inject('db')):
|
|
158
|
+
pass
|
|
159
|
+
"""
|
|
160
|
+
sig = inspect.signature(func)
|
|
161
|
+
|
|
162
|
+
@wraps(func)
|
|
163
|
+
def wrapper(*args, **kwargs):
|
|
164
|
+
bound = sig.bind_partial(*args, **kwargs)
|
|
165
|
+
bound.apply_defaults()
|
|
166
|
+
|
|
167
|
+
for param_name, param in sig.parameters.items():
|
|
168
|
+
if (
|
|
169
|
+
param_name not in bound.arguments
|
|
170
|
+
or bound.arguments[param_name] is None
|
|
171
|
+
):
|
|
172
|
+
# Try to resolve from container
|
|
173
|
+
if self.has(param_name):
|
|
174
|
+
bound.arguments[param_name] = self.get(param_name)
|
|
175
|
+
|
|
176
|
+
return func(*bound.args, **bound.kwargs)
|
|
177
|
+
|
|
178
|
+
return wrapper
|
|
179
|
+
|
|
180
|
+
def create_scope(self) -> "Scope":
|
|
181
|
+
"""Create a new scope for request-level instances"""
|
|
182
|
+
return Scope(self)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
class Scope:
|
|
186
|
+
"""
|
|
187
|
+
Request-scoped container
|
|
188
|
+
Creates instances per request/scope
|
|
189
|
+
"""
|
|
190
|
+
|
|
191
|
+
def __init__(self, parent: Container):
|
|
192
|
+
self._parent = parent
|
|
193
|
+
self._scoped: dict[str, Any] = {}
|
|
194
|
+
|
|
195
|
+
def get(self, name: str) -> Any:
|
|
196
|
+
"""Get instance, preferring scoped version"""
|
|
197
|
+
if name in self._scoped:
|
|
198
|
+
return self._scoped[name]
|
|
199
|
+
|
|
200
|
+
instance = self._parent.get(name)
|
|
201
|
+
|
|
202
|
+
# If it's a scoped service, cache it
|
|
203
|
+
if self._is_scoped(name):
|
|
204
|
+
self._scoped[name] = instance
|
|
205
|
+
|
|
206
|
+
return instance
|
|
207
|
+
|
|
208
|
+
def set(self, name: str, instance: Any) -> "Scope":
|
|
209
|
+
"""Set scoped instance"""
|
|
210
|
+
self._scoped[name] = instance
|
|
211
|
+
return self
|
|
212
|
+
|
|
213
|
+
def _is_scoped(self, name: str) -> bool:
|
|
214
|
+
"""Check if service is scoped"""
|
|
215
|
+
# Could be configured per service
|
|
216
|
+
return name.endswith("_scoped")
|
|
217
|
+
|
|
218
|
+
def dispose(self):
|
|
219
|
+
"""Clean up scoped instances"""
|
|
220
|
+
# Call dispose on instances if they have the method
|
|
221
|
+
for instance in self._scoped.values():
|
|
222
|
+
if hasattr(instance, "dispose") and callable(getattr(instance, "dispose")):
|
|
223
|
+
try:
|
|
224
|
+
instance.dispose()
|
|
225
|
+
except Exception as e:
|
|
226
|
+
logger.error(f"Error disposing {instance}: {e}")
|
|
227
|
+
|
|
228
|
+
self._scoped.clear()
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
# Global container instance
|
|
232
|
+
_global_container: Optional[Container] = None
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def get_container() -> Container:
|
|
236
|
+
"""Get global container instance"""
|
|
237
|
+
global _global_container
|
|
238
|
+
if _global_container is None:
|
|
239
|
+
_global_container = Container()
|
|
240
|
+
return _global_container
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def set_container(container: Container):
|
|
244
|
+
"""Set global container instance"""
|
|
245
|
+
global _global_container
|
|
246
|
+
_global_container = container
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def inject(name: str) -> Any:
|
|
250
|
+
"""
|
|
251
|
+
Marker for dependency injection.
|
|
252
|
+
Use with type hints to indicate injection point.
|
|
253
|
+
"""
|
|
254
|
+
|
|
255
|
+
class InjectMarker:
|
|
256
|
+
def __init__(self, dep_name: str):
|
|
257
|
+
self.dep_name = dep_name
|
|
258
|
+
|
|
259
|
+
def resolve(self) -> Any:
|
|
260
|
+
return get_container().get(self.dep_name)
|
|
261
|
+
|
|
262
|
+
return InjectMarker(name)
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
# Context manager for scoped operations
|
|
266
|
+
from contextlib import asynccontextmanager
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
@asynccontextmanager
|
|
270
|
+
async def scope():
|
|
271
|
+
"""Create a scoped context"""
|
|
272
|
+
container = get_container()
|
|
273
|
+
scope = container.create_scope()
|
|
274
|
+
try:
|
|
275
|
+
yield scope
|
|
276
|
+
finally:
|
|
277
|
+
scope.dispose()
|
core/database.py
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Database Module - Wrapper for CVE and Ransomware Database Access
|
|
3
|
+
"""
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
from typing import Dict, List, Any, Optional
|
|
7
|
+
|
|
8
|
+
# Add parent directory to path for imports
|
|
9
|
+
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
10
|
+
|
|
11
|
+
from modules.cve_database import CVEDatabase, CVEEntry, RansomwareEntry
|
|
12
|
+
|
|
13
|
+
# Global database instance
|
|
14
|
+
_db_instance: Optional[CVEDatabase] = None
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _get_db() -> CVEDatabase:
|
|
18
|
+
"""Get or create global database instance"""
|
|
19
|
+
global _db_instance
|
|
20
|
+
if _db_instance is None:
|
|
21
|
+
_db_instance = CVEDatabase()
|
|
22
|
+
return _db_instance
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def get_cve_db() -> List[Dict[str, Any]]:
|
|
26
|
+
"""Get CVE database as list of dictionaries"""
|
|
27
|
+
db = _get_db()
|
|
28
|
+
cves = []
|
|
29
|
+
for cve_id, cve_data in db.cve_data.items():
|
|
30
|
+
entry = {"cve_id": cve_id}
|
|
31
|
+
if isinstance(cve_data, dict):
|
|
32
|
+
entry.update(cve_data)
|
|
33
|
+
cves.append(entry)
|
|
34
|
+
return cves
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def get_ransomware_db() -> List[Dict[str, Any]]:
|
|
38
|
+
"""Get Ransomware database as list of dictionaries"""
|
|
39
|
+
db = _get_db()
|
|
40
|
+
ransomware_list = []
|
|
41
|
+
for name, data in db.ransomware_data.items():
|
|
42
|
+
entry = {"name": name}
|
|
43
|
+
if isinstance(data, dict):
|
|
44
|
+
entry.update(data)
|
|
45
|
+
ransomware_list.append(entry)
|
|
46
|
+
return ransomware_list
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def search_cve(query: str) -> List[Dict[str, Any]]:
|
|
50
|
+
"""Search CVE database by keyword"""
|
|
51
|
+
db = get_cve_db()
|
|
52
|
+
query = query.lower()
|
|
53
|
+
results = []
|
|
54
|
+
for cve in db:
|
|
55
|
+
# Search in ID
|
|
56
|
+
if query in str(cve.get("cve_id", "")).lower():
|
|
57
|
+
results.append(cve)
|
|
58
|
+
continue
|
|
59
|
+
# Search in description
|
|
60
|
+
if query in str(cve.get("description", "")).lower():
|
|
61
|
+
results.append(cve)
|
|
62
|
+
continue
|
|
63
|
+
# Search in name
|
|
64
|
+
if query in str(cve.get("name", "")).lower():
|
|
65
|
+
results.append(cve)
|
|
66
|
+
return results
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def get_cve_by_year(year: int) -> List[Dict[str, Any]]:
|
|
70
|
+
"""Get CVEs from a specific year"""
|
|
71
|
+
db = get_cve_db()
|
|
72
|
+
year_str = str(year)
|
|
73
|
+
results = []
|
|
74
|
+
for cve in db:
|
|
75
|
+
cve_id = str(cve.get("cve_id", ""))
|
|
76
|
+
# CVE IDs are in format CVE-YYYY-NNNNN
|
|
77
|
+
if f"CVE-{year_str}-" in cve_id:
|
|
78
|
+
results.append(cve)
|
|
79
|
+
return results
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def get_cve_by_id(cve_id: str) -> Optional[Dict[str, Any]]:
|
|
83
|
+
"""Get a specific CVE by ID"""
|
|
84
|
+
db = _get_db()
|
|
85
|
+
cve_data = db.cve_data.get(cve_id.upper())
|
|
86
|
+
if cve_data:
|
|
87
|
+
if isinstance(cve_data, dict):
|
|
88
|
+
return {"cve_id": cve_id, **cve_data}
|
|
89
|
+
return {"cve_id": cve_id, "data": cve_data}
|
|
90
|
+
return None
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def get_ransomware_by_name(name: str) -> Optional[Dict[str, Any]]:
|
|
94
|
+
"""Get ransomware info by name"""
|
|
95
|
+
db = _get_db()
|
|
96
|
+
ransomware_data = db.ransomware_data.get(name)
|
|
97
|
+
if ransomware_data:
|
|
98
|
+
if isinstance(ransomware_data, dict):
|
|
99
|
+
return {"name": name, **ransomware_data}
|
|
100
|
+
return {"name": name, "data": ransomware_data}
|
|
101
|
+
return None
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
__all__ = [
|
|
105
|
+
"get_cve_db",
|
|
106
|
+
"get_ransomware_db",
|
|
107
|
+
"search_cve",
|
|
108
|
+
"get_cve_by_year",
|
|
109
|
+
"get_cve_by_id",
|
|
110
|
+
"get_ransomware_by_name",
|
|
111
|
+
"CVEDatabase",
|
|
112
|
+
"CVEEntry",
|
|
113
|
+
"RansomwareEntry",
|
|
114
|
+
]
|