souleyez 2.43.29__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.
- souleyez/__init__.py +1 -2
- souleyez/ai/__init__.py +21 -15
- souleyez/ai/action_mapper.py +249 -150
- souleyez/ai/chain_advisor.py +116 -100
- souleyez/ai/claude_provider.py +29 -28
- souleyez/ai/context_builder.py +80 -62
- souleyez/ai/executor.py +158 -117
- souleyez/ai/feedback_handler.py +136 -121
- souleyez/ai/llm_factory.py +27 -20
- souleyez/ai/llm_provider.py +4 -2
- souleyez/ai/ollama_provider.py +6 -9
- souleyez/ai/ollama_service.py +44 -37
- souleyez/ai/path_scorer.py +91 -76
- souleyez/ai/recommender.py +176 -144
- souleyez/ai/report_context.py +74 -73
- souleyez/ai/report_service.py +84 -66
- souleyez/ai/result_parser.py +222 -229
- souleyez/ai/safety.py +67 -44
- souleyez/auth/__init__.py +23 -22
- souleyez/auth/audit.py +36 -26
- souleyez/auth/engagement_access.py +65 -48
- souleyez/auth/permissions.py +14 -3
- souleyez/auth/session_manager.py +54 -37
- souleyez/auth/user_manager.py +109 -64
- souleyez/commands/audit.py +40 -43
- souleyez/commands/auth.py +35 -15
- souleyez/commands/deliverables.py +55 -50
- souleyez/commands/engagement.py +47 -28
- souleyez/commands/license.py +32 -23
- souleyez/commands/screenshots.py +36 -32
- souleyez/commands/user.py +82 -36
- souleyez/config.py +52 -44
- souleyez/core/credential_tester.py +87 -81
- souleyez/core/cve_mappings.py +179 -192
- souleyez/core/cve_matcher.py +162 -148
- souleyez/core/msf_auto_mapper.py +100 -83
- souleyez/core/msf_chain_engine.py +294 -256
- souleyez/core/msf_database.py +153 -70
- souleyez/core/msf_integration.py +679 -673
- souleyez/core/msf_rpc_client.py +40 -42
- souleyez/core/msf_rpc_manager.py +77 -79
- souleyez/core/msf_sync_manager.py +241 -181
- souleyez/core/network_utils.py +22 -15
- souleyez/core/parser_handler.py +34 -25
- souleyez/core/pending_chains.py +114 -63
- souleyez/core/templates.py +158 -107
- souleyez/core/tool_chaining.py +9526 -2879
- souleyez/core/version_utils.py +79 -94
- souleyez/core/vuln_correlation.py +136 -89
- souleyez/core/web_utils.py +33 -32
- souleyez/data/wordlists/ad_users.txt +378 -0
- souleyez/data/wordlists/api_endpoints_large.txt +769 -0
- souleyez/data/wordlists/home_dir_sensitive.txt +39 -0
- souleyez/data/wordlists/lfi_payloads.txt +82 -0
- souleyez/data/wordlists/passwords_brute.txt +1548 -0
- souleyez/data/wordlists/passwords_crack.txt +2479 -0
- souleyez/data/wordlists/passwords_spray.txt +386 -0
- souleyez/data/wordlists/subdomains_large.txt +5057 -0
- souleyez/data/wordlists/usernames_common.txt +694 -0
- souleyez/data/wordlists/web_dirs_large.txt +4769 -0
- souleyez/detection/__init__.py +1 -1
- souleyez/detection/attack_signatures.py +12 -17
- souleyez/detection/mitre_mappings.py +61 -55
- souleyez/detection/validator.py +97 -86
- souleyez/devtools.py +23 -10
- souleyez/docs/README.md +4 -4
- souleyez/docs/api-reference/cli-commands.md +2 -2
- souleyez/docs/developer-guide/adding-new-tools.md +562 -0
- souleyez/docs/user-guide/auto-chaining.md +30 -8
- souleyez/docs/user-guide/getting-started.md +1 -1
- souleyez/docs/user-guide/installation.md +26 -3
- souleyez/docs/user-guide/metasploit-integration.md +2 -2
- souleyez/docs/user-guide/rbac.md +1 -1
- souleyez/docs/user-guide/scope-management.md +1 -1
- souleyez/docs/user-guide/siem-integration.md +1 -1
- souleyez/docs/user-guide/tools-reference.md +1 -8
- souleyez/docs/user-guide/worker-management.md +1 -1
- souleyez/engine/background.py +1239 -535
- souleyez/engine/base.py +4 -1
- souleyez/engine/job_status.py +17 -49
- souleyez/engine/log_sanitizer.py +103 -77
- souleyez/engine/manager.py +38 -7
- souleyez/engine/result_handler.py +2200 -1550
- souleyez/engine/worker_manager.py +50 -41
- souleyez/export/evidence_bundle.py +72 -62
- souleyez/feature_flags/features.py +16 -20
- souleyez/feature_flags.py +5 -9
- souleyez/handlers/__init__.py +11 -0
- souleyez/handlers/base.py +188 -0
- souleyez/handlers/bash_handler.py +277 -0
- souleyez/handlers/bloodhound_handler.py +243 -0
- souleyez/handlers/certipy_handler.py +311 -0
- souleyez/handlers/crackmapexec_handler.py +486 -0
- souleyez/handlers/dnsrecon_handler.py +344 -0
- souleyez/handlers/enum4linux_handler.py +400 -0
- souleyez/handlers/evil_winrm_handler.py +493 -0
- souleyez/handlers/ffuf_handler.py +815 -0
- souleyez/handlers/gobuster_handler.py +1114 -0
- souleyez/handlers/gpp_extract_handler.py +334 -0
- souleyez/handlers/hashcat_handler.py +444 -0
- souleyez/handlers/hydra_handler.py +563 -0
- souleyez/handlers/impacket_getuserspns_handler.py +343 -0
- souleyez/handlers/impacket_psexec_handler.py +222 -0
- souleyez/handlers/impacket_secretsdump_handler.py +426 -0
- souleyez/handlers/john_handler.py +286 -0
- souleyez/handlers/katana_handler.py +425 -0
- souleyez/handlers/kerbrute_handler.py +298 -0
- souleyez/handlers/ldapsearch_handler.py +636 -0
- souleyez/handlers/lfi_extract_handler.py +464 -0
- souleyez/handlers/msf_auxiliary_handler.py +408 -0
- souleyez/handlers/msf_exploit_handler.py +380 -0
- souleyez/handlers/nikto_handler.py +413 -0
- souleyez/handlers/nmap_handler.py +821 -0
- souleyez/handlers/nuclei_handler.py +359 -0
- souleyez/handlers/nxc_handler.py +371 -0
- souleyez/handlers/rdp_sec_check_handler.py +353 -0
- souleyez/handlers/registry.py +292 -0
- souleyez/handlers/responder_handler.py +232 -0
- souleyez/handlers/service_explorer_handler.py +434 -0
- souleyez/handlers/smbclient_handler.py +344 -0
- souleyez/handlers/smbmap_handler.py +510 -0
- souleyez/handlers/smbpasswd_handler.py +296 -0
- souleyez/handlers/sqlmap_handler.py +1116 -0
- souleyez/handlers/theharvester_handler.py +601 -0
- souleyez/handlers/web_login_test_handler.py +327 -0
- souleyez/handlers/whois_handler.py +277 -0
- souleyez/handlers/wpscan_handler.py +554 -0
- souleyez/history.py +32 -16
- souleyez/importers/msf_importer.py +106 -75
- souleyez/importers/smart_importer.py +208 -147
- souleyez/integrations/siem/__init__.py +10 -10
- souleyez/integrations/siem/base.py +17 -18
- souleyez/integrations/siem/elastic.py +108 -122
- souleyez/integrations/siem/factory.py +207 -80
- souleyez/integrations/siem/googlesecops.py +146 -154
- souleyez/integrations/siem/rule_mappings/__init__.py +1 -1
- souleyez/integrations/siem/rule_mappings/wazuh_rules.py +8 -5
- souleyez/integrations/siem/sentinel.py +107 -109
- souleyez/integrations/siem/splunk.py +246 -212
- souleyez/integrations/siem/wazuh.py +65 -71
- souleyez/integrations/wazuh/__init__.py +5 -5
- souleyez/integrations/wazuh/client.py +70 -93
- souleyez/integrations/wazuh/config.py +85 -57
- souleyez/integrations/wazuh/host_mapper.py +28 -36
- souleyez/integrations/wazuh/sync.py +78 -68
- souleyez/intelligence/__init__.py +4 -5
- souleyez/intelligence/correlation_analyzer.py +309 -295
- souleyez/intelligence/exploit_knowledge.py +661 -623
- souleyez/intelligence/exploit_suggestions.py +159 -139
- souleyez/intelligence/gap_analyzer.py +132 -97
- souleyez/intelligence/gap_detector.py +251 -214
- souleyez/intelligence/sensitive_tables.py +266 -129
- souleyez/intelligence/service_parser.py +137 -123
- souleyez/intelligence/surface_analyzer.py +407 -268
- souleyez/intelligence/target_parser.py +159 -162
- souleyez/licensing/__init__.py +6 -6
- souleyez/licensing/validator.py +17 -19
- souleyez/log_config.py +79 -54
- souleyez/main.py +1505 -687
- souleyez/migrations/fix_job_counter.py +16 -14
- souleyez/parsers/bloodhound_parser.py +41 -39
- souleyez/parsers/crackmapexec_parser.py +178 -111
- souleyez/parsers/dalfox_parser.py +72 -77
- souleyez/parsers/dnsrecon_parser.py +103 -91
- souleyez/parsers/enum4linux_parser.py +183 -153
- souleyez/parsers/ffuf_parser.py +29 -25
- souleyez/parsers/gobuster_parser.py +301 -41
- souleyez/parsers/hashcat_parser.py +324 -79
- souleyez/parsers/http_fingerprint_parser.py +350 -103
- souleyez/parsers/hydra_parser.py +131 -111
- souleyez/parsers/impacket_parser.py +231 -178
- souleyez/parsers/john_parser.py +98 -86
- souleyez/parsers/katana_parser.py +316 -0
- souleyez/parsers/msf_parser.py +943 -498
- souleyez/parsers/nikto_parser.py +346 -65
- souleyez/parsers/nmap_parser.py +262 -174
- souleyez/parsers/nuclei_parser.py +40 -44
- souleyez/parsers/responder_parser.py +26 -26
- souleyez/parsers/searchsploit_parser.py +74 -74
- souleyez/parsers/service_explorer_parser.py +279 -0
- souleyez/parsers/smbmap_parser.py +180 -124
- souleyez/parsers/sqlmap_parser.py +434 -308
- souleyez/parsers/theharvester_parser.py +75 -57
- souleyez/parsers/whois_parser.py +135 -94
- souleyez/parsers/wpscan_parser.py +278 -190
- souleyez/plugins/afp.py +44 -36
- souleyez/plugins/afp_brute.py +114 -46
- souleyez/plugins/ard.py +48 -37
- souleyez/plugins/bloodhound.py +95 -61
- souleyez/plugins/certipy.py +303 -0
- souleyez/plugins/crackmapexec.py +186 -85
- souleyez/plugins/dalfox.py +120 -59
- souleyez/plugins/dns_hijack.py +146 -41
- souleyez/plugins/dnsrecon.py +97 -61
- souleyez/plugins/enum4linux.py +91 -66
- souleyez/plugins/evil_winrm.py +291 -0
- souleyez/plugins/ffuf.py +166 -90
- souleyez/plugins/firmware_extract.py +133 -29
- souleyez/plugins/gobuster.py +387 -190
- souleyez/plugins/gpp_extract.py +393 -0
- souleyez/plugins/hashcat.py +100 -73
- souleyez/plugins/http_fingerprint.py +854 -267
- souleyez/plugins/hydra.py +566 -200
- souleyez/plugins/impacket_getnpusers.py +117 -69
- souleyez/plugins/impacket_psexec.py +84 -64
- souleyez/plugins/impacket_secretsdump.py +103 -69
- souleyez/plugins/impacket_smbclient.py +89 -75
- souleyez/plugins/john.py +86 -69
- souleyez/plugins/katana.py +313 -0
- souleyez/plugins/kerbrute.py +237 -0
- souleyez/plugins/lfi_extract.py +541 -0
- souleyez/plugins/macos_ssh.py +117 -48
- souleyez/plugins/mdns.py +35 -30
- souleyez/plugins/msf_auxiliary.py +253 -130
- souleyez/plugins/msf_exploit.py +239 -161
- souleyez/plugins/nikto.py +134 -78
- souleyez/plugins/nmap.py +275 -91
- souleyez/plugins/nuclei.py +180 -89
- souleyez/plugins/nxc.py +285 -0
- souleyez/plugins/plugin_base.py +35 -36
- souleyez/plugins/plugin_template.py +13 -5
- souleyez/plugins/rdp_sec_check.py +130 -0
- souleyez/plugins/responder.py +112 -71
- souleyez/plugins/router_http_brute.py +76 -65
- souleyez/plugins/router_ssh_brute.py +118 -41
- souleyez/plugins/router_telnet_brute.py +124 -42
- souleyez/plugins/routersploit.py +91 -59
- souleyez/plugins/routersploit_exploit.py +77 -55
- souleyez/plugins/searchsploit.py +91 -77
- souleyez/plugins/service_explorer.py +1160 -0
- souleyez/plugins/smbmap.py +122 -72
- souleyez/plugins/smbpasswd.py +215 -0
- souleyez/plugins/sqlmap.py +301 -113
- souleyez/plugins/theharvester.py +127 -75
- souleyez/plugins/tr069.py +79 -57
- souleyez/plugins/upnp.py +65 -47
- souleyez/plugins/upnp_abuse.py +73 -55
- souleyez/plugins/vnc_access.py +129 -42
- souleyez/plugins/vnc_brute.py +109 -38
- souleyez/plugins/web_login_test.py +417 -0
- souleyez/plugins/whois.py +77 -58
- souleyez/plugins/wpscan.py +173 -69
- souleyez/reporting/__init__.py +2 -1
- souleyez/reporting/attack_chain.py +411 -346
- souleyez/reporting/charts.py +436 -501
- souleyez/reporting/compliance_mappings.py +334 -201
- souleyez/reporting/detection_report.py +126 -125
- souleyez/reporting/formatters.py +828 -591
- souleyez/reporting/generator.py +386 -302
- souleyez/reporting/metrics.py +72 -75
- souleyez/scanner.py +35 -29
- souleyez/security/__init__.py +37 -11
- souleyez/security/scope_validator.py +175 -106
- souleyez/security/validation.py +223 -149
- souleyez/security.py +22 -6
- souleyez/storage/credentials.py +247 -186
- souleyez/storage/crypto.py +296 -129
- souleyez/storage/database.py +73 -50
- souleyez/storage/db.py +58 -36
- souleyez/storage/deliverable_evidence.py +177 -128
- souleyez/storage/deliverable_exporter.py +282 -246
- souleyez/storage/deliverable_templates.py +134 -116
- souleyez/storage/deliverables.py +135 -130
- souleyez/storage/engagements.py +109 -56
- souleyez/storage/evidence.py +181 -152
- souleyez/storage/execution_log.py +31 -17
- souleyez/storage/exploit_attempts.py +93 -57
- souleyez/storage/exploits.py +67 -36
- souleyez/storage/findings.py +48 -61
- souleyez/storage/hosts.py +176 -144
- souleyez/storage/migrate_to_engagements.py +43 -19
- souleyez/storage/migrations/_001_add_credential_enhancements.py +22 -12
- souleyez/storage/migrations/_002_add_status_tracking.py +10 -7
- souleyez/storage/migrations/_003_add_execution_log.py +14 -8
- souleyez/storage/migrations/_005_screenshots.py +13 -5
- souleyez/storage/migrations/_006_deliverables.py +13 -5
- souleyez/storage/migrations/_007_deliverable_templates.py +12 -7
- souleyez/storage/migrations/_008_add_nuclei_table.py +10 -4
- souleyez/storage/migrations/_010_evidence_linking.py +17 -10
- souleyez/storage/migrations/_011_timeline_tracking.py +20 -13
- souleyez/storage/migrations/_012_team_collaboration.py +34 -21
- souleyez/storage/migrations/_013_add_host_tags.py +12 -6
- souleyez/storage/migrations/_014_exploit_attempts.py +22 -10
- souleyez/storage/migrations/_015_add_mac_os_fields.py +15 -7
- souleyez/storage/migrations/_016_add_domain_field.py +10 -4
- souleyez/storage/migrations/_017_msf_sessions.py +16 -8
- souleyez/storage/migrations/_018_add_osint_target.py +10 -6
- souleyez/storage/migrations/_019_add_engagement_type.py +10 -6
- souleyez/storage/migrations/_020_add_rbac.py +36 -15
- souleyez/storage/migrations/_021_wazuh_integration.py +20 -8
- souleyez/storage/migrations/_022_wazuh_indexer_columns.py +6 -4
- souleyez/storage/migrations/_023_fix_detection_results_fk.py +16 -6
- souleyez/storage/migrations/_024_wazuh_vulnerabilities.py +26 -10
- souleyez/storage/migrations/_025_multi_siem_support.py +3 -5
- souleyez/storage/migrations/_026_add_engagement_scope.py +31 -12
- souleyez/storage/migrations/_027_multi_siem_persistence.py +32 -15
- souleyez/storage/migrations/__init__.py +26 -26
- souleyez/storage/migrations/migration_manager.py +19 -19
- souleyez/storage/msf_sessions.py +100 -65
- souleyez/storage/osint.py +17 -24
- souleyez/storage/recommendation_engine.py +269 -235
- souleyez/storage/screenshots.py +33 -32
- souleyez/storage/smb_shares.py +136 -92
- souleyez/storage/sqlmap_data.py +183 -128
- souleyez/storage/team_collaboration.py +135 -141
- souleyez/storage/timeline_tracker.py +122 -94
- souleyez/storage/wazuh_vulns.py +64 -66
- souleyez/storage/web_paths.py +33 -37
- souleyez/testing/credential_tester.py +221 -205
- souleyez/ui/__init__.py +1 -1
- souleyez/ui/ai_quotes.py +12 -12
- souleyez/ui/attack_surface.py +2439 -1516
- souleyez/ui/chain_rules_view.py +914 -382
- souleyez/ui/correlation_view.py +312 -230
- souleyez/ui/dashboard.py +2382 -1130
- souleyez/ui/deliverables_view.py +148 -62
- souleyez/ui/design_system.py +13 -13
- souleyez/ui/errors.py +49 -49
- souleyez/ui/evidence_linking_view.py +284 -179
- souleyez/ui/evidence_vault.py +393 -285
- souleyez/ui/exploit_suggestions_view.py +555 -349
- souleyez/ui/export_view.py +100 -66
- souleyez/ui/gap_analysis_view.py +315 -171
- souleyez/ui/help_system.py +105 -97
- souleyez/ui/intelligence_view.py +436 -293
- souleyez/ui/interactive.py +22827 -10678
- souleyez/ui/interactive_selector.py +75 -68
- souleyez/ui/log_formatter.py +47 -39
- souleyez/ui/menu_components.py +22 -13
- souleyez/ui/msf_auxiliary_menu.py +184 -133
- souleyez/ui/pending_chains_view.py +336 -172
- souleyez/ui/progress_indicators.py +5 -3
- souleyez/ui/recommendations_view.py +195 -137
- souleyez/ui/rule_builder.py +343 -225
- souleyez/ui/setup_wizard.py +678 -284
- souleyez/ui/shortcuts.py +217 -165
- souleyez/ui/splunk_gap_analysis_view.py +452 -270
- souleyez/ui/splunk_vulns_view.py +139 -86
- souleyez/ui/team_dashboard.py +498 -335
- souleyez/ui/template_selector.py +196 -105
- souleyez/ui/terminal.py +6 -6
- souleyez/ui/timeline_view.py +198 -127
- souleyez/ui/tool_setup.py +264 -164
- souleyez/ui/tutorial.py +202 -72
- souleyez/ui/tutorial_state.py +40 -40
- souleyez/ui/wazuh_vulns_view.py +235 -141
- souleyez/ui/wordlist_browser.py +260 -107
- souleyez/ui.py +464 -312
- souleyez/utils/tool_checker.py +427 -367
- souleyez/utils.py +33 -29
- souleyez/wordlists.py +134 -167
- {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/METADATA +1 -1
- souleyez-2.43.34.dist-info/RECORD +443 -0
- {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/WHEEL +1 -1
- souleyez-2.43.29.dist-info/RECORD +0 -379
- {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/entry_points.txt +0 -0
- {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/licenses/LICENSE +0 -0
- {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/top_level.txt +0 -0
|
@@ -13,18 +13,25 @@ def is_worker_running() -> Tuple[bool, Optional[int]]:
|
|
|
13
13
|
|
|
14
14
|
Returns: (is_running, pid)
|
|
15
15
|
"""
|
|
16
|
-
for proc in psutil.process_iter([
|
|
16
|
+
for proc in psutil.process_iter(["pid", "cmdline"]):
|
|
17
17
|
try:
|
|
18
|
-
cmdline = proc.info.get(
|
|
18
|
+
cmdline = proc.info.get("cmdline", [])
|
|
19
19
|
if not cmdline:
|
|
20
20
|
continue
|
|
21
|
-
cmdline_str =
|
|
21
|
+
cmdline_str = " ".join(str(arg) for arg in cmdline)
|
|
22
22
|
# Check for Python-based worker (dev mode)
|
|
23
|
-
if
|
|
24
|
-
|
|
23
|
+
if (
|
|
24
|
+
"souleyez.engine.background" in cmdline_str
|
|
25
|
+
and "worker_loop" in cmdline_str
|
|
26
|
+
):
|
|
27
|
+
return True, proc.info["pid"]
|
|
25
28
|
# Check for binary-based worker (compiled mode)
|
|
26
|
-
if
|
|
27
|
-
|
|
29
|
+
if (
|
|
30
|
+
"souleyez" in cmdline_str
|
|
31
|
+
and "worker" in cmdline_str
|
|
32
|
+
and "start" in cmdline_str
|
|
33
|
+
):
|
|
34
|
+
return True, proc.info["pid"]
|
|
28
35
|
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
|
29
36
|
continue
|
|
30
37
|
return False, None
|
|
@@ -42,9 +49,7 @@ def is_worker_healthy() -> Tuple[bool, Optional[int], Optional[str]]:
|
|
|
42
49
|
- pid: Worker PID if found, None otherwise
|
|
43
50
|
- issue: Description of issue if not healthy, None otherwise
|
|
44
51
|
"""
|
|
45
|
-
from souleyez.engine.background import
|
|
46
|
-
get_heartbeat_age, HEARTBEAT_STALE_THRESHOLD
|
|
47
|
-
)
|
|
52
|
+
from souleyez.engine.background import get_heartbeat_age, HEARTBEAT_STALE_THRESHOLD
|
|
48
53
|
|
|
49
54
|
is_running, pid = is_worker_running()
|
|
50
55
|
|
|
@@ -59,7 +64,11 @@ def is_worker_healthy() -> Tuple[bool, Optional[int], Optional[str]]:
|
|
|
59
64
|
return True, pid, "No heartbeat yet (may be starting)"
|
|
60
65
|
|
|
61
66
|
if heartbeat_age > HEARTBEAT_STALE_THRESHOLD:
|
|
62
|
-
return
|
|
67
|
+
return (
|
|
68
|
+
False,
|
|
69
|
+
pid,
|
|
70
|
+
f"Heartbeat stale ({int(heartbeat_age)}s old, threshold: {HEARTBEAT_STALE_THRESHOLD}s)",
|
|
71
|
+
)
|
|
63
72
|
|
|
64
73
|
return True, pid, None
|
|
65
74
|
|
|
@@ -76,6 +85,7 @@ def start_worker_if_needed() -> bool:
|
|
|
76
85
|
|
|
77
86
|
# Start the worker
|
|
78
87
|
from souleyez.engine.background import start_worker
|
|
88
|
+
|
|
79
89
|
start_worker(detach=True)
|
|
80
90
|
time.sleep(1) # Give it a moment to start
|
|
81
91
|
|
|
@@ -125,19 +135,19 @@ def get_worker_status() -> dict:
|
|
|
125
135
|
is_running, pid = is_worker_running()
|
|
126
136
|
|
|
127
137
|
status = {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
138
|
+
"running": is_running,
|
|
139
|
+
"pid": pid,
|
|
140
|
+
"uptime": None,
|
|
141
|
+
"cpu_percent": None,
|
|
142
|
+
"memory_mb": None,
|
|
133
143
|
}
|
|
134
144
|
|
|
135
145
|
if is_running and pid:
|
|
136
146
|
try:
|
|
137
147
|
proc = psutil.Process(pid)
|
|
138
|
-
status[
|
|
139
|
-
status[
|
|
140
|
-
status[
|
|
148
|
+
status["uptime"] = int(time.time() - proc.create_time())
|
|
149
|
+
status["cpu_percent"] = proc.cpu_percent(interval=0.1)
|
|
150
|
+
status["memory_mb"] = proc.memory_info().rss / 1024 / 1024
|
|
141
151
|
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
|
142
152
|
pass
|
|
143
153
|
|
|
@@ -159,47 +169,46 @@ def get_worker_health() -> Dict[str, Any]:
|
|
|
159
169
|
- cpu_percent: CPU usage percentage
|
|
160
170
|
- memory_mb: Memory usage in MB
|
|
161
171
|
"""
|
|
162
|
-
from souleyez.engine.background import
|
|
163
|
-
get_heartbeat_age, HEARTBEAT_STALE_THRESHOLD
|
|
164
|
-
)
|
|
172
|
+
from souleyez.engine.background import get_heartbeat_age, HEARTBEAT_STALE_THRESHOLD
|
|
165
173
|
|
|
166
174
|
is_running, pid = is_worker_running()
|
|
167
175
|
heartbeat_age = get_heartbeat_age()
|
|
168
176
|
|
|
169
177
|
health = {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
178
|
+
"running": is_running,
|
|
179
|
+
"healthy": False,
|
|
180
|
+
"pid": pid,
|
|
181
|
+
"uptime": None,
|
|
182
|
+
"heartbeat_age": heartbeat_age,
|
|
183
|
+
"heartbeat_stale": heartbeat_age is None
|
|
184
|
+
or heartbeat_age > HEARTBEAT_STALE_THRESHOLD,
|
|
185
|
+
"issue": None,
|
|
186
|
+
"cpu_percent": None,
|
|
187
|
+
"memory_mb": None,
|
|
179
188
|
}
|
|
180
189
|
|
|
181
190
|
if not is_running:
|
|
182
|
-
health[
|
|
191
|
+
health["issue"] = "Worker process not found"
|
|
183
192
|
return health
|
|
184
193
|
|
|
185
194
|
# Get process info
|
|
186
195
|
try:
|
|
187
196
|
proc = psutil.Process(pid)
|
|
188
|
-
health[
|
|
189
|
-
health[
|
|
190
|
-
health[
|
|
197
|
+
health["uptime"] = int(time.time() - proc.create_time())
|
|
198
|
+
health["cpu_percent"] = proc.cpu_percent(interval=0.1)
|
|
199
|
+
health["memory_mb"] = round(proc.memory_info().rss / 1024 / 1024, 1)
|
|
191
200
|
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
|
192
|
-
health[
|
|
201
|
+
health["issue"] = "Cannot access worker process"
|
|
193
202
|
return health
|
|
194
203
|
|
|
195
204
|
# Check heartbeat
|
|
196
205
|
if heartbeat_age is None:
|
|
197
|
-
health[
|
|
198
|
-
health[
|
|
206
|
+
health["issue"] = "No heartbeat yet (worker may be starting)"
|
|
207
|
+
health["healthy"] = True # Give benefit of doubt for new workers
|
|
199
208
|
elif heartbeat_age > HEARTBEAT_STALE_THRESHOLD:
|
|
200
|
-
health[
|
|
201
|
-
health[
|
|
209
|
+
health["issue"] = f"Worker unresponsive (heartbeat {int(heartbeat_age)}s old)"
|
|
210
|
+
health["healthy"] = False
|
|
202
211
|
else:
|
|
203
|
-
health[
|
|
212
|
+
health["healthy"] = True
|
|
204
213
|
|
|
205
214
|
return health
|
|
@@ -9,62 +9,68 @@ from datetime import datetime
|
|
|
9
9
|
from typing import Dict, List
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
def create_evidence_bundle(
|
|
12
|
+
def create_evidence_bundle(
|
|
13
|
+
engagement_id: int, engagement: Dict, evidence: Dict[str, List[Dict]]
|
|
14
|
+
) -> str:
|
|
13
15
|
"""
|
|
14
16
|
Create ZIP bundle of all evidence.
|
|
15
|
-
|
|
17
|
+
|
|
16
18
|
Returns:
|
|
17
19
|
Path to created ZIP file
|
|
18
20
|
"""
|
|
19
21
|
# Create output directory
|
|
20
22
|
output_dir = os.path.expanduser("~/.souleyez/exports")
|
|
21
23
|
os.makedirs(output_dir, exist_ok=True)
|
|
22
|
-
|
|
24
|
+
|
|
23
25
|
# Generate filename
|
|
24
26
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
25
|
-
safe_name =
|
|
27
|
+
safe_name = (
|
|
28
|
+
engagement["name"].replace(" ", "_").replace("/", "_").replace("\\", "_")
|
|
29
|
+
)
|
|
26
30
|
zip_filename = f"{safe_name}_evidence_{timestamp}.zip"
|
|
27
31
|
zip_path = os.path.join(output_dir, zip_filename)
|
|
28
|
-
|
|
32
|
+
|
|
29
33
|
# Create ZIP
|
|
30
|
-
with zipfile.ZipFile(zip_path,
|
|
34
|
+
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zipf:
|
|
31
35
|
# Add README
|
|
32
36
|
readme = generate_readme(engagement, evidence)
|
|
33
37
|
zipf.writestr("README.txt", readme)
|
|
34
|
-
|
|
38
|
+
|
|
35
39
|
# Add evidence by phase
|
|
36
40
|
for phase, items in evidence.items():
|
|
37
|
-
phase_dir = phase.replace(
|
|
38
|
-
|
|
41
|
+
phase_dir = phase.replace("_", "-")
|
|
42
|
+
|
|
39
43
|
# Create phase summary
|
|
40
44
|
phase_summary = generate_phase_summary(phase, items)
|
|
41
45
|
zipf.writestr(f"{phase_dir}/SUMMARY.txt", phase_summary)
|
|
42
|
-
|
|
46
|
+
|
|
43
47
|
for idx, item in enumerate(items, 1):
|
|
44
|
-
if item[
|
|
48
|
+
if item["type"] == "job":
|
|
45
49
|
# Add job log if exists
|
|
46
|
-
log_path = item.get(
|
|
50
|
+
log_path = item.get("log_path")
|
|
47
51
|
if log_path and os.path.exists(log_path):
|
|
48
|
-
safe_tool = item[
|
|
49
|
-
safe_target =
|
|
52
|
+
safe_tool = item["tool"].replace("/", "_")
|
|
53
|
+
safe_target = (
|
|
54
|
+
item["target"].replace("/", "_").replace(":", "_")[:50]
|
|
55
|
+
)
|
|
50
56
|
arcname = f"{phase_dir}/{idx:03d}_{safe_tool}_{safe_target}.log"
|
|
51
57
|
zipf.write(log_path, arcname)
|
|
52
|
-
|
|
58
|
+
|
|
53
59
|
# Add credentials file
|
|
54
60
|
creds_content = export_credentials(engagement_id)
|
|
55
61
|
if creds_content:
|
|
56
62
|
zipf.writestr("CREDENTIALS.txt", creds_content)
|
|
57
|
-
|
|
63
|
+
|
|
58
64
|
# Add findings file
|
|
59
65
|
findings_content = export_findings(engagement_id)
|
|
60
66
|
if findings_content:
|
|
61
67
|
zipf.writestr("FINDINGS.txt", findings_content)
|
|
62
|
-
|
|
68
|
+
|
|
63
69
|
# Add hosts summary
|
|
64
70
|
hosts_content = export_hosts(engagement_id)
|
|
65
71
|
if hosts_content:
|
|
66
72
|
zipf.writestr("HOSTS.txt", hosts_content)
|
|
67
|
-
|
|
73
|
+
|
|
68
74
|
return zip_path
|
|
69
75
|
|
|
70
76
|
|
|
@@ -77,18 +83,18 @@ def generate_readme(engagement: Dict, evidence: Dict[str, List[Dict]]) -> str:
|
|
|
77
83
|
lines.append(f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
|
78
84
|
lines.append(f"Engagement ID: {engagement['id']}")
|
|
79
85
|
lines.append("")
|
|
80
|
-
|
|
86
|
+
|
|
81
87
|
# Summary
|
|
82
88
|
total = sum(len(items) for items in evidence.values())
|
|
83
89
|
lines.append(f"Total Evidence Items: {total}")
|
|
84
90
|
lines.append("")
|
|
85
|
-
|
|
91
|
+
|
|
86
92
|
lines.append("Evidence by Phase:")
|
|
87
93
|
lines.append("-" * 70)
|
|
88
94
|
for phase, items in evidence.items():
|
|
89
|
-
phase_name = phase.replace(
|
|
95
|
+
phase_name = phase.replace("_", " ").title()
|
|
90
96
|
lines.append(f" {phase_name:30} {len(items):3} items")
|
|
91
|
-
|
|
97
|
+
|
|
92
98
|
lines.append("")
|
|
93
99
|
lines.append("=" * 70)
|
|
94
100
|
lines.append("")
|
|
@@ -131,151 +137,155 @@ def generate_readme(engagement: Dict, evidence: Dict[str, List[Dict]]) -> str:
|
|
|
131
137
|
lines.append("- Timestamps are in UTC")
|
|
132
138
|
lines.append("- Sensitive data (passwords) may be redacted")
|
|
133
139
|
lines.append("")
|
|
134
|
-
|
|
140
|
+
|
|
135
141
|
return "\n".join(lines)
|
|
136
142
|
|
|
137
143
|
|
|
138
144
|
def generate_phase_summary(phase: str, items: List[Dict]) -> str:
|
|
139
145
|
"""Generate summary for a phase."""
|
|
140
146
|
lines = []
|
|
141
|
-
phase_name = phase.replace(
|
|
142
|
-
|
|
147
|
+
phase_name = phase.replace("_", " ").upper()
|
|
148
|
+
|
|
143
149
|
lines.append("=" * 70)
|
|
144
150
|
lines.append(f"{phase_name} - EVIDENCE SUMMARY")
|
|
145
151
|
lines.append("=" * 70)
|
|
146
152
|
lines.append("")
|
|
147
153
|
lines.append(f"Total Items: {len(items)}")
|
|
148
154
|
lines.append("")
|
|
149
|
-
|
|
155
|
+
|
|
150
156
|
for idx, item in enumerate(items, 1):
|
|
151
157
|
lines.append(f"[{idx:03d}] {item['title']}")
|
|
152
158
|
lines.append(f" Tool: {item['tool']}")
|
|
153
159
|
lines.append(f" Target: {item['target']}")
|
|
154
160
|
lines.append(f" Date: {item['created_at']}")
|
|
155
161
|
lines.append(f" Description: {item['description']}")
|
|
156
|
-
|
|
157
|
-
if item[
|
|
162
|
+
|
|
163
|
+
if item["type"] == "finding":
|
|
158
164
|
lines.append(f" Severity: {item['severity'].upper()}")
|
|
159
|
-
elif item[
|
|
165
|
+
elif item["type"] == "credential":
|
|
160
166
|
lines.append(f" Type: Credential Discovery")
|
|
161
|
-
|
|
167
|
+
|
|
162
168
|
lines.append("")
|
|
163
|
-
|
|
169
|
+
|
|
164
170
|
return "\n".join(lines)
|
|
165
171
|
|
|
166
172
|
|
|
167
173
|
def export_credentials(engagement_id: int) -> str:
|
|
168
174
|
"""Export credentials as text."""
|
|
169
175
|
from souleyez.storage.credentials import CredentialsManager
|
|
170
|
-
|
|
176
|
+
|
|
171
177
|
cm = CredentialsManager()
|
|
172
178
|
creds = cm.list_credentials(engagement_id)
|
|
173
|
-
|
|
179
|
+
|
|
174
180
|
if not creds:
|
|
175
181
|
return ""
|
|
176
|
-
|
|
182
|
+
|
|
177
183
|
lines = []
|
|
178
184
|
lines.append("=" * 70)
|
|
179
185
|
lines.append("CREDENTIALS DISCOVERED")
|
|
180
186
|
lines.append("=" * 70)
|
|
181
187
|
lines.append(f"Total: {len(creds)} credentials")
|
|
182
188
|
lines.append("")
|
|
183
|
-
|
|
189
|
+
|
|
184
190
|
for idx, cred in enumerate(creds, 1):
|
|
185
|
-
lines.append(
|
|
191
|
+
lines.append(
|
|
192
|
+
f"[{idx:03d}] Host: {cred.get('host', 'N/A')}:{cred.get('port', '?')}"
|
|
193
|
+
)
|
|
186
194
|
lines.append(f" Service: {cred.get('service', 'unknown')}")
|
|
187
195
|
lines.append(f" Username: {cred.get('username', 'N/A')}")
|
|
188
196
|
lines.append(f" Status: {cred.get('status', 'unknown')}")
|
|
189
197
|
lines.append(f" Source: {cred.get('source', 'unknown')}")
|
|
190
198
|
lines.append(f" Created: {cred.get('created_at', 'N/A')}")
|
|
191
199
|
lines.append("-" * 70)
|
|
192
|
-
|
|
200
|
+
|
|
193
201
|
return "\n".join(lines)
|
|
194
202
|
|
|
195
203
|
|
|
196
204
|
def export_findings(engagement_id: int) -> str:
|
|
197
205
|
"""Export findings as text."""
|
|
198
206
|
from souleyez.storage.findings import FindingsManager
|
|
199
|
-
|
|
207
|
+
|
|
200
208
|
fm = FindingsManager()
|
|
201
209
|
findings = fm.list_findings(engagement_id)
|
|
202
|
-
|
|
210
|
+
|
|
203
211
|
if not findings:
|
|
204
212
|
return ""
|
|
205
|
-
|
|
213
|
+
|
|
206
214
|
lines = []
|
|
207
215
|
lines.append("=" * 70)
|
|
208
216
|
lines.append("SECURITY FINDINGS")
|
|
209
217
|
lines.append("=" * 70)
|
|
210
218
|
lines.append(f"Total: {len(findings)} findings")
|
|
211
219
|
lines.append("")
|
|
212
|
-
|
|
220
|
+
|
|
213
221
|
# Group by severity
|
|
214
222
|
by_severity = {}
|
|
215
223
|
for finding in findings:
|
|
216
|
-
sev = finding.get(
|
|
224
|
+
sev = finding.get("severity", "info")
|
|
217
225
|
if sev not in by_severity:
|
|
218
226
|
by_severity[sev] = []
|
|
219
227
|
by_severity[sev].append(finding)
|
|
220
|
-
|
|
221
|
-
for severity in [
|
|
228
|
+
|
|
229
|
+
for severity in ["critical", "high", "medium", "low", "info"]:
|
|
222
230
|
sev_findings = by_severity.get(severity, [])
|
|
223
231
|
if sev_findings:
|
|
224
232
|
lines.append(f"\n{severity.upper()}: {len(sev_findings)} findings")
|
|
225
233
|
lines.append("-" * 70)
|
|
226
|
-
|
|
234
|
+
|
|
227
235
|
for finding in sev_findings:
|
|
228
236
|
lines.append(f"\nTitle: {finding['title']}")
|
|
229
237
|
lines.append(f"Tool: {finding.get('tool', 'Unknown')}")
|
|
230
|
-
target = finding.get(
|
|
238
|
+
target = finding.get("host") or finding.get("url", "Unknown")
|
|
231
239
|
lines.append(f"Target: {target}")
|
|
232
|
-
|
|
233
|
-
if finding.get(
|
|
240
|
+
|
|
241
|
+
if finding.get("cve"):
|
|
234
242
|
lines.append(f"CVE: {finding['cve']}")
|
|
235
|
-
if finding.get(
|
|
243
|
+
if finding.get("cvss"):
|
|
236
244
|
lines.append(f"CVSS: {finding['cvss']}")
|
|
237
|
-
|
|
238
|
-
desc = finding.get(
|
|
245
|
+
|
|
246
|
+
desc = finding.get("description", "")
|
|
239
247
|
if desc:
|
|
240
248
|
lines.append(f"Description: {desc[:500]}")
|
|
241
|
-
|
|
249
|
+
|
|
242
250
|
lines.append("")
|
|
243
|
-
|
|
251
|
+
|
|
244
252
|
return "\n".join(lines)
|
|
245
253
|
|
|
246
254
|
|
|
247
255
|
def export_hosts(engagement_id: int) -> str:
|
|
248
256
|
"""Export hosts summary."""
|
|
249
257
|
from souleyez.storage.hosts import HostManager
|
|
250
|
-
|
|
258
|
+
|
|
251
259
|
hm = HostManager()
|
|
252
260
|
hosts = hm.list_hosts(engagement_id)
|
|
253
|
-
|
|
261
|
+
|
|
254
262
|
if not hosts:
|
|
255
263
|
return ""
|
|
256
|
-
|
|
264
|
+
|
|
257
265
|
lines = []
|
|
258
266
|
lines.append("=" * 70)
|
|
259
267
|
lines.append("DISCOVERED HOSTS")
|
|
260
268
|
lines.append("=" * 70)
|
|
261
269
|
lines.append(f"Total: {len(hosts)} hosts")
|
|
262
270
|
lines.append("")
|
|
263
|
-
|
|
271
|
+
|
|
264
272
|
for host in hosts:
|
|
265
273
|
lines.append(f"Host: {host.get('ip', 'N/A')}")
|
|
266
274
|
lines.append(f" Hostname: {host.get('hostname', 'N/A')}")
|
|
267
275
|
lines.append(f" Status: {host.get('status', 'unknown')}")
|
|
268
276
|
lines.append(f" OS: {host.get('os', 'Unknown')}")
|
|
269
|
-
|
|
277
|
+
|
|
270
278
|
# Get services count
|
|
271
|
-
services = host.get(
|
|
279
|
+
services = host.get("services", [])
|
|
272
280
|
if services:
|
|
273
281
|
lines.append(f" Services: {len(services)}")
|
|
274
282
|
for svc in services[:5]: # First 5 services
|
|
275
|
-
lines.append(
|
|
283
|
+
lines.append(
|
|
284
|
+
f" - {svc.get('port', '?')}/{svc.get('protocol', 'tcp')}: {svc.get('service', 'unknown')}"
|
|
285
|
+
)
|
|
276
286
|
if len(services) > 5:
|
|
277
287
|
lines.append(f" (and {len(services) - 5} more...)")
|
|
278
|
-
|
|
288
|
+
|
|
279
289
|
lines.append("")
|
|
280
|
-
|
|
290
|
+
|
|
281
291
|
return "\n".join(lines)
|
|
@@ -11,11 +11,12 @@ from typing import Dict, Optional
|
|
|
11
11
|
|
|
12
12
|
class FeatureStatus(Enum):
|
|
13
13
|
"""Status of a feature."""
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
|
|
15
|
+
ENABLED = "enabled" # Feature is fully implemented and available
|
|
16
|
+
DISABLED = "disabled" # Feature is hidden from users
|
|
17
|
+
BETA = "beta" # Feature is available but marked as beta
|
|
18
|
+
DEVELOPMENT = "development" # Feature is under development (hidden in production)
|
|
19
|
+
PRO = "pro" # Feature requires Pro tier
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
class Feature(Enum):
|
|
@@ -62,28 +63,23 @@ class FeatureFlags:
|
|
|
62
63
|
# Export Features - Placeholder implementations
|
|
63
64
|
Feature.JSON_EXPORT: FeatureStatus.DISABLED,
|
|
64
65
|
Feature.HOSTS_SERVICES_EXPORT: FeatureStatus.DISABLED,
|
|
65
|
-
|
|
66
66
|
# Import Features - Placeholder implementations
|
|
67
67
|
Feature.NMAP_XML_IMPORT: FeatureStatus.DISABLED,
|
|
68
68
|
Feature.NESSUS_IMPORT: FeatureStatus.DISABLED,
|
|
69
|
-
|
|
70
69
|
# Analysis Features
|
|
71
|
-
Feature.EVIDENCE_LINKING: FeatureStatus.ENABLED,
|
|
72
|
-
Feature.CORRELATION_ENGINE: FeatureStatus.PRO,
|
|
73
|
-
Feature.ATTACK_SURFACE: FeatureStatus.PRO,
|
|
74
|
-
Feature.EXPLOIT_SUGGESTIONS: FeatureStatus.PRO,
|
|
75
|
-
|
|
70
|
+
Feature.EVIDENCE_LINKING: FeatureStatus.ENABLED, # FREE - basic feature
|
|
71
|
+
Feature.CORRELATION_ENGINE: FeatureStatus.PRO, # PRO - advanced analysis
|
|
72
|
+
Feature.ATTACK_SURFACE: FeatureStatus.PRO, # PRO - priority scoring
|
|
73
|
+
Feature.EXPLOIT_SUGGESTIONS: FeatureStatus.PRO, # PRO - CVE/MSF recommendations
|
|
76
74
|
# Dashboard Features
|
|
77
|
-
Feature.TEAM_DASHBOARD: FeatureStatus.PRO,
|
|
78
|
-
Feature.TIMELINE_VIEW: FeatureStatus.ENABLED,
|
|
79
|
-
|
|
75
|
+
Feature.TEAM_DASHBOARD: FeatureStatus.PRO, # PRO - collaboration
|
|
76
|
+
Feature.TIMELINE_VIEW: FeatureStatus.ENABLED, # FREE - basic timeline
|
|
80
77
|
# Reporting Features
|
|
81
|
-
Feature.DELIVERABLES: FeatureStatus.ENABLED,
|
|
82
|
-
Feature.EXPORT_VIEW: FeatureStatus.PRO,
|
|
83
|
-
|
|
78
|
+
Feature.DELIVERABLES: FeatureStatus.ENABLED, # FREE - basic tracking
|
|
79
|
+
Feature.EXPORT_VIEW: FeatureStatus.PRO, # PRO - report export
|
|
84
80
|
# Advanced Features
|
|
85
|
-
Feature.AUTO_CHAINING: FeatureStatus.PRO,
|
|
86
|
-
Feature.AI_RECOMMENDATIONS: FeatureStatus.PRO,
|
|
81
|
+
Feature.AUTO_CHAINING: FeatureStatus.PRO, # PRO - automation
|
|
82
|
+
Feature.AI_RECOMMENDATIONS: FeatureStatus.PRO, # PRO - AI features
|
|
87
83
|
}
|
|
88
84
|
|
|
89
85
|
@classmethod
|
souleyez/feature_flags.py
CHANGED
|
@@ -11,10 +11,11 @@ from typing import Dict, Optional
|
|
|
11
11
|
|
|
12
12
|
class FeatureStatus(Enum):
|
|
13
13
|
"""Status of a feature."""
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
|
|
15
|
+
ENABLED = "enabled" # Feature is fully implemented and available
|
|
16
|
+
DISABLED = "disabled" # Feature is hidden from users
|
|
17
|
+
BETA = "beta" # Feature is available but marked as beta
|
|
18
|
+
DEVELOPMENT = "development" # Feature is under development (hidden in production)
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
class Feature(Enum):
|
|
@@ -61,25 +62,20 @@ class FeatureFlags:
|
|
|
61
62
|
# Export Features - Placeholder implementations
|
|
62
63
|
Feature.JSON_EXPORT: FeatureStatus.DISABLED,
|
|
63
64
|
Feature.HOSTS_SERVICES_EXPORT: FeatureStatus.DISABLED,
|
|
64
|
-
|
|
65
65
|
# Import Features - Placeholder implementations
|
|
66
66
|
Feature.NMAP_XML_IMPORT: FeatureStatus.DISABLED,
|
|
67
67
|
Feature.NESSUS_IMPORT: FeatureStatus.DISABLED,
|
|
68
|
-
|
|
69
68
|
# Analysis Features - Implemented
|
|
70
69
|
Feature.EVIDENCE_LINKING: FeatureStatus.ENABLED,
|
|
71
70
|
Feature.CORRELATION_ENGINE: FeatureStatus.ENABLED,
|
|
72
71
|
Feature.ATTACK_SURFACE: FeatureStatus.ENABLED,
|
|
73
72
|
Feature.EXPLOIT_SUGGESTIONS: FeatureStatus.ENABLED,
|
|
74
|
-
|
|
75
73
|
# Dashboard Features - Implemented
|
|
76
74
|
Feature.TEAM_DASHBOARD: FeatureStatus.ENABLED,
|
|
77
75
|
Feature.TIMELINE_VIEW: FeatureStatus.ENABLED,
|
|
78
|
-
|
|
79
76
|
# Reporting Features - Implemented
|
|
80
77
|
Feature.DELIVERABLES: FeatureStatus.ENABLED,
|
|
81
78
|
Feature.EXPORT_VIEW: FeatureStatus.ENABLED,
|
|
82
|
-
|
|
83
79
|
# Advanced Features
|
|
84
80
|
Feature.AUTO_CHAINING: FeatureStatus.ENABLED,
|
|
85
81
|
Feature.AI_RECOMMENDATIONS: FeatureStatus.ENABLED,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Tool handlers package.
|
|
4
|
+
|
|
5
|
+
Each tool has a handler class that consolidates:
|
|
6
|
+
- Parsing logic (from result_handler.py)
|
|
7
|
+
- Display logic (from interactive.py)
|
|
8
|
+
- Capability flags (replaces manual lists)
|
|
9
|
+
|
|
10
|
+
Auto-discovery: Handlers are registered automatically when imported.
|
|
11
|
+
"""
|