crackerjack 0.31.9__py3-none-any.whl → 0.31.12__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.

Files changed (155) hide show
  1. crackerjack/CLAUDE.md +288 -705
  2. crackerjack/__main__.py +22 -8
  3. crackerjack/agents/__init__.py +0 -3
  4. crackerjack/agents/architect_agent.py +0 -43
  5. crackerjack/agents/base.py +1 -9
  6. crackerjack/agents/coordinator.py +2 -148
  7. crackerjack/agents/documentation_agent.py +109 -81
  8. crackerjack/agents/dry_agent.py +122 -97
  9. crackerjack/agents/formatting_agent.py +3 -16
  10. crackerjack/agents/import_optimization_agent.py +1174 -130
  11. crackerjack/agents/performance_agent.py +956 -188
  12. crackerjack/agents/performance_helpers.py +229 -0
  13. crackerjack/agents/proactive_agent.py +1 -48
  14. crackerjack/agents/refactoring_agent.py +516 -246
  15. crackerjack/agents/refactoring_helpers.py +282 -0
  16. crackerjack/agents/security_agent.py +393 -90
  17. crackerjack/agents/test_creation_agent.py +1776 -120
  18. crackerjack/agents/test_specialist_agent.py +59 -15
  19. crackerjack/agents/tracker.py +0 -102
  20. crackerjack/api.py +145 -37
  21. crackerjack/cli/handlers.py +48 -30
  22. crackerjack/cli/interactive.py +11 -11
  23. crackerjack/cli/options.py +66 -4
  24. crackerjack/code_cleaner.py +808 -148
  25. crackerjack/config/global_lock_config.py +110 -0
  26. crackerjack/config/hooks.py +43 -64
  27. crackerjack/core/async_workflow_orchestrator.py +247 -97
  28. crackerjack/core/autofix_coordinator.py +192 -109
  29. crackerjack/core/enhanced_container.py +46 -63
  30. crackerjack/core/file_lifecycle.py +549 -0
  31. crackerjack/core/performance.py +9 -8
  32. crackerjack/core/performance_monitor.py +395 -0
  33. crackerjack/core/phase_coordinator.py +282 -95
  34. crackerjack/core/proactive_workflow.py +9 -58
  35. crackerjack/core/resource_manager.py +501 -0
  36. crackerjack/core/service_watchdog.py +490 -0
  37. crackerjack/core/session_coordinator.py +4 -8
  38. crackerjack/core/timeout_manager.py +504 -0
  39. crackerjack/core/websocket_lifecycle.py +475 -0
  40. crackerjack/core/workflow_orchestrator.py +355 -204
  41. crackerjack/dynamic_config.py +47 -6
  42. crackerjack/errors.py +3 -4
  43. crackerjack/executors/async_hook_executor.py +63 -13
  44. crackerjack/executors/cached_hook_executor.py +14 -14
  45. crackerjack/executors/hook_executor.py +100 -37
  46. crackerjack/executors/hook_lock_manager.py +856 -0
  47. crackerjack/executors/individual_hook_executor.py +120 -86
  48. crackerjack/intelligence/__init__.py +0 -7
  49. crackerjack/intelligence/adaptive_learning.py +13 -86
  50. crackerjack/intelligence/agent_orchestrator.py +15 -78
  51. crackerjack/intelligence/agent_registry.py +12 -59
  52. crackerjack/intelligence/agent_selector.py +31 -92
  53. crackerjack/intelligence/integration.py +1 -41
  54. crackerjack/interactive.py +9 -9
  55. crackerjack/managers/async_hook_manager.py +25 -8
  56. crackerjack/managers/hook_manager.py +9 -9
  57. crackerjack/managers/publish_manager.py +57 -59
  58. crackerjack/managers/test_command_builder.py +6 -36
  59. crackerjack/managers/test_executor.py +9 -61
  60. crackerjack/managers/test_manager.py +52 -62
  61. crackerjack/managers/test_manager_backup.py +77 -127
  62. crackerjack/managers/test_progress.py +4 -23
  63. crackerjack/mcp/cache.py +5 -12
  64. crackerjack/mcp/client_runner.py +10 -10
  65. crackerjack/mcp/context.py +64 -6
  66. crackerjack/mcp/dashboard.py +14 -11
  67. crackerjack/mcp/enhanced_progress_monitor.py +55 -55
  68. crackerjack/mcp/file_monitor.py +72 -42
  69. crackerjack/mcp/progress_components.py +103 -84
  70. crackerjack/mcp/progress_monitor.py +122 -49
  71. crackerjack/mcp/rate_limiter.py +12 -12
  72. crackerjack/mcp/server_core.py +16 -22
  73. crackerjack/mcp/service_watchdog.py +26 -26
  74. crackerjack/mcp/state.py +15 -0
  75. crackerjack/mcp/tools/core_tools.py +95 -39
  76. crackerjack/mcp/tools/error_analyzer.py +6 -32
  77. crackerjack/mcp/tools/execution_tools.py +1 -56
  78. crackerjack/mcp/tools/execution_tools_backup.py +35 -131
  79. crackerjack/mcp/tools/intelligence_tool_registry.py +0 -36
  80. crackerjack/mcp/tools/intelligence_tools.py +2 -55
  81. crackerjack/mcp/tools/monitoring_tools.py +308 -145
  82. crackerjack/mcp/tools/proactive_tools.py +12 -42
  83. crackerjack/mcp/tools/progress_tools.py +23 -15
  84. crackerjack/mcp/tools/utility_tools.py +3 -40
  85. crackerjack/mcp/tools/workflow_executor.py +40 -60
  86. crackerjack/mcp/websocket/app.py +0 -3
  87. crackerjack/mcp/websocket/endpoints.py +206 -268
  88. crackerjack/mcp/websocket/jobs.py +213 -66
  89. crackerjack/mcp/websocket/server.py +84 -6
  90. crackerjack/mcp/websocket/websocket_handler.py +137 -29
  91. crackerjack/models/config_adapter.py +3 -16
  92. crackerjack/models/protocols.py +162 -3
  93. crackerjack/models/resource_protocols.py +454 -0
  94. crackerjack/models/task.py +3 -3
  95. crackerjack/monitoring/__init__.py +0 -0
  96. crackerjack/monitoring/ai_agent_watchdog.py +25 -71
  97. crackerjack/monitoring/regression_prevention.py +28 -87
  98. crackerjack/orchestration/advanced_orchestrator.py +44 -78
  99. crackerjack/orchestration/coverage_improvement.py +10 -60
  100. crackerjack/orchestration/execution_strategies.py +16 -16
  101. crackerjack/orchestration/test_progress_streamer.py +61 -53
  102. crackerjack/plugins/base.py +1 -1
  103. crackerjack/plugins/managers.py +22 -20
  104. crackerjack/py313.py +65 -21
  105. crackerjack/services/backup_service.py +467 -0
  106. crackerjack/services/bounded_status_operations.py +627 -0
  107. crackerjack/services/cache.py +7 -9
  108. crackerjack/services/config.py +35 -52
  109. crackerjack/services/config_integrity.py +5 -16
  110. crackerjack/services/config_merge.py +542 -0
  111. crackerjack/services/contextual_ai_assistant.py +17 -19
  112. crackerjack/services/coverage_ratchet.py +51 -76
  113. crackerjack/services/debug.py +25 -39
  114. crackerjack/services/dependency_monitor.py +52 -50
  115. crackerjack/services/enhanced_filesystem.py +14 -11
  116. crackerjack/services/file_hasher.py +1 -1
  117. crackerjack/services/filesystem.py +1 -12
  118. crackerjack/services/git.py +78 -44
  119. crackerjack/services/health_metrics.py +31 -27
  120. crackerjack/services/initialization.py +281 -433
  121. crackerjack/services/input_validator.py +760 -0
  122. crackerjack/services/log_manager.py +16 -16
  123. crackerjack/services/logging.py +7 -6
  124. crackerjack/services/metrics.py +43 -43
  125. crackerjack/services/pattern_cache.py +2 -31
  126. crackerjack/services/pattern_detector.py +26 -63
  127. crackerjack/services/performance_benchmarks.py +20 -45
  128. crackerjack/services/regex_patterns.py +2887 -0
  129. crackerjack/services/regex_utils.py +537 -0
  130. crackerjack/services/secure_path_utils.py +683 -0
  131. crackerjack/services/secure_status_formatter.py +534 -0
  132. crackerjack/services/secure_subprocess.py +605 -0
  133. crackerjack/services/security.py +47 -10
  134. crackerjack/services/security_logger.py +492 -0
  135. crackerjack/services/server_manager.py +109 -50
  136. crackerjack/services/smart_scheduling.py +8 -25
  137. crackerjack/services/status_authentication.py +603 -0
  138. crackerjack/services/status_security_manager.py +442 -0
  139. crackerjack/services/thread_safe_status_collector.py +546 -0
  140. crackerjack/services/tool_version_service.py +1 -23
  141. crackerjack/services/unified_config.py +36 -58
  142. crackerjack/services/validation_rate_limiter.py +269 -0
  143. crackerjack/services/version_checker.py +9 -40
  144. crackerjack/services/websocket_resource_limiter.py +572 -0
  145. crackerjack/slash_commands/__init__.py +52 -2
  146. crackerjack/tools/__init__.py +0 -0
  147. crackerjack/tools/validate_input_validator_patterns.py +262 -0
  148. crackerjack/tools/validate_regex_patterns.py +198 -0
  149. {crackerjack-0.31.9.dist-info → crackerjack-0.31.12.dist-info}/METADATA +197 -12
  150. crackerjack-0.31.12.dist-info/RECORD +178 -0
  151. crackerjack/cli/facade.py +0 -104
  152. crackerjack-0.31.9.dist-info/RECORD +0 -149
  153. {crackerjack-0.31.9.dist-info → crackerjack-0.31.12.dist-info}/WHEEL +0 -0
  154. {crackerjack-0.31.9.dist-info → crackerjack-0.31.12.dist-info}/entry_points.txt +0 -0
  155. {crackerjack-0.31.9.dist-info → crackerjack-0.31.12.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,442 @@
1
+ """
2
+ Status Security Manager for comprehensive security controls.
3
+
4
+ Provides authentication, authorization, rate limiting, and resource protection
5
+ for status collection operations to prevent security vulnerabilities.
6
+ """
7
+
8
+ import asyncio
9
+ import threading
10
+ import time
11
+ import typing as t
12
+ from collections import defaultdict
13
+ from pathlib import Path
14
+
15
+ from .security_logger import SecurityEventLevel, SecurityEventType, get_security_logger
16
+
17
+
18
+ class StatusSecurityError(Exception):
19
+ """Base exception for status security violations."""
20
+
21
+ pass
22
+
23
+
24
+ class AccessDeniedError(StatusSecurityError):
25
+ """Raised when access is denied to status information."""
26
+
27
+ pass
28
+
29
+
30
+ class ResourceLimitExceededError(StatusSecurityError):
31
+ """Raised when resource limits are exceeded."""
32
+
33
+ pass
34
+
35
+
36
+ class RateLimitExceededError(StatusSecurityError):
37
+ """Raised when rate limits are exceeded."""
38
+
39
+ pass
40
+
41
+
42
+ class StatusSecurityManager:
43
+ """
44
+ Comprehensive security manager for status operations.
45
+
46
+ Provides:
47
+ - Authentication and authorization controls
48
+ - Rate limiting for status requests
49
+ - Resource usage monitoring and limits
50
+ - Concurrent operation tracking
51
+ - Path traversal protection
52
+ """
53
+
54
+ def __init__(
55
+ self,
56
+ max_concurrent_requests: int = 5,
57
+ rate_limit_per_minute: int = 60,
58
+ max_resource_usage_mb: int = 100,
59
+ allowed_paths: set[str] | None = None,
60
+ ):
61
+ """
62
+ Initialize status security manager.
63
+
64
+ Args:
65
+ max_concurrent_requests: Maximum concurrent status requests
66
+ rate_limit_per_minute: Maximum requests per minute per client
67
+ max_resource_usage_mb: Maximum memory usage in MB
68
+ allowed_paths: Set of allowed paths for file operations
69
+ """
70
+ self.max_concurrent_requests = max_concurrent_requests
71
+ self.rate_limit_per_minute = rate_limit_per_minute
72
+ self.max_resource_usage_mb = max_resource_usage_mb
73
+ self.allowed_paths = allowed_paths or set()
74
+
75
+ # Thread-safe tracking
76
+ self._lock = threading.RLock()
77
+ self._concurrent_requests = 0
78
+ self._rate_limit_tracker: dict[str, list[float]] = defaultdict(list)
79
+ self._resource_usage = 0.0
80
+
81
+ # Security logging
82
+ self.security_logger = get_security_logger()
83
+
84
+ # Active request tracking for resource cleanup
85
+ self._active_requests: set[str] = set()
86
+
87
+ def validate_request(
88
+ self,
89
+ client_id: str,
90
+ operation: str,
91
+ request_data: dict[str, t.Any] | None = None,
92
+ ) -> None:
93
+ """
94
+ Validate status request for security compliance.
95
+
96
+ Args:
97
+ client_id: Unique client identifier
98
+ operation: Operation being requested
99
+ request_data: Additional request data to validate
100
+
101
+ Raises:
102
+ AccessDeniedError: If access is denied
103
+ RateLimitExceededError: If rate limit exceeded
104
+ ResourceLimitExceededError: If resource limits exceeded
105
+ """
106
+ with self._lock:
107
+ # Check concurrent request limit
108
+ if self._concurrent_requests >= self.max_concurrent_requests:
109
+ self.security_logger.log_security_event(
110
+ event_type=SecurityEventType.RATE_LIMIT_EXCEEDED,
111
+ level=SecurityEventLevel.WARNING,
112
+ message=f"Concurrent request limit exceeded: {self._concurrent_requests}",
113
+ client_id=client_id,
114
+ operation=operation,
115
+ )
116
+ raise ResourceLimitExceededError(
117
+ f"Too many concurrent requests: {self._concurrent_requests}"
118
+ )
119
+
120
+ # Check rate limiting
121
+ self._check_rate_limit(client_id, operation)
122
+
123
+ # Validate request data if provided
124
+ if request_data:
125
+ self._validate_request_data(client_id, operation, request_data)
126
+
127
+ def _check_rate_limit(self, client_id: str, operation: str) -> None:
128
+ """Check if client has exceeded rate limits."""
129
+
130
+ current_time = time.time()
131
+ client_requests = self._rate_limit_tracker[client_id]
132
+
133
+ # Remove requests older than 1 minute
134
+ client_requests[:] = [
135
+ req_time for req_time in client_requests if current_time - req_time < 60
136
+ ]
137
+
138
+ # Check if limit exceeded
139
+ if len(client_requests) >= self.rate_limit_per_minute:
140
+ self.security_logger.log_security_event(
141
+ event_type=SecurityEventType.RATE_LIMIT_EXCEEDED,
142
+ level=SecurityEventLevel.WARNING,
143
+ message=f"Rate limit exceeded for client {client_id}",
144
+ client_id=client_id,
145
+ operation=operation,
146
+ )
147
+ raise RateLimitExceededError(
148
+ f"Rate limit exceeded: {len(client_requests)} requests in last minute"
149
+ )
150
+
151
+ # Record this request
152
+ client_requests.append(current_time)
153
+
154
+ def _validate_request_data(
155
+ self,
156
+ client_id: str,
157
+ operation: str,
158
+ request_data: dict[str, t.Any],
159
+ ) -> None:
160
+ """Validate request data for security issues."""
161
+
162
+ # Check for path traversal attempts
163
+ for key, value in request_data.items():
164
+ if isinstance(value, str):
165
+ if self._contains_path_traversal(value):
166
+ self.security_logger.log_security_event(
167
+ event_type=SecurityEventType.PATH_TRAVERSAL_ATTEMPT,
168
+ level=SecurityEventLevel.CRITICAL,
169
+ message=f"Path traversal attempt detected in {key}: {value}",
170
+ client_id=client_id,
171
+ operation=operation,
172
+ additional_data={"suspicious_value": value},
173
+ )
174
+ raise AccessDeniedError(f"Invalid path in parameter: {key}")
175
+
176
+ # Validate file paths if present
177
+ if "path" in request_data or "file_path" in request_data:
178
+ path_value = request_data.get("path") or request_data.get("file_path")
179
+ if path_value:
180
+ self._validate_file_path(client_id, operation, str(path_value))
181
+
182
+ def _contains_path_traversal(self, value: str) -> bool:
183
+ """Check if value contains path traversal patterns."""
184
+
185
+ # Common path traversal patterns
186
+ traversal_patterns = [
187
+ "../",
188
+ "..\\",
189
+ "..%2f",
190
+ "..%5c",
191
+ "%2e%2e%2f",
192
+ "%2e%2e%5c",
193
+ "....//",
194
+ "....\\\\",
195
+ "..\\/",
196
+ "../\\",
197
+ "%252e%252e%252f", # Double URL encoded
198
+ ]
199
+
200
+ value_lower = value.lower()
201
+ return any(pattern in value_lower for pattern in traversal_patterns)
202
+
203
+ def _validate_file_path(
204
+ self, client_id: str, operation: str, file_path: str
205
+ ) -> None:
206
+ """Validate file path for security compliance."""
207
+
208
+ try:
209
+ path = Path(file_path).resolve()
210
+
211
+ # Check if path is within allowed paths
212
+ if self.allowed_paths:
213
+ path_allowed = any(
214
+ path.is_relative_to(Path(allowed_path).resolve())
215
+ for allowed_path in self.allowed_paths
216
+ )
217
+
218
+ if not path_allowed:
219
+ self.security_logger.log_security_event(
220
+ event_type=SecurityEventType.UNAUTHORIZED_ACCESS_ATTEMPT,
221
+ level=SecurityEventLevel.HIGH,
222
+ message=f"Access to unauthorized path: {path}",
223
+ client_id=client_id,
224
+ operation=operation,
225
+ additional_data={"requested_path": str(path)},
226
+ )
227
+ raise AccessDeniedError(f"Access denied to path: {file_path}")
228
+
229
+ except (OSError, ValueError) as e:
230
+ self.security_logger.log_security_event(
231
+ event_type=SecurityEventType.INVALID_INPUT,
232
+ level=SecurityEventLevel.WARNING,
233
+ message=f"Invalid file path: {file_path} - {e}",
234
+ client_id=client_id,
235
+ operation=operation,
236
+ )
237
+ raise AccessDeniedError(f"Invalid file path: {file_path}")
238
+
239
+ async def acquire_request_lock(
240
+ self,
241
+ client_id: str,
242
+ operation: str,
243
+ timeout: float = 30.0,
244
+ ) -> "RequestLock":
245
+ """
246
+ Acquire a request lock for concurrent operation tracking.
247
+
248
+ Args:
249
+ client_id: Client identifier
250
+ operation: Operation being performed
251
+ timeout: Maximum wait time for lock acquisition
252
+
253
+ Returns:
254
+ RequestLock context manager
255
+
256
+ Raises:
257
+ ResourceLimitExceededError: If unable to acquire lock within timeout
258
+ """
259
+
260
+ request_id = f"{client_id}:{operation}:{int(time.time())}"
261
+
262
+ # Try to acquire lock with timeout
263
+ start_time = time.time()
264
+ while time.time() - start_time < timeout:
265
+ with self._lock:
266
+ if self._concurrent_requests < self.max_concurrent_requests:
267
+ self._concurrent_requests += 1
268
+ self._active_requests.add(request_id)
269
+
270
+ self.security_logger.log_security_event(
271
+ event_type=SecurityEventType.REQUEST_START,
272
+ level=SecurityEventLevel.INFO,
273
+ message=f"Request lock acquired: {request_id}",
274
+ client_id=client_id,
275
+ operation=operation,
276
+ )
277
+
278
+ return RequestLock(self, request_id, client_id, operation)
279
+
280
+ # Wait briefly before retrying
281
+ await asyncio.sleep(0.1)
282
+
283
+ # Timeout exceeded
284
+ self.security_logger.log_security_event(
285
+ event_type=SecurityEventType.REQUEST_TIMEOUT,
286
+ level=SecurityEventLevel.ERROR,
287
+ message=f"Request lock timeout: {request_id}",
288
+ client_id=client_id,
289
+ operation=operation,
290
+ )
291
+
292
+ raise ResourceLimitExceededError(
293
+ f"Unable to acquire request lock within {timeout}s"
294
+ )
295
+
296
+ def _release_request_lock(
297
+ self, request_id: str, client_id: str, operation: str
298
+ ) -> None:
299
+ """Release a request lock."""
300
+
301
+ with self._lock:
302
+ if request_id in self._active_requests:
303
+ self._active_requests.remove(request_id)
304
+ self._concurrent_requests = max(0, self._concurrent_requests - 1)
305
+
306
+ self.security_logger.log_security_event(
307
+ event_type=SecurityEventType.REQUEST_END,
308
+ level=SecurityEventLevel.INFO,
309
+ message=f"Request lock released: {request_id}",
310
+ client_id=client_id,
311
+ operation=operation,
312
+ )
313
+
314
+ def get_security_status(self) -> dict[str, t.Any]:
315
+ """Get current security status and metrics."""
316
+
317
+ with self._lock:
318
+ current_time = time.time()
319
+
320
+ # Calculate recent request rates
321
+ recent_requests = 0
322
+ for client_requests in self._rate_limit_tracker.values():
323
+ recent_requests += len(
324
+ [
325
+ req_time
326
+ for req_time in client_requests
327
+ if current_time - req_time < 60
328
+ ]
329
+ )
330
+
331
+ return {
332
+ "concurrent_requests": self._concurrent_requests,
333
+ "active_request_ids": list(self._active_requests),
334
+ "recent_requests_per_minute": recent_requests,
335
+ "rate_limit_clients": len(self._rate_limit_tracker),
336
+ "max_concurrent_limit": self.max_concurrent_requests,
337
+ "rate_limit_per_minute": self.rate_limit_per_minute,
338
+ "resource_usage_mb": self._resource_usage,
339
+ "max_resource_limit_mb": self.max_resource_usage_mb,
340
+ "allowed_paths_count": len(self.allowed_paths),
341
+ }
342
+
343
+
344
+ class RequestLock:
345
+ """Context manager for request lock acquisition and release."""
346
+
347
+ def __init__(
348
+ self,
349
+ security_manager: StatusSecurityManager,
350
+ request_id: str,
351
+ client_id: str,
352
+ operation: str,
353
+ ):
354
+ self.security_manager = security_manager
355
+ self.request_id = request_id
356
+ self.client_id = client_id
357
+ self.operation = operation
358
+
359
+ async def __aenter__(self) -> "RequestLock":
360
+ return self
361
+
362
+ async def __aexit__(self, exc_type: t.Any, exc_val: t.Any, exc_tb: t.Any) -> None:
363
+ self.security_manager._release_request_lock(
364
+ self.request_id,
365
+ self.client_id,
366
+ self.operation,
367
+ )
368
+
369
+
370
+ # Global instance for singleton pattern
371
+ _security_manager: StatusSecurityManager | None = None
372
+
373
+
374
+ def get_status_security_manager() -> StatusSecurityManager:
375
+ """Get the global status security manager instance."""
376
+
377
+ global _security_manager
378
+ if _security_manager is None:
379
+ # Initialize with project-specific paths
380
+ import tempfile
381
+ from pathlib import Path
382
+
383
+ project_root = Path.cwd()
384
+ temp_dir = Path(tempfile.gettempdir())
385
+ allowed_paths = {
386
+ str(project_root),
387
+ str(project_root / "temp"),
388
+ str(
389
+ temp_dir / "crackerjack-mcp-progress"
390
+ ), # B108: Use tempfile.gettempdir()
391
+ }
392
+
393
+ _security_manager = StatusSecurityManager(
394
+ allowed_paths=allowed_paths,
395
+ )
396
+
397
+ return _security_manager
398
+
399
+
400
+ async def validate_status_request(
401
+ client_id: str,
402
+ operation: str,
403
+ request_data: dict[str, t.Any] | None = None,
404
+ ) -> None:
405
+ """
406
+ Convenience function to validate status requests.
407
+
408
+ Args:
409
+ client_id: Client identifier
410
+ operation: Operation being requested
411
+ request_data: Optional request data to validate
412
+
413
+ Raises:
414
+ StatusSecurityError: If security validation fails
415
+ """
416
+
417
+ security_manager = get_status_security_manager()
418
+ security_manager.validate_request(client_id, operation, request_data)
419
+
420
+
421
+ async def secure_status_operation(
422
+ client_id: str,
423
+ operation: str,
424
+ timeout: float = 30.0,
425
+ ) -> RequestLock:
426
+ """
427
+ Acquire security lock for status operations.
428
+
429
+ Args:
430
+ client_id: Client identifier
431
+ operation: Operation being performed
432
+ timeout: Maximum wait time for lock
433
+
434
+ Returns:
435
+ RequestLock context manager
436
+
437
+ Raises:
438
+ ResourceLimitExceededError: If unable to acquire lock
439
+ """
440
+
441
+ security_manager = get_status_security_manager()
442
+ return await security_manager.acquire_request_lock(client_id, operation, timeout)