aiptx 2.0.7__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 (187) hide show
  1. aipt_v2/__init__.py +110 -0
  2. aipt_v2/__main__.py +24 -0
  3. aipt_v2/agents/AIPTxAgent/__init__.py +10 -0
  4. aipt_v2/agents/AIPTxAgent/aiptx_agent.py +211 -0
  5. aipt_v2/agents/__init__.py +46 -0
  6. aipt_v2/agents/base.py +520 -0
  7. aipt_v2/agents/exploit_agent.py +688 -0
  8. aipt_v2/agents/ptt.py +406 -0
  9. aipt_v2/agents/state.py +168 -0
  10. aipt_v2/app.py +957 -0
  11. aipt_v2/browser/__init__.py +31 -0
  12. aipt_v2/browser/automation.py +458 -0
  13. aipt_v2/browser/crawler.py +453 -0
  14. aipt_v2/cli.py +2933 -0
  15. aipt_v2/compliance/__init__.py +71 -0
  16. aipt_v2/compliance/compliance_report.py +449 -0
  17. aipt_v2/compliance/framework_mapper.py +424 -0
  18. aipt_v2/compliance/nist_mapping.py +345 -0
  19. aipt_v2/compliance/owasp_mapping.py +330 -0
  20. aipt_v2/compliance/pci_mapping.py +297 -0
  21. aipt_v2/config.py +341 -0
  22. aipt_v2/core/__init__.py +43 -0
  23. aipt_v2/core/agent.py +630 -0
  24. aipt_v2/core/llm.py +395 -0
  25. aipt_v2/core/memory.py +305 -0
  26. aipt_v2/core/ptt.py +329 -0
  27. aipt_v2/database/__init__.py +14 -0
  28. aipt_v2/database/models.py +232 -0
  29. aipt_v2/database/repository.py +384 -0
  30. aipt_v2/docker/__init__.py +23 -0
  31. aipt_v2/docker/builder.py +260 -0
  32. aipt_v2/docker/manager.py +222 -0
  33. aipt_v2/docker/sandbox.py +371 -0
  34. aipt_v2/evasion/__init__.py +58 -0
  35. aipt_v2/evasion/request_obfuscator.py +272 -0
  36. aipt_v2/evasion/tls_fingerprint.py +285 -0
  37. aipt_v2/evasion/ua_rotator.py +301 -0
  38. aipt_v2/evasion/waf_bypass.py +439 -0
  39. aipt_v2/execution/__init__.py +23 -0
  40. aipt_v2/execution/executor.py +302 -0
  41. aipt_v2/execution/parser.py +544 -0
  42. aipt_v2/execution/terminal.py +337 -0
  43. aipt_v2/health.py +437 -0
  44. aipt_v2/intelligence/__init__.py +194 -0
  45. aipt_v2/intelligence/adaptation.py +474 -0
  46. aipt_v2/intelligence/auth.py +520 -0
  47. aipt_v2/intelligence/chaining.py +775 -0
  48. aipt_v2/intelligence/correlation.py +536 -0
  49. aipt_v2/intelligence/cve_aipt.py +334 -0
  50. aipt_v2/intelligence/cve_info.py +1111 -0
  51. aipt_v2/intelligence/knowledge_graph.py +590 -0
  52. aipt_v2/intelligence/learning.py +626 -0
  53. aipt_v2/intelligence/llm_analyzer.py +502 -0
  54. aipt_v2/intelligence/llm_tool_selector.py +518 -0
  55. aipt_v2/intelligence/payload_generator.py +562 -0
  56. aipt_v2/intelligence/rag.py +239 -0
  57. aipt_v2/intelligence/scope.py +442 -0
  58. aipt_v2/intelligence/searchers/__init__.py +5 -0
  59. aipt_v2/intelligence/searchers/exploitdb_searcher.py +523 -0
  60. aipt_v2/intelligence/searchers/github_searcher.py +467 -0
  61. aipt_v2/intelligence/searchers/google_searcher.py +281 -0
  62. aipt_v2/intelligence/tools.json +443 -0
  63. aipt_v2/intelligence/triage.py +670 -0
  64. aipt_v2/interactive_shell.py +559 -0
  65. aipt_v2/interface/__init__.py +5 -0
  66. aipt_v2/interface/cli.py +230 -0
  67. aipt_v2/interface/main.py +501 -0
  68. aipt_v2/interface/tui.py +1276 -0
  69. aipt_v2/interface/utils.py +583 -0
  70. aipt_v2/llm/__init__.py +39 -0
  71. aipt_v2/llm/config.py +26 -0
  72. aipt_v2/llm/llm.py +514 -0
  73. aipt_v2/llm/memory.py +214 -0
  74. aipt_v2/llm/request_queue.py +89 -0
  75. aipt_v2/llm/utils.py +89 -0
  76. aipt_v2/local_tool_installer.py +1467 -0
  77. aipt_v2/models/__init__.py +15 -0
  78. aipt_v2/models/findings.py +295 -0
  79. aipt_v2/models/phase_result.py +224 -0
  80. aipt_v2/models/scan_config.py +207 -0
  81. aipt_v2/monitoring/grafana/dashboards/aipt-dashboard.json +355 -0
  82. aipt_v2/monitoring/grafana/dashboards/default.yml +17 -0
  83. aipt_v2/monitoring/grafana/datasources/prometheus.yml +17 -0
  84. aipt_v2/monitoring/prometheus.yml +60 -0
  85. aipt_v2/orchestration/__init__.py +52 -0
  86. aipt_v2/orchestration/pipeline.py +398 -0
  87. aipt_v2/orchestration/progress.py +300 -0
  88. aipt_v2/orchestration/scheduler.py +296 -0
  89. aipt_v2/orchestrator.py +2427 -0
  90. aipt_v2/payloads/__init__.py +27 -0
  91. aipt_v2/payloads/cmdi.py +150 -0
  92. aipt_v2/payloads/sqli.py +263 -0
  93. aipt_v2/payloads/ssrf.py +204 -0
  94. aipt_v2/payloads/templates.py +222 -0
  95. aipt_v2/payloads/traversal.py +166 -0
  96. aipt_v2/payloads/xss.py +204 -0
  97. aipt_v2/prompts/__init__.py +60 -0
  98. aipt_v2/proxy/__init__.py +29 -0
  99. aipt_v2/proxy/history.py +352 -0
  100. aipt_v2/proxy/interceptor.py +452 -0
  101. aipt_v2/recon/__init__.py +44 -0
  102. aipt_v2/recon/dns.py +241 -0
  103. aipt_v2/recon/osint.py +367 -0
  104. aipt_v2/recon/subdomain.py +372 -0
  105. aipt_v2/recon/tech_detect.py +311 -0
  106. aipt_v2/reports/__init__.py +17 -0
  107. aipt_v2/reports/generator.py +313 -0
  108. aipt_v2/reports/html_report.py +378 -0
  109. aipt_v2/runtime/__init__.py +53 -0
  110. aipt_v2/runtime/base.py +30 -0
  111. aipt_v2/runtime/docker.py +401 -0
  112. aipt_v2/runtime/local.py +346 -0
  113. aipt_v2/runtime/tool_server.py +205 -0
  114. aipt_v2/runtime/vps.py +830 -0
  115. aipt_v2/scanners/__init__.py +28 -0
  116. aipt_v2/scanners/base.py +273 -0
  117. aipt_v2/scanners/nikto.py +244 -0
  118. aipt_v2/scanners/nmap.py +402 -0
  119. aipt_v2/scanners/nuclei.py +273 -0
  120. aipt_v2/scanners/web.py +454 -0
  121. aipt_v2/scripts/security_audit.py +366 -0
  122. aipt_v2/setup_wizard.py +941 -0
  123. aipt_v2/skills/__init__.py +80 -0
  124. aipt_v2/skills/agents/__init__.py +14 -0
  125. aipt_v2/skills/agents/api_tester.py +706 -0
  126. aipt_v2/skills/agents/base.py +477 -0
  127. aipt_v2/skills/agents/code_review.py +459 -0
  128. aipt_v2/skills/agents/security_agent.py +336 -0
  129. aipt_v2/skills/agents/web_pentest.py +818 -0
  130. aipt_v2/skills/prompts/__init__.py +647 -0
  131. aipt_v2/system_detector.py +539 -0
  132. aipt_v2/telemetry/__init__.py +7 -0
  133. aipt_v2/telemetry/tracer.py +347 -0
  134. aipt_v2/terminal/__init__.py +28 -0
  135. aipt_v2/terminal/executor.py +400 -0
  136. aipt_v2/terminal/sandbox.py +350 -0
  137. aipt_v2/tools/__init__.py +44 -0
  138. aipt_v2/tools/active_directory/__init__.py +78 -0
  139. aipt_v2/tools/active_directory/ad_config.py +238 -0
  140. aipt_v2/tools/active_directory/bloodhound_wrapper.py +447 -0
  141. aipt_v2/tools/active_directory/kerberos_attacks.py +430 -0
  142. aipt_v2/tools/active_directory/ldap_enum.py +533 -0
  143. aipt_v2/tools/active_directory/smb_attacks.py +505 -0
  144. aipt_v2/tools/agents_graph/__init__.py +19 -0
  145. aipt_v2/tools/agents_graph/agents_graph_actions.py +69 -0
  146. aipt_v2/tools/api_security/__init__.py +76 -0
  147. aipt_v2/tools/api_security/api_discovery.py +608 -0
  148. aipt_v2/tools/api_security/graphql_scanner.py +622 -0
  149. aipt_v2/tools/api_security/jwt_analyzer.py +577 -0
  150. aipt_v2/tools/api_security/openapi_fuzzer.py +761 -0
  151. aipt_v2/tools/browser/__init__.py +5 -0
  152. aipt_v2/tools/browser/browser_actions.py +238 -0
  153. aipt_v2/tools/browser/browser_instance.py +535 -0
  154. aipt_v2/tools/browser/tab_manager.py +344 -0
  155. aipt_v2/tools/cloud/__init__.py +70 -0
  156. aipt_v2/tools/cloud/cloud_config.py +273 -0
  157. aipt_v2/tools/cloud/cloud_scanner.py +639 -0
  158. aipt_v2/tools/cloud/prowler_tool.py +571 -0
  159. aipt_v2/tools/cloud/scoutsuite_tool.py +359 -0
  160. aipt_v2/tools/executor.py +307 -0
  161. aipt_v2/tools/parser.py +408 -0
  162. aipt_v2/tools/proxy/__init__.py +5 -0
  163. aipt_v2/tools/proxy/proxy_actions.py +103 -0
  164. aipt_v2/tools/proxy/proxy_manager.py +789 -0
  165. aipt_v2/tools/registry.py +196 -0
  166. aipt_v2/tools/scanners/__init__.py +343 -0
  167. aipt_v2/tools/scanners/acunetix_tool.py +712 -0
  168. aipt_v2/tools/scanners/burp_tool.py +631 -0
  169. aipt_v2/tools/scanners/config.py +156 -0
  170. aipt_v2/tools/scanners/nessus_tool.py +588 -0
  171. aipt_v2/tools/scanners/zap_tool.py +612 -0
  172. aipt_v2/tools/terminal/__init__.py +5 -0
  173. aipt_v2/tools/terminal/terminal_actions.py +37 -0
  174. aipt_v2/tools/terminal/terminal_manager.py +153 -0
  175. aipt_v2/tools/terminal/terminal_session.py +449 -0
  176. aipt_v2/tools/tool_processing.py +108 -0
  177. aipt_v2/utils/__init__.py +17 -0
  178. aipt_v2/utils/logging.py +202 -0
  179. aipt_v2/utils/model_manager.py +187 -0
  180. aipt_v2/utils/searchers/__init__.py +269 -0
  181. aipt_v2/verify_install.py +793 -0
  182. aiptx-2.0.7.dist-info/METADATA +345 -0
  183. aiptx-2.0.7.dist-info/RECORD +187 -0
  184. aiptx-2.0.7.dist-info/WHEEL +5 -0
  185. aiptx-2.0.7.dist-info/entry_points.txt +7 -0
  186. aiptx-2.0.7.dist-info/licenses/LICENSE +21 -0
  187. aiptx-2.0.7.dist-info/top_level.txt +1 -0
@@ -0,0 +1,612 @@
1
+ """
2
+ OWASP ZAP (Zed Attack Proxy) Integration for AIPTX
3
+
4
+ Provides web application security testing through ZAP's REST API.
5
+ Supports spidering, active scanning, and passive scanning.
6
+
7
+ Environment Variables:
8
+ ZAP_URL: ZAP API URL (default: http://localhost:8080)
9
+ ZAP_API_KEY: API key for authentication
10
+
11
+ Usage:
12
+ from aipt_v2.tools.scanners.zap_tool import get_zap, zap_scan
13
+
14
+ zap = get_zap()
15
+ if zap.connect():
16
+ scan_id = zap.active_scan("https://example.com")
17
+ result = zap.wait_for_scan(scan_id)
18
+ alerts = zap.get_alerts()
19
+ """
20
+
21
+ import json
22
+ import logging
23
+ import os
24
+ import time
25
+ from dataclasses import dataclass, field
26
+ from datetime import datetime, timezone
27
+ from enum import Enum
28
+ from typing import Any, Callable, Dict, List, Optional
29
+
30
+ import requests
31
+
32
+ logger = logging.getLogger(__name__)
33
+
34
+
35
+ # ==================== Enums ====================
36
+
37
+ class ScanStatus(Enum):
38
+ """ZAP scan status."""
39
+ RUNNING = "running"
40
+ COMPLETED = "completed"
41
+ STOPPED = "stopped"
42
+ FAILED = "failed"
43
+
44
+
45
+ class RiskLevel(Enum):
46
+ """ZAP alert risk levels."""
47
+ HIGH = 3
48
+ MEDIUM = 2
49
+ LOW = 1
50
+ INFORMATIONAL = 0
51
+
52
+
53
+ class ConfidenceLevel(Enum):
54
+ """ZAP alert confidence levels."""
55
+ HIGH = 3
56
+ MEDIUM = 2
57
+ LOW = 1
58
+ FALSE_POSITIVE = 0
59
+
60
+
61
+ # ==================== Data Classes ====================
62
+
63
+ @dataclass
64
+ class ZAPConfig:
65
+ """Configuration for ZAP connection."""
66
+ base_url: str = field(default_factory=lambda: os.getenv("ZAP_URL", "http://localhost:8080"))
67
+ api_key: str = field(default_factory=lambda: os.getenv("ZAP_API_KEY", ""))
68
+ timeout: int = 30
69
+
70
+
71
+ @dataclass
72
+ class ScanResult:
73
+ """Result of a ZAP scan."""
74
+ scan_id: str
75
+ status: str
76
+ progress: int = 0
77
+ alerts_count: int = 0
78
+ urls_found: int = 0
79
+ start_time: str = ""
80
+ end_time: str = ""
81
+ error: str = ""
82
+
83
+
84
+ @dataclass
85
+ class Alert:
86
+ """ZAP security alert."""
87
+ alert_id: str
88
+ name: str
89
+ risk: int
90
+ risk_name: str
91
+ confidence: int
92
+ confidence_name: str
93
+ url: str
94
+ description: str = ""
95
+ solution: str = ""
96
+ reference: str = ""
97
+ cwe_id: int = 0
98
+ wasc_id: int = 0
99
+ evidence: str = ""
100
+ param: str = ""
101
+ attack: str = ""
102
+ other_info: str = ""
103
+
104
+
105
+ # ==================== Main Tool Class ====================
106
+
107
+ class ZAPTool:
108
+ """
109
+ OWASP ZAP integration for AIPTX.
110
+
111
+ Provides methods for:
112
+ - URL spidering
113
+ - Active vulnerability scanning
114
+ - Passive scanning
115
+ - Alert retrieval and management
116
+ """
117
+
118
+ def __init__(self, config: Optional[ZAPConfig] = None):
119
+ """Initialize ZAP tool with configuration."""
120
+ self.config = config or ZAPConfig()
121
+ self._session = requests.Session()
122
+ self._connected = False
123
+
124
+ def _request(self, component: str, action: str, params: dict = None) -> dict:
125
+ """Make request to ZAP API."""
126
+ url = f"{self.config.base_url}/JSON/{component}/view/{action}/"
127
+ params = params or {}
128
+ if self.config.api_key:
129
+ params["apikey"] = self.config.api_key
130
+
131
+ try:
132
+ response = self._session.get(url, params=params, timeout=self.config.timeout)
133
+ response.raise_for_status()
134
+ return response.json()
135
+ except requests.exceptions.RequestException as e:
136
+ logger.error(f"ZAP API error: {e}")
137
+ raise
138
+
139
+ def _action(self, component: str, action: str, params: dict = None) -> dict:
140
+ """Execute ZAP API action."""
141
+ url = f"{self.config.base_url}/JSON/{component}/action/{action}/"
142
+ params = params or {}
143
+ if self.config.api_key:
144
+ params["apikey"] = self.config.api_key
145
+
146
+ try:
147
+ response = self._session.get(url, params=params, timeout=self.config.timeout)
148
+ response.raise_for_status()
149
+ return response.json()
150
+ except requests.exceptions.RequestException as e:
151
+ logger.error(f"ZAP API action error: {e}")
152
+ raise
153
+
154
+ # ==================== Connection ====================
155
+
156
+ def connect(self) -> bool:
157
+ """Test connection to ZAP."""
158
+ try:
159
+ result = self._request("core", "version")
160
+ self._connected = "version" in result
161
+ if self._connected:
162
+ logger.info(f"Connected to ZAP at {self.config.base_url}")
163
+ return self._connected
164
+ except Exception as e:
165
+ logger.error(f"Failed to connect to ZAP: {e}")
166
+ self._connected = False
167
+ return False
168
+
169
+ def is_connected(self) -> bool:
170
+ """Check if connected to ZAP."""
171
+ return self._connected
172
+
173
+ def get_info(self) -> Dict:
174
+ """Get ZAP version and info."""
175
+ try:
176
+ version = self._request("core", "version")
177
+ return {"version": version.get("version", "unknown")}
178
+ except Exception:
179
+ return {}
180
+
181
+ # ==================== Context Management ====================
182
+
183
+ def new_session(self, name: str = None) -> bool:
184
+ """Create a new ZAP session."""
185
+ try:
186
+ params = {}
187
+ if name:
188
+ params["name"] = name
189
+ self._action("core", "newSession", params)
190
+ return True
191
+ except Exception:
192
+ return False
193
+
194
+ def set_mode(self, mode: str = "standard") -> bool:
195
+ """Set ZAP mode (safe, protect, standard, attack)."""
196
+ try:
197
+ self._action("core", "setMode", {"mode": mode})
198
+ return True
199
+ except Exception:
200
+ return False
201
+
202
+ # ==================== Spider ====================
203
+
204
+ def spider(self, url: str, max_children: int = 0, recurse: bool = True) -> str:
205
+ """
206
+ Start spidering a URL.
207
+
208
+ Args:
209
+ url: Target URL to spider
210
+ max_children: Max children to crawl (0 = unlimited)
211
+ recurse: Whether to recurse into found URLs
212
+
213
+ Returns:
214
+ Spider scan ID
215
+ """
216
+ try:
217
+ params = {
218
+ "url": url,
219
+ "maxChildren": str(max_children),
220
+ "recurse": str(recurse).lower()
221
+ }
222
+ result = self._action("spider", "scan", params)
223
+ scan_id = result.get("scan", "")
224
+ logger.info(f"Started spider scan: {scan_id} for {url}")
225
+ return str(scan_id)
226
+ except Exception as e:
227
+ logger.error(f"Failed to start spider: {e}")
228
+ return ""
229
+
230
+ def get_spider_status(self, scan_id: str) -> int:
231
+ """Get spider progress (0-100)."""
232
+ try:
233
+ result = self._request("spider", "status", {"scanId": scan_id})
234
+ return int(result.get("status", 0))
235
+ except Exception:
236
+ return 0
237
+
238
+ def wait_for_spider(self, scan_id: str, timeout: int = 300) -> bool:
239
+ """Wait for spider to complete."""
240
+ start_time = time.time()
241
+ while time.time() - start_time < timeout:
242
+ progress = self.get_spider_status(scan_id)
243
+ if progress >= 100:
244
+ return True
245
+ time.sleep(5)
246
+ return False
247
+
248
+ def get_spider_results(self, scan_id: str) -> List[str]:
249
+ """Get URLs found by spider."""
250
+ try:
251
+ result = self._request("spider", "results", {"scanId": scan_id})
252
+ return result.get("results", [])
253
+ except Exception:
254
+ return []
255
+
256
+ # ==================== Active Scan ====================
257
+
258
+ def active_scan(
259
+ self,
260
+ url: str,
261
+ recurse: bool = True,
262
+ in_scope_only: bool = False,
263
+ scan_policy: str = None
264
+ ) -> str:
265
+ """
266
+ Start active vulnerability scan.
267
+
268
+ Args:
269
+ url: Target URL to scan
270
+ recurse: Scan recursively
271
+ in_scope_only: Only scan URLs in scope
272
+ scan_policy: Scan policy name (optional)
273
+
274
+ Returns:
275
+ Active scan ID
276
+ """
277
+ try:
278
+ params = {
279
+ "url": url,
280
+ "recurse": str(recurse).lower(),
281
+ "inScopeOnly": str(in_scope_only).lower()
282
+ }
283
+ if scan_policy:
284
+ params["scanPolicyName"] = scan_policy
285
+
286
+ result = self._action("ascan", "scan", params)
287
+ scan_id = result.get("scan", "")
288
+ logger.info(f"Started active scan: {scan_id} for {url}")
289
+ return str(scan_id)
290
+ except Exception as e:
291
+ logger.error(f"Failed to start active scan: {e}")
292
+ return ""
293
+
294
+ def get_scan_status(self, scan_id: str) -> ScanResult:
295
+ """Get active scan status."""
296
+ try:
297
+ status_result = self._request("ascan", "status", {"scanId": scan_id})
298
+ progress = int(status_result.get("status", 0))
299
+
300
+ # Get alerts count
301
+ alerts = self.get_alerts()
302
+
303
+ status = "running" if progress < 100 else "completed"
304
+
305
+ return ScanResult(
306
+ scan_id=scan_id,
307
+ status=status,
308
+ progress=progress,
309
+ alerts_count=len(alerts)
310
+ )
311
+ except Exception as e:
312
+ return ScanResult(scan_id=scan_id, status="error", error=str(e))
313
+
314
+ def wait_for_scan(
315
+ self,
316
+ scan_id: str,
317
+ timeout: int = 3600,
318
+ poll_interval: int = 10,
319
+ callback: Callable[[ScanResult], None] = None
320
+ ) -> ScanResult:
321
+ """
322
+ Wait for active scan to complete.
323
+
324
+ Args:
325
+ scan_id: Scan ID to monitor
326
+ timeout: Maximum wait time in seconds
327
+ poll_interval: Polling interval in seconds
328
+ callback: Optional progress callback
329
+
330
+ Returns:
331
+ Final scan result
332
+ """
333
+ start_time = time.time()
334
+ while time.time() - start_time < timeout:
335
+ result = self.get_scan_status(scan_id)
336
+
337
+ if callback:
338
+ callback(result)
339
+
340
+ if result.progress >= 100 or result.status in ["completed", "stopped", "error"]:
341
+ result.status = "completed" if result.progress >= 100 else result.status
342
+ return result
343
+
344
+ time.sleep(poll_interval)
345
+
346
+ return ScanResult(
347
+ scan_id=scan_id,
348
+ status="timeout",
349
+ error=f"Scan timed out after {timeout}s"
350
+ )
351
+
352
+ def stop_scan(self, scan_id: str) -> bool:
353
+ """Stop an active scan."""
354
+ try:
355
+ self._action("ascan", "stop", {"scanId": scan_id})
356
+ return True
357
+ except Exception:
358
+ return False
359
+
360
+ def pause_scan(self, scan_id: str) -> bool:
361
+ """Pause an active scan."""
362
+ try:
363
+ self._action("ascan", "pause", {"scanId": scan_id})
364
+ return True
365
+ except Exception:
366
+ return False
367
+
368
+ def resume_scan(self, scan_id: str) -> bool:
369
+ """Resume a paused scan."""
370
+ try:
371
+ self._action("ascan", "resume", {"scanId": scan_id})
372
+ return True
373
+ except Exception:
374
+ return False
375
+
376
+ # ==================== Full Scan (Spider + Active) ====================
377
+
378
+ def full_scan(self, url: str, spider_timeout: int = 300) -> str:
379
+ """
380
+ Run a full scan (spider + active scan).
381
+
382
+ Args:
383
+ url: Target URL
384
+ spider_timeout: Max time for spider phase
385
+
386
+ Returns:
387
+ Active scan ID
388
+ """
389
+ # First spider the target
390
+ spider_id = self.spider(url)
391
+ if spider_id:
392
+ self.wait_for_spider(spider_id, spider_timeout)
393
+
394
+ # Then run active scan
395
+ return self.active_scan(url)
396
+
397
+ # ==================== Alert Management ====================
398
+
399
+ def get_alerts(
400
+ self,
401
+ base_url: str = None,
402
+ risk: str = None,
403
+ start: int = 0,
404
+ count: int = 1000
405
+ ) -> List[Alert]:
406
+ """
407
+ Get security alerts.
408
+
409
+ Args:
410
+ base_url: Filter by base URL
411
+ risk: Filter by risk level (high, medium, low, informational)
412
+ start: Start index
413
+ count: Number of alerts to retrieve
414
+
415
+ Returns:
416
+ List of Alert objects
417
+ """
418
+ try:
419
+ params = {"start": str(start), "count": str(count)}
420
+ if base_url:
421
+ params["baseurl"] = base_url
422
+ if risk:
423
+ params["riskId"] = str(self._risk_to_int(risk))
424
+
425
+ result = self._request("alert", "alerts", params)
426
+ alerts = []
427
+
428
+ for a in result.get("alerts", []):
429
+ alerts.append(Alert(
430
+ alert_id=str(a.get("id", "")),
431
+ name=a.get("name", "Unknown"),
432
+ risk=int(a.get("riskcode", 0)),
433
+ risk_name=a.get("risk", "Unknown"),
434
+ confidence=int(a.get("confidence", 0)),
435
+ confidence_name=a.get("confidence", "Unknown"),
436
+ url=a.get("url", ""),
437
+ description=a.get("description", ""),
438
+ solution=a.get("solution", ""),
439
+ reference=a.get("reference", ""),
440
+ cwe_id=int(a.get("cweid", 0) or 0),
441
+ wasc_id=int(a.get("wascid", 0) or 0),
442
+ evidence=a.get("evidence", ""),
443
+ param=a.get("param", ""),
444
+ attack=a.get("attack", ""),
445
+ other_info=a.get("other", "")
446
+ ))
447
+
448
+ return alerts
449
+ except Exception as e:
450
+ logger.error(f"Failed to get alerts: {e}")
451
+ return []
452
+
453
+ def _risk_to_int(self, risk: str) -> int:
454
+ """Convert risk string to int."""
455
+ mapping = {"high": 3, "medium": 2, "low": 1, "informational": 0, "info": 0}
456
+ return mapping.get(risk.lower(), 0)
457
+
458
+ def get_alerts_summary(self) -> Dict:
459
+ """Get summary of alerts by risk level."""
460
+ try:
461
+ result = self._request("alert", "alertsSummary")
462
+ return result.get("alertsSummary", {})
463
+ except Exception:
464
+ return {}
465
+
466
+ # ==================== AIPTX Integration ====================
467
+
468
+ def to_finding(self, alert: Alert) -> Dict:
469
+ """Convert ZAP alert to AIPTX finding format."""
470
+ severity_map = {3: "high", 2: "medium", 1: "low", 0: "info"}
471
+
472
+ return {
473
+ "type": "vulnerability",
474
+ "value": alert.name,
475
+ "description": alert.description or alert.name,
476
+ "severity": severity_map.get(alert.risk, "info"),
477
+ "phase": "scan",
478
+ "tool": "zap",
479
+ "target": alert.url,
480
+ "metadata": {
481
+ "alert_id": alert.alert_id,
482
+ "risk": alert.risk_name,
483
+ "confidence": alert.confidence_name,
484
+ "cwe_id": alert.cwe_id,
485
+ "wasc_id": alert.wasc_id,
486
+ "solution": alert.solution,
487
+ "evidence": alert.evidence[:500] if alert.evidence else "",
488
+ "param": alert.param,
489
+ "attack": alert.attack
490
+ },
491
+ "timestamp": datetime.now(timezone.utc).isoformat()
492
+ }
493
+
494
+ def export_findings(self, output_path: str = None, base_url: str = None) -> List[Dict]:
495
+ """
496
+ Export alerts in AIPTX format.
497
+
498
+ Args:
499
+ output_path: Optional file path to save JSON
500
+ base_url: Optional URL filter
501
+
502
+ Returns:
503
+ List of AIPTX findings
504
+ """
505
+ alerts = self.get_alerts(base_url=base_url)
506
+ findings = [self.to_finding(a) for a in alerts]
507
+
508
+ if output_path:
509
+ with open(output_path, "w") as f:
510
+ json.dump(findings, f, indent=2)
511
+
512
+ return findings
513
+
514
+
515
+ # ==================== Global Instance & Helper Functions ====================
516
+
517
+ _zap: Optional[ZAPTool] = None
518
+
519
+
520
+ def get_zap(config: Optional[ZAPConfig] = None) -> ZAPTool:
521
+ """Get or create global ZAP instance."""
522
+ global _zap
523
+ if _zap is None or config is not None:
524
+ _zap = ZAPTool(config)
525
+ return _zap
526
+
527
+
528
+ def zap_scan(url: str, full: bool = True) -> ScanResult:
529
+ """Quick scan a target."""
530
+ zap = get_zap()
531
+ if not zap.connect():
532
+ return ScanResult(scan_id="", status="error", error="Connection failed")
533
+
534
+ if full:
535
+ scan_id = zap.full_scan(url)
536
+ else:
537
+ scan_id = zap.active_scan(url)
538
+
539
+ return zap.get_scan_status(scan_id)
540
+
541
+
542
+ def zap_status(scan_id: str) -> ScanResult:
543
+ """Get scan status."""
544
+ return get_zap().get_scan_status(scan_id)
545
+
546
+
547
+ def zap_alerts(base_url: str = None, risk: str = None) -> List[Dict]:
548
+ """Get alerts in AIPTX format."""
549
+ zap = get_zap()
550
+ alerts = zap.get_alerts(base_url=base_url, risk=risk)
551
+ return [zap.to_finding(a) for a in alerts]
552
+
553
+
554
+ def zap_summary() -> Dict:
555
+ """Get ZAP scanner summary."""
556
+ zap = get_zap()
557
+ if not zap.connect():
558
+ return {"connected": False, "error": "Connection failed"}
559
+
560
+ info = zap.get_info()
561
+ alerts_summary = zap.get_alerts_summary()
562
+
563
+ return {
564
+ "connected": True,
565
+ "url": zap.config.base_url,
566
+ "version": info.get("version", "unknown"),
567
+ "alerts": alerts_summary
568
+ }
569
+
570
+
571
+ # ==================== CLI Testing ====================
572
+
573
+ if __name__ == "__main__":
574
+ import sys
575
+
576
+ print("OWASP ZAP Integration Test")
577
+ print("=" * 50)
578
+
579
+ zap = get_zap()
580
+
581
+ if zap.connect():
582
+ print(f"✓ Connected to ZAP at {zap.config.base_url}")
583
+
584
+ info = zap.get_info()
585
+ print(f" Version: {info.get('version', 'unknown')}")
586
+
587
+ if len(sys.argv) > 1:
588
+ target = sys.argv[1]
589
+ print(f"\nScanning {target}...")
590
+
591
+ # Spider first
592
+ spider_id = zap.spider(target)
593
+ print(f" Spider ID: {spider_id}")
594
+ zap.wait_for_spider(spider_id)
595
+ urls = zap.get_spider_results(spider_id)
596
+ print(f" URLs found: {len(urls)}")
597
+
598
+ # Active scan
599
+ scan_id = zap.active_scan(target)
600
+ print(f" Scan ID: {scan_id}")
601
+
602
+ result = zap.wait_for_scan(scan_id, timeout=1800)
603
+ print(f" Status: {result.status}")
604
+
605
+ alerts = zap.get_alerts()
606
+ print(f" Alerts: {len(alerts)}")
607
+
608
+ for alert in alerts[:5]:
609
+ print(f" [{alert.risk_name}] {alert.name}")
610
+ else:
611
+ print("✗ Failed to connect to ZAP")
612
+ print(" Set ZAP_URL and ZAP_API_KEY environment variables")
@@ -0,0 +1,5 @@
1
+ """
2
+ AIPT Terminal Tools - Shell session management
3
+ """
4
+
5
+ __all__ = []
@@ -0,0 +1,37 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from aipt_v2.tools.registry import register_tool
6
+
7
+ from .terminal_manager import get_terminal_manager
8
+
9
+
10
+ @register_tool
11
+ def terminal_execute(
12
+ command: str,
13
+ is_input: bool = False,
14
+ timeout: float | None = None,
15
+ terminal_id: str | None = None,
16
+ no_enter: bool = False,
17
+ ) -> dict[str, Any]:
18
+ manager = get_terminal_manager()
19
+
20
+ try:
21
+ return manager.execute_command(
22
+ command=command,
23
+ is_input=is_input,
24
+ timeout=timeout,
25
+ terminal_id=terminal_id,
26
+ no_enter=no_enter,
27
+ )
28
+ except (ValueError, RuntimeError) as e:
29
+ return {
30
+ "error": str(e),
31
+ "command": command,
32
+ "terminal_id": terminal_id or "default",
33
+ "content": "",
34
+ "status": "error",
35
+ "exit_code": None,
36
+ "working_dir": None,
37
+ }