souleyez 2.43.26__py3-none-any.whl → 2.43.34__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 (358) hide show
  1. souleyez/__init__.py +1 -2
  2. souleyez/ai/__init__.py +21 -15
  3. souleyez/ai/action_mapper.py +249 -150
  4. souleyez/ai/chain_advisor.py +116 -100
  5. souleyez/ai/claude_provider.py +29 -28
  6. souleyez/ai/context_builder.py +80 -62
  7. souleyez/ai/executor.py +158 -117
  8. souleyez/ai/feedback_handler.py +136 -121
  9. souleyez/ai/llm_factory.py +27 -20
  10. souleyez/ai/llm_provider.py +4 -2
  11. souleyez/ai/ollama_provider.py +6 -9
  12. souleyez/ai/ollama_service.py +44 -37
  13. souleyez/ai/path_scorer.py +91 -76
  14. souleyez/ai/recommender.py +176 -144
  15. souleyez/ai/report_context.py +74 -73
  16. souleyez/ai/report_service.py +84 -66
  17. souleyez/ai/result_parser.py +222 -229
  18. souleyez/ai/safety.py +67 -44
  19. souleyez/auth/__init__.py +23 -22
  20. souleyez/auth/audit.py +36 -26
  21. souleyez/auth/engagement_access.py +65 -48
  22. souleyez/auth/permissions.py +14 -3
  23. souleyez/auth/session_manager.py +54 -37
  24. souleyez/auth/user_manager.py +109 -64
  25. souleyez/commands/audit.py +40 -43
  26. souleyez/commands/auth.py +35 -15
  27. souleyez/commands/deliverables.py +55 -50
  28. souleyez/commands/engagement.py +47 -28
  29. souleyez/commands/license.py +32 -23
  30. souleyez/commands/screenshots.py +36 -32
  31. souleyez/commands/user.py +82 -36
  32. souleyez/config.py +52 -44
  33. souleyez/core/credential_tester.py +87 -81
  34. souleyez/core/cve_mappings.py +179 -192
  35. souleyez/core/cve_matcher.py +162 -148
  36. souleyez/core/msf_auto_mapper.py +100 -83
  37. souleyez/core/msf_chain_engine.py +294 -256
  38. souleyez/core/msf_database.py +153 -70
  39. souleyez/core/msf_integration.py +679 -673
  40. souleyez/core/msf_rpc_client.py +40 -42
  41. souleyez/core/msf_rpc_manager.py +77 -79
  42. souleyez/core/msf_sync_manager.py +241 -181
  43. souleyez/core/network_utils.py +22 -15
  44. souleyez/core/parser_handler.py +34 -25
  45. souleyez/core/pending_chains.py +114 -63
  46. souleyez/core/templates.py +158 -107
  47. souleyez/core/tool_chaining.py +9526 -2879
  48. souleyez/core/version_utils.py +79 -94
  49. souleyez/core/vuln_correlation.py +136 -89
  50. souleyez/core/web_utils.py +33 -32
  51. souleyez/data/wordlists/ad_users.txt +378 -0
  52. souleyez/data/wordlists/api_endpoints_large.txt +769 -0
  53. souleyez/data/wordlists/home_dir_sensitive.txt +39 -0
  54. souleyez/data/wordlists/lfi_payloads.txt +82 -0
  55. souleyez/data/wordlists/passwords_brute.txt +1548 -0
  56. souleyez/data/wordlists/passwords_crack.txt +2479 -0
  57. souleyez/data/wordlists/passwords_spray.txt +386 -0
  58. souleyez/data/wordlists/subdomains_large.txt +5057 -0
  59. souleyez/data/wordlists/usernames_common.txt +694 -0
  60. souleyez/data/wordlists/web_dirs_large.txt +4769 -0
  61. souleyez/detection/__init__.py +1 -1
  62. souleyez/detection/attack_signatures.py +12 -17
  63. souleyez/detection/mitre_mappings.py +61 -55
  64. souleyez/detection/validator.py +97 -86
  65. souleyez/devtools.py +23 -10
  66. souleyez/docs/README.md +4 -4
  67. souleyez/docs/api-reference/cli-commands.md +2 -2
  68. souleyez/docs/developer-guide/adding-new-tools.md +562 -0
  69. souleyez/docs/user-guide/auto-chaining.md +30 -8
  70. souleyez/docs/user-guide/getting-started.md +1 -1
  71. souleyez/docs/user-guide/installation.md +26 -3
  72. souleyez/docs/user-guide/metasploit-integration.md +2 -2
  73. souleyez/docs/user-guide/rbac.md +1 -1
  74. souleyez/docs/user-guide/scope-management.md +1 -1
  75. souleyez/docs/user-guide/siem-integration.md +1 -1
  76. souleyez/docs/user-guide/tools-reference.md +1 -8
  77. souleyez/docs/user-guide/worker-management.md +1 -1
  78. souleyez/engine/background.py +1239 -535
  79. souleyez/engine/base.py +4 -1
  80. souleyez/engine/job_status.py +17 -49
  81. souleyez/engine/log_sanitizer.py +103 -77
  82. souleyez/engine/manager.py +38 -7
  83. souleyez/engine/result_handler.py +2200 -1550
  84. souleyez/engine/worker_manager.py +50 -41
  85. souleyez/export/evidence_bundle.py +72 -62
  86. souleyez/feature_flags/features.py +16 -20
  87. souleyez/feature_flags.py +5 -9
  88. souleyez/handlers/__init__.py +11 -0
  89. souleyez/handlers/base.py +188 -0
  90. souleyez/handlers/bash_handler.py +277 -0
  91. souleyez/handlers/bloodhound_handler.py +243 -0
  92. souleyez/handlers/certipy_handler.py +311 -0
  93. souleyez/handlers/crackmapexec_handler.py +486 -0
  94. souleyez/handlers/dnsrecon_handler.py +344 -0
  95. souleyez/handlers/enum4linux_handler.py +400 -0
  96. souleyez/handlers/evil_winrm_handler.py +493 -0
  97. souleyez/handlers/ffuf_handler.py +815 -0
  98. souleyez/handlers/gobuster_handler.py +1114 -0
  99. souleyez/handlers/gpp_extract_handler.py +334 -0
  100. souleyez/handlers/hashcat_handler.py +444 -0
  101. souleyez/handlers/hydra_handler.py +563 -0
  102. souleyez/handlers/impacket_getuserspns_handler.py +343 -0
  103. souleyez/handlers/impacket_psexec_handler.py +222 -0
  104. souleyez/handlers/impacket_secretsdump_handler.py +426 -0
  105. souleyez/handlers/john_handler.py +286 -0
  106. souleyez/handlers/katana_handler.py +425 -0
  107. souleyez/handlers/kerbrute_handler.py +298 -0
  108. souleyez/handlers/ldapsearch_handler.py +636 -0
  109. souleyez/handlers/lfi_extract_handler.py +464 -0
  110. souleyez/handlers/msf_auxiliary_handler.py +408 -0
  111. souleyez/handlers/msf_exploit_handler.py +380 -0
  112. souleyez/handlers/nikto_handler.py +413 -0
  113. souleyez/handlers/nmap_handler.py +821 -0
  114. souleyez/handlers/nuclei_handler.py +359 -0
  115. souleyez/handlers/nxc_handler.py +371 -0
  116. souleyez/handlers/rdp_sec_check_handler.py +353 -0
  117. souleyez/handlers/registry.py +292 -0
  118. souleyez/handlers/responder_handler.py +232 -0
  119. souleyez/handlers/service_explorer_handler.py +434 -0
  120. souleyez/handlers/smbclient_handler.py +344 -0
  121. souleyez/handlers/smbmap_handler.py +510 -0
  122. souleyez/handlers/smbpasswd_handler.py +296 -0
  123. souleyez/handlers/sqlmap_handler.py +1116 -0
  124. souleyez/handlers/theharvester_handler.py +601 -0
  125. souleyez/handlers/web_login_test_handler.py +327 -0
  126. souleyez/handlers/whois_handler.py +277 -0
  127. souleyez/handlers/wpscan_handler.py +554 -0
  128. souleyez/history.py +32 -16
  129. souleyez/importers/msf_importer.py +106 -75
  130. souleyez/importers/smart_importer.py +208 -147
  131. souleyez/integrations/siem/__init__.py +10 -10
  132. souleyez/integrations/siem/base.py +17 -18
  133. souleyez/integrations/siem/elastic.py +108 -122
  134. souleyez/integrations/siem/factory.py +207 -80
  135. souleyez/integrations/siem/googlesecops.py +146 -154
  136. souleyez/integrations/siem/rule_mappings/__init__.py +1 -1
  137. souleyez/integrations/siem/rule_mappings/wazuh_rules.py +8 -5
  138. souleyez/integrations/siem/sentinel.py +107 -109
  139. souleyez/integrations/siem/splunk.py +246 -212
  140. souleyez/integrations/siem/wazuh.py +65 -71
  141. souleyez/integrations/wazuh/__init__.py +5 -5
  142. souleyez/integrations/wazuh/client.py +70 -93
  143. souleyez/integrations/wazuh/config.py +85 -57
  144. souleyez/integrations/wazuh/host_mapper.py +28 -36
  145. souleyez/integrations/wazuh/sync.py +78 -68
  146. souleyez/intelligence/__init__.py +4 -5
  147. souleyez/intelligence/correlation_analyzer.py +309 -295
  148. souleyez/intelligence/exploit_knowledge.py +661 -623
  149. souleyez/intelligence/exploit_suggestions.py +159 -139
  150. souleyez/intelligence/gap_analyzer.py +132 -97
  151. souleyez/intelligence/gap_detector.py +251 -214
  152. souleyez/intelligence/sensitive_tables.py +266 -129
  153. souleyez/intelligence/service_parser.py +137 -123
  154. souleyez/intelligence/surface_analyzer.py +407 -268
  155. souleyez/intelligence/target_parser.py +159 -162
  156. souleyez/licensing/__init__.py +6 -6
  157. souleyez/licensing/validator.py +17 -19
  158. souleyez/log_config.py +79 -54
  159. souleyez/main.py +1505 -687
  160. souleyez/migrations/fix_job_counter.py +16 -14
  161. souleyez/parsers/bloodhound_parser.py +41 -39
  162. souleyez/parsers/crackmapexec_parser.py +178 -111
  163. souleyez/parsers/dalfox_parser.py +72 -77
  164. souleyez/parsers/dnsrecon_parser.py +103 -91
  165. souleyez/parsers/enum4linux_parser.py +183 -153
  166. souleyez/parsers/ffuf_parser.py +29 -25
  167. souleyez/parsers/gobuster_parser.py +301 -41
  168. souleyez/parsers/hashcat_parser.py +324 -79
  169. souleyez/parsers/http_fingerprint_parser.py +350 -103
  170. souleyez/parsers/hydra_parser.py +131 -111
  171. souleyez/parsers/impacket_parser.py +231 -178
  172. souleyez/parsers/john_parser.py +98 -86
  173. souleyez/parsers/katana_parser.py +316 -0
  174. souleyez/parsers/msf_parser.py +943 -498
  175. souleyez/parsers/nikto_parser.py +346 -65
  176. souleyez/parsers/nmap_parser.py +262 -174
  177. souleyez/parsers/nuclei_parser.py +40 -44
  178. souleyez/parsers/responder_parser.py +26 -26
  179. souleyez/parsers/searchsploit_parser.py +74 -74
  180. souleyez/parsers/service_explorer_parser.py +279 -0
  181. souleyez/parsers/smbmap_parser.py +180 -124
  182. souleyez/parsers/sqlmap_parser.py +434 -308
  183. souleyez/parsers/theharvester_parser.py +75 -57
  184. souleyez/parsers/whois_parser.py +135 -94
  185. souleyez/parsers/wpscan_parser.py +278 -190
  186. souleyez/plugins/afp.py +44 -36
  187. souleyez/plugins/afp_brute.py +114 -46
  188. souleyez/plugins/ard.py +48 -37
  189. souleyez/plugins/bloodhound.py +95 -61
  190. souleyez/plugins/certipy.py +303 -0
  191. souleyez/plugins/crackmapexec.py +186 -85
  192. souleyez/plugins/dalfox.py +120 -59
  193. souleyez/plugins/dns_hijack.py +146 -41
  194. souleyez/plugins/dnsrecon.py +97 -61
  195. souleyez/plugins/enum4linux.py +91 -66
  196. souleyez/plugins/evil_winrm.py +291 -0
  197. souleyez/plugins/ffuf.py +166 -90
  198. souleyez/plugins/firmware_extract.py +133 -29
  199. souleyez/plugins/gobuster.py +387 -190
  200. souleyez/plugins/gpp_extract.py +393 -0
  201. souleyez/plugins/hashcat.py +100 -73
  202. souleyez/plugins/http_fingerprint.py +854 -267
  203. souleyez/plugins/hydra.py +566 -200
  204. souleyez/plugins/impacket_getnpusers.py +117 -69
  205. souleyez/plugins/impacket_psexec.py +84 -64
  206. souleyez/plugins/impacket_secretsdump.py +103 -69
  207. souleyez/plugins/impacket_smbclient.py +89 -75
  208. souleyez/plugins/john.py +86 -69
  209. souleyez/plugins/katana.py +313 -0
  210. souleyez/plugins/kerbrute.py +237 -0
  211. souleyez/plugins/lfi_extract.py +541 -0
  212. souleyez/plugins/macos_ssh.py +117 -48
  213. souleyez/plugins/mdns.py +35 -30
  214. souleyez/plugins/msf_auxiliary.py +253 -130
  215. souleyez/plugins/msf_exploit.py +239 -161
  216. souleyez/plugins/nikto.py +134 -78
  217. souleyez/plugins/nmap.py +275 -91
  218. souleyez/plugins/nuclei.py +180 -89
  219. souleyez/plugins/nxc.py +285 -0
  220. souleyez/plugins/plugin_base.py +35 -36
  221. souleyez/plugins/plugin_template.py +13 -5
  222. souleyez/plugins/rdp_sec_check.py +130 -0
  223. souleyez/plugins/responder.py +112 -71
  224. souleyez/plugins/router_http_brute.py +76 -65
  225. souleyez/plugins/router_ssh_brute.py +118 -41
  226. souleyez/plugins/router_telnet_brute.py +124 -42
  227. souleyez/plugins/routersploit.py +91 -59
  228. souleyez/plugins/routersploit_exploit.py +77 -55
  229. souleyez/plugins/searchsploit.py +91 -77
  230. souleyez/plugins/service_explorer.py +1160 -0
  231. souleyez/plugins/smbmap.py +122 -72
  232. souleyez/plugins/smbpasswd.py +215 -0
  233. souleyez/plugins/sqlmap.py +301 -113
  234. souleyez/plugins/theharvester.py +127 -75
  235. souleyez/plugins/tr069.py +79 -57
  236. souleyez/plugins/upnp.py +65 -47
  237. souleyez/plugins/upnp_abuse.py +73 -55
  238. souleyez/plugins/vnc_access.py +129 -42
  239. souleyez/plugins/vnc_brute.py +109 -38
  240. souleyez/plugins/web_login_test.py +417 -0
  241. souleyez/plugins/whois.py +77 -58
  242. souleyez/plugins/wpscan.py +173 -69
  243. souleyez/reporting/__init__.py +2 -1
  244. souleyez/reporting/attack_chain.py +411 -346
  245. souleyez/reporting/charts.py +436 -501
  246. souleyez/reporting/compliance_mappings.py +334 -201
  247. souleyez/reporting/detection_report.py +126 -125
  248. souleyez/reporting/formatters.py +828 -591
  249. souleyez/reporting/generator.py +386 -302
  250. souleyez/reporting/metrics.py +72 -75
  251. souleyez/scanner.py +35 -29
  252. souleyez/security/__init__.py +37 -11
  253. souleyez/security/scope_validator.py +175 -106
  254. souleyez/security/validation.py +223 -149
  255. souleyez/security.py +22 -6
  256. souleyez/storage/credentials.py +247 -186
  257. souleyez/storage/crypto.py +296 -129
  258. souleyez/storage/database.py +73 -50
  259. souleyez/storage/db.py +58 -36
  260. souleyez/storage/deliverable_evidence.py +177 -128
  261. souleyez/storage/deliverable_exporter.py +282 -246
  262. souleyez/storage/deliverable_templates.py +134 -116
  263. souleyez/storage/deliverables.py +135 -130
  264. souleyez/storage/engagements.py +109 -56
  265. souleyez/storage/evidence.py +181 -152
  266. souleyez/storage/execution_log.py +31 -17
  267. souleyez/storage/exploit_attempts.py +93 -57
  268. souleyez/storage/exploits.py +67 -36
  269. souleyez/storage/findings.py +48 -61
  270. souleyez/storage/hosts.py +176 -144
  271. souleyez/storage/migrate_to_engagements.py +43 -19
  272. souleyez/storage/migrations/_001_add_credential_enhancements.py +22 -12
  273. souleyez/storage/migrations/_002_add_status_tracking.py +10 -7
  274. souleyez/storage/migrations/_003_add_execution_log.py +14 -8
  275. souleyez/storage/migrations/_005_screenshots.py +13 -5
  276. souleyez/storage/migrations/_006_deliverables.py +13 -5
  277. souleyez/storage/migrations/_007_deliverable_templates.py +12 -7
  278. souleyez/storage/migrations/_008_add_nuclei_table.py +10 -4
  279. souleyez/storage/migrations/_010_evidence_linking.py +17 -10
  280. souleyez/storage/migrations/_011_timeline_tracking.py +20 -13
  281. souleyez/storage/migrations/_012_team_collaboration.py +34 -21
  282. souleyez/storage/migrations/_013_add_host_tags.py +12 -6
  283. souleyez/storage/migrations/_014_exploit_attempts.py +22 -10
  284. souleyez/storage/migrations/_015_add_mac_os_fields.py +15 -7
  285. souleyez/storage/migrations/_016_add_domain_field.py +10 -4
  286. souleyez/storage/migrations/_017_msf_sessions.py +16 -8
  287. souleyez/storage/migrations/_018_add_osint_target.py +10 -6
  288. souleyez/storage/migrations/_019_add_engagement_type.py +10 -6
  289. souleyez/storage/migrations/_020_add_rbac.py +36 -15
  290. souleyez/storage/migrations/_021_wazuh_integration.py +20 -8
  291. souleyez/storage/migrations/_022_wazuh_indexer_columns.py +6 -4
  292. souleyez/storage/migrations/_023_fix_detection_results_fk.py +16 -6
  293. souleyez/storage/migrations/_024_wazuh_vulnerabilities.py +26 -10
  294. souleyez/storage/migrations/_025_multi_siem_support.py +3 -5
  295. souleyez/storage/migrations/_026_add_engagement_scope.py +31 -12
  296. souleyez/storage/migrations/_027_multi_siem_persistence.py +32 -15
  297. souleyez/storage/migrations/__init__.py +26 -26
  298. souleyez/storage/migrations/migration_manager.py +19 -19
  299. souleyez/storage/msf_sessions.py +100 -65
  300. souleyez/storage/osint.py +17 -24
  301. souleyez/storage/recommendation_engine.py +269 -235
  302. souleyez/storage/screenshots.py +33 -32
  303. souleyez/storage/smb_shares.py +136 -92
  304. souleyez/storage/sqlmap_data.py +183 -128
  305. souleyez/storage/team_collaboration.py +135 -141
  306. souleyez/storage/timeline_tracker.py +122 -94
  307. souleyez/storage/wazuh_vulns.py +64 -66
  308. souleyez/storage/web_paths.py +33 -37
  309. souleyez/testing/credential_tester.py +221 -205
  310. souleyez/ui/__init__.py +1 -1
  311. souleyez/ui/ai_quotes.py +12 -12
  312. souleyez/ui/attack_surface.py +2439 -1516
  313. souleyez/ui/chain_rules_view.py +914 -382
  314. souleyez/ui/correlation_view.py +312 -230
  315. souleyez/ui/dashboard.py +2382 -1130
  316. souleyez/ui/deliverables_view.py +148 -62
  317. souleyez/ui/design_system.py +13 -13
  318. souleyez/ui/errors.py +49 -49
  319. souleyez/ui/evidence_linking_view.py +284 -179
  320. souleyez/ui/evidence_vault.py +393 -285
  321. souleyez/ui/exploit_suggestions_view.py +555 -349
  322. souleyez/ui/export_view.py +100 -66
  323. souleyez/ui/gap_analysis_view.py +315 -171
  324. souleyez/ui/help_system.py +105 -97
  325. souleyez/ui/intelligence_view.py +436 -293
  326. souleyez/ui/interactive.py +23434 -10286
  327. souleyez/ui/interactive_selector.py +75 -68
  328. souleyez/ui/log_formatter.py +47 -39
  329. souleyez/ui/menu_components.py +22 -13
  330. souleyez/ui/msf_auxiliary_menu.py +184 -133
  331. souleyez/ui/pending_chains_view.py +336 -172
  332. souleyez/ui/progress_indicators.py +5 -3
  333. souleyez/ui/recommendations_view.py +195 -137
  334. souleyez/ui/rule_builder.py +343 -225
  335. souleyez/ui/setup_wizard.py +678 -284
  336. souleyez/ui/shortcuts.py +217 -165
  337. souleyez/ui/splunk_gap_analysis_view.py +452 -270
  338. souleyez/ui/splunk_vulns_view.py +139 -86
  339. souleyez/ui/team_dashboard.py +498 -335
  340. souleyez/ui/template_selector.py +196 -105
  341. souleyez/ui/terminal.py +6 -6
  342. souleyez/ui/timeline_view.py +198 -127
  343. souleyez/ui/tool_setup.py +264 -164
  344. souleyez/ui/tutorial.py +202 -72
  345. souleyez/ui/tutorial_state.py +40 -40
  346. souleyez/ui/wazuh_vulns_view.py +235 -141
  347. souleyez/ui/wordlist_browser.py +260 -107
  348. souleyez/ui.py +464 -312
  349. souleyez/utils/tool_checker.py +427 -367
  350. souleyez/utils.py +33 -29
  351. souleyez/wordlists.py +134 -167
  352. {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/METADATA +1 -1
  353. souleyez-2.43.34.dist-info/RECORD +443 -0
  354. {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/WHEEL +1 -1
  355. souleyez-2.43.26.dist-info/RECORD +0 -379
  356. {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/entry_points.txt +0 -0
  357. {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/licenses/LICENSE +0 -0
  358. {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Export deliverables in multiple formats (CSV, JSON, Markdown).
3
3
  """
4
+
4
5
  import csv
5
6
  import json
6
7
  from typing import Dict, List, Optional
@@ -13,379 +14,414 @@ from .engagements import EngagementManager
13
14
 
14
15
  class DeliverableExporter:
15
16
  """Export deliverables with evidence in various formats."""
16
-
17
+
17
18
  def __init__(self):
18
19
  self.db = get_db()
19
20
  self.dm = DeliverableManager()
20
21
  self.em = EvidenceManager()
21
22
  self.eng_mgr = EngagementManager()
22
-
23
+
23
24
  def export_csv(
24
- self,
25
- engagement_id: int,
26
- output_path: str,
27
- include_evidence: bool = True
25
+ self, engagement_id: int, output_path: str, include_evidence: bool = True
28
26
  ) -> bool:
29
27
  """
30
28
  Export deliverables to CSV format.
31
-
29
+
32
30
  Args:
33
31
  engagement_id: Target engagement
34
32
  output_path: Output file path
35
33
  include_evidence: Include evidence counts/details
36
-
34
+
37
35
  Returns:
38
36
  True if successful
39
37
  """
40
38
  deliverables = self.dm.list_deliverables(engagement_id)
41
39
  engagement = self.eng_mgr.get_by_id(engagement_id)
42
-
40
+
43
41
  if not deliverables:
44
42
  return False
45
-
46
- with open(output_path, 'w', newline='', encoding='utf-8') as f:
43
+
44
+ with open(output_path, "w", newline="", encoding="utf-8") as f:
47
45
  # Define CSV columns
48
46
  fieldnames = [
49
- 'ID',
50
- 'Category',
51
- 'Title',
52
- 'Description',
53
- 'Status',
54
- 'Priority',
55
- 'Target Type',
56
- 'Target Value',
57
- 'Current Value',
58
- 'Completion %',
59
- 'Started At',
60
- 'Completed At',
61
- 'Estimated Hours',
62
- 'Actual Hours',
63
- 'Blocker'
47
+ "ID",
48
+ "Category",
49
+ "Title",
50
+ "Description",
51
+ "Status",
52
+ "Priority",
53
+ "Target Type",
54
+ "Target Value",
55
+ "Current Value",
56
+ "Completion %",
57
+ "Started At",
58
+ "Completed At",
59
+ "Estimated Hours",
60
+ "Actual Hours",
61
+ "Blocker",
64
62
  ]
65
-
63
+
66
64
  if include_evidence:
67
- fieldnames.extend([
68
- 'Findings Count',
69
- 'Credentials Count',
70
- 'Screenshots Count',
71
- 'Jobs Count',
72
- 'Total Evidence'
73
- ])
74
-
65
+ fieldnames.extend(
66
+ [
67
+ "Findings Count",
68
+ "Credentials Count",
69
+ "Screenshots Count",
70
+ "Jobs Count",
71
+ "Total Evidence",
72
+ ]
73
+ )
74
+
75
75
  writer = csv.DictWriter(f, fieldnames=fieldnames)
76
76
  writer.writeheader()
77
-
77
+
78
78
  for d in deliverables:
79
79
  row = {
80
- 'ID': d['id'],
81
- 'Category': d['category'].replace('_', ' ').title(),
82
- 'Title': d['title'],
83
- 'Description': d.get('description', ''),
84
- 'Status': d['status'].replace('_', ' ').title(),
85
- 'Priority': d.get('priority', 'medium').title(),
86
- 'Target Type': d.get('target_type', 'manual').title(),
87
- 'Target Value': d.get('target_value', ''),
88
- 'Current Value': d.get('current_value', ''),
89
- 'Completion %': f"{d.get('completion_rate', 0) * 100:.0f}%",
90
- 'Started At': d.get('started_at', ''),
91
- 'Completed At': d.get('completed_at', ''),
92
- 'Estimated Hours': d.get('estimated_hours', 0),
93
- 'Actual Hours': d.get('actual_hours', 0),
94
- 'Blocker': d.get('blocker', '')
80
+ "ID": d["id"],
81
+ "Category": d["category"].replace("_", " ").title(),
82
+ "Title": d["title"],
83
+ "Description": d.get("description", ""),
84
+ "Status": d["status"].replace("_", " ").title(),
85
+ "Priority": d.get("priority", "medium").title(),
86
+ "Target Type": d.get("target_type", "manual").title(),
87
+ "Target Value": d.get("target_value", ""),
88
+ "Current Value": d.get("current_value", ""),
89
+ "Completion %": f"{d.get('completion_rate', 0) * 100:.0f}%",
90
+ "Started At": d.get("started_at", ""),
91
+ "Completed At": d.get("completed_at", ""),
92
+ "Estimated Hours": d.get("estimated_hours", 0),
93
+ "Actual Hours": d.get("actual_hours", 0),
94
+ "Blocker": d.get("blocker", ""),
95
95
  }
96
-
96
+
97
97
  if include_evidence:
98
- evidence = self.em.get_evidence(d['id'])
99
- row.update({
100
- 'Findings Count': len(evidence['findings']),
101
- 'Credentials Count': len(evidence['credentials']),
102
- 'Screenshots Count': len(evidence['screenshots']),
103
- 'Jobs Count': len(evidence['jobs']),
104
- 'Total Evidence': sum([
105
- len(evidence['findings']),
106
- len(evidence['credentials']),
107
- len(evidence['screenshots']),
108
- len(evidence['jobs'])
109
- ])
110
- })
111
-
98
+ evidence = self.em.get_evidence(d["id"])
99
+ row.update(
100
+ {
101
+ "Findings Count": len(evidence["findings"]),
102
+ "Credentials Count": len(evidence["credentials"]),
103
+ "Screenshots Count": len(evidence["screenshots"]),
104
+ "Jobs Count": len(evidence["jobs"]),
105
+ "Total Evidence": sum(
106
+ [
107
+ len(evidence["findings"]),
108
+ len(evidence["credentials"]),
109
+ len(evidence["screenshots"]),
110
+ len(evidence["jobs"]),
111
+ ]
112
+ ),
113
+ }
114
+ )
115
+
112
116
  writer.writerow(row)
113
-
117
+
114
118
  return True
115
-
119
+
116
120
  def export_json(
117
- self,
118
- engagement_id: int,
119
- output_path: str,
120
- include_evidence: bool = True
121
+ self, engagement_id: int, output_path: str, include_evidence: bool = True
121
122
  ) -> bool:
122
123
  """
123
124
  Export deliverables to JSON format.
124
-
125
+
125
126
  Args:
126
127
  engagement_id: Target engagement
127
128
  output_path: Output file path
128
129
  include_evidence: Include full evidence details
129
-
130
+
130
131
  Returns:
131
132
  True if successful
132
133
  """
133
134
  deliverables = self.dm.list_deliverables(engagement_id)
134
135
  engagement = self.eng_mgr.get_by_id(engagement_id)
135
136
  summary = self.dm.get_summary(engagement_id)
136
-
137
+
137
138
  export_data = {
138
- 'engagement': {
139
- 'id': engagement['id'],
140
- 'name': engagement['name'],
141
- 'description': engagement.get('description'),
142
- 'created_at': engagement.get('created_at'),
143
- 'engagement_type': engagement.get('engagement_type', 'network'),
144
- 'estimated_hours': engagement.get('estimated_hours', 0),
145
- 'actual_hours': engagement.get('actual_hours', 0)
139
+ "engagement": {
140
+ "id": engagement["id"],
141
+ "name": engagement["name"],
142
+ "description": engagement.get("description"),
143
+ "created_at": engagement.get("created_at"),
144
+ "engagement_type": engagement.get("engagement_type", "network"),
145
+ "estimated_hours": engagement.get("estimated_hours", 0),
146
+ "actual_hours": engagement.get("actual_hours", 0),
146
147
  },
147
- 'summary': {
148
- 'total_deliverables': summary['total'],
149
- 'completed': summary['completed'],
150
- 'in_progress': summary['in_progress'],
151
- 'pending': summary['pending'],
152
- 'completion_rate': f"{summary['completion_rate'] * 100:.1f}%"
148
+ "summary": {
149
+ "total_deliverables": summary["total"],
150
+ "completed": summary["completed"],
151
+ "in_progress": summary["in_progress"],
152
+ "pending": summary["pending"],
153
+ "completion_rate": f"{summary['completion_rate'] * 100:.1f}%",
153
154
  },
154
- 'deliverables': [],
155
- 'exported_at': datetime.now().isoformat()
155
+ "deliverables": [],
156
+ "exported_at": datetime.now().isoformat(),
156
157
  }
157
-
158
+
158
159
  for d in deliverables:
159
160
  deliverable_data = {
160
- 'id': d['id'],
161
- 'category': d['category'],
162
- 'title': d['title'],
163
- 'description': d.get('description'),
164
- 'status': d['status'],
165
- 'priority': d.get('priority', 'medium'),
166
- 'target_type': d.get('target_type', 'manual'),
167
- 'target_value': d.get('target_value'),
168
- 'current_value': d.get('current_value'),
169
- 'completion_rate': d.get('completion_rate', 0),
170
- 'auto_validate': d.get('auto_validate', False),
171
- 'validation_query': d.get('validation_query'),
172
- 'started_at': d.get('started_at'),
173
- 'completed_at': d.get('completed_at'),
174
- 'estimated_hours': d.get('estimated_hours', 0),
175
- 'actual_hours': d.get('actual_hours', 0),
176
- 'blocker': d.get('blocker'),
177
- 'assigned_to': d.get('assigned_to')
161
+ "id": d["id"],
162
+ "category": d["category"],
163
+ "title": d["title"],
164
+ "description": d.get("description"),
165
+ "status": d["status"],
166
+ "priority": d.get("priority", "medium"),
167
+ "target_type": d.get("target_type", "manual"),
168
+ "target_value": d.get("target_value"),
169
+ "current_value": d.get("current_value"),
170
+ "completion_rate": d.get("completion_rate", 0),
171
+ "auto_validate": d.get("auto_validate", False),
172
+ "validation_query": d.get("validation_query"),
173
+ "started_at": d.get("started_at"),
174
+ "completed_at": d.get("completed_at"),
175
+ "estimated_hours": d.get("estimated_hours", 0),
176
+ "actual_hours": d.get("actual_hours", 0),
177
+ "blocker": d.get("blocker"),
178
+ "assigned_to": d.get("assigned_to"),
178
179
  }
179
-
180
+
180
181
  if include_evidence:
181
- evidence = self.em.get_evidence(d['id'])
182
-
183
- deliverable_data['evidence'] = {
184
- 'findings': [
182
+ evidence = self.em.get_evidence(d["id"])
183
+
184
+ deliverable_data["evidence"] = {
185
+ "findings": [
185
186
  {
186
- 'id': f['id'],
187
- 'title': f.get('title'),
188
- 'severity': f.get('severity'),
189
- 'host': f.get('host'),
190
- 'link_notes': f.get('_link_notes'),
191
- 'linked_at': f.get('_linked_at')
192
- } for f in evidence['findings']
187
+ "id": f["id"],
188
+ "title": f.get("title"),
189
+ "severity": f.get("severity"),
190
+ "host": f.get("host"),
191
+ "link_notes": f.get("_link_notes"),
192
+ "linked_at": f.get("_linked_at"),
193
+ }
194
+ for f in evidence["findings"]
193
195
  ],
194
- 'credentials': [
196
+ "credentials": [
195
197
  {
196
- 'id': c['id'],
197
- 'username': c.get('username'),
198
- 'host': c.get('host'),
199
- 'credential_type': c.get('credential_type'),
200
- 'link_notes': c.get('_link_notes'),
201
- 'linked_at': c.get('_linked_at')
202
- } for c in evidence['credentials']
198
+ "id": c["id"],
199
+ "username": c.get("username"),
200
+ "host": c.get("host"),
201
+ "credential_type": c.get("credential_type"),
202
+ "link_notes": c.get("_link_notes"),
203
+ "linked_at": c.get("_linked_at"),
204
+ }
205
+ for c in evidence["credentials"]
203
206
  ],
204
- 'screenshots': [
207
+ "screenshots": [
205
208
  {
206
- 'id': s['id'],
207
- 'filename': s.get('filename'),
208
- 'description': s.get('description'),
209
- 'link_notes': s.get('_link_notes'),
210
- 'linked_at': s.get('_linked_at')
211
- } for s in evidence['screenshots']
209
+ "id": s["id"],
210
+ "filename": s.get("filename"),
211
+ "description": s.get("description"),
212
+ "link_notes": s.get("_link_notes"),
213
+ "linked_at": s.get("_linked_at"),
214
+ }
215
+ for s in evidence["screenshots"]
212
216
  ],
213
- 'jobs': [
217
+ "jobs": [
214
218
  {
215
- 'id': j['id'],
216
- 'tool': j.get('tool'),
217
- 'target': j.get('target'),
218
- 'status': j.get('status'),
219
- 'link_notes': j.get('_link_notes'),
220
- 'linked_at': j.get('_linked_at')
221
- } for j in evidence['jobs']
219
+ "id": j["id"],
220
+ "tool": j.get("tool"),
221
+ "target": j.get("target"),
222
+ "status": j.get("status"),
223
+ "link_notes": j.get("_link_notes"),
224
+ "linked_at": j.get("_linked_at"),
225
+ }
226
+ for j in evidence["jobs"]
222
227
  ],
223
- 'total_evidence': sum([
224
- len(evidence['findings']),
225
- len(evidence['credentials']),
226
- len(evidence['screenshots']),
227
- len(evidence['jobs'])
228
- ])
228
+ "total_evidence": sum(
229
+ [
230
+ len(evidence["findings"]),
231
+ len(evidence["credentials"]),
232
+ len(evidence["screenshots"]),
233
+ len(evidence["jobs"]),
234
+ ]
235
+ ),
229
236
  }
230
-
231
- export_data['deliverables'].append(deliverable_data)
232
-
233
- with open(output_path, 'w', encoding='utf-8') as f:
237
+
238
+ export_data["deliverables"].append(deliverable_data)
239
+
240
+ with open(output_path, "w", encoding="utf-8") as f:
234
241
  json.dump(export_data, f, indent=2, ensure_ascii=False)
235
-
242
+
236
243
  return True
237
-
244
+
238
245
  def export_markdown(
239
- self,
240
- engagement_id: int,
241
- output_path: str,
242
- include_evidence: bool = True
246
+ self, engagement_id: int, output_path: str, include_evidence: bool = True
243
247
  ) -> bool:
244
248
  """
245
249
  Export deliverables to Markdown format.
246
-
250
+
247
251
  Args:
248
252
  engagement_id: Target engagement
249
253
  output_path: Output file path
250
254
  include_evidence: Include evidence details
251
-
255
+
252
256
  Returns:
253
257
  True if successful
254
258
  """
255
259
  deliverables = self.dm.list_deliverables(engagement_id)
256
260
  engagement = self.eng_mgr.get_by_id(engagement_id)
257
261
  summary = self.dm.get_summary(engagement_id)
258
-
262
+
259
263
  if not deliverables:
260
264
  return False
261
-
262
- with open(output_path, 'w', encoding='utf-8') as f:
265
+
266
+ with open(output_path, "w", encoding="utf-8") as f:
263
267
  # Header
264
268
  f.write(f"# Deliverables Report: {engagement['name']}\n\n")
265
- f.write(f"**Generated:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n")
266
-
267
- if engagement.get('description'):
269
+ f.write(
270
+ f"**Generated:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n"
271
+ )
272
+
273
+ if engagement.get("description"):
268
274
  f.write(f"**Description:** {engagement['description']}\n\n")
269
-
275
+
270
276
  # Summary section
271
277
  f.write("## Summary\n\n")
272
278
  f.write(f"- **Total Deliverables:** {summary['total']}\n")
273
279
  f.write(f"- **Completed:** {summary['completed']}\n")
274
280
  f.write(f"- **In Progress:** {summary['in_progress']}\n")
275
281
  f.write(f"- **Pending:** {summary['pending']}\n")
276
- f.write(f"- **Completion Rate:** {summary['completion_rate'] * 100:.1f}%\n\n")
277
-
278
- if engagement.get('actual_hours'):
282
+ f.write(
283
+ f"- **Completion Rate:** {summary['completion_rate'] * 100:.1f}%\n\n"
284
+ )
285
+
286
+ if engagement.get("actual_hours"):
279
287
  f.write(f"- **Time Spent:** {engagement['actual_hours']:.1f} hours\n")
280
- if engagement.get('estimated_hours'):
281
- f.write(f"- **Estimated Time:** {engagement['estimated_hours']:.1f} hours\n")
282
-
288
+ if engagement.get("estimated_hours"):
289
+ f.write(
290
+ f"- **Estimated Time:** {engagement['estimated_hours']:.1f} hours\n"
291
+ )
292
+
283
293
  f.write("\n---\n\n")
284
-
294
+
285
295
  # Group by category
286
296
  categories = {}
287
297
  for d in deliverables:
288
- cat = d['category']
298
+ cat = d["category"]
289
299
  if cat not in categories:
290
300
  categories[cat] = []
291
301
  categories[cat].append(d)
292
-
302
+
293
303
  # Write deliverables by category
294
304
  category_names = {
295
- 'reconnaissance': 'Reconnaissance',
296
- 'enumeration': 'Enumeration',
297
- 'exploitation': 'Exploitation',
298
- 'post_exploitation': 'Post-Exploitation',
299
- 'techniques': 'Techniques'
305
+ "reconnaissance": "Reconnaissance",
306
+ "enumeration": "Enumeration",
307
+ "exploitation": "Exploitation",
308
+ "post_exploitation": "Post-Exploitation",
309
+ "techniques": "Techniques",
300
310
  }
301
-
302
- for category in ['reconnaissance', 'enumeration', 'exploitation', 'post_exploitation', 'techniques']:
311
+
312
+ for category in [
313
+ "reconnaissance",
314
+ "enumeration",
315
+ "exploitation",
316
+ "post_exploitation",
317
+ "techniques",
318
+ ]:
303
319
  if category not in categories:
304
320
  continue
305
-
321
+
306
322
  cat_deliverables = categories[category]
307
323
  cat_name = category_names.get(category, category.title())
308
-
324
+
309
325
  f.write(f"## {cat_name}\n\n")
310
-
326
+
311
327
  for d in cat_deliverables:
312
328
  # Status emoji
313
329
  status_emoji = {
314
- 'completed': '',
315
- 'in_progress': '🔄',
316
- 'pending': '',
317
- 'failed': ''
318
- }.get(d['status'], '')
319
-
330
+ "completed": "",
331
+ "in_progress": "🔄",
332
+ "pending": "",
333
+ "failed": "",
334
+ }.get(d["status"], "")
335
+
320
336
  # Priority badge
321
- priority = d.get('priority', 'medium')
337
+ priority = d.get("priority", "medium")
322
338
  priority_badge = {
323
- 'critical': '🔴 CRITICAL',
324
- 'high': '🟡 HIGH',
325
- 'medium': '🟢 MEDIUM',
326
- 'low': '⚪ LOW'
327
- }.get(priority, 'MEDIUM')
328
-
339
+ "critical": "🔴 CRITICAL",
340
+ "high": "🟡 HIGH",
341
+ "medium": "🟢 MEDIUM",
342
+ "low": "⚪ LOW",
343
+ }.get(priority, "MEDIUM")
344
+
329
345
  f.write(f"### {status_emoji} {d['title']}\n\n")
330
346
  f.write(f"**Priority:** {priority_badge} \n")
331
347
  f.write(f"**Status:** {d['status'].replace('_', ' ').title()} \n")
332
-
333
- if d.get('description'):
348
+
349
+ if d.get("description"):
334
350
  f.write(f"\n{d['description']}\n\n")
335
-
351
+
336
352
  # Progress info
337
- if d.get('target_type') == 'count':
338
- current = d.get('current_value', 0)
339
- target = d.get('target_value', 0)
353
+ if d.get("target_type") == "count":
354
+ current = d.get("current_value", 0)
355
+ target = d.get("target_value", 0)
340
356
  f.write(f"**Progress:** {current}/{target}\n\n")
341
- elif d.get('target_type') == 'boolean':
342
- status = '✓ Complete' if d['status'] == 'completed' else '✗ Incomplete'
357
+ elif d.get("target_type") == "boolean":
358
+ status = (
359
+ "✓ Complete"
360
+ if d["status"] == "completed"
361
+ else "✗ Incomplete"
362
+ )
343
363
  f.write(f"**Status:** {status}\n\n")
344
-
364
+
345
365
  # Time info
346
- if d.get('actual_hours'):
366
+ if d.get("actual_hours"):
347
367
  f.write(f"**Time Spent:** {d['actual_hours']:.1f}h\n\n")
348
-
368
+
349
369
  # Blocker
350
- if d.get('blocker'):
370
+ if d.get("blocker"):
351
371
  f.write(f"⚠️ **Blocker:** {d['blocker']}\n\n")
352
-
372
+
353
373
  # Evidence
354
374
  if include_evidence:
355
- evidence = self.em.get_evidence(d['id'])
356
- total_evidence = sum([
357
- len(evidence['findings']),
358
- len(evidence['credentials']),
359
- len(evidence['screenshots']),
360
- len(evidence['jobs'])
361
- ])
362
-
375
+ evidence = self.em.get_evidence(d["id"])
376
+ total_evidence = sum(
377
+ [
378
+ len(evidence["findings"]),
379
+ len(evidence["credentials"]),
380
+ len(evidence["screenshots"]),
381
+ len(evidence["jobs"]),
382
+ ]
383
+ )
384
+
363
385
  if total_evidence > 0:
364
386
  f.write("**Evidence:**\n\n")
365
-
366
- if evidence['findings']:
367
- f.write(f"- **Findings:** {len(evidence['findings'])}\n")
368
- for finding in evidence['findings'][:3]:
369
- severity = finding.get('severity', 'N/A').upper()
370
- f.write(f" - [{severity}] {finding.get('title', 'Unknown')}\n")
371
- if len(evidence['findings']) > 3:
372
- f.write(f" - ... and {len(evidence['findings']) - 3} more\n")
373
-
374
- if evidence['credentials']:
375
- f.write(f"- **Credentials:** {len(evidence['credentials'])}\n")
376
- for cred in evidence['credentials'][:3]:
377
- f.write(f" - {cred.get('username', 'N/A')}@{cred.get('host', 'N/A')}\n")
378
- if len(evidence['credentials']) > 3:
379
- f.write(f" - ... and {len(evidence['credentials']) - 3} more\n")
380
-
381
- if evidence['screenshots']:
382
- f.write(f"- **Screenshots:** {len(evidence['screenshots'])}\n")
383
-
384
- if evidence['jobs']:
387
+
388
+ if evidence["findings"]:
389
+ f.write(
390
+ f"- **Findings:** {len(evidence['findings'])}\n"
391
+ )
392
+ for finding in evidence["findings"][:3]:
393
+ severity = finding.get("severity", "N/A").upper()
394
+ f.write(
395
+ f" - [{severity}] {finding.get('title', 'Unknown')}\n"
396
+ )
397
+ if len(evidence["findings"]) > 3:
398
+ f.write(
399
+ f" - ... and {len(evidence['findings']) - 3} more\n"
400
+ )
401
+
402
+ if evidence["credentials"]:
403
+ f.write(
404
+ f"- **Credentials:** {len(evidence['credentials'])}\n"
405
+ )
406
+ for cred in evidence["credentials"][:3]:
407
+ f.write(
408
+ f" - {cred.get('username', 'N/A')}@{cred.get('host', 'N/A')}\n"
409
+ )
410
+ if len(evidence["credentials"]) > 3:
411
+ f.write(
412
+ f" - ... and {len(evidence['credentials']) - 3} more\n"
413
+ )
414
+
415
+ if evidence["screenshots"]:
416
+ f.write(
417
+ f"- **Screenshots:** {len(evidence['screenshots'])}\n"
418
+ )
419
+
420
+ if evidence["jobs"]:
385
421
  f.write(f"- **Jobs:** {len(evidence['jobs'])}\n")
386
-
422
+
387
423
  f.write("\n")
388
-
424
+
389
425
  f.write("---\n\n")
390
-
426
+
391
427
  return True