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.

Files changed (198) hide show
  1. crackerjack/__main__.py +1350 -34
  2. crackerjack/adapters/__init__.py +17 -0
  3. crackerjack/adapters/lsp_client.py +358 -0
  4. crackerjack/adapters/rust_tool_adapter.py +194 -0
  5. crackerjack/adapters/rust_tool_manager.py +193 -0
  6. crackerjack/adapters/skylos_adapter.py +231 -0
  7. crackerjack/adapters/zuban_adapter.py +560 -0
  8. crackerjack/agents/base.py +7 -3
  9. crackerjack/agents/coordinator.py +271 -33
  10. crackerjack/agents/documentation_agent.py +9 -15
  11. crackerjack/agents/dry_agent.py +3 -15
  12. crackerjack/agents/formatting_agent.py +1 -1
  13. crackerjack/agents/import_optimization_agent.py +36 -180
  14. crackerjack/agents/performance_agent.py +17 -98
  15. crackerjack/agents/performance_helpers.py +7 -31
  16. crackerjack/agents/proactive_agent.py +1 -3
  17. crackerjack/agents/refactoring_agent.py +16 -85
  18. crackerjack/agents/refactoring_helpers.py +7 -42
  19. crackerjack/agents/security_agent.py +9 -48
  20. crackerjack/agents/test_creation_agent.py +356 -513
  21. crackerjack/agents/test_specialist_agent.py +0 -4
  22. crackerjack/api.py +6 -25
  23. crackerjack/cli/cache_handlers.py +204 -0
  24. crackerjack/cli/cache_handlers_enhanced.py +683 -0
  25. crackerjack/cli/facade.py +100 -0
  26. crackerjack/cli/handlers.py +224 -9
  27. crackerjack/cli/interactive.py +6 -4
  28. crackerjack/cli/options.py +642 -55
  29. crackerjack/cli/utils.py +2 -1
  30. crackerjack/code_cleaner.py +58 -117
  31. crackerjack/config/global_lock_config.py +8 -48
  32. crackerjack/config/hooks.py +53 -62
  33. crackerjack/core/async_workflow_orchestrator.py +24 -34
  34. crackerjack/core/autofix_coordinator.py +3 -17
  35. crackerjack/core/enhanced_container.py +4 -13
  36. crackerjack/core/file_lifecycle.py +12 -89
  37. crackerjack/core/performance.py +2 -2
  38. crackerjack/core/performance_monitor.py +15 -55
  39. crackerjack/core/phase_coordinator.py +104 -204
  40. crackerjack/core/resource_manager.py +14 -90
  41. crackerjack/core/service_watchdog.py +62 -95
  42. crackerjack/core/session_coordinator.py +149 -0
  43. crackerjack/core/timeout_manager.py +14 -72
  44. crackerjack/core/websocket_lifecycle.py +13 -78
  45. crackerjack/core/workflow_orchestrator.py +171 -174
  46. crackerjack/docs/INDEX.md +11 -0
  47. crackerjack/docs/generated/api/API_REFERENCE.md +10895 -0
  48. crackerjack/docs/generated/api/CLI_REFERENCE.md +109 -0
  49. crackerjack/docs/generated/api/CROSS_REFERENCES.md +1755 -0
  50. crackerjack/docs/generated/api/PROTOCOLS.md +3 -0
  51. crackerjack/docs/generated/api/SERVICES.md +1252 -0
  52. crackerjack/documentation/__init__.py +31 -0
  53. crackerjack/documentation/ai_templates.py +756 -0
  54. crackerjack/documentation/dual_output_generator.py +765 -0
  55. crackerjack/documentation/mkdocs_integration.py +518 -0
  56. crackerjack/documentation/reference_generator.py +977 -0
  57. crackerjack/dynamic_config.py +55 -50
  58. crackerjack/executors/async_hook_executor.py +10 -15
  59. crackerjack/executors/cached_hook_executor.py +117 -43
  60. crackerjack/executors/hook_executor.py +8 -34
  61. crackerjack/executors/hook_lock_manager.py +26 -183
  62. crackerjack/executors/individual_hook_executor.py +13 -11
  63. crackerjack/executors/lsp_aware_hook_executor.py +270 -0
  64. crackerjack/executors/tool_proxy.py +417 -0
  65. crackerjack/hooks/lsp_hook.py +79 -0
  66. crackerjack/intelligence/adaptive_learning.py +25 -10
  67. crackerjack/intelligence/agent_orchestrator.py +2 -5
  68. crackerjack/intelligence/agent_registry.py +34 -24
  69. crackerjack/intelligence/agent_selector.py +5 -7
  70. crackerjack/interactive.py +17 -6
  71. crackerjack/managers/async_hook_manager.py +0 -1
  72. crackerjack/managers/hook_manager.py +79 -1
  73. crackerjack/managers/publish_manager.py +44 -8
  74. crackerjack/managers/test_command_builder.py +1 -15
  75. crackerjack/managers/test_executor.py +1 -3
  76. crackerjack/managers/test_manager.py +98 -7
  77. crackerjack/managers/test_manager_backup.py +10 -9
  78. crackerjack/mcp/cache.py +2 -2
  79. crackerjack/mcp/client_runner.py +1 -1
  80. crackerjack/mcp/context.py +191 -68
  81. crackerjack/mcp/dashboard.py +7 -5
  82. crackerjack/mcp/enhanced_progress_monitor.py +31 -28
  83. crackerjack/mcp/file_monitor.py +30 -23
  84. crackerjack/mcp/progress_components.py +31 -21
  85. crackerjack/mcp/progress_monitor.py +50 -53
  86. crackerjack/mcp/rate_limiter.py +6 -6
  87. crackerjack/mcp/server_core.py +17 -16
  88. crackerjack/mcp/service_watchdog.py +2 -1
  89. crackerjack/mcp/state.py +4 -7
  90. crackerjack/mcp/task_manager.py +11 -9
  91. crackerjack/mcp/tools/core_tools.py +173 -32
  92. crackerjack/mcp/tools/error_analyzer.py +3 -2
  93. crackerjack/mcp/tools/execution_tools.py +8 -10
  94. crackerjack/mcp/tools/execution_tools_backup.py +42 -30
  95. crackerjack/mcp/tools/intelligence_tool_registry.py +7 -5
  96. crackerjack/mcp/tools/intelligence_tools.py +5 -2
  97. crackerjack/mcp/tools/monitoring_tools.py +33 -70
  98. crackerjack/mcp/tools/proactive_tools.py +24 -11
  99. crackerjack/mcp/tools/progress_tools.py +5 -8
  100. crackerjack/mcp/tools/utility_tools.py +20 -14
  101. crackerjack/mcp/tools/workflow_executor.py +62 -40
  102. crackerjack/mcp/websocket/app.py +8 -0
  103. crackerjack/mcp/websocket/endpoints.py +352 -357
  104. crackerjack/mcp/websocket/jobs.py +40 -57
  105. crackerjack/mcp/websocket/monitoring_endpoints.py +2935 -0
  106. crackerjack/mcp/websocket/server.py +7 -25
  107. crackerjack/mcp/websocket/websocket_handler.py +6 -17
  108. crackerjack/mixins/__init__.py +0 -2
  109. crackerjack/mixins/error_handling.py +1 -70
  110. crackerjack/models/config.py +12 -1
  111. crackerjack/models/config_adapter.py +49 -1
  112. crackerjack/models/protocols.py +122 -122
  113. crackerjack/models/resource_protocols.py +55 -210
  114. crackerjack/monitoring/ai_agent_watchdog.py +13 -13
  115. crackerjack/monitoring/metrics_collector.py +426 -0
  116. crackerjack/monitoring/regression_prevention.py +8 -8
  117. crackerjack/monitoring/websocket_server.py +643 -0
  118. crackerjack/orchestration/advanced_orchestrator.py +11 -6
  119. crackerjack/orchestration/coverage_improvement.py +3 -3
  120. crackerjack/orchestration/execution_strategies.py +26 -6
  121. crackerjack/orchestration/test_progress_streamer.py +8 -5
  122. crackerjack/plugins/base.py +2 -2
  123. crackerjack/plugins/hooks.py +7 -0
  124. crackerjack/plugins/managers.py +11 -8
  125. crackerjack/security/__init__.py +0 -1
  126. crackerjack/security/audit.py +6 -35
  127. crackerjack/services/anomaly_detector.py +392 -0
  128. crackerjack/services/api_extractor.py +615 -0
  129. crackerjack/services/backup_service.py +2 -2
  130. crackerjack/services/bounded_status_operations.py +15 -152
  131. crackerjack/services/cache.py +127 -1
  132. crackerjack/services/changelog_automation.py +395 -0
  133. crackerjack/services/config.py +15 -9
  134. crackerjack/services/config_merge.py +19 -80
  135. crackerjack/services/config_template.py +506 -0
  136. crackerjack/services/contextual_ai_assistant.py +48 -22
  137. crackerjack/services/coverage_badge_service.py +171 -0
  138. crackerjack/services/coverage_ratchet.py +27 -25
  139. crackerjack/services/debug.py +3 -3
  140. crackerjack/services/dependency_analyzer.py +460 -0
  141. crackerjack/services/dependency_monitor.py +14 -11
  142. crackerjack/services/documentation_generator.py +491 -0
  143. crackerjack/services/documentation_service.py +675 -0
  144. crackerjack/services/enhanced_filesystem.py +6 -5
  145. crackerjack/services/enterprise_optimizer.py +865 -0
  146. crackerjack/services/error_pattern_analyzer.py +676 -0
  147. crackerjack/services/file_hasher.py +1 -1
  148. crackerjack/services/git.py +8 -25
  149. crackerjack/services/health_metrics.py +10 -8
  150. crackerjack/services/heatmap_generator.py +735 -0
  151. crackerjack/services/initialization.py +11 -30
  152. crackerjack/services/input_validator.py +5 -97
  153. crackerjack/services/intelligent_commit.py +327 -0
  154. crackerjack/services/log_manager.py +15 -12
  155. crackerjack/services/logging.py +4 -3
  156. crackerjack/services/lsp_client.py +628 -0
  157. crackerjack/services/memory_optimizer.py +19 -87
  158. crackerjack/services/metrics.py +42 -33
  159. crackerjack/services/parallel_executor.py +9 -67
  160. crackerjack/services/pattern_cache.py +1 -1
  161. crackerjack/services/pattern_detector.py +6 -6
  162. crackerjack/services/performance_benchmarks.py +18 -59
  163. crackerjack/services/performance_cache.py +20 -81
  164. crackerjack/services/performance_monitor.py +27 -95
  165. crackerjack/services/predictive_analytics.py +510 -0
  166. crackerjack/services/quality_baseline.py +234 -0
  167. crackerjack/services/quality_baseline_enhanced.py +646 -0
  168. crackerjack/services/quality_intelligence.py +785 -0
  169. crackerjack/services/regex_patterns.py +605 -524
  170. crackerjack/services/regex_utils.py +43 -123
  171. crackerjack/services/secure_path_utils.py +5 -164
  172. crackerjack/services/secure_status_formatter.py +30 -141
  173. crackerjack/services/secure_subprocess.py +11 -92
  174. crackerjack/services/security.py +9 -41
  175. crackerjack/services/security_logger.py +12 -24
  176. crackerjack/services/server_manager.py +124 -16
  177. crackerjack/services/status_authentication.py +16 -159
  178. crackerjack/services/status_security_manager.py +4 -131
  179. crackerjack/services/thread_safe_status_collector.py +19 -125
  180. crackerjack/services/unified_config.py +21 -13
  181. crackerjack/services/validation_rate_limiter.py +5 -54
  182. crackerjack/services/version_analyzer.py +459 -0
  183. crackerjack/services/version_checker.py +1 -1
  184. crackerjack/services/websocket_resource_limiter.py +10 -144
  185. crackerjack/services/zuban_lsp_service.py +390 -0
  186. crackerjack/slash_commands/__init__.py +2 -7
  187. crackerjack/slash_commands/run.md +2 -2
  188. crackerjack/tools/validate_input_validator_patterns.py +14 -40
  189. crackerjack/tools/validate_regex_patterns.py +19 -48
  190. {crackerjack-0.33.0.dist-info → crackerjack-0.33.1.dist-info}/METADATA +196 -25
  191. crackerjack-0.33.1.dist-info/RECORD +229 -0
  192. crackerjack/CLAUDE.md +0 -207
  193. crackerjack/RULES.md +0 -380
  194. crackerjack/py313.py +0 -234
  195. crackerjack-0.33.0.dist-info/RECORD +0 -187
  196. {crackerjack-0.33.0.dist-info → crackerjack-0.33.1.dist-info}/WHEEL +0 -0
  197. {crackerjack-0.33.0.dist-info → crackerjack-0.33.1.dist-info}/entry_points.txt +0 -0
  198. {crackerjack-0.33.0.dist-info → crackerjack-0.33.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,11 +1,3 @@
1
- """
2
- Secure status formatter to prevent information disclosure vulnerabilities.
3
-
4
- This module provides secure sanitization of status responses to prevent
5
- leaking sensitive system information such as absolute paths, internal URLs,
6
- configuration details, and other sensitive data.
7
- """
8
-
9
1
  import tempfile
10
2
  import typing as t
11
3
  from enum import Enum
@@ -15,51 +7,37 @@ from .security_logger import get_security_logger
15
7
 
16
8
 
17
9
  class StatusVerbosity(str, Enum):
18
- """Status output verbosity levels for security-aware responses."""
19
-
20
- MINIMAL = "minimal" # Only essential operational status
21
- STANDARD = "standard" # Standard operational information (default)
22
- DETAILED = "detailed" # More detailed information for debugging
23
- FULL = "full" # Complete information (for internal use only)
10
+ MINIMAL = "minimal"
11
+ STANDARD = "standard"
12
+ DETAILED = "detailed"
13
+ FULL = "full"
24
14
 
25
15
 
26
16
  class SecureStatusFormatter:
27
- """
28
- Secure status formatter with configurable verbosity levels.
29
-
30
- Sanitizes sensitive information while preserving necessary operational data.
31
- """
32
-
33
- # Patterns for sensitive information that should be masked or removed
34
17
  SENSITIVE_PATTERNS = {
35
- # Absolute system paths (replace with relative paths)
36
18
  "absolute_paths": [
37
- r"(/[^/\s]*){2,}", # Paths like /Users/username/...
38
- rf"{tempfile.gettempdir()}/[^\s]*", # Temp directory paths - using tempfile.gettempdir() (B108)
39
- r"/var/[^\s]*", # Var directory paths
40
- r"/home/[^\s]*", # Home directory paths
19
+ r"(/[^/\s]*){2, }",
20
+ rf"{tempfile.gettempdir()}/[^\s]*",
21
+ r"/var/[^\s]*",
22
+ r"/home/[^\s]*",
41
23
  ],
42
- # URLs with localhost/internal IPs
43
24
  "internal_urls": [
44
- r"https?://localhost:\d+",
45
- r"https?://127\.0\.0\.1:\d+",
46
- r"https?://0\.0\.0\.0:\d+",
47
- r"ws://localhost:\d+",
48
- r"ws://127\.0\.0\.1:\d+",
25
+ r"https?: //localhost: \d+",
26
+ r"https?: //127\.0\.0\.1: \d+",
27
+ r"https?: //0\.0\.0\.0: \d+",
28
+ r"ws: //localhost: \d+",
29
+ r"ws: //127\.0\.0\.1: \d+",
49
30
  ],
50
- # Tokens and API keys
51
31
  "secrets": [
52
- r"[A-Za-z0-9]{20,}", # Long alphanumeric strings (potential tokens)
53
- r"[A-Za-z0-9+/]{32,}={0,2}", # Base64-like strings
32
+ r"[A-Za-z0-9]{20, }",
33
+ r"[A-Za-z0-9+/]{32, }={0, 2}",
54
34
  ],
55
- # Process IDs and system identifiers
56
35
  "system_ids": [
57
- r"pid:\d+",
58
- r"process_id:\s*\d+",
36
+ r"pid: \d+",
37
+ r"process_id: \s*\d+",
59
38
  ],
60
39
  }
61
40
 
62
- # Sensitive keys that should be masked or removed
63
41
  SENSITIVE_KEYS = {
64
42
  "remove_minimal": {
65
43
  "progress_dir",
@@ -83,12 +61,6 @@ class SecureStatusFormatter:
83
61
  }
84
62
 
85
63
  def __init__(self, project_root: Path | None = None):
86
- """
87
- Initialize secure status formatter.
88
-
89
- Args:
90
- project_root: Project root path for relative path conversion
91
- """
92
64
  self.project_root = project_root or Path.cwd()
93
65
  self.security_logger = get_security_logger()
94
66
 
@@ -98,17 +70,6 @@ class SecureStatusFormatter:
98
70
  verbosity: StatusVerbosity = StatusVerbosity.STANDARD,
99
71
  user_context: str | None = None,
100
72
  ) -> dict[str, t.Any]:
101
- """
102
- Format status data with security sanitization.
103
-
104
- Args:
105
- status_data: Raw status data to sanitize
106
- verbosity: Output verbosity level
107
- user_context: Optional user context for logging
108
-
109
- Returns:
110
- Sanitized status data appropriate for the verbosity level
111
- """
112
73
  self._log_status_access(status_data, verbosity, user_context)
113
74
  sanitized = self._prepare_data_for_sanitization(status_data)
114
75
  sanitized = self._apply_all_sanitization_steps(sanitized, verbosity)
@@ -120,31 +81,27 @@ class SecureStatusFormatter:
120
81
  verbosity: StatusVerbosity,
121
82
  user_context: str | None,
122
83
  ) -> None:
123
- """Log status access attempt for security monitoring."""
124
84
  self.security_logger.log_status_access_attempt(
125
85
  endpoint="status_data",
126
86
  verbosity_level=verbosity.value,
127
87
  user_context=user_context,
128
- data_keys=list(status_data.keys()),
88
+ data_keys=list[t.Any](status_data.keys()),
129
89
  )
130
90
 
131
91
  def _prepare_data_for_sanitization(
132
92
  self, status_data: dict[str, t.Any]
133
93
  ) -> dict[str, t.Any]:
134
- """Create a deep copy of status data to avoid modifying original."""
135
- return self._deep_copy_dict(status_data)
94
+ return self._deep_copy_dict(status_data) # type: ignore[no-any-return]
136
95
 
137
96
  def _apply_all_sanitization_steps(
138
97
  self, data: dict[str, t.Any], verbosity: StatusVerbosity
139
98
  ) -> dict[str, t.Any]:
140
- """Apply all sanitization steps in proper order."""
141
99
  data = self._apply_verbosity_filter(data, verbosity)
142
100
  return self._sanitize_sensitive_data(data, verbosity)
143
101
 
144
102
  def _add_security_metadata(
145
103
  self, data: dict[str, t.Any], verbosity: StatusVerbosity
146
104
  ) -> dict[str, t.Any]:
147
- """Add security metadata to sanitized response."""
148
105
  data["_security"] = {
149
106
  "sanitized": True,
150
107
  "verbosity": verbosity.value,
@@ -155,22 +112,17 @@ class SecureStatusFormatter:
155
112
  def _apply_verbosity_filter(
156
113
  self, data: dict[str, t.Any], verbosity: StatusVerbosity
157
114
  ) -> dict[str, t.Any]:
158
- """Apply verbosity-based key filtering."""
159
-
160
- # Keys to remove based on verbosity level
161
115
  if verbosity == StatusVerbosity.MINIMAL:
162
116
  remove_keys = self.SENSITIVE_KEYS["remove_minimal"]
163
117
  elif verbosity == StatusVerbosity.STANDARD:
164
118
  remove_keys = self.SENSITIVE_KEYS["remove_standard"]
165
119
  else:
166
- remove_keys = set() # Keep all keys for DETAILED/FULL
120
+ remove_keys = set()
167
121
 
168
- # Remove sensitive keys
169
- for key in list(data.keys()):
122
+ for key in list[t.Any](data.keys()):
170
123
  if key in remove_keys:
171
124
  del data[key]
172
125
 
173
- # Recursively apply to nested dictionaries
174
126
  for key, value in data.items():
175
127
  if isinstance(value, dict):
176
128
  data[key] = self._apply_verbosity_filter(value, verbosity)
@@ -180,20 +132,14 @@ class SecureStatusFormatter:
180
132
  def _sanitize_sensitive_data(
181
133
  self, data: dict[str, t.Any], verbosity: StatusVerbosity
182
134
  ) -> dict[str, t.Any]:
183
- """Sanitize sensitive data based on patterns and keys."""
184
-
185
- return self._sanitize_recursive(data, verbosity)
135
+ return self._sanitize_recursive(data, verbosity) # type: ignore[no-any-return]
186
136
 
187
137
  def _sanitize_recursive(self, obj: t.Any, verbosity: StatusVerbosity) -> t.Any:
188
- """Recursively sanitize data structures."""
189
-
190
138
  if isinstance(obj, dict):
191
139
  sanitized = {}
192
140
  for key, value in obj.items():
193
- # Sanitize the key
194
141
  sanitized_key = self._sanitize_string(key, verbosity)
195
142
 
196
- # Sanitize the value
197
143
  if (
198
144
  key in self.SENSITIVE_KEYS["mask"]
199
145
  and verbosity != StatusVerbosity.FULL
@@ -215,16 +161,14 @@ class SecureStatusFormatter:
215
161
  return obj
216
162
 
217
163
  def _sanitize_string(self, text: str, verbosity: StatusVerbosity) -> str:
218
- """Sanitize string content based on verbosity level."""
219
164
  if verbosity == StatusVerbosity.FULL:
220
- return text # No sanitization for full verbosity
165
+ return text
221
166
 
222
167
  return self._apply_string_sanitization_pipeline(text, verbosity)
223
168
 
224
169
  def _apply_string_sanitization_pipeline(
225
170
  self, text: str, verbosity: StatusVerbosity
226
171
  ) -> str:
227
- """Apply string sanitization steps in correct order."""
228
172
  sanitized = self._sanitize_internal_urls(text)
229
173
  sanitized = self._sanitize_paths(sanitized)
230
174
  return self._apply_secret_masking_if_needed(sanitized, verbosity)
@@ -232,16 +176,13 @@ class SecureStatusFormatter:
232
176
  def _apply_secret_masking_if_needed(
233
177
  self, text: str, verbosity: StatusVerbosity
234
178
  ) -> str:
235
- """Apply secret masking for minimal verbosity only."""
236
179
  if verbosity == StatusVerbosity.MINIMAL:
237
180
  return self._mask_potential_secrets(text)
238
181
  return text
239
182
 
240
183
  def _sanitize_paths(self, text: str) -> str:
241
- """Convert absolute paths to relative paths where possible."""
242
184
  from .regex_patterns import SAFE_PATTERNS
243
185
 
244
- # Use validated patterns for path detection
245
186
  unix_path_pattern = SAFE_PATTERNS.get("detect_absolute_unix_paths")
246
187
 
247
188
  if not unix_path_pattern:
@@ -250,10 +191,9 @@ class SecureStatusFormatter:
250
191
  return text
251
192
 
252
193
  def _sanitize_paths_fallback(self, text: str) -> str:
253
- """Fallback path sanitization when patterns don't exist."""
254
194
  path_patterns = [
255
- r"/[a-zA-Z0-9_\-\.\/]+", # Unix-style absolute paths
256
- r"[A-Z]:[\\\/][a-zA-Z0-9_\-\.\\\/]+", # Windows-style absolute paths
195
+ r"/[a-zA-Z0-9_\-\.\/]+",
196
+ r"[A-Z]: [\\\/][a-zA-Z0-9_\-\.\\\/]+",
257
197
  ]
258
198
 
259
199
  for pattern_str in path_patterns:
@@ -262,7 +202,6 @@ class SecureStatusFormatter:
262
202
  return text
263
203
 
264
204
  def _process_path_pattern(self, text: str, pattern_str: str) -> str:
265
- """Process a single path pattern safely."""
266
205
  from contextlib import suppress
267
206
 
268
207
  from .regex_patterns import CompiledPatternCache
@@ -272,19 +211,17 @@ class SecureStatusFormatter:
272
211
  matches = compiled.findall(text)
273
212
 
274
213
  for match in matches:
275
- if len(match) > 3: # Only process paths longer than 3 chars
214
+ if len(match) > 3:
276
215
  text = self._replace_path_match(text, match)
277
216
 
278
217
  return text
279
218
 
280
219
  def _replace_path_match(self, text: str, match: str) -> str:
281
- """Replace a single path match with relative or redacted version."""
282
220
  try:
283
221
  abs_path = Path(match)
284
222
  if abs_path.is_absolute():
285
223
  return self._convert_to_relative_or_redact(text, match, abs_path)
286
224
  except (ValueError, OSError):
287
- # If path operations fail, mask it
288
225
  text = text.replace(match, "[REDACTED_PATH]")
289
226
 
290
227
  return text
@@ -292,22 +229,18 @@ class SecureStatusFormatter:
292
229
  def _convert_to_relative_or_redact(
293
230
  self, text: str, match: str, abs_path: Path
294
231
  ) -> str:
295
- """Convert absolute path to relative or redact if outside project."""
296
232
  try:
297
233
  rel_path = abs_path.relative_to(self.project_root)
298
234
  return text.replace(match, f"./{rel_path}")
299
235
  except (ValueError, OSError):
300
- # If not within project, mask it
301
236
  return text.replace(match, "[REDACTED_PATH]")
302
237
 
303
238
  def _sanitize_internal_urls(self, text: str) -> str:
304
- """Replace internal URLs with generic placeholders."""
305
239
  from .regex_patterns import sanitize_internal_urls
306
240
 
307
241
  return sanitize_internal_urls(text)
308
242
 
309
243
  def _mask_potential_secrets(self, text: str) -> str:
310
- """Mask strings that might be secrets."""
311
244
  if self._should_skip_secret_masking(text):
312
245
  return text
313
246
 
@@ -318,11 +251,9 @@ class SecureStatusFormatter:
318
251
  return self._apply_fallback_secret_patterns(text)
319
252
 
320
253
  def _should_skip_secret_masking(self, text: str) -> bool:
321
- """Check if secret masking should be skipped for already sanitized content."""
322
254
  return "[INTERNAL_URL]" in text or "[REDACTED_PATH]" in text
323
255
 
324
256
  def _get_validated_secret_patterns(self) -> list[t.Any]:
325
- """Get validated patterns from the safe patterns registry."""
326
257
  from .regex_patterns import SAFE_PATTERNS
327
258
 
328
259
  patterns = []
@@ -337,16 +268,14 @@ class SecureStatusFormatter:
337
268
  return patterns
338
269
 
339
270
  def _apply_validated_secret_patterns(self, text: str, patterns: list[t.Any]) -> str:
340
- """Apply validated patterns for secret detection."""
341
271
  for pattern in patterns:
342
272
  try:
343
273
  text = self._mask_pattern_matches(text, pattern.findall(text))
344
274
  except Exception:
345
- continue # Skip failed pattern matching
275
+ continue
346
276
  return text
347
277
 
348
278
  def _apply_fallback_secret_patterns(self, text: str) -> str:
349
- """Apply fallback patterns when validated patterns don't exist."""
350
279
  for pattern_str in self.SENSITIVE_PATTERNS["secrets"]:
351
280
  try:
352
281
  from .regex_patterns import CompiledPatternCache
@@ -354,11 +283,10 @@ class SecureStatusFormatter:
354
283
  compiled = CompiledPatternCache.get_compiled_pattern(pattern_str)
355
284
  text = self._mask_pattern_matches(text, compiled.findall(text))
356
285
  except Exception:
357
- continue # Skip failed pattern compilation
286
+ continue
358
287
  return text
359
288
 
360
289
  def _mask_pattern_matches(self, text: str, matches: list[str]) -> str:
361
- """Mask matches from pattern matching."""
362
290
  for match in matches:
363
291
  if self._should_mask_match(match):
364
292
  masked = self._create_masked_string(match)
@@ -366,19 +294,15 @@ class SecureStatusFormatter:
366
294
  return text
367
295
 
368
296
  def _should_mask_match(self, match: str) -> bool:
369
- """Determine if a match should be masked."""
370
297
  if len(match) <= 16:
371
298
  return False
372
- # Don't mask if it looks like a URL or path component
373
- return not any(x in match for x in ("://", "/", "\\", "."))
299
+
300
+ return not any(x in match for x in (": //", "/", "\\", "."))
374
301
 
375
302
  def _create_masked_string(self, text: str) -> str:
376
- """Create a masked version of the text."""
377
303
  return text[:4] + "*" * (len(text) - 8) + text[-4:]
378
304
 
379
305
  def _mask_sensitive_value(self, value: str) -> str:
380
- """Mask a known sensitive value."""
381
-
382
306
  if len(value) <= 4:
383
307
  return "***"
384
308
  elif len(value) <= 8:
@@ -386,8 +310,6 @@ class SecureStatusFormatter:
386
310
  return value[:2] + "*" * (len(value) - 4) + value[-2:]
387
311
 
388
312
  def _deep_copy_dict(self, obj: t.Any) -> t.Any:
389
- """Deep copy a dictionary-like object safely."""
390
-
391
313
  if isinstance(obj, dict):
392
314
  return {key: self._deep_copy_dict(value) for key, value in obj.items()}
393
315
  elif isinstance(obj, list):
@@ -395,7 +317,6 @@ class SecureStatusFormatter:
395
317
  return obj
396
318
 
397
319
  def _get_timestamp(self) -> float:
398
- """Get current timestamp."""
399
320
  import time
400
321
 
401
322
  return time.time()
@@ -406,17 +327,6 @@ class SecureStatusFormatter:
406
327
  verbosity: StatusVerbosity = StatusVerbosity.STANDARD,
407
328
  include_details: bool = False,
408
329
  ) -> dict[str, t.Any]:
409
- """
410
- Format error responses without leaking system details.
411
-
412
- Args:
413
- error_message: Original error message
414
- verbosity: Output verbosity level
415
- include_details: Whether to include error details
416
-
417
- Returns:
418
- Sanitized error response
419
- """
420
330
  error_type = self._classify_error(error_message)
421
331
 
422
332
  if verbosity == StatusVerbosity.MINIMAL:
@@ -427,7 +337,6 @@ class SecureStatusFormatter:
427
337
  )
428
338
 
429
339
  def _create_minimal_error_response(self, error_type: str) -> dict[str, t.Any]:
430
- """Create minimal error response for production use."""
431
340
  generic_messages = {
432
341
  "connection": "Service temporarily unavailable. Please try again later.",
433
342
  "validation": "Invalid request parameters.",
@@ -449,7 +358,6 @@ class SecureStatusFormatter:
449
358
  verbosity: StatusVerbosity,
450
359
  include_details: bool,
451
360
  ) -> dict[str, t.Any]:
452
- """Create detailed error response with sanitized message."""
453
361
  sanitized_message = self._sanitize_string(error_message, verbosity)
454
362
 
455
363
  response: dict[str, t.Any] = {
@@ -470,15 +378,12 @@ class SecureStatusFormatter:
470
378
  def _should_include_error_details(
471
379
  self, include_details: bool, verbosity: StatusVerbosity
472
380
  ) -> bool:
473
- """Determine if error details should be included."""
474
381
  return include_details and verbosity in (
475
382
  StatusVerbosity.DETAILED,
476
383
  StatusVerbosity.FULL,
477
384
  )
478
385
 
479
386
  def _classify_error(self, error_message: str) -> str:
480
- """Classify error message type for appropriate handling."""
481
-
482
387
  error_patterns = {
483
388
  "connection": ["connection", "timeout", "refused", "unavailable"],
484
389
  "validation": ["invalid", "validation", "format", "parameter"],
@@ -495,15 +400,12 @@ class SecureStatusFormatter:
495
400
  return "internal"
496
401
 
497
402
 
498
- # Singleton instance for global use
499
403
  _secure_formatter: SecureStatusFormatter | None = None
500
404
 
501
405
 
502
406
  def get_secure_status_formatter(
503
407
  project_root: Path | None = None,
504
408
  ) -> SecureStatusFormatter:
505
- """Get the global secure status formatter instance."""
506
-
507
409
  global _secure_formatter
508
410
  if _secure_formatter is None:
509
411
  _secure_formatter = SecureStatusFormatter(project_root)
@@ -516,19 +418,6 @@ def format_secure_status(
516
418
  project_root: Path | None = None,
517
419
  user_context: str | None = None,
518
420
  ) -> dict[str, t.Any]:
519
- """
520
- Convenience function for secure status formatting.
521
-
522
- Args:
523
- status_data: Raw status data to sanitize
524
- verbosity: Output verbosity level
525
- project_root: Project root for relative path conversion
526
- user_context: Optional user context for logging
527
-
528
- Returns:
529
- Sanitized status data
530
- """
531
-
532
421
  return get_secure_status_formatter(project_root).format_status(
533
422
  status_data, verbosity, user_context
534
423
  )