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
souleyez/ai/safety.py
CHANGED
|
@@ -10,6 +10,7 @@ from souleyez.ui.design_system import DesignSystem
|
|
|
10
10
|
|
|
11
11
|
class RiskLevel(Enum):
|
|
12
12
|
"""Risk levels for actions."""
|
|
13
|
+
|
|
13
14
|
LOW = "LOW"
|
|
14
15
|
MEDIUM = "MEDIUM"
|
|
15
16
|
HIGH = "HIGH"
|
|
@@ -17,23 +18,24 @@ class RiskLevel(Enum):
|
|
|
17
18
|
|
|
18
19
|
class ApprovalMode(Enum):
|
|
19
20
|
"""Approval modes."""
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
|
|
22
|
+
MANUAL = "manual" # Ask for every action
|
|
23
|
+
AUTO_LOW = "auto_low" # Auto-approve LOW only
|
|
24
|
+
AUTO_MEDIUM = "auto_medium" # Auto-approve LOW + MEDIUM
|
|
25
|
+
DRY_RUN = "dry_run" # Show but don't execute
|
|
24
26
|
|
|
25
27
|
|
|
26
28
|
class SafetyFramework:
|
|
27
29
|
"""
|
|
28
30
|
Safety framework for command execution.
|
|
29
|
-
|
|
31
|
+
|
|
30
32
|
Handles risk assessment and approval prompts.
|
|
31
33
|
"""
|
|
32
34
|
|
|
33
35
|
def __init__(self, approval_mode: ApprovalMode = ApprovalMode.MANUAL):
|
|
34
36
|
"""
|
|
35
37
|
Initialize safety framework.
|
|
36
|
-
|
|
38
|
+
|
|
37
39
|
Args:
|
|
38
40
|
approval_mode: How to handle approvals
|
|
39
41
|
"""
|
|
@@ -42,11 +44,11 @@ class SafetyFramework:
|
|
|
42
44
|
def assess_risk(self, action: str, command: str) -> RiskLevel:
|
|
43
45
|
"""
|
|
44
46
|
Assess risk level of an action.
|
|
45
|
-
|
|
47
|
+
|
|
46
48
|
Args:
|
|
47
49
|
action: AI recommendation action text
|
|
48
50
|
command: Actual command to execute
|
|
49
|
-
|
|
51
|
+
|
|
50
52
|
Returns:
|
|
51
53
|
RiskLevel enum
|
|
52
54
|
"""
|
|
@@ -58,9 +60,20 @@ class SafetyFramework:
|
|
|
58
60
|
|
|
59
61
|
# HIGH risk patterns
|
|
60
62
|
high_risk_patterns = [
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
"rm ",
|
|
64
|
+
"delete",
|
|
65
|
+
"drop",
|
|
66
|
+
"exploit",
|
|
67
|
+
"payload",
|
|
68
|
+
"shell",
|
|
69
|
+
"reverse",
|
|
70
|
+
"meterpreter",
|
|
71
|
+
"privilege",
|
|
72
|
+
"escalat",
|
|
73
|
+
"root",
|
|
74
|
+
"admin",
|
|
75
|
+
"sudo",
|
|
76
|
+
"persistence",
|
|
64
77
|
]
|
|
65
78
|
|
|
66
79
|
for pattern in high_risk_patterns:
|
|
@@ -69,8 +82,14 @@ class SafetyFramework:
|
|
|
69
82
|
|
|
70
83
|
# MEDIUM risk patterns
|
|
71
84
|
medium_risk_patterns = [
|
|
72
|
-
|
|
73
|
-
|
|
85
|
+
"password",
|
|
86
|
+
"credential",
|
|
87
|
+
"login",
|
|
88
|
+
"auth",
|
|
89
|
+
"brute",
|
|
90
|
+
"test",
|
|
91
|
+
"try",
|
|
92
|
+
"attempt",
|
|
74
93
|
]
|
|
75
94
|
|
|
76
95
|
for pattern in medium_risk_patterns:
|
|
@@ -81,38 +100,44 @@ class SafetyFramework:
|
|
|
81
100
|
return RiskLevel.LOW
|
|
82
101
|
|
|
83
102
|
def require_approval(
|
|
84
|
-
self,
|
|
85
|
-
action: str,
|
|
86
|
-
target: str,
|
|
87
|
-
command: str,
|
|
88
|
-
risk_level: RiskLevel
|
|
103
|
+
self, action: str, target: str, command: str, risk_level: RiskLevel
|
|
89
104
|
) -> bool:
|
|
90
105
|
"""
|
|
91
106
|
Check if action requires approval and prompt user if needed.
|
|
92
|
-
|
|
107
|
+
|
|
93
108
|
Args:
|
|
94
109
|
action: Human-readable action description
|
|
95
110
|
target: Target of the action
|
|
96
111
|
command: Actual command to execute
|
|
97
112
|
risk_level: Assessed risk level
|
|
98
|
-
|
|
113
|
+
|
|
99
114
|
Returns:
|
|
100
115
|
True if approved (execute), False if rejected
|
|
101
116
|
"""
|
|
102
117
|
# Dry-run mode: never execute
|
|
103
118
|
if self.approval_mode == ApprovalMode.DRY_RUN:
|
|
104
|
-
click.echo(
|
|
119
|
+
click.echo(
|
|
120
|
+
click.style("\n[DRY-RUN] Would execute but skipping", fg="yellow")
|
|
121
|
+
)
|
|
105
122
|
return False
|
|
106
123
|
|
|
107
124
|
# Auto-approval logic
|
|
108
125
|
if self.approval_mode == ApprovalMode.AUTO_MEDIUM:
|
|
109
126
|
if risk_level in [RiskLevel.LOW, RiskLevel.MEDIUM]:
|
|
110
|
-
click.echo(
|
|
127
|
+
click.echo(
|
|
128
|
+
click.style(
|
|
129
|
+
f"\n✅ {risk_level.value} risk - Auto-approved\n", fg="green"
|
|
130
|
+
)
|
|
131
|
+
)
|
|
111
132
|
return True
|
|
112
133
|
|
|
113
134
|
if self.approval_mode == ApprovalMode.AUTO_LOW:
|
|
114
135
|
if risk_level == RiskLevel.LOW:
|
|
115
|
-
click.echo(
|
|
136
|
+
click.echo(
|
|
137
|
+
click.style(
|
|
138
|
+
f"\n✅ {risk_level.value} risk - Auto-approved\n", fg="green"
|
|
139
|
+
)
|
|
140
|
+
)
|
|
116
141
|
return True
|
|
117
142
|
|
|
118
143
|
# Manual approval required
|
|
@@ -120,45 +145,43 @@ class SafetyFramework:
|
|
|
120
145
|
|
|
121
146
|
while True:
|
|
122
147
|
choice = click.prompt(
|
|
123
|
-
click.style("\nExecute this command?", fg=
|
|
124
|
-
type=click.Choice([
|
|
125
|
-
show_choices=True
|
|
148
|
+
click.style("\nExecute this command?", fg="yellow"),
|
|
149
|
+
type=click.Choice(["y", "n", "skip", "abort"], case_sensitive=False),
|
|
150
|
+
show_choices=True,
|
|
126
151
|
)
|
|
127
152
|
|
|
128
|
-
if choice ==
|
|
153
|
+
if choice == "y":
|
|
129
154
|
return True
|
|
130
|
-
elif choice ==
|
|
131
|
-
click.echo(click.style("⏭ Skipped", fg=
|
|
155
|
+
elif choice == "n" or choice == "skip":
|
|
156
|
+
click.echo(click.style("⏭ Skipped", fg="yellow"))
|
|
132
157
|
return False
|
|
133
|
-
elif choice ==
|
|
134
|
-
click.echo(click.style("\n🛑 Execution aborted by user", fg=
|
|
158
|
+
elif choice == "abort":
|
|
159
|
+
click.echo(click.style("\n🛑 Execution aborted by user", fg="red"))
|
|
135
160
|
raise KeyboardInterrupt("User aborted execution")
|
|
136
161
|
|
|
137
162
|
def _show_approval_prompt(
|
|
138
|
-
self,
|
|
139
|
-
action: str,
|
|
140
|
-
target: str,
|
|
141
|
-
command: str,
|
|
142
|
-
risk_level: RiskLevel
|
|
163
|
+
self, action: str, target: str, command: str, risk_level: RiskLevel
|
|
143
164
|
):
|
|
144
165
|
"""Show formatted approval prompt."""
|
|
145
166
|
# Risk indicator
|
|
146
167
|
if risk_level == RiskLevel.HIGH:
|
|
147
|
-
risk_color =
|
|
148
|
-
risk_icon =
|
|
168
|
+
risk_color = "red"
|
|
169
|
+
risk_icon = "🚨"
|
|
149
170
|
elif risk_level == RiskLevel.MEDIUM:
|
|
150
|
-
risk_color =
|
|
151
|
-
risk_icon =
|
|
171
|
+
risk_color = "yellow"
|
|
172
|
+
risk_icon = "⚠️ "
|
|
152
173
|
else:
|
|
153
|
-
risk_color =
|
|
154
|
-
risk_icon =
|
|
174
|
+
risk_color = "green"
|
|
175
|
+
risk_icon = "ℹ️ "
|
|
155
176
|
|
|
156
177
|
click.echo()
|
|
157
178
|
click.echo(DesignSystem.separator(60))
|
|
158
|
-
click.echo(
|
|
179
|
+
click.echo(
|
|
180
|
+
f"{risk_icon} {click.style(f'{risk_level.value} RISK', fg=risk_color, bold=True)} - Approval Required"
|
|
181
|
+
)
|
|
159
182
|
click.echo(DesignSystem.separator(60))
|
|
160
183
|
click.echo(f"ACTION: {action}")
|
|
161
184
|
click.echo(f"TARGET: {target}")
|
|
162
185
|
click.echo(f"\n📋 Command to execute:")
|
|
163
|
-
click.echo(click.style(f" {command}", fg=
|
|
186
|
+
click.echo(click.style(f" {command}", fg="cyan", bold=True))
|
|
164
187
|
click.echo(DesignSystem.separator(60))
|
souleyez/auth/__init__.py
CHANGED
|
@@ -9,6 +9,7 @@ Usage:
|
|
|
9
9
|
# Pro feature access
|
|
10
10
|
pass
|
|
11
11
|
"""
|
|
12
|
+
|
|
12
13
|
from .permissions import (
|
|
13
14
|
Role,
|
|
14
15
|
Tier,
|
|
@@ -63,29 +64,29 @@ def is_pro() -> bool:
|
|
|
63
64
|
|
|
64
65
|
__all__ = [
|
|
65
66
|
# Classes
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
67
|
+
"Role",
|
|
68
|
+
"Tier",
|
|
69
|
+
"Permission",
|
|
70
|
+
"PermissionChecker",
|
|
71
|
+
"User",
|
|
72
|
+
"UserManager",
|
|
73
|
+
"Session",
|
|
74
|
+
"SessionManager",
|
|
75
|
+
"AuditLogger",
|
|
76
|
+
"AuditAction",
|
|
76
77
|
# Decorators
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
"requires_permission",
|
|
79
|
+
"requires_pro",
|
|
80
|
+
"requires_role",
|
|
80
81
|
# Functions
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
82
|
+
"init_auth",
|
|
83
|
+
"get_session_manager",
|
|
84
|
+
"get_current_user",
|
|
85
|
+
"is_logged_in",
|
|
86
|
+
"is_pro",
|
|
87
|
+
"audit_log",
|
|
88
|
+
"get_audit_logger",
|
|
88
89
|
# Constants
|
|
89
|
-
|
|
90
|
-
|
|
90
|
+
"PRO_TIER_PERMISSIONS",
|
|
91
|
+
"ROLE_PERMISSIONS",
|
|
91
92
|
]
|
souleyez/auth/audit.py
CHANGED
|
@@ -4,6 +4,7 @@ souleyez.auth.audit - Centralized audit logging
|
|
|
4
4
|
All sensitive actions should be logged through this module.
|
|
5
5
|
Logs are immutable and include user context automatically.
|
|
6
6
|
"""
|
|
7
|
+
|
|
7
8
|
import sqlite3
|
|
8
9
|
import json
|
|
9
10
|
from datetime import datetime, timedelta
|
|
@@ -15,6 +16,7 @@ from souleyez.storage.database import get_db
|
|
|
15
16
|
|
|
16
17
|
class AuditAction(Enum):
|
|
17
18
|
"""All auditable actions in the system."""
|
|
19
|
+
|
|
18
20
|
# User actions
|
|
19
21
|
USER_LOGIN = "user.login"
|
|
20
22
|
USER_LOGOUT = "user.logout"
|
|
@@ -110,7 +112,7 @@ class AuditLogger:
|
|
|
110
112
|
resource_id: Optional[str] = None,
|
|
111
113
|
details: Optional[Dict[str, Any]] = None,
|
|
112
114
|
ip_address: Optional[str] = None,
|
|
113
|
-
success: bool = True
|
|
115
|
+
success: bool = True,
|
|
114
116
|
):
|
|
115
117
|
"""
|
|
116
118
|
Log an audit event.
|
|
@@ -129,6 +131,7 @@ class AuditLogger:
|
|
|
129
131
|
if user_id is None or username is None:
|
|
130
132
|
try:
|
|
131
133
|
from souleyez.auth import get_current_user
|
|
134
|
+
|
|
132
135
|
user = get_current_user()
|
|
133
136
|
if user:
|
|
134
137
|
user_id = user_id or user.id
|
|
@@ -141,21 +144,24 @@ class AuditLogger:
|
|
|
141
144
|
|
|
142
145
|
try:
|
|
143
146
|
conn = sqlite3.connect(self.db_path)
|
|
144
|
-
conn.execute(
|
|
147
|
+
conn.execute(
|
|
148
|
+
"""
|
|
145
149
|
INSERT INTO audit_log
|
|
146
150
|
(timestamp, user_id, username, action, resource_type, resource_id, details, ip_address, success)
|
|
147
151
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
148
|
-
""",
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
152
|
+
""",
|
|
153
|
+
(
|
|
154
|
+
datetime.now().isoformat(),
|
|
155
|
+
user_id,
|
|
156
|
+
username,
|
|
157
|
+
action.value,
|
|
158
|
+
resource_type,
|
|
159
|
+
str(resource_id) if resource_id else None,
|
|
160
|
+
details_json,
|
|
161
|
+
ip_address,
|
|
162
|
+
success,
|
|
163
|
+
),
|
|
164
|
+
)
|
|
159
165
|
conn.commit()
|
|
160
166
|
conn.close()
|
|
161
167
|
except Exception:
|
|
@@ -167,11 +173,11 @@ class AuditLogger:
|
|
|
167
173
|
action: AuditAction,
|
|
168
174
|
ip_address: Optional[str] = None,
|
|
169
175
|
details: Optional[Dict[str, Any]] = None,
|
|
170
|
-
success: bool = True
|
|
176
|
+
success: bool = True,
|
|
171
177
|
):
|
|
172
178
|
"""
|
|
173
179
|
Log vault events (no user_id since pre-login).
|
|
174
|
-
|
|
180
|
+
|
|
175
181
|
Args:
|
|
176
182
|
action: Vault action being logged
|
|
177
183
|
ip_address: Client IP address
|
|
@@ -185,7 +191,7 @@ class AuditLogger:
|
|
|
185
191
|
resource_type="vault",
|
|
186
192
|
details=details,
|
|
187
193
|
ip_address=ip_address,
|
|
188
|
-
success=success
|
|
194
|
+
success=success,
|
|
189
195
|
)
|
|
190
196
|
|
|
191
197
|
def query(
|
|
@@ -198,7 +204,7 @@ class AuditLogger:
|
|
|
198
204
|
end_date: Optional[datetime] = None,
|
|
199
205
|
success_only: bool = False,
|
|
200
206
|
limit: int = 100,
|
|
201
|
-
offset: int = 0
|
|
207
|
+
offset: int = 0,
|
|
202
208
|
) -> List[Dict[str, Any]]:
|
|
203
209
|
"""
|
|
204
210
|
Query audit logs with filters.
|
|
@@ -251,8 +257,9 @@ class AuditLogger:
|
|
|
251
257
|
"""Get audit log statistics for the last N days."""
|
|
252
258
|
conn = sqlite3.connect(self.db_path)
|
|
253
259
|
|
|
254
|
-
cutoff = (
|
|
255
|
-
|
|
260
|
+
cutoff = (
|
|
261
|
+
datetime.now().replace(hour=0, minute=0, second=0) - timedelta(days=days)
|
|
262
|
+
).isoformat()
|
|
256
263
|
|
|
257
264
|
# Total events
|
|
258
265
|
total = conn.execute(
|
|
@@ -260,7 +267,8 @@ class AuditLogger:
|
|
|
260
267
|
).fetchone()[0]
|
|
261
268
|
|
|
262
269
|
# Events by action category
|
|
263
|
-
by_category = conn.execute(
|
|
270
|
+
by_category = conn.execute(
|
|
271
|
+
"""
|
|
264
272
|
SELECT
|
|
265
273
|
SUBSTR(action, 1, INSTR(action, '.') - 1) as category,
|
|
266
274
|
COUNT(*) as count
|
|
@@ -268,18 +276,20 @@ class AuditLogger:
|
|
|
268
276
|
WHERE timestamp >= ?
|
|
269
277
|
GROUP BY category
|
|
270
278
|
ORDER BY count DESC
|
|
271
|
-
""",
|
|
279
|
+
""",
|
|
280
|
+
(cutoff,),
|
|
281
|
+
).fetchall()
|
|
272
282
|
|
|
273
283
|
# Failed events
|
|
274
284
|
failed = conn.execute(
|
|
275
285
|
"SELECT COUNT(*) FROM audit_log WHERE timestamp >= ? AND success = 0",
|
|
276
|
-
(cutoff,)
|
|
286
|
+
(cutoff,),
|
|
277
287
|
).fetchone()[0]
|
|
278
288
|
|
|
279
289
|
# Unique users
|
|
280
290
|
users = conn.execute(
|
|
281
291
|
"SELECT COUNT(DISTINCT user_id) FROM audit_log WHERE timestamp >= ?",
|
|
282
|
-
(cutoff,)
|
|
292
|
+
(cutoff,),
|
|
283
293
|
).fetchone()[0]
|
|
284
294
|
|
|
285
295
|
conn.close()
|
|
@@ -289,7 +299,7 @@ class AuditLogger:
|
|
|
289
299
|
"failed_events": failed,
|
|
290
300
|
"unique_users": users,
|
|
291
301
|
"by_category": {row[0]: row[1] for row in by_category},
|
|
292
|
-
"period_days": days
|
|
302
|
+
"period_days": days,
|
|
293
303
|
}
|
|
294
304
|
|
|
295
305
|
|
|
@@ -310,7 +320,7 @@ def audit_log(
|
|
|
310
320
|
resource_type: Optional[str] = None,
|
|
311
321
|
resource_id: Optional[str] = None,
|
|
312
322
|
details: Optional[Dict[str, Any]] = None,
|
|
313
|
-
success: bool = True
|
|
323
|
+
success: bool = True,
|
|
314
324
|
):
|
|
315
325
|
"""
|
|
316
326
|
Convenience function for audit logging.
|
|
@@ -323,5 +333,5 @@ def audit_log(
|
|
|
323
333
|
resource_type=resource_type,
|
|
324
334
|
resource_id=resource_id,
|
|
325
335
|
details=details,
|
|
326
|
-
success=success
|
|
336
|
+
success=success,
|
|
327
337
|
)
|