crackerjack 0.33.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 +4 -13
- 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 +104 -204
- 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 +171 -174
- 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 +44 -8
- crackerjack/managers/test_command_builder.py +1 -15
- crackerjack/managers/test_executor.py +1 -3
- crackerjack/managers/test_manager.py +98 -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 +17 -16
- 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 +173 -32
- crackerjack/mcp/tools/error_analyzer.py +3 -2
- crackerjack/mcp/tools/execution_tools.py +8 -10
- 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 +0 -2
- crackerjack/mixins/error_handling.py +1 -70
- crackerjack/models/config.py +12 -1
- crackerjack/models/config_adapter.py +49 -1
- crackerjack/models/protocols.py +122 -122
- crackerjack/models/resource_protocols.py +55 -210
- 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 +6 -35
- 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 +15 -9
- crackerjack/services/config_merge.py +19 -80
- 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 +27 -25
- 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 +8 -25
- crackerjack/services/health_metrics.py +10 -8
- crackerjack/services/heatmap_generator.py +735 -0
- crackerjack/services/initialization.py +11 -30
- 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 +19 -87
- crackerjack/services/metrics.py +42 -33
- crackerjack/services/parallel_executor.py +9 -67
- crackerjack/services/pattern_cache.py +1 -1
- crackerjack/services/pattern_detector.py +6 -6
- crackerjack/services/performance_benchmarks.py +18 -59
- crackerjack/services/performance_cache.py +20 -81
- crackerjack/services/performance_monitor.py +27 -95
- 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 +9 -41
- crackerjack/services/security_logger.py +12 -24
- crackerjack/services/server_manager.py +124 -16
- crackerjack/services/status_authentication.py +16 -159
- crackerjack/services/status_security_manager.py +4 -131
- 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.33.0.dist-info → crackerjack-0.33.1.dist-info}/METADATA +196 -25
- 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.33.0.dist-info/RECORD +0 -187
- {crackerjack-0.33.0.dist-info → crackerjack-0.33.1.dist-info}/WHEEL +0 -0
- {crackerjack-0.33.0.dist-info → crackerjack-0.33.1.dist-info}/entry_points.txt +0 -0
- {crackerjack-0.33.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
|
@@ -9,7 +9,6 @@ from crackerjack.services.regex_patterns import SAFE_PATTERNS
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class SecurityService:
|
|
12
|
-
# Security token masking patterns - now using validated patterns from regex_patterns.py
|
|
13
12
|
TOKEN_PATTERN_NAMES = [
|
|
14
13
|
"mask_pypi_token",
|
|
15
14
|
"mask_github_token",
|
|
@@ -29,31 +28,16 @@ class SecurityService:
|
|
|
29
28
|
}
|
|
30
29
|
|
|
31
30
|
def mask_tokens(self, text: str) -> str:
|
|
32
|
-
"""
|
|
33
|
-
Mask sensitive tokens in text using validated regex patterns.
|
|
34
|
-
|
|
35
|
-
This method applies security token masking patterns to hide:
|
|
36
|
-
- PyPI authentication tokens (pypi-*)
|
|
37
|
-
- GitHub personal access tokens (ghp_*)
|
|
38
|
-
- Generic long tokens (32+ characters)
|
|
39
|
-
- Token assignments (token="value")
|
|
40
|
-
- Password assignments (password="value")
|
|
41
|
-
- Environment variable values
|
|
42
|
-
|
|
43
|
-
Returns masked text with sensitive data replaced by "**** or similar.
|
|
44
|
-
"""
|
|
45
31
|
if not text:
|
|
46
32
|
return text
|
|
47
33
|
|
|
48
34
|
masked_text = text
|
|
49
35
|
|
|
50
|
-
# Apply validated token masking patterns
|
|
51
36
|
for pattern_name in self.TOKEN_PATTERN_NAMES:
|
|
52
37
|
if pattern_name in SAFE_PATTERNS:
|
|
53
38
|
pattern = SAFE_PATTERNS[pattern_name]
|
|
54
39
|
masked_text = pattern.apply(masked_text)
|
|
55
40
|
|
|
56
|
-
# Also mask sensitive environment variable values
|
|
57
41
|
for env_var in self.SENSITIVE_ENV_VARS:
|
|
58
42
|
value = os.getenv(env_var)
|
|
59
43
|
if value and len(value) > 8:
|
|
@@ -97,7 +81,7 @@ class SecurityService:
|
|
|
97
81
|
with suppress(OSError):
|
|
98
82
|
temp_file.unlink()
|
|
99
83
|
raise FileError(
|
|
100
|
-
message="Failed to set secure file permissions",
|
|
84
|
+
message="Failed to set[t.Any] secure file permissions",
|
|
101
85
|
details=str(e),
|
|
102
86
|
recovery="Check file system permissions and try again",
|
|
103
87
|
) from e
|
|
@@ -148,30 +132,17 @@ class SecurityService:
|
|
|
148
132
|
return env_summary
|
|
149
133
|
|
|
150
134
|
def validate_token_format(self, token: str, token_type: str | None = None) -> bool:
|
|
151
|
-
"""
|
|
152
|
-
Validate token format for known token types.
|
|
153
|
-
|
|
154
|
-
Args:
|
|
155
|
-
token: The token string to validate
|
|
156
|
-
token_type: Optional token type ("pypi", "github", or None)
|
|
157
|
-
|
|
158
|
-
Returns:
|
|
159
|
-
True if the token appears to be valid for the specified type
|
|
160
|
-
"""
|
|
161
135
|
if not token:
|
|
162
136
|
return False
|
|
163
137
|
if len(token) < 8:
|
|
164
138
|
return False
|
|
165
139
|
|
|
166
140
|
if token_type and token_type.lower() == "pypi":
|
|
167
|
-
# PyPI tokens start with "pypi-" (not "pypi -" which was a typo)
|
|
168
141
|
return token.startswith("pypi-") and len(token) >= 16
|
|
169
142
|
|
|
170
143
|
if token_type and token_type.lower() == "github":
|
|
171
|
-
# GitHub personal access tokens: ghp_ + 36 chars = 40 total
|
|
172
144
|
return token.startswith("ghp_") and len(token) == 40
|
|
173
145
|
|
|
174
|
-
# Generic validation for unknown token types
|
|
175
146
|
return len(token) >= 16 and not token.isspace()
|
|
176
147
|
|
|
177
148
|
def create_secure_command_env(
|
|
@@ -201,13 +172,12 @@ class SecurityService:
|
|
|
201
172
|
return secure_env
|
|
202
173
|
|
|
203
174
|
def validate_file_safety(self, path: str | Path) -> bool:
|
|
204
|
-
"""Protocol method: Validate file safety."""
|
|
205
175
|
try:
|
|
206
176
|
file_path = Path(path)
|
|
207
|
-
|
|
177
|
+
|
|
208
178
|
if not file_path.exists():
|
|
209
179
|
return False
|
|
210
|
-
|
|
180
|
+
|
|
211
181
|
if file_path.is_symlink():
|
|
212
182
|
return False
|
|
213
183
|
return True
|
|
@@ -215,13 +185,12 @@ class SecurityService:
|
|
|
215
185
|
return False
|
|
216
186
|
|
|
217
187
|
def check_hardcoded_secrets(self, content: str) -> list[dict[str, t.Any]]:
|
|
218
|
-
"""Protocol method: Check for hardcoded secrets."""
|
|
219
188
|
secrets = []
|
|
220
|
-
|
|
189
|
+
|
|
221
190
|
patterns = {
|
|
222
|
-
"api_key": r'api[_-]?key["\s]*[
|
|
223
|
-
"password": r'password["\s]*[
|
|
224
|
-
"token": r'token["\s]*[
|
|
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, })',
|
|
225
194
|
}
|
|
226
195
|
|
|
227
196
|
import re
|
|
@@ -232,14 +201,13 @@ class SecurityService:
|
|
|
232
201
|
secrets.append(
|
|
233
202
|
{
|
|
234
203
|
"type": secret_type,
|
|
235
|
-
"value": match.group(1)[:10] + "...",
|
|
204
|
+
"value": match.group(1)[:10] + "...",
|
|
236
205
|
"line": content[: match.start()].count("\n") + 1,
|
|
237
206
|
}
|
|
238
207
|
)
|
|
239
208
|
return secrets
|
|
240
209
|
|
|
241
210
|
def is_safe_subprocess_call(self, cmd: list[str]) -> bool:
|
|
242
|
-
"""Protocol method: Check if subprocess call is safe."""
|
|
243
211
|
if not cmd:
|
|
244
212
|
return False
|
|
245
213
|
|
|
@@ -259,5 +227,5 @@ class SecurityService:
|
|
|
259
227
|
"netcat",
|
|
260
228
|
}
|
|
261
229
|
|
|
262
|
-
command = cmd[0].split("/")[-1]
|
|
230
|
+
command = cmd[0].split("/")[-1]
|
|
263
231
|
return command not in dangerous_commands
|
|
@@ -37,7 +37,7 @@ class SecurityEventType(str, Enum):
|
|
|
37
37
|
STATUS_ACCESS_ATTEMPT = "status_access_attempt"
|
|
38
38
|
SENSITIVE_DATA_SANITIZED = "sensitive_data_sanitized"
|
|
39
39
|
STATUS_INFORMATION_DISCLOSURE = "status_information_disclosure"
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
ACCESS_DENIED = "access_denied"
|
|
42
42
|
API_KEY_CREATED = "api_key_created"
|
|
43
43
|
API_KEY_REVOKED = "api_key_revoked"
|
|
@@ -46,40 +46,40 @@ class SecurityEventType(str, Enum):
|
|
|
46
46
|
AUTH_SUCCESS = "auth_success"
|
|
47
47
|
LOCAL_ACCESS_GRANTED = "local_access_granted"
|
|
48
48
|
INSUFFICIENT_PRIVILEGES = "insufficient_privileges"
|
|
49
|
-
|
|
49
|
+
|
|
50
50
|
CIRCUIT_BREAKER_CLOSED = "circuit_breaker_closed"
|
|
51
51
|
CIRCUIT_BREAKER_HALF_OPEN = "circuit_breaker_half_open"
|
|
52
52
|
CIRCUIT_BREAKER_OPEN = "circuit_breaker_open"
|
|
53
53
|
CIRCUIT_BREAKER_RESET = "circuit_breaker_reset"
|
|
54
|
-
|
|
54
|
+
|
|
55
55
|
COLLECTION_END = "collection_end"
|
|
56
56
|
COLLECTION_ERROR = "collection_error"
|
|
57
57
|
COLLECTION_START = "collection_start"
|
|
58
58
|
STATUS_COLLECTED = "status_collected"
|
|
59
59
|
FILE_READ_ERROR = "file_read_error"
|
|
60
|
-
|
|
60
|
+
|
|
61
61
|
CONNECTION_CLOSED = "connection_closed"
|
|
62
62
|
CONNECTION_ESTABLISHED = "connection_established"
|
|
63
63
|
CONNECTION_IDLE = "connection_idle"
|
|
64
64
|
CONNECTION_TIMEOUT = "connection_timeout"
|
|
65
|
-
|
|
65
|
+
|
|
66
66
|
REQUEST_END = "request_end"
|
|
67
67
|
REQUEST_START = "request_start"
|
|
68
68
|
REQUEST_TIMEOUT = "request_timeout"
|
|
69
|
-
|
|
69
|
+
|
|
70
70
|
RESOURCE_CLEANUP = "resource_cleanup"
|
|
71
71
|
RESOURCE_EXHAUSTED = "resource_exhausted"
|
|
72
72
|
RESOURCE_LIMIT_EXCEEDED = "resource_limit_exceeded"
|
|
73
73
|
SERVICE_CLEANUP = "service_cleanup"
|
|
74
74
|
SERVICE_START = "service_start"
|
|
75
75
|
SERVICE_STOP = "service_stop"
|
|
76
|
-
|
|
76
|
+
|
|
77
77
|
MONITORING_ERROR = "monitoring_error"
|
|
78
78
|
OPERATION_DURATION_EXCEEDED = "operation_duration_exceeded"
|
|
79
79
|
OPERATION_FAILURE = "operation_failure"
|
|
80
80
|
OPERATION_SUCCESS = "operation_success"
|
|
81
81
|
OPERATION_TIMEOUT = "operation_timeout"
|
|
82
|
-
|
|
82
|
+
|
|
83
83
|
INVALID_INPUT = "invalid_input"
|
|
84
84
|
|
|
85
85
|
|
|
@@ -127,13 +127,11 @@ class SecurityLogger:
|
|
|
127
127
|
if not self.logger.handlers:
|
|
128
128
|
console_handler = logging.StreamHandler()
|
|
129
129
|
|
|
130
|
-
# Only show security logs in debug modes
|
|
131
130
|
debug_enabled = os.environ.get("CRACKERJACK_DEBUG", "0") == "1"
|
|
132
131
|
if debug_enabled:
|
|
133
132
|
console_handler.setLevel(logging.WARNING)
|
|
134
133
|
else:
|
|
135
|
-
|
|
136
|
-
console_handler.setLevel(logging.CRITICAL + 1) # Effectively disable
|
|
134
|
+
console_handler.setLevel(logging.CRITICAL + 1)
|
|
137
135
|
|
|
138
136
|
formatter = logging.Formatter(
|
|
139
137
|
"%(asctime)s - SECURITY - %(levelname)s-%(message)s"
|
|
@@ -304,12 +302,11 @@ class SecurityLogger:
|
|
|
304
302
|
env_vars_count: int = 0,
|
|
305
303
|
**kwargs: t.Any,
|
|
306
304
|
) -> None:
|
|
307
|
-
"""Log secure subprocess execution."""
|
|
308
305
|
self.log_security_event(
|
|
309
306
|
SecurityEventType.SUBPROCESS_EXECUTION,
|
|
310
307
|
SecurityEventLevel.LOW,
|
|
311
308
|
f"Subprocess executed: {' '.join(command[:3])}{'...' if len(command) > 3 else ''}",
|
|
312
|
-
command=command[:10],
|
|
309
|
+
command=command[:10],
|
|
313
310
|
cwd=cwd,
|
|
314
311
|
env_vars_count=env_vars_count,
|
|
315
312
|
**kwargs,
|
|
@@ -322,14 +319,13 @@ class SecurityLogger:
|
|
|
322
319
|
filtered_vars: list[str],
|
|
323
320
|
**kwargs: t.Any,
|
|
324
321
|
) -> None:
|
|
325
|
-
"""Log environment sanitization for subprocess."""
|
|
326
322
|
self.log_security_event(
|
|
327
323
|
SecurityEventType.SUBPROCESS_ENVIRONMENT_SANITIZED,
|
|
328
324
|
SecurityEventLevel.LOW,
|
|
329
325
|
f"Environment sanitized: {original_count} -> {sanitized_count} vars",
|
|
330
326
|
original_count=original_count,
|
|
331
327
|
sanitized_count=sanitized_count,
|
|
332
|
-
filtered_vars=filtered_vars[:20],
|
|
328
|
+
filtered_vars=filtered_vars[:20],
|
|
333
329
|
**kwargs,
|
|
334
330
|
)
|
|
335
331
|
|
|
@@ -340,7 +336,6 @@ class SecurityLogger:
|
|
|
340
336
|
issues: list[str] | None = None,
|
|
341
337
|
**kwargs: t.Any,
|
|
342
338
|
) -> None:
|
|
343
|
-
"""Log subprocess command validation results."""
|
|
344
339
|
level = SecurityEventLevel.LOW if validation_result else SecurityEventLevel.HIGH
|
|
345
340
|
status = "passed" if validation_result else "failed"
|
|
346
341
|
|
|
@@ -361,7 +356,6 @@ class SecurityLogger:
|
|
|
361
356
|
actual_duration: float,
|
|
362
357
|
**kwargs: t.Any,
|
|
363
358
|
) -> None:
|
|
364
|
-
"""Log subprocess timeout events."""
|
|
365
359
|
self.log_security_event(
|
|
366
360
|
SecurityEventType.SUBPROCESS_TIMEOUT,
|
|
367
361
|
SecurityEventLevel.MEDIUM,
|
|
@@ -375,14 +369,13 @@ class SecurityLogger:
|
|
|
375
369
|
def log_subprocess_failure(
|
|
376
370
|
self, command: list[str], exit_code: int, error_output: str, **kwargs: t.Any
|
|
377
371
|
) -> None:
|
|
378
|
-
"""Log subprocess execution failures."""
|
|
379
372
|
self.log_security_event(
|
|
380
373
|
SecurityEventType.SUBPROCESS_FAILURE,
|
|
381
374
|
SecurityEventLevel.MEDIUM,
|
|
382
375
|
f"Subprocess failed (exit code {exit_code}): {' '.join(command[:2])}{'...' if len(command) > 2 else ''}",
|
|
383
376
|
command_preview=command[:3],
|
|
384
377
|
exit_code=exit_code,
|
|
385
|
-
error_preview=error_output[:200],
|
|
378
|
+
error_preview=error_output[:200],
|
|
386
379
|
**kwargs,
|
|
387
380
|
)
|
|
388
381
|
|
|
@@ -393,7 +386,6 @@ class SecurityLogger:
|
|
|
393
386
|
dangerous_patterns: list[str],
|
|
394
387
|
**kwargs: t.Any,
|
|
395
388
|
) -> None:
|
|
396
|
-
"""Log blocking of dangerous commands."""
|
|
397
389
|
self.log_security_event(
|
|
398
390
|
SecurityEventType.DANGEROUS_COMMAND_BLOCKED,
|
|
399
391
|
SecurityEventLevel.CRITICAL,
|
|
@@ -411,7 +403,6 @@ class SecurityLogger:
|
|
|
411
403
|
value_preview: str | None = None,
|
|
412
404
|
**kwargs: t.Any,
|
|
413
405
|
) -> None:
|
|
414
|
-
"""Log filtering of environment variables."""
|
|
415
406
|
self.log_security_event(
|
|
416
407
|
SecurityEventType.ENVIRONMENT_VARIABLE_FILTERED,
|
|
417
408
|
SecurityEventLevel.LOW,
|
|
@@ -430,7 +421,6 @@ class SecurityLogger:
|
|
|
430
421
|
data_keys: list[str] | None = None,
|
|
431
422
|
**kwargs: t.Any,
|
|
432
423
|
) -> None:
|
|
433
|
-
"""Log status endpoint access attempts."""
|
|
434
424
|
self.log_security_event(
|
|
435
425
|
SecurityEventType.STATUS_ACCESS_ATTEMPT,
|
|
436
426
|
SecurityEventLevel.LOW,
|
|
@@ -450,7 +440,6 @@ class SecurityLogger:
|
|
|
450
440
|
patterns_matched: list[str] | None = None,
|
|
451
441
|
**kwargs: t.Any,
|
|
452
442
|
) -> None:
|
|
453
|
-
"""Log sensitive data sanitization events."""
|
|
454
443
|
self.log_security_event(
|
|
455
444
|
SecurityEventType.SENSITIVE_DATA_SANITIZED,
|
|
456
445
|
SecurityEventLevel.LOW,
|
|
@@ -470,7 +459,6 @@ class SecurityLogger:
|
|
|
470
459
|
severity: str = "medium",
|
|
471
460
|
**kwargs: t.Any,
|
|
472
461
|
) -> None:
|
|
473
|
-
"""Log potential information disclosure in status responses."""
|
|
474
462
|
level_map = {
|
|
475
463
|
"low": SecurityEventLevel.LOW,
|
|
476
464
|
"medium": SecurityEventLevel.MEDIUM,
|