crackerjack 0.32.0__py3-none-any.whl → 0.33.1__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.
Potentially problematic release.
This version of crackerjack might be problematic. Click here for more details.
- crackerjack/__main__.py +1350 -34
- crackerjack/adapters/__init__.py +17 -0
- crackerjack/adapters/lsp_client.py +358 -0
- crackerjack/adapters/rust_tool_adapter.py +194 -0
- crackerjack/adapters/rust_tool_manager.py +193 -0
- crackerjack/adapters/skylos_adapter.py +231 -0
- crackerjack/adapters/zuban_adapter.py +560 -0
- crackerjack/agents/base.py +7 -3
- crackerjack/agents/coordinator.py +271 -33
- crackerjack/agents/documentation_agent.py +9 -15
- crackerjack/agents/dry_agent.py +3 -15
- crackerjack/agents/formatting_agent.py +1 -1
- crackerjack/agents/import_optimization_agent.py +36 -180
- crackerjack/agents/performance_agent.py +17 -98
- crackerjack/agents/performance_helpers.py +7 -31
- crackerjack/agents/proactive_agent.py +1 -3
- crackerjack/agents/refactoring_agent.py +16 -85
- crackerjack/agents/refactoring_helpers.py +7 -42
- crackerjack/agents/security_agent.py +9 -48
- crackerjack/agents/test_creation_agent.py +356 -513
- crackerjack/agents/test_specialist_agent.py +0 -4
- crackerjack/api.py +6 -25
- crackerjack/cli/cache_handlers.py +204 -0
- crackerjack/cli/cache_handlers_enhanced.py +683 -0
- crackerjack/cli/facade.py +100 -0
- crackerjack/cli/handlers.py +224 -9
- crackerjack/cli/interactive.py +6 -4
- crackerjack/cli/options.py +642 -55
- crackerjack/cli/utils.py +2 -1
- crackerjack/code_cleaner.py +58 -117
- crackerjack/config/global_lock_config.py +8 -48
- crackerjack/config/hooks.py +53 -62
- crackerjack/core/async_workflow_orchestrator.py +24 -34
- crackerjack/core/autofix_coordinator.py +3 -17
- crackerjack/core/enhanced_container.py +64 -6
- crackerjack/core/file_lifecycle.py +12 -89
- crackerjack/core/performance.py +2 -2
- crackerjack/core/performance_monitor.py +15 -55
- crackerjack/core/phase_coordinator.py +257 -218
- crackerjack/core/resource_manager.py +14 -90
- crackerjack/core/service_watchdog.py +62 -95
- crackerjack/core/session_coordinator.py +149 -0
- crackerjack/core/timeout_manager.py +14 -72
- crackerjack/core/websocket_lifecycle.py +13 -78
- crackerjack/core/workflow_orchestrator.py +558 -240
- crackerjack/docs/INDEX.md +11 -0
- crackerjack/docs/generated/api/API_REFERENCE.md +10895 -0
- crackerjack/docs/generated/api/CLI_REFERENCE.md +109 -0
- crackerjack/docs/generated/api/CROSS_REFERENCES.md +1755 -0
- crackerjack/docs/generated/api/PROTOCOLS.md +3 -0
- crackerjack/docs/generated/api/SERVICES.md +1252 -0
- crackerjack/documentation/__init__.py +31 -0
- crackerjack/documentation/ai_templates.py +756 -0
- crackerjack/documentation/dual_output_generator.py +765 -0
- crackerjack/documentation/mkdocs_integration.py +518 -0
- crackerjack/documentation/reference_generator.py +977 -0
- crackerjack/dynamic_config.py +55 -50
- crackerjack/executors/async_hook_executor.py +10 -15
- crackerjack/executors/cached_hook_executor.py +117 -43
- crackerjack/executors/hook_executor.py +8 -34
- crackerjack/executors/hook_lock_manager.py +26 -183
- crackerjack/executors/individual_hook_executor.py +13 -11
- crackerjack/executors/lsp_aware_hook_executor.py +270 -0
- crackerjack/executors/tool_proxy.py +417 -0
- crackerjack/hooks/lsp_hook.py +79 -0
- crackerjack/intelligence/adaptive_learning.py +25 -10
- crackerjack/intelligence/agent_orchestrator.py +2 -5
- crackerjack/intelligence/agent_registry.py +34 -24
- crackerjack/intelligence/agent_selector.py +5 -7
- crackerjack/interactive.py +17 -6
- crackerjack/managers/async_hook_manager.py +0 -1
- crackerjack/managers/hook_manager.py +79 -1
- crackerjack/managers/publish_manager.py +66 -13
- crackerjack/managers/test_command_builder.py +5 -17
- crackerjack/managers/test_executor.py +1 -3
- crackerjack/managers/test_manager.py +109 -7
- crackerjack/managers/test_manager_backup.py +10 -9
- crackerjack/mcp/cache.py +2 -2
- crackerjack/mcp/client_runner.py +1 -1
- crackerjack/mcp/context.py +191 -68
- crackerjack/mcp/dashboard.py +7 -5
- crackerjack/mcp/enhanced_progress_monitor.py +31 -28
- crackerjack/mcp/file_monitor.py +30 -23
- crackerjack/mcp/progress_components.py +31 -21
- crackerjack/mcp/progress_monitor.py +50 -53
- crackerjack/mcp/rate_limiter.py +6 -6
- crackerjack/mcp/server_core.py +161 -32
- crackerjack/mcp/service_watchdog.py +2 -1
- crackerjack/mcp/state.py +4 -7
- crackerjack/mcp/task_manager.py +11 -9
- crackerjack/mcp/tools/core_tools.py +174 -33
- crackerjack/mcp/tools/error_analyzer.py +3 -2
- crackerjack/mcp/tools/execution_tools.py +15 -12
- crackerjack/mcp/tools/execution_tools_backup.py +42 -30
- crackerjack/mcp/tools/intelligence_tool_registry.py +7 -5
- crackerjack/mcp/tools/intelligence_tools.py +5 -2
- crackerjack/mcp/tools/monitoring_tools.py +33 -70
- crackerjack/mcp/tools/proactive_tools.py +24 -11
- crackerjack/mcp/tools/progress_tools.py +5 -8
- crackerjack/mcp/tools/utility_tools.py +20 -14
- crackerjack/mcp/tools/workflow_executor.py +62 -40
- crackerjack/mcp/websocket/app.py +8 -0
- crackerjack/mcp/websocket/endpoints.py +352 -357
- crackerjack/mcp/websocket/jobs.py +40 -57
- crackerjack/mcp/websocket/monitoring_endpoints.py +2935 -0
- crackerjack/mcp/websocket/server.py +7 -25
- crackerjack/mcp/websocket/websocket_handler.py +6 -17
- crackerjack/mixins/__init__.py +3 -0
- crackerjack/mixins/error_handling.py +145 -0
- crackerjack/models/config.py +21 -1
- crackerjack/models/config_adapter.py +49 -1
- crackerjack/models/protocols.py +176 -107
- crackerjack/models/resource_protocols.py +55 -210
- crackerjack/models/task.py +3 -0
- crackerjack/monitoring/ai_agent_watchdog.py +13 -13
- crackerjack/monitoring/metrics_collector.py +426 -0
- crackerjack/monitoring/regression_prevention.py +8 -8
- crackerjack/monitoring/websocket_server.py +643 -0
- crackerjack/orchestration/advanced_orchestrator.py +11 -6
- crackerjack/orchestration/coverage_improvement.py +3 -3
- crackerjack/orchestration/execution_strategies.py +26 -6
- crackerjack/orchestration/test_progress_streamer.py +8 -5
- crackerjack/plugins/base.py +2 -2
- crackerjack/plugins/hooks.py +7 -0
- crackerjack/plugins/managers.py +11 -8
- crackerjack/security/__init__.py +0 -1
- crackerjack/security/audit.py +90 -105
- crackerjack/services/anomaly_detector.py +392 -0
- crackerjack/services/api_extractor.py +615 -0
- crackerjack/services/backup_service.py +2 -2
- crackerjack/services/bounded_status_operations.py +15 -152
- crackerjack/services/cache.py +127 -1
- crackerjack/services/changelog_automation.py +395 -0
- crackerjack/services/config.py +18 -11
- crackerjack/services/config_merge.py +30 -85
- crackerjack/services/config_template.py +506 -0
- crackerjack/services/contextual_ai_assistant.py +48 -22
- crackerjack/services/coverage_badge_service.py +171 -0
- crackerjack/services/coverage_ratchet.py +41 -17
- crackerjack/services/debug.py +3 -3
- crackerjack/services/dependency_analyzer.py +460 -0
- crackerjack/services/dependency_monitor.py +14 -11
- crackerjack/services/documentation_generator.py +491 -0
- crackerjack/services/documentation_service.py +675 -0
- crackerjack/services/enhanced_filesystem.py +6 -5
- crackerjack/services/enterprise_optimizer.py +865 -0
- crackerjack/services/error_pattern_analyzer.py +676 -0
- crackerjack/services/file_hasher.py +1 -1
- crackerjack/services/git.py +41 -45
- crackerjack/services/health_metrics.py +10 -8
- crackerjack/services/heatmap_generator.py +735 -0
- crackerjack/services/initialization.py +30 -33
- crackerjack/services/input_validator.py +5 -97
- crackerjack/services/intelligent_commit.py +327 -0
- crackerjack/services/log_manager.py +15 -12
- crackerjack/services/logging.py +4 -3
- crackerjack/services/lsp_client.py +628 -0
- crackerjack/services/memory_optimizer.py +409 -0
- crackerjack/services/metrics.py +42 -33
- crackerjack/services/parallel_executor.py +416 -0
- crackerjack/services/pattern_cache.py +1 -1
- crackerjack/services/pattern_detector.py +6 -6
- crackerjack/services/performance_benchmarks.py +250 -576
- crackerjack/services/performance_cache.py +382 -0
- crackerjack/services/performance_monitor.py +565 -0
- crackerjack/services/predictive_analytics.py +510 -0
- crackerjack/services/quality_baseline.py +234 -0
- crackerjack/services/quality_baseline_enhanced.py +646 -0
- crackerjack/services/quality_intelligence.py +785 -0
- crackerjack/services/regex_patterns.py +605 -524
- crackerjack/services/regex_utils.py +43 -123
- crackerjack/services/secure_path_utils.py +5 -164
- crackerjack/services/secure_status_formatter.py +30 -141
- crackerjack/services/secure_subprocess.py +11 -92
- crackerjack/services/security.py +61 -30
- crackerjack/services/security_logger.py +18 -22
- crackerjack/services/server_manager.py +124 -16
- crackerjack/services/status_authentication.py +16 -159
- crackerjack/services/status_security_manager.py +4 -131
- crackerjack/services/terminal_utils.py +0 -0
- crackerjack/services/thread_safe_status_collector.py +19 -125
- crackerjack/services/unified_config.py +21 -13
- crackerjack/services/validation_rate_limiter.py +5 -54
- crackerjack/services/version_analyzer.py +459 -0
- crackerjack/services/version_checker.py +1 -1
- crackerjack/services/websocket_resource_limiter.py +10 -144
- crackerjack/services/zuban_lsp_service.py +390 -0
- crackerjack/slash_commands/__init__.py +2 -7
- crackerjack/slash_commands/run.md +2 -2
- crackerjack/tools/validate_input_validator_patterns.py +14 -40
- crackerjack/tools/validate_regex_patterns.py +19 -48
- {crackerjack-0.32.0.dist-info → crackerjack-0.33.1.dist-info}/METADATA +197 -26
- crackerjack-0.33.1.dist-info/RECORD +229 -0
- crackerjack/CLAUDE.md +0 -207
- crackerjack/RULES.md +0 -380
- crackerjack/py313.py +0 -234
- crackerjack-0.32.0.dist-info/RECORD +0 -180
- {crackerjack-0.32.0.dist-info → crackerjack-0.33.1.dist-info}/WHEEL +0 -0
- {crackerjack-0.32.0.dist-info → crackerjack-0.33.1.dist-info}/entry_points.txt +0 -0
- {crackerjack-0.32.0.dist-info → crackerjack-0.33.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Secure subprocess execution with environment sanitization and command validation.
|
|
3
|
-
|
|
4
|
-
This module provides production-ready security for all subprocess operations in Crackerjack,
|
|
5
|
-
implementing comprehensive validation, sanitization, and logging to prevent injection attacks.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
1
|
import os
|
|
9
2
|
import re
|
|
10
3
|
import subprocess
|
|
@@ -16,26 +9,18 @@ from .security_logger import SecurityEventLevel, SecurityEventType, get_security
|
|
|
16
9
|
|
|
17
10
|
|
|
18
11
|
class SecurityError(Exception):
|
|
19
|
-
"""Raised when a security violation is detected."""
|
|
20
|
-
|
|
21
12
|
pass
|
|
22
13
|
|
|
23
14
|
|
|
24
15
|
class CommandValidationError(SecurityError):
|
|
25
|
-
"""Raised when command validation fails."""
|
|
26
|
-
|
|
27
16
|
pass
|
|
28
17
|
|
|
29
18
|
|
|
30
19
|
class EnvironmentValidationError(SecurityError):
|
|
31
|
-
"""Raised when environment validation fails."""
|
|
32
|
-
|
|
33
20
|
pass
|
|
34
21
|
|
|
35
22
|
|
|
36
23
|
class SubprocessSecurityConfig:
|
|
37
|
-
"""Configuration for secure subprocess execution."""
|
|
38
|
-
|
|
39
24
|
def __init__(
|
|
40
25
|
self,
|
|
41
26
|
max_command_length: int = 10000,
|
|
@@ -44,7 +29,7 @@ class SubprocessSecurityConfig:
|
|
|
44
29
|
max_env_vars: int = 1000,
|
|
45
30
|
allowed_executables: set[str] | None = None,
|
|
46
31
|
blocked_executables: set[str] | None = None,
|
|
47
|
-
max_timeout: float = 3600,
|
|
32
|
+
max_timeout: float = 3600,
|
|
48
33
|
enable_path_validation: bool = True,
|
|
49
34
|
enable_command_logging: bool = True,
|
|
50
35
|
):
|
|
@@ -92,24 +77,20 @@ class SubprocessSecurityConfig:
|
|
|
92
77
|
|
|
93
78
|
|
|
94
79
|
class SecureSubprocessExecutor:
|
|
95
|
-
"""Secure subprocess executor with comprehensive validation and logging."""
|
|
96
|
-
|
|
97
80
|
def __init__(self, config: SubprocessSecurityConfig | None = None):
|
|
98
81
|
self.config = config or SubprocessSecurityConfig()
|
|
99
82
|
self.security_logger = get_security_logger()
|
|
100
83
|
|
|
101
|
-
# Dangerous patterns for command injection detection
|
|
102
84
|
self.dangerous_patterns = [
|
|
103
|
-
r"[;&|`$(){}[\]<>*?~]",
|
|
104
|
-
r"\.\./",
|
|
105
|
-
r"\$\{.*\}",
|
|
106
|
-
r"`.*`",
|
|
107
|
-
r"\$\(.*\)",
|
|
108
|
-
r">\s*/",
|
|
109
|
-
r"<\s*/",
|
|
85
|
+
r"[;&|`$(){}[\]<>*?~]",
|
|
86
|
+
r"\.\./",
|
|
87
|
+
r"\$\{.*\}",
|
|
88
|
+
r"`.*`",
|
|
89
|
+
r"\$\(.*\)",
|
|
90
|
+
r">\s*/",
|
|
91
|
+
r"<\s*/",
|
|
110
92
|
]
|
|
111
93
|
|
|
112
|
-
# Environment variables that should never be passed through
|
|
113
94
|
self.dangerous_env_vars = {
|
|
114
95
|
"LD_PRELOAD",
|
|
115
96
|
"DYLD_INSERT_LIBRARIES",
|
|
@@ -125,7 +106,6 @@ class SecureSubprocessExecutor:
|
|
|
125
106
|
"BASHOPTS",
|
|
126
107
|
}
|
|
127
108
|
|
|
128
|
-
# Minimal safe environment variables
|
|
129
109
|
self.safe_env_vars = {
|
|
130
110
|
"HOME",
|
|
131
111
|
"USER",
|
|
@@ -152,28 +132,6 @@ class SecureSubprocessExecutor:
|
|
|
152
132
|
check: bool = False,
|
|
153
133
|
**kwargs: t.Any,
|
|
154
134
|
) -> subprocess.CompletedProcess[str]:
|
|
155
|
-
"""
|
|
156
|
-
Execute a subprocess with comprehensive security validation.
|
|
157
|
-
|
|
158
|
-
Args:
|
|
159
|
-
command: Command and arguments as list
|
|
160
|
-
cwd: Working directory (validated for path traversal)
|
|
161
|
-
env: Environment variables (will be sanitized)
|
|
162
|
-
timeout: Maximum execution time
|
|
163
|
-
input_data: Input to pass to subprocess
|
|
164
|
-
capture_output: Whether to capture stdout/stderr
|
|
165
|
-
text: Whether to use text mode
|
|
166
|
-
check: Whether to raise on non-zero exit
|
|
167
|
-
**kwargs: Additional subprocess.run arguments
|
|
168
|
-
|
|
169
|
-
Returns:
|
|
170
|
-
CompletedProcess result
|
|
171
|
-
|
|
172
|
-
Raises:
|
|
173
|
-
SecurityError: If security validation fails
|
|
174
|
-
CommandValidationError: If command validation fails
|
|
175
|
-
EnvironmentValidationError: If environment validation fails
|
|
176
|
-
"""
|
|
177
135
|
start_time = time.time()
|
|
178
136
|
|
|
179
137
|
try:
|
|
@@ -215,16 +173,12 @@ class SecureSubprocessExecutor:
|
|
|
215
173
|
kwargs: dict[str, t.Any],
|
|
216
174
|
start_time: float,
|
|
217
175
|
) -> subprocess.CompletedProcess[str]:
|
|
218
|
-
"""Execute subprocess with validation and logging."""
|
|
219
|
-
# Validate and sanitize all inputs
|
|
220
176
|
execution_params = self._prepare_execution_params(command, cwd, env, timeout)
|
|
221
177
|
|
|
222
|
-
# Log and execute subprocess
|
|
223
178
|
result = self._execute_subprocess(
|
|
224
179
|
execution_params, input_data, capture_output, text, check, kwargs
|
|
225
180
|
)
|
|
226
181
|
|
|
227
|
-
# Log success
|
|
228
182
|
self._log_successful_execution(execution_params, result, start_time)
|
|
229
183
|
return result
|
|
230
184
|
|
|
@@ -235,7 +189,6 @@ class SecureSubprocessExecutor:
|
|
|
235
189
|
env: dict[str, str] | None,
|
|
236
190
|
timeout: float | None,
|
|
237
191
|
) -> dict[str, t.Any]:
|
|
238
|
-
"""Prepare and validate all execution parameters."""
|
|
239
192
|
return {
|
|
240
193
|
"command": self._validate_command(command),
|
|
241
194
|
"cwd": self._validate_cwd(cwd),
|
|
@@ -252,7 +205,6 @@ class SecureSubprocessExecutor:
|
|
|
252
205
|
check: bool,
|
|
253
206
|
kwargs: dict[str, t.Any],
|
|
254
207
|
) -> subprocess.CompletedProcess[str]:
|
|
255
|
-
"""Execute subprocess with validated parameters."""
|
|
256
208
|
if self.config.enable_command_logging:
|
|
257
209
|
self.security_logger.log_subprocess_execution(
|
|
258
210
|
command=params["command"],
|
|
@@ -279,13 +231,12 @@ class SecureSubprocessExecutor:
|
|
|
279
231
|
result: subprocess.CompletedProcess[str],
|
|
280
232
|
start_time: float,
|
|
281
233
|
) -> None:
|
|
282
|
-
"""Log successful subprocess execution."""
|
|
283
234
|
execution_time = time.time() - start_time
|
|
284
235
|
if self.config.enable_command_logging:
|
|
285
236
|
self.security_logger.log_security_event(
|
|
286
237
|
SecurityEventType.SUBPROCESS_EXECUTION,
|
|
287
238
|
SecurityEventLevel.LOW,
|
|
288
|
-
f"Subprocess completed successfully in {execution_time
|
|
239
|
+
f"Subprocess completed successfully in {execution_time: .2f}s",
|
|
289
240
|
command_preview=params["command"][:3],
|
|
290
241
|
execution_time=execution_time,
|
|
291
242
|
exit_code=result.returncode,
|
|
@@ -294,7 +245,6 @@ class SecureSubprocessExecutor:
|
|
|
294
245
|
def _handle_timeout_error(
|
|
295
246
|
self, command: list[str], timeout: float | None, start_time: float
|
|
296
247
|
) -> None:
|
|
297
|
-
"""Handle subprocess timeout errors."""
|
|
298
248
|
execution_time = time.time() - start_time
|
|
299
249
|
self.security_logger.log_subprocess_timeout(
|
|
300
250
|
command=command,
|
|
@@ -305,7 +255,6 @@ class SecureSubprocessExecutor:
|
|
|
305
255
|
def _handle_process_error(
|
|
306
256
|
self, command: list[str], error: subprocess.CalledProcessError
|
|
307
257
|
) -> None:
|
|
308
|
-
"""Handle subprocess called process errors."""
|
|
309
258
|
self.security_logger.log_subprocess_failure(
|
|
310
259
|
command=command,
|
|
311
260
|
exit_code=error.returncode,
|
|
@@ -313,7 +262,6 @@ class SecureSubprocessExecutor:
|
|
|
313
262
|
)
|
|
314
263
|
|
|
315
264
|
def _handle_unexpected_error(self, command: list[str], error: Exception) -> None:
|
|
316
|
-
"""Handle unexpected subprocess errors."""
|
|
317
265
|
self.security_logger.log_security_event(
|
|
318
266
|
SecurityEventType.SUBPROCESS_FAILURE,
|
|
319
267
|
SecurityEventLevel.HIGH,
|
|
@@ -324,7 +272,6 @@ class SecureSubprocessExecutor:
|
|
|
324
272
|
)
|
|
325
273
|
|
|
326
274
|
def _validate_command(self, command: list[str]) -> list[str]:
|
|
327
|
-
"""Validate command arguments for security issues."""
|
|
328
275
|
self._validate_command_structure(command)
|
|
329
276
|
|
|
330
277
|
validated_command, issues = self._validate_command_arguments(command)
|
|
@@ -334,11 +281,9 @@ class SecureSubprocessExecutor:
|
|
|
334
281
|
return validated_command
|
|
335
282
|
|
|
336
283
|
def _validate_command_structure(self, command: list[str]) -> None:
|
|
337
|
-
"""Validate basic command structure."""
|
|
338
284
|
if not command:
|
|
339
285
|
raise CommandValidationError("Command cannot be empty")
|
|
340
286
|
|
|
341
|
-
# Check overall command length
|
|
342
287
|
total_length = sum(len(arg) for arg in command)
|
|
343
288
|
if total_length > self.config.max_command_length:
|
|
344
289
|
raise CommandValidationError(
|
|
@@ -348,19 +293,16 @@ class SecureSubprocessExecutor:
|
|
|
348
293
|
def _validate_command_arguments(
|
|
349
294
|
self, command: list[str]
|
|
350
295
|
) -> tuple[list[str], list[str]]:
|
|
351
|
-
"""Validate individual command arguments."""
|
|
352
296
|
validated_command = []
|
|
353
297
|
issues = []
|
|
354
298
|
|
|
355
299
|
for i, arg in enumerate(command):
|
|
356
|
-
# Check argument length
|
|
357
300
|
if len(arg) > self.config.max_arg_length:
|
|
358
301
|
issues.append(
|
|
359
302
|
f"Argument {i} too long: {len(arg)} > {self.config.max_arg_length}"
|
|
360
303
|
)
|
|
361
304
|
continue
|
|
362
305
|
|
|
363
|
-
# Check for injection patterns
|
|
364
306
|
if self._has_dangerous_patterns(arg, i, issues):
|
|
365
307
|
continue
|
|
366
308
|
|
|
@@ -369,7 +311,6 @@ class SecureSubprocessExecutor:
|
|
|
369
311
|
return validated_command, issues
|
|
370
312
|
|
|
371
313
|
def _has_dangerous_patterns(self, arg: str, index: int, issues: list[str]) -> bool:
|
|
372
|
-
"""Check if argument has dangerous patterns."""
|
|
373
314
|
for pattern in self.dangerous_patterns:
|
|
374
315
|
if re.search(pattern, arg):
|
|
375
316
|
issues.append(
|
|
@@ -381,7 +322,6 @@ class SecureSubprocessExecutor:
|
|
|
381
322
|
def _validate_executable_permissions(
|
|
382
323
|
self, validated_command: list[str], issues: list[str]
|
|
383
324
|
) -> None:
|
|
384
|
-
"""Validate executable allowlist/blocklist."""
|
|
385
325
|
if not validated_command:
|
|
386
326
|
return
|
|
387
327
|
|
|
@@ -397,7 +337,6 @@ class SecureSubprocessExecutor:
|
|
|
397
337
|
issues.append(f"Executable '{executable}' is blocked")
|
|
398
338
|
|
|
399
339
|
def _handle_validation_results(self, command: list[str], issues: list[str]) -> None:
|
|
400
|
-
"""Handle validation results and logging."""
|
|
401
340
|
validation_passed = len(issues) == 0
|
|
402
341
|
if self.config.enable_command_logging:
|
|
403
342
|
self.security_logger.log_subprocess_command_validation(
|
|
@@ -407,7 +346,6 @@ class SecureSubprocessExecutor:
|
|
|
407
346
|
)
|
|
408
347
|
|
|
409
348
|
if issues:
|
|
410
|
-
# Block dangerous commands
|
|
411
349
|
self.security_logger.log_dangerous_command_blocked(
|
|
412
350
|
command=command,
|
|
413
351
|
reason="Command validation failed",
|
|
@@ -418,7 +356,6 @@ class SecureSubprocessExecutor:
|
|
|
418
356
|
)
|
|
419
357
|
|
|
420
358
|
def _validate_cwd(self, cwd: Path | str | None) -> Path | None:
|
|
421
|
-
"""Validate working directory for path traversal."""
|
|
422
359
|
if cwd is None:
|
|
423
360
|
return None
|
|
424
361
|
|
|
@@ -428,10 +365,8 @@ class SecureSubprocessExecutor:
|
|
|
428
365
|
cwd_path = Path(cwd) if isinstance(cwd, str) else cwd
|
|
429
366
|
|
|
430
367
|
try:
|
|
431
|
-
# Resolve to absolute path and check for traversal
|
|
432
368
|
resolved_path = cwd_path.resolve()
|
|
433
369
|
|
|
434
|
-
# Check for dangerous path components
|
|
435
370
|
path_str = str(resolved_path)
|
|
436
371
|
if ".." in path_str or path_str.startswith(
|
|
437
372
|
("/etc", "/usr/bin", "/bin", "/sbin")
|
|
@@ -448,13 +383,12 @@ class SecureSubprocessExecutor:
|
|
|
448
383
|
raise CommandValidationError(f"Invalid working directory '{cwd}': {e}")
|
|
449
384
|
|
|
450
385
|
def _sanitize_environment(self, env: dict[str, str] | None) -> dict[str, str]:
|
|
451
|
-
"""Sanitize environment variables."""
|
|
452
386
|
if env is None:
|
|
453
387
|
env = os.environ.copy()
|
|
454
388
|
|
|
455
389
|
self._validate_environment_size(env)
|
|
456
390
|
|
|
457
|
-
filtered_vars = []
|
|
391
|
+
filtered_vars: list[str] = []
|
|
458
392
|
sanitized_env = self._filter_environment_variables(env, filtered_vars)
|
|
459
393
|
|
|
460
394
|
self._add_safe_environment_variables(sanitized_env)
|
|
@@ -463,7 +397,6 @@ class SecureSubprocessExecutor:
|
|
|
463
397
|
return sanitized_env
|
|
464
398
|
|
|
465
399
|
def _validate_environment_size(self, env: dict[str, str]) -> None:
|
|
466
|
-
"""Validate environment variable count limits."""
|
|
467
400
|
if len(env) > self.config.max_env_vars:
|
|
468
401
|
self.security_logger.log_security_event(
|
|
469
402
|
SecurityEventType.INPUT_SIZE_EXCEEDED,
|
|
@@ -479,7 +412,6 @@ class SecureSubprocessExecutor:
|
|
|
479
412
|
def _filter_environment_variables(
|
|
480
413
|
self, env: dict[str, str], filtered_vars: list[str]
|
|
481
414
|
) -> dict[str, str]:
|
|
482
|
-
"""Filter environment variables for security."""
|
|
483
415
|
sanitized_env = {}
|
|
484
416
|
|
|
485
417
|
for key, value in env.items():
|
|
@@ -499,7 +431,6 @@ class SecureSubprocessExecutor:
|
|
|
499
431
|
def _is_dangerous_environment_key(
|
|
500
432
|
self, key: str, value: str, filtered_vars: list[str]
|
|
501
433
|
) -> bool:
|
|
502
|
-
"""Check if environment key is dangerous."""
|
|
503
434
|
if key in self.dangerous_env_vars:
|
|
504
435
|
filtered_vars.append(key)
|
|
505
436
|
self.security_logger.log_environment_variable_filtered(
|
|
@@ -513,7 +444,6 @@ class SecureSubprocessExecutor:
|
|
|
513
444
|
def _is_environment_value_too_long(
|
|
514
445
|
self, key: str, value: str, filtered_vars: list[str]
|
|
515
446
|
) -> bool:
|
|
516
|
-
"""Check if environment value exceeds length limits."""
|
|
517
447
|
if len(value) > self.config.max_env_var_length:
|
|
518
448
|
filtered_vars.append(key)
|
|
519
449
|
self.security_logger.log_environment_variable_filtered(
|
|
@@ -527,8 +457,7 @@ class SecureSubprocessExecutor:
|
|
|
527
457
|
def _has_environment_injection(
|
|
528
458
|
self, key: str, value: str, filtered_vars: list[str]
|
|
529
459
|
) -> bool:
|
|
530
|
-
|
|
531
|
-
for pattern in self.dangerous_patterns[:3]: # Check first 3 most dangerous
|
|
460
|
+
for pattern in self.dangerous_patterns[:3]:
|
|
532
461
|
if re.search(pattern, value):
|
|
533
462
|
filtered_vars.append(key)
|
|
534
463
|
self.security_logger.log_environment_variable_filtered(
|
|
@@ -540,7 +469,6 @@ class SecureSubprocessExecutor:
|
|
|
540
469
|
return False
|
|
541
470
|
|
|
542
471
|
def _add_safe_environment_variables(self, sanitized_env: dict[str, str]) -> None:
|
|
543
|
-
"""Add essential safe environment variables."""
|
|
544
472
|
for safe_var in self.safe_env_vars:
|
|
545
473
|
if safe_var not in sanitized_env and safe_var in os.environ:
|
|
546
474
|
sanitized_env[safe_var] = os.environ[safe_var]
|
|
@@ -548,7 +476,6 @@ class SecureSubprocessExecutor:
|
|
|
548
476
|
def _log_environment_sanitization(
|
|
549
477
|
self, original_count: int, sanitized_count: int, filtered_vars: list[str]
|
|
550
478
|
) -> None:
|
|
551
|
-
"""Log environment sanitization results."""
|
|
552
479
|
if self.config.enable_command_logging:
|
|
553
480
|
self.security_logger.log_subprocess_environment_sanitized(
|
|
554
481
|
original_count=original_count,
|
|
@@ -557,7 +484,6 @@ class SecureSubprocessExecutor:
|
|
|
557
484
|
)
|
|
558
485
|
|
|
559
486
|
def _validate_timeout(self, timeout: float | None) -> float | None:
|
|
560
|
-
"""Validate timeout value."""
|
|
561
487
|
if timeout is None:
|
|
562
488
|
return None
|
|
563
489
|
|
|
@@ -579,14 +505,12 @@ class SecureSubprocessExecutor:
|
|
|
579
505
|
return timeout
|
|
580
506
|
|
|
581
507
|
|
|
582
|
-
# Global secure executor instance
|
|
583
508
|
_global_executor: SecureSubprocessExecutor | None = None
|
|
584
509
|
|
|
585
510
|
|
|
586
511
|
def get_secure_executor(
|
|
587
512
|
config: SubprocessSecurityConfig | None = None,
|
|
588
513
|
) -> SecureSubprocessExecutor:
|
|
589
|
-
"""Get the global secure subprocess executor."""
|
|
590
514
|
global _global_executor
|
|
591
515
|
if _global_executor is None:
|
|
592
516
|
_global_executor = SecureSubprocessExecutor(config)
|
|
@@ -597,9 +521,4 @@ def execute_secure_subprocess(
|
|
|
597
521
|
command: list[str],
|
|
598
522
|
**kwargs: t.Any,
|
|
599
523
|
) -> subprocess.CompletedProcess[str]:
|
|
600
|
-
"""
|
|
601
|
-
Convenience function for secure subprocess execution.
|
|
602
|
-
|
|
603
|
-
This is the recommended way to execute subprocesses in Crackerjack.
|
|
604
|
-
"""
|
|
605
524
|
return get_secure_executor().execute_secure(command, **kwargs)
|
crackerjack/services/security.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import tempfile
|
|
3
|
+
import typing as t
|
|
3
4
|
from contextlib import suppress
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
|
|
@@ -8,7 +9,6 @@ from crackerjack.services.regex_patterns import SAFE_PATTERNS
|
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
class SecurityService:
|
|
11
|
-
# Security token masking patterns - now using validated patterns from regex_patterns.py
|
|
12
12
|
TOKEN_PATTERN_NAMES = [
|
|
13
13
|
"mask_pypi_token",
|
|
14
14
|
"mask_github_token",
|
|
@@ -28,31 +28,16 @@ class SecurityService:
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
def mask_tokens(self, text: str) -> str:
|
|
31
|
-
"""
|
|
32
|
-
Mask sensitive tokens in text using validated regex patterns.
|
|
33
|
-
|
|
34
|
-
This method applies security token masking patterns to hide:
|
|
35
|
-
- PyPI authentication tokens (pypi-*)
|
|
36
|
-
- GitHub personal access tokens (ghp_*)
|
|
37
|
-
- Generic long tokens (32+ characters)
|
|
38
|
-
- Token assignments (token="value")
|
|
39
|
-
- Password assignments (password="value")
|
|
40
|
-
- Environment variable values
|
|
41
|
-
|
|
42
|
-
Returns masked text with sensitive data replaced by "**** or similar.
|
|
43
|
-
"""
|
|
44
31
|
if not text:
|
|
45
32
|
return text
|
|
46
33
|
|
|
47
34
|
masked_text = text
|
|
48
35
|
|
|
49
|
-
# Apply validated token masking patterns
|
|
50
36
|
for pattern_name in self.TOKEN_PATTERN_NAMES:
|
|
51
37
|
if pattern_name in SAFE_PATTERNS:
|
|
52
38
|
pattern = SAFE_PATTERNS[pattern_name]
|
|
53
39
|
masked_text = pattern.apply(masked_text)
|
|
54
40
|
|
|
55
|
-
# Also mask sensitive environment variable values
|
|
56
41
|
for env_var in self.SENSITIVE_ENV_VARS:
|
|
57
42
|
value = os.getenv(env_var)
|
|
58
43
|
if value and len(value) > 8:
|
|
@@ -96,7 +81,7 @@ class SecurityService:
|
|
|
96
81
|
with suppress(OSError):
|
|
97
82
|
temp_file.unlink()
|
|
98
83
|
raise FileError(
|
|
99
|
-
message="Failed to set secure file permissions",
|
|
84
|
+
message="Failed to set[t.Any] secure file permissions",
|
|
100
85
|
details=str(e),
|
|
101
86
|
recovery="Check file system permissions and try again",
|
|
102
87
|
) from e
|
|
@@ -147,30 +132,17 @@ class SecurityService:
|
|
|
147
132
|
return env_summary
|
|
148
133
|
|
|
149
134
|
def validate_token_format(self, token: str, token_type: str | None = None) -> bool:
|
|
150
|
-
"""
|
|
151
|
-
Validate token format for known token types.
|
|
152
|
-
|
|
153
|
-
Args:
|
|
154
|
-
token: The token string to validate
|
|
155
|
-
token_type: Optional token type ("pypi", "github", or None)
|
|
156
|
-
|
|
157
|
-
Returns:
|
|
158
|
-
True if the token appears to be valid for the specified type
|
|
159
|
-
"""
|
|
160
135
|
if not token:
|
|
161
136
|
return False
|
|
162
137
|
if len(token) < 8:
|
|
163
138
|
return False
|
|
164
139
|
|
|
165
140
|
if token_type and token_type.lower() == "pypi":
|
|
166
|
-
# PyPI tokens start with "pypi-" (not "pypi -" which was a typo)
|
|
167
141
|
return token.startswith("pypi-") and len(token) >= 16
|
|
168
142
|
|
|
169
143
|
if token_type and token_type.lower() == "github":
|
|
170
|
-
# GitHub personal access tokens: ghp_ + 36 chars = 40 total
|
|
171
144
|
return token.startswith("ghp_") and len(token) == 40
|
|
172
145
|
|
|
173
|
-
# Generic validation for unknown token types
|
|
174
146
|
return len(token) >= 16 and not token.isspace()
|
|
175
147
|
|
|
176
148
|
def create_secure_command_env(
|
|
@@ -198,3 +170,62 @@ class SecurityService:
|
|
|
198
170
|
secure_env.pop(var, None)
|
|
199
171
|
|
|
200
172
|
return secure_env
|
|
173
|
+
|
|
174
|
+
def validate_file_safety(self, path: str | Path) -> bool:
|
|
175
|
+
try:
|
|
176
|
+
file_path = Path(path)
|
|
177
|
+
|
|
178
|
+
if not file_path.exists():
|
|
179
|
+
return False
|
|
180
|
+
|
|
181
|
+
if file_path.is_symlink():
|
|
182
|
+
return False
|
|
183
|
+
return True
|
|
184
|
+
except Exception:
|
|
185
|
+
return False
|
|
186
|
+
|
|
187
|
+
def check_hardcoded_secrets(self, content: str) -> list[dict[str, t.Any]]:
|
|
188
|
+
secrets = []
|
|
189
|
+
|
|
190
|
+
patterns = {
|
|
191
|
+
"api_key": r'api[_-]?key["\s]*[: =]["\s]*([a-zA-Z0-9_-]{20, })',
|
|
192
|
+
"password": r'password["\s]*[: =]["\s]*([^\s"]{8, })',
|
|
193
|
+
"token": r'token["\s]*[: =]["\s]*([a-zA-Z0-9_-]{20, })',
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
import re
|
|
197
|
+
|
|
198
|
+
for secret_type, pattern in patterns.items():
|
|
199
|
+
matches = re.finditer(pattern, content, re.IGNORECASE)
|
|
200
|
+
for match in matches:
|
|
201
|
+
secrets.append(
|
|
202
|
+
{
|
|
203
|
+
"type": secret_type,
|
|
204
|
+
"value": match.group(1)[:10] + "...",
|
|
205
|
+
"line": content[: match.start()].count("\n") + 1,
|
|
206
|
+
}
|
|
207
|
+
)
|
|
208
|
+
return secrets
|
|
209
|
+
|
|
210
|
+
def is_safe_subprocess_call(self, cmd: list[str]) -> bool:
|
|
211
|
+
if not cmd:
|
|
212
|
+
return False
|
|
213
|
+
|
|
214
|
+
dangerous_commands = {
|
|
215
|
+
"rm",
|
|
216
|
+
"rmdir",
|
|
217
|
+
"del",
|
|
218
|
+
"format",
|
|
219
|
+
"fdisk",
|
|
220
|
+
"sudo",
|
|
221
|
+
"su",
|
|
222
|
+
"chmod",
|
|
223
|
+
"chown",
|
|
224
|
+
"curl",
|
|
225
|
+
"wget",
|
|
226
|
+
"nc",
|
|
227
|
+
"netcat",
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
command = cmd[0].split("/")[-1]
|
|
231
|
+
return command not in dangerous_commands
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import logging
|
|
3
|
+
import os
|
|
3
4
|
import time
|
|
4
5
|
import typing as t
|
|
5
6
|
from enum import Enum
|
|
@@ -36,7 +37,7 @@ class SecurityEventType(str, Enum):
|
|
|
36
37
|
STATUS_ACCESS_ATTEMPT = "status_access_attempt"
|
|
37
38
|
SENSITIVE_DATA_SANITIZED = "sensitive_data_sanitized"
|
|
38
39
|
STATUS_INFORMATION_DISCLOSURE = "status_information_disclosure"
|
|
39
|
-
|
|
40
|
+
|
|
40
41
|
ACCESS_DENIED = "access_denied"
|
|
41
42
|
API_KEY_CREATED = "api_key_created"
|
|
42
43
|
API_KEY_REVOKED = "api_key_revoked"
|
|
@@ -45,40 +46,40 @@ class SecurityEventType(str, Enum):
|
|
|
45
46
|
AUTH_SUCCESS = "auth_success"
|
|
46
47
|
LOCAL_ACCESS_GRANTED = "local_access_granted"
|
|
47
48
|
INSUFFICIENT_PRIVILEGES = "insufficient_privileges"
|
|
48
|
-
|
|
49
|
+
|
|
49
50
|
CIRCUIT_BREAKER_CLOSED = "circuit_breaker_closed"
|
|
50
51
|
CIRCUIT_BREAKER_HALF_OPEN = "circuit_breaker_half_open"
|
|
51
52
|
CIRCUIT_BREAKER_OPEN = "circuit_breaker_open"
|
|
52
53
|
CIRCUIT_BREAKER_RESET = "circuit_breaker_reset"
|
|
53
|
-
|
|
54
|
+
|
|
54
55
|
COLLECTION_END = "collection_end"
|
|
55
56
|
COLLECTION_ERROR = "collection_error"
|
|
56
57
|
COLLECTION_START = "collection_start"
|
|
57
58
|
STATUS_COLLECTED = "status_collected"
|
|
58
59
|
FILE_READ_ERROR = "file_read_error"
|
|
59
|
-
|
|
60
|
+
|
|
60
61
|
CONNECTION_CLOSED = "connection_closed"
|
|
61
62
|
CONNECTION_ESTABLISHED = "connection_established"
|
|
62
63
|
CONNECTION_IDLE = "connection_idle"
|
|
63
64
|
CONNECTION_TIMEOUT = "connection_timeout"
|
|
64
|
-
|
|
65
|
+
|
|
65
66
|
REQUEST_END = "request_end"
|
|
66
67
|
REQUEST_START = "request_start"
|
|
67
68
|
REQUEST_TIMEOUT = "request_timeout"
|
|
68
|
-
|
|
69
|
+
|
|
69
70
|
RESOURCE_CLEANUP = "resource_cleanup"
|
|
70
71
|
RESOURCE_EXHAUSTED = "resource_exhausted"
|
|
71
72
|
RESOURCE_LIMIT_EXCEEDED = "resource_limit_exceeded"
|
|
72
73
|
SERVICE_CLEANUP = "service_cleanup"
|
|
73
74
|
SERVICE_START = "service_start"
|
|
74
75
|
SERVICE_STOP = "service_stop"
|
|
75
|
-
|
|
76
|
+
|
|
76
77
|
MONITORING_ERROR = "monitoring_error"
|
|
77
78
|
OPERATION_DURATION_EXCEEDED = "operation_duration_exceeded"
|
|
78
79
|
OPERATION_FAILURE = "operation_failure"
|
|
79
80
|
OPERATION_SUCCESS = "operation_success"
|
|
80
81
|
OPERATION_TIMEOUT = "operation_timeout"
|
|
81
|
-
|
|
82
|
+
|
|
82
83
|
INVALID_INPUT = "invalid_input"
|
|
83
84
|
|
|
84
85
|
|
|
@@ -125,7 +126,12 @@ class SecurityLogger:
|
|
|
125
126
|
|
|
126
127
|
if not self.logger.handlers:
|
|
127
128
|
console_handler = logging.StreamHandler()
|
|
128
|
-
|
|
129
|
+
|
|
130
|
+
debug_enabled = os.environ.get("CRACKERJACK_DEBUG", "0") == "1"
|
|
131
|
+
if debug_enabled:
|
|
132
|
+
console_handler.setLevel(logging.WARNING)
|
|
133
|
+
else:
|
|
134
|
+
console_handler.setLevel(logging.CRITICAL + 1)
|
|
129
135
|
|
|
130
136
|
formatter = logging.Formatter(
|
|
131
137
|
"%(asctime)s - SECURITY - %(levelname)s-%(message)s"
|
|
@@ -296,12 +302,11 @@ class SecurityLogger:
|
|
|
296
302
|
env_vars_count: int = 0,
|
|
297
303
|
**kwargs: t.Any,
|
|
298
304
|
) -> None:
|
|
299
|
-
"""Log secure subprocess execution."""
|
|
300
305
|
self.log_security_event(
|
|
301
306
|
SecurityEventType.SUBPROCESS_EXECUTION,
|
|
302
307
|
SecurityEventLevel.LOW,
|
|
303
308
|
f"Subprocess executed: {' '.join(command[:3])}{'...' if len(command) > 3 else ''}",
|
|
304
|
-
command=command[:10],
|
|
309
|
+
command=command[:10],
|
|
305
310
|
cwd=cwd,
|
|
306
311
|
env_vars_count=env_vars_count,
|
|
307
312
|
**kwargs,
|
|
@@ -314,14 +319,13 @@ class SecurityLogger:
|
|
|
314
319
|
filtered_vars: list[str],
|
|
315
320
|
**kwargs: t.Any,
|
|
316
321
|
) -> None:
|
|
317
|
-
"""Log environment sanitization for subprocess."""
|
|
318
322
|
self.log_security_event(
|
|
319
323
|
SecurityEventType.SUBPROCESS_ENVIRONMENT_SANITIZED,
|
|
320
324
|
SecurityEventLevel.LOW,
|
|
321
325
|
f"Environment sanitized: {original_count} -> {sanitized_count} vars",
|
|
322
326
|
original_count=original_count,
|
|
323
327
|
sanitized_count=sanitized_count,
|
|
324
|
-
filtered_vars=filtered_vars[:20],
|
|
328
|
+
filtered_vars=filtered_vars[:20],
|
|
325
329
|
**kwargs,
|
|
326
330
|
)
|
|
327
331
|
|
|
@@ -332,7 +336,6 @@ class SecurityLogger:
|
|
|
332
336
|
issues: list[str] | None = None,
|
|
333
337
|
**kwargs: t.Any,
|
|
334
338
|
) -> None:
|
|
335
|
-
"""Log subprocess command validation results."""
|
|
336
339
|
level = SecurityEventLevel.LOW if validation_result else SecurityEventLevel.HIGH
|
|
337
340
|
status = "passed" if validation_result else "failed"
|
|
338
341
|
|
|
@@ -353,7 +356,6 @@ class SecurityLogger:
|
|
|
353
356
|
actual_duration: float,
|
|
354
357
|
**kwargs: t.Any,
|
|
355
358
|
) -> None:
|
|
356
|
-
"""Log subprocess timeout events."""
|
|
357
359
|
self.log_security_event(
|
|
358
360
|
SecurityEventType.SUBPROCESS_TIMEOUT,
|
|
359
361
|
SecurityEventLevel.MEDIUM,
|
|
@@ -367,14 +369,13 @@ class SecurityLogger:
|
|
|
367
369
|
def log_subprocess_failure(
|
|
368
370
|
self, command: list[str], exit_code: int, error_output: str, **kwargs: t.Any
|
|
369
371
|
) -> None:
|
|
370
|
-
"""Log subprocess execution failures."""
|
|
371
372
|
self.log_security_event(
|
|
372
373
|
SecurityEventType.SUBPROCESS_FAILURE,
|
|
373
374
|
SecurityEventLevel.MEDIUM,
|
|
374
375
|
f"Subprocess failed (exit code {exit_code}): {' '.join(command[:2])}{'...' if len(command) > 2 else ''}",
|
|
375
376
|
command_preview=command[:3],
|
|
376
377
|
exit_code=exit_code,
|
|
377
|
-
error_preview=error_output[:200],
|
|
378
|
+
error_preview=error_output[:200],
|
|
378
379
|
**kwargs,
|
|
379
380
|
)
|
|
380
381
|
|
|
@@ -385,7 +386,6 @@ class SecurityLogger:
|
|
|
385
386
|
dangerous_patterns: list[str],
|
|
386
387
|
**kwargs: t.Any,
|
|
387
388
|
) -> None:
|
|
388
|
-
"""Log blocking of dangerous commands."""
|
|
389
389
|
self.log_security_event(
|
|
390
390
|
SecurityEventType.DANGEROUS_COMMAND_BLOCKED,
|
|
391
391
|
SecurityEventLevel.CRITICAL,
|
|
@@ -403,7 +403,6 @@ class SecurityLogger:
|
|
|
403
403
|
value_preview: str | None = None,
|
|
404
404
|
**kwargs: t.Any,
|
|
405
405
|
) -> None:
|
|
406
|
-
"""Log filtering of environment variables."""
|
|
407
406
|
self.log_security_event(
|
|
408
407
|
SecurityEventType.ENVIRONMENT_VARIABLE_FILTERED,
|
|
409
408
|
SecurityEventLevel.LOW,
|
|
@@ -422,7 +421,6 @@ class SecurityLogger:
|
|
|
422
421
|
data_keys: list[str] | None = None,
|
|
423
422
|
**kwargs: t.Any,
|
|
424
423
|
) -> None:
|
|
425
|
-
"""Log status endpoint access attempts."""
|
|
426
424
|
self.log_security_event(
|
|
427
425
|
SecurityEventType.STATUS_ACCESS_ATTEMPT,
|
|
428
426
|
SecurityEventLevel.LOW,
|
|
@@ -442,7 +440,6 @@ class SecurityLogger:
|
|
|
442
440
|
patterns_matched: list[str] | None = None,
|
|
443
441
|
**kwargs: t.Any,
|
|
444
442
|
) -> None:
|
|
445
|
-
"""Log sensitive data sanitization events."""
|
|
446
443
|
self.log_security_event(
|
|
447
444
|
SecurityEventType.SENSITIVE_DATA_SANITIZED,
|
|
448
445
|
SecurityEventLevel.LOW,
|
|
@@ -462,7 +459,6 @@ class SecurityLogger:
|
|
|
462
459
|
severity: str = "medium",
|
|
463
460
|
**kwargs: t.Any,
|
|
464
461
|
) -> None:
|
|
465
|
-
"""Log potential information disclosure in status responses."""
|
|
466
462
|
level_map = {
|
|
467
463
|
"low": SecurityEventLevel.LOW,
|
|
468
464
|
"medium": SecurityEventLevel.MEDIUM,
|