crackerjack 0.18.2__py3-none-any.whl → 0.45.2__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.
Files changed (533) hide show
  1. crackerjack/README.md +19 -0
  2. crackerjack/__init__.py +96 -2
  3. crackerjack/__main__.py +637 -138
  4. crackerjack/adapters/README.md +18 -0
  5. crackerjack/adapters/__init__.py +39 -0
  6. crackerjack/adapters/_output_paths.py +167 -0
  7. crackerjack/adapters/_qa_adapter_base.py +309 -0
  8. crackerjack/adapters/_tool_adapter_base.py +706 -0
  9. crackerjack/adapters/ai/README.md +65 -0
  10. crackerjack/adapters/ai/__init__.py +5 -0
  11. crackerjack/adapters/ai/claude.py +853 -0
  12. crackerjack/adapters/complexity/README.md +53 -0
  13. crackerjack/adapters/complexity/__init__.py +10 -0
  14. crackerjack/adapters/complexity/complexipy.py +641 -0
  15. crackerjack/adapters/dependency/__init__.py +22 -0
  16. crackerjack/adapters/dependency/pip_audit.py +418 -0
  17. crackerjack/adapters/format/README.md +72 -0
  18. crackerjack/adapters/format/__init__.py +11 -0
  19. crackerjack/adapters/format/mdformat.py +313 -0
  20. crackerjack/adapters/format/ruff.py +516 -0
  21. crackerjack/adapters/lint/README.md +47 -0
  22. crackerjack/adapters/lint/__init__.py +11 -0
  23. crackerjack/adapters/lint/codespell.py +273 -0
  24. crackerjack/adapters/lsp/README.md +49 -0
  25. crackerjack/adapters/lsp/__init__.py +27 -0
  26. crackerjack/adapters/lsp/_base.py +194 -0
  27. crackerjack/adapters/lsp/_client.py +358 -0
  28. crackerjack/adapters/lsp/_manager.py +193 -0
  29. crackerjack/adapters/lsp/skylos.py +283 -0
  30. crackerjack/adapters/lsp/zuban.py +557 -0
  31. crackerjack/adapters/refactor/README.md +59 -0
  32. crackerjack/adapters/refactor/__init__.py +12 -0
  33. crackerjack/adapters/refactor/creosote.py +318 -0
  34. crackerjack/adapters/refactor/refurb.py +406 -0
  35. crackerjack/adapters/refactor/skylos.py +494 -0
  36. crackerjack/adapters/sast/README.md +132 -0
  37. crackerjack/adapters/sast/__init__.py +32 -0
  38. crackerjack/adapters/sast/_base.py +201 -0
  39. crackerjack/adapters/sast/bandit.py +423 -0
  40. crackerjack/adapters/sast/pyscn.py +405 -0
  41. crackerjack/adapters/sast/semgrep.py +241 -0
  42. crackerjack/adapters/security/README.md +111 -0
  43. crackerjack/adapters/security/__init__.py +17 -0
  44. crackerjack/adapters/security/gitleaks.py +339 -0
  45. crackerjack/adapters/type/README.md +52 -0
  46. crackerjack/adapters/type/__init__.py +12 -0
  47. crackerjack/adapters/type/pyrefly.py +402 -0
  48. crackerjack/adapters/type/ty.py +402 -0
  49. crackerjack/adapters/type/zuban.py +522 -0
  50. crackerjack/adapters/utility/README.md +51 -0
  51. crackerjack/adapters/utility/__init__.py +10 -0
  52. crackerjack/adapters/utility/checks.py +884 -0
  53. crackerjack/agents/README.md +264 -0
  54. crackerjack/agents/__init__.py +66 -0
  55. crackerjack/agents/architect_agent.py +238 -0
  56. crackerjack/agents/base.py +167 -0
  57. crackerjack/agents/claude_code_bridge.py +641 -0
  58. crackerjack/agents/coordinator.py +600 -0
  59. crackerjack/agents/documentation_agent.py +520 -0
  60. crackerjack/agents/dry_agent.py +585 -0
  61. crackerjack/agents/enhanced_coordinator.py +279 -0
  62. crackerjack/agents/enhanced_proactive_agent.py +185 -0
  63. crackerjack/agents/error_middleware.py +53 -0
  64. crackerjack/agents/formatting_agent.py +230 -0
  65. crackerjack/agents/helpers/__init__.py +9 -0
  66. crackerjack/agents/helpers/performance/__init__.py +22 -0
  67. crackerjack/agents/helpers/performance/performance_ast_analyzer.py +357 -0
  68. crackerjack/agents/helpers/performance/performance_pattern_detector.py +909 -0
  69. crackerjack/agents/helpers/performance/performance_recommender.py +572 -0
  70. crackerjack/agents/helpers/refactoring/__init__.py +22 -0
  71. crackerjack/agents/helpers/refactoring/code_transformer.py +536 -0
  72. crackerjack/agents/helpers/refactoring/complexity_analyzer.py +344 -0
  73. crackerjack/agents/helpers/refactoring/dead_code_detector.py +437 -0
  74. crackerjack/agents/helpers/test_creation/__init__.py +19 -0
  75. crackerjack/agents/helpers/test_creation/test_ast_analyzer.py +216 -0
  76. crackerjack/agents/helpers/test_creation/test_coverage_analyzer.py +643 -0
  77. crackerjack/agents/helpers/test_creation/test_template_generator.py +1031 -0
  78. crackerjack/agents/import_optimization_agent.py +1181 -0
  79. crackerjack/agents/performance_agent.py +325 -0
  80. crackerjack/agents/performance_helpers.py +205 -0
  81. crackerjack/agents/proactive_agent.py +55 -0
  82. crackerjack/agents/refactoring_agent.py +511 -0
  83. crackerjack/agents/refactoring_helpers.py +247 -0
  84. crackerjack/agents/security_agent.py +793 -0
  85. crackerjack/agents/semantic_agent.py +479 -0
  86. crackerjack/agents/semantic_helpers.py +356 -0
  87. crackerjack/agents/test_creation_agent.py +570 -0
  88. crackerjack/agents/test_specialist_agent.py +526 -0
  89. crackerjack/agents/tracker.py +110 -0
  90. crackerjack/api.py +647 -0
  91. crackerjack/cli/README.md +394 -0
  92. crackerjack/cli/__init__.py +24 -0
  93. crackerjack/cli/cache_handlers.py +209 -0
  94. crackerjack/cli/cache_handlers_enhanced.py +680 -0
  95. crackerjack/cli/facade.py +162 -0
  96. crackerjack/cli/formatting.py +13 -0
  97. crackerjack/cli/handlers/__init__.py +85 -0
  98. crackerjack/cli/handlers/advanced.py +103 -0
  99. crackerjack/cli/handlers/ai_features.py +62 -0
  100. crackerjack/cli/handlers/analytics.py +479 -0
  101. crackerjack/cli/handlers/changelog.py +271 -0
  102. crackerjack/cli/handlers/config_handlers.py +16 -0
  103. crackerjack/cli/handlers/coverage.py +84 -0
  104. crackerjack/cli/handlers/documentation.py +280 -0
  105. crackerjack/cli/handlers/main_handlers.py +497 -0
  106. crackerjack/cli/handlers/monitoring.py +371 -0
  107. crackerjack/cli/handlers.py +700 -0
  108. crackerjack/cli/interactive.py +488 -0
  109. crackerjack/cli/options.py +1216 -0
  110. crackerjack/cli/semantic_handlers.py +292 -0
  111. crackerjack/cli/utils.py +19 -0
  112. crackerjack/cli/version.py +19 -0
  113. crackerjack/code_cleaner.py +1307 -0
  114. crackerjack/config/README.md +472 -0
  115. crackerjack/config/__init__.py +275 -0
  116. crackerjack/config/global_lock_config.py +207 -0
  117. crackerjack/config/hooks.py +390 -0
  118. crackerjack/config/loader.py +239 -0
  119. crackerjack/config/settings.py +141 -0
  120. crackerjack/config/tool_commands.py +331 -0
  121. crackerjack/core/README.md +393 -0
  122. crackerjack/core/__init__.py +0 -0
  123. crackerjack/core/async_workflow_orchestrator.py +738 -0
  124. crackerjack/core/autofix_coordinator.py +282 -0
  125. crackerjack/core/container.py +105 -0
  126. crackerjack/core/enhanced_container.py +583 -0
  127. crackerjack/core/file_lifecycle.py +472 -0
  128. crackerjack/core/performance.py +244 -0
  129. crackerjack/core/performance_monitor.py +357 -0
  130. crackerjack/core/phase_coordinator.py +1227 -0
  131. crackerjack/core/proactive_workflow.py +267 -0
  132. crackerjack/core/resource_manager.py +425 -0
  133. crackerjack/core/retry.py +275 -0
  134. crackerjack/core/service_watchdog.py +601 -0
  135. crackerjack/core/session_coordinator.py +239 -0
  136. crackerjack/core/timeout_manager.py +563 -0
  137. crackerjack/core/websocket_lifecycle.py +410 -0
  138. crackerjack/core/workflow/__init__.py +21 -0
  139. crackerjack/core/workflow/workflow_ai_coordinator.py +863 -0
  140. crackerjack/core/workflow/workflow_event_orchestrator.py +1107 -0
  141. crackerjack/core/workflow/workflow_issue_parser.py +714 -0
  142. crackerjack/core/workflow/workflow_phase_executor.py +1158 -0
  143. crackerjack/core/workflow/workflow_security_gates.py +400 -0
  144. crackerjack/core/workflow_orchestrator.py +2243 -0
  145. crackerjack/data/README.md +11 -0
  146. crackerjack/data/__init__.py +8 -0
  147. crackerjack/data/models.py +79 -0
  148. crackerjack/data/repository.py +210 -0
  149. crackerjack/decorators/README.md +180 -0
  150. crackerjack/decorators/__init__.py +35 -0
  151. crackerjack/decorators/error_handling.py +649 -0
  152. crackerjack/decorators/error_handling_decorators.py +334 -0
  153. crackerjack/decorators/helpers.py +58 -0
  154. crackerjack/decorators/patterns.py +281 -0
  155. crackerjack/decorators/utils.py +58 -0
  156. crackerjack/docs/INDEX.md +11 -0
  157. crackerjack/docs/README.md +11 -0
  158. crackerjack/docs/generated/api/API_REFERENCE.md +10895 -0
  159. crackerjack/docs/generated/api/CLI_REFERENCE.md +109 -0
  160. crackerjack/docs/generated/api/CROSS_REFERENCES.md +1755 -0
  161. crackerjack/docs/generated/api/PROTOCOLS.md +3 -0
  162. crackerjack/docs/generated/api/SERVICES.md +1252 -0
  163. crackerjack/documentation/README.md +11 -0
  164. crackerjack/documentation/__init__.py +31 -0
  165. crackerjack/documentation/ai_templates.py +756 -0
  166. crackerjack/documentation/dual_output_generator.py +767 -0
  167. crackerjack/documentation/mkdocs_integration.py +518 -0
  168. crackerjack/documentation/reference_generator.py +1065 -0
  169. crackerjack/dynamic_config.py +678 -0
  170. crackerjack/errors.py +378 -0
  171. crackerjack/events/README.md +11 -0
  172. crackerjack/events/__init__.py +16 -0
  173. crackerjack/events/telemetry.py +175 -0
  174. crackerjack/events/workflow_bus.py +346 -0
  175. crackerjack/exceptions/README.md +301 -0
  176. crackerjack/exceptions/__init__.py +5 -0
  177. crackerjack/exceptions/config.py +4 -0
  178. crackerjack/exceptions/tool_execution_error.py +245 -0
  179. crackerjack/executors/README.md +591 -0
  180. crackerjack/executors/__init__.py +13 -0
  181. crackerjack/executors/async_hook_executor.py +938 -0
  182. crackerjack/executors/cached_hook_executor.py +316 -0
  183. crackerjack/executors/hook_executor.py +1295 -0
  184. crackerjack/executors/hook_lock_manager.py +708 -0
  185. crackerjack/executors/individual_hook_executor.py +739 -0
  186. crackerjack/executors/lsp_aware_hook_executor.py +349 -0
  187. crackerjack/executors/progress_hook_executor.py +282 -0
  188. crackerjack/executors/tool_proxy.py +433 -0
  189. crackerjack/hooks/README.md +485 -0
  190. crackerjack/hooks/lsp_hook.py +93 -0
  191. crackerjack/intelligence/README.md +557 -0
  192. crackerjack/intelligence/__init__.py +37 -0
  193. crackerjack/intelligence/adaptive_learning.py +693 -0
  194. crackerjack/intelligence/agent_orchestrator.py +485 -0
  195. crackerjack/intelligence/agent_registry.py +377 -0
  196. crackerjack/intelligence/agent_selector.py +439 -0
  197. crackerjack/intelligence/integration.py +250 -0
  198. crackerjack/interactive.py +719 -0
  199. crackerjack/managers/README.md +369 -0
  200. crackerjack/managers/__init__.py +11 -0
  201. crackerjack/managers/async_hook_manager.py +135 -0
  202. crackerjack/managers/hook_manager.py +585 -0
  203. crackerjack/managers/publish_manager.py +631 -0
  204. crackerjack/managers/test_command_builder.py +391 -0
  205. crackerjack/managers/test_executor.py +474 -0
  206. crackerjack/managers/test_manager.py +1357 -0
  207. crackerjack/managers/test_progress.py +187 -0
  208. crackerjack/mcp/README.md +374 -0
  209. crackerjack/mcp/__init__.py +0 -0
  210. crackerjack/mcp/cache.py +352 -0
  211. crackerjack/mcp/client_runner.py +121 -0
  212. crackerjack/mcp/context.py +802 -0
  213. crackerjack/mcp/dashboard.py +657 -0
  214. crackerjack/mcp/enhanced_progress_monitor.py +493 -0
  215. crackerjack/mcp/file_monitor.py +394 -0
  216. crackerjack/mcp/progress_components.py +607 -0
  217. crackerjack/mcp/progress_monitor.py +1016 -0
  218. crackerjack/mcp/rate_limiter.py +336 -0
  219. crackerjack/mcp/server.py +24 -0
  220. crackerjack/mcp/server_core.py +526 -0
  221. crackerjack/mcp/service_watchdog.py +505 -0
  222. crackerjack/mcp/state.py +407 -0
  223. crackerjack/mcp/task_manager.py +259 -0
  224. crackerjack/mcp/tools/README.md +27 -0
  225. crackerjack/mcp/tools/__init__.py +19 -0
  226. crackerjack/mcp/tools/core_tools.py +469 -0
  227. crackerjack/mcp/tools/error_analyzer.py +283 -0
  228. crackerjack/mcp/tools/execution_tools.py +384 -0
  229. crackerjack/mcp/tools/intelligence_tool_registry.py +46 -0
  230. crackerjack/mcp/tools/intelligence_tools.py +264 -0
  231. crackerjack/mcp/tools/monitoring_tools.py +628 -0
  232. crackerjack/mcp/tools/proactive_tools.py +367 -0
  233. crackerjack/mcp/tools/progress_tools.py +222 -0
  234. crackerjack/mcp/tools/semantic_tools.py +584 -0
  235. crackerjack/mcp/tools/utility_tools.py +358 -0
  236. crackerjack/mcp/tools/workflow_executor.py +699 -0
  237. crackerjack/mcp/websocket/README.md +31 -0
  238. crackerjack/mcp/websocket/__init__.py +14 -0
  239. crackerjack/mcp/websocket/app.py +54 -0
  240. crackerjack/mcp/websocket/endpoints.py +492 -0
  241. crackerjack/mcp/websocket/event_bridge.py +188 -0
  242. crackerjack/mcp/websocket/jobs.py +406 -0
  243. crackerjack/mcp/websocket/monitoring/__init__.py +25 -0
  244. crackerjack/mcp/websocket/monitoring/api/__init__.py +19 -0
  245. crackerjack/mcp/websocket/monitoring/api/dependencies.py +141 -0
  246. crackerjack/mcp/websocket/monitoring/api/heatmap.py +154 -0
  247. crackerjack/mcp/websocket/monitoring/api/intelligence.py +199 -0
  248. crackerjack/mcp/websocket/monitoring/api/metrics.py +203 -0
  249. crackerjack/mcp/websocket/monitoring/api/telemetry.py +101 -0
  250. crackerjack/mcp/websocket/monitoring/dashboard.py +18 -0
  251. crackerjack/mcp/websocket/monitoring/factory.py +109 -0
  252. crackerjack/mcp/websocket/monitoring/filters.py +10 -0
  253. crackerjack/mcp/websocket/monitoring/metrics.py +64 -0
  254. crackerjack/mcp/websocket/monitoring/models.py +90 -0
  255. crackerjack/mcp/websocket/monitoring/utils.py +171 -0
  256. crackerjack/mcp/websocket/monitoring/websocket_manager.py +78 -0
  257. crackerjack/mcp/websocket/monitoring/websockets/__init__.py +17 -0
  258. crackerjack/mcp/websocket/monitoring/websockets/dependencies.py +126 -0
  259. crackerjack/mcp/websocket/monitoring/websockets/heatmap.py +176 -0
  260. crackerjack/mcp/websocket/monitoring/websockets/intelligence.py +291 -0
  261. crackerjack/mcp/websocket/monitoring/websockets/metrics.py +291 -0
  262. crackerjack/mcp/websocket/monitoring_endpoints.py +21 -0
  263. crackerjack/mcp/websocket/server.py +174 -0
  264. crackerjack/mcp/websocket/websocket_handler.py +276 -0
  265. crackerjack/mcp/websocket_server.py +10 -0
  266. crackerjack/models/README.md +308 -0
  267. crackerjack/models/__init__.py +40 -0
  268. crackerjack/models/config.py +730 -0
  269. crackerjack/models/config_adapter.py +265 -0
  270. crackerjack/models/protocols.py +1535 -0
  271. crackerjack/models/pydantic_models.py +320 -0
  272. crackerjack/models/qa_config.py +145 -0
  273. crackerjack/models/qa_results.py +134 -0
  274. crackerjack/models/resource_protocols.py +299 -0
  275. crackerjack/models/results.py +35 -0
  276. crackerjack/models/semantic_models.py +258 -0
  277. crackerjack/models/task.py +173 -0
  278. crackerjack/models/test_models.py +60 -0
  279. crackerjack/monitoring/README.md +11 -0
  280. crackerjack/monitoring/__init__.py +0 -0
  281. crackerjack/monitoring/ai_agent_watchdog.py +405 -0
  282. crackerjack/monitoring/metrics_collector.py +427 -0
  283. crackerjack/monitoring/regression_prevention.py +580 -0
  284. crackerjack/monitoring/websocket_server.py +406 -0
  285. crackerjack/orchestration/README.md +340 -0
  286. crackerjack/orchestration/__init__.py +43 -0
  287. crackerjack/orchestration/advanced_orchestrator.py +894 -0
  288. crackerjack/orchestration/cache/README.md +312 -0
  289. crackerjack/orchestration/cache/__init__.py +37 -0
  290. crackerjack/orchestration/cache/memory_cache.py +338 -0
  291. crackerjack/orchestration/cache/tool_proxy_cache.py +340 -0
  292. crackerjack/orchestration/config.py +297 -0
  293. crackerjack/orchestration/coverage_improvement.py +180 -0
  294. crackerjack/orchestration/execution_strategies.py +361 -0
  295. crackerjack/orchestration/hook_orchestrator.py +1398 -0
  296. crackerjack/orchestration/strategies/README.md +401 -0
  297. crackerjack/orchestration/strategies/__init__.py +39 -0
  298. crackerjack/orchestration/strategies/adaptive_strategy.py +630 -0
  299. crackerjack/orchestration/strategies/parallel_strategy.py +237 -0
  300. crackerjack/orchestration/strategies/sequential_strategy.py +299 -0
  301. crackerjack/orchestration/test_progress_streamer.py +647 -0
  302. crackerjack/plugins/README.md +11 -0
  303. crackerjack/plugins/__init__.py +15 -0
  304. crackerjack/plugins/base.py +200 -0
  305. crackerjack/plugins/hooks.py +254 -0
  306. crackerjack/plugins/loader.py +335 -0
  307. crackerjack/plugins/managers.py +264 -0
  308. crackerjack/py313.py +191 -0
  309. crackerjack/security/README.md +11 -0
  310. crackerjack/security/__init__.py +0 -0
  311. crackerjack/security/audit.py +197 -0
  312. crackerjack/services/README.md +374 -0
  313. crackerjack/services/__init__.py +9 -0
  314. crackerjack/services/ai/README.md +295 -0
  315. crackerjack/services/ai/__init__.py +7 -0
  316. crackerjack/services/ai/advanced_optimizer.py +878 -0
  317. crackerjack/services/ai/contextual_ai_assistant.py +542 -0
  318. crackerjack/services/ai/embeddings.py +444 -0
  319. crackerjack/services/ai/intelligent_commit.py +328 -0
  320. crackerjack/services/ai/predictive_analytics.py +510 -0
  321. crackerjack/services/anomaly_detector.py +392 -0
  322. crackerjack/services/api_extractor.py +617 -0
  323. crackerjack/services/backup_service.py +467 -0
  324. crackerjack/services/bounded_status_operations.py +530 -0
  325. crackerjack/services/cache.py +369 -0
  326. crackerjack/services/changelog_automation.py +399 -0
  327. crackerjack/services/command_execution_service.py +305 -0
  328. crackerjack/services/config_integrity.py +132 -0
  329. crackerjack/services/config_merge.py +546 -0
  330. crackerjack/services/config_service.py +198 -0
  331. crackerjack/services/config_template.py +493 -0
  332. crackerjack/services/coverage_badge_service.py +173 -0
  333. crackerjack/services/coverage_ratchet.py +381 -0
  334. crackerjack/services/debug.py +733 -0
  335. crackerjack/services/dependency_analyzer.py +460 -0
  336. crackerjack/services/dependency_monitor.py +622 -0
  337. crackerjack/services/documentation_generator.py +493 -0
  338. crackerjack/services/documentation_service.py +704 -0
  339. crackerjack/services/enhanced_filesystem.py +497 -0
  340. crackerjack/services/enterprise_optimizer.py +865 -0
  341. crackerjack/services/error_pattern_analyzer.py +676 -0
  342. crackerjack/services/file_filter.py +221 -0
  343. crackerjack/services/file_hasher.py +149 -0
  344. crackerjack/services/file_io_service.py +361 -0
  345. crackerjack/services/file_modifier.py +615 -0
  346. crackerjack/services/filesystem.py +381 -0
  347. crackerjack/services/git.py +422 -0
  348. crackerjack/services/health_metrics.py +615 -0
  349. crackerjack/services/heatmap_generator.py +744 -0
  350. crackerjack/services/incremental_executor.py +380 -0
  351. crackerjack/services/initialization.py +823 -0
  352. crackerjack/services/input_validator.py +668 -0
  353. crackerjack/services/intelligent_commit.py +327 -0
  354. crackerjack/services/log_manager.py +289 -0
  355. crackerjack/services/logging.py +228 -0
  356. crackerjack/services/lsp_client.py +628 -0
  357. crackerjack/services/memory_optimizer.py +414 -0
  358. crackerjack/services/metrics.py +587 -0
  359. crackerjack/services/monitoring/README.md +30 -0
  360. crackerjack/services/monitoring/__init__.py +9 -0
  361. crackerjack/services/monitoring/dependency_monitor.py +678 -0
  362. crackerjack/services/monitoring/error_pattern_analyzer.py +676 -0
  363. crackerjack/services/monitoring/health_metrics.py +716 -0
  364. crackerjack/services/monitoring/metrics.py +587 -0
  365. crackerjack/services/monitoring/performance_benchmarks.py +410 -0
  366. crackerjack/services/monitoring/performance_cache.py +388 -0
  367. crackerjack/services/monitoring/performance_monitor.py +569 -0
  368. crackerjack/services/parallel_executor.py +527 -0
  369. crackerjack/services/pattern_cache.py +333 -0
  370. crackerjack/services/pattern_detector.py +478 -0
  371. crackerjack/services/patterns/__init__.py +142 -0
  372. crackerjack/services/patterns/agents.py +107 -0
  373. crackerjack/services/patterns/code/__init__.py +15 -0
  374. crackerjack/services/patterns/code/detection.py +118 -0
  375. crackerjack/services/patterns/code/imports.py +107 -0
  376. crackerjack/services/patterns/code/paths.py +159 -0
  377. crackerjack/services/patterns/code/performance.py +119 -0
  378. crackerjack/services/patterns/code/replacement.py +36 -0
  379. crackerjack/services/patterns/core.py +212 -0
  380. crackerjack/services/patterns/documentation/__init__.py +14 -0
  381. crackerjack/services/patterns/documentation/badges_markdown.py +96 -0
  382. crackerjack/services/patterns/documentation/comments_blocks.py +83 -0
  383. crackerjack/services/patterns/documentation/docstrings.py +89 -0
  384. crackerjack/services/patterns/formatting.py +226 -0
  385. crackerjack/services/patterns/operations.py +339 -0
  386. crackerjack/services/patterns/security/__init__.py +23 -0
  387. crackerjack/services/patterns/security/code_injection.py +122 -0
  388. crackerjack/services/patterns/security/credentials.py +190 -0
  389. crackerjack/services/patterns/security/path_traversal.py +221 -0
  390. crackerjack/services/patterns/security/unsafe_operations.py +216 -0
  391. crackerjack/services/patterns/templates.py +62 -0
  392. crackerjack/services/patterns/testing/__init__.py +18 -0
  393. crackerjack/services/patterns/testing/error_patterns.py +107 -0
  394. crackerjack/services/patterns/testing/pytest_output.py +126 -0
  395. crackerjack/services/patterns/tool_output/__init__.py +16 -0
  396. crackerjack/services/patterns/tool_output/bandit.py +72 -0
  397. crackerjack/services/patterns/tool_output/other.py +97 -0
  398. crackerjack/services/patterns/tool_output/pyright.py +67 -0
  399. crackerjack/services/patterns/tool_output/ruff.py +44 -0
  400. crackerjack/services/patterns/url_sanitization.py +114 -0
  401. crackerjack/services/patterns/utilities.py +42 -0
  402. crackerjack/services/patterns/utils.py +339 -0
  403. crackerjack/services/patterns/validation.py +46 -0
  404. crackerjack/services/patterns/versioning.py +62 -0
  405. crackerjack/services/predictive_analytics.py +523 -0
  406. crackerjack/services/profiler.py +280 -0
  407. crackerjack/services/quality/README.md +415 -0
  408. crackerjack/services/quality/__init__.py +11 -0
  409. crackerjack/services/quality/anomaly_detector.py +392 -0
  410. crackerjack/services/quality/pattern_cache.py +333 -0
  411. crackerjack/services/quality/pattern_detector.py +479 -0
  412. crackerjack/services/quality/qa_orchestrator.py +491 -0
  413. crackerjack/services/quality/quality_baseline.py +395 -0
  414. crackerjack/services/quality/quality_baseline_enhanced.py +649 -0
  415. crackerjack/services/quality/quality_intelligence.py +949 -0
  416. crackerjack/services/regex_patterns.py +58 -0
  417. crackerjack/services/regex_utils.py +483 -0
  418. crackerjack/services/secure_path_utils.py +524 -0
  419. crackerjack/services/secure_status_formatter.py +450 -0
  420. crackerjack/services/secure_subprocess.py +635 -0
  421. crackerjack/services/security.py +239 -0
  422. crackerjack/services/security_logger.py +495 -0
  423. crackerjack/services/server_manager.py +411 -0
  424. crackerjack/services/smart_scheduling.py +167 -0
  425. crackerjack/services/status_authentication.py +460 -0
  426. crackerjack/services/status_security_manager.py +315 -0
  427. crackerjack/services/terminal_utils.py +0 -0
  428. crackerjack/services/thread_safe_status_collector.py +441 -0
  429. crackerjack/services/tool_filter.py +368 -0
  430. crackerjack/services/tool_version_service.py +43 -0
  431. crackerjack/services/unified_config.py +115 -0
  432. crackerjack/services/validation_rate_limiter.py +220 -0
  433. crackerjack/services/vector_store.py +689 -0
  434. crackerjack/services/version_analyzer.py +461 -0
  435. crackerjack/services/version_checker.py +223 -0
  436. crackerjack/services/websocket_resource_limiter.py +438 -0
  437. crackerjack/services/zuban_lsp_service.py +391 -0
  438. crackerjack/slash_commands/README.md +11 -0
  439. crackerjack/slash_commands/__init__.py +59 -0
  440. crackerjack/slash_commands/init.md +112 -0
  441. crackerjack/slash_commands/run.md +197 -0
  442. crackerjack/slash_commands/status.md +127 -0
  443. crackerjack/tools/README.md +11 -0
  444. crackerjack/tools/__init__.py +30 -0
  445. crackerjack/tools/_git_utils.py +105 -0
  446. crackerjack/tools/check_added_large_files.py +139 -0
  447. crackerjack/tools/check_ast.py +105 -0
  448. crackerjack/tools/check_json.py +103 -0
  449. crackerjack/tools/check_jsonschema.py +297 -0
  450. crackerjack/tools/check_toml.py +103 -0
  451. crackerjack/tools/check_yaml.py +110 -0
  452. crackerjack/tools/codespell_wrapper.py +72 -0
  453. crackerjack/tools/end_of_file_fixer.py +202 -0
  454. crackerjack/tools/format_json.py +128 -0
  455. crackerjack/tools/mdformat_wrapper.py +114 -0
  456. crackerjack/tools/trailing_whitespace.py +198 -0
  457. crackerjack/tools/validate_input_validator_patterns.py +236 -0
  458. crackerjack/tools/validate_regex_patterns.py +188 -0
  459. crackerjack/ui/README.md +11 -0
  460. crackerjack/ui/__init__.py +1 -0
  461. crackerjack/ui/dashboard_renderer.py +28 -0
  462. crackerjack/ui/templates/README.md +11 -0
  463. crackerjack/utils/console_utils.py +13 -0
  464. crackerjack/utils/dependency_guard.py +230 -0
  465. crackerjack/utils/retry_utils.py +275 -0
  466. crackerjack/workflows/README.md +590 -0
  467. crackerjack/workflows/__init__.py +46 -0
  468. crackerjack/workflows/actions.py +811 -0
  469. crackerjack/workflows/auto_fix.py +444 -0
  470. crackerjack/workflows/container_builder.py +499 -0
  471. crackerjack/workflows/definitions.py +443 -0
  472. crackerjack/workflows/engine.py +177 -0
  473. crackerjack/workflows/event_bridge.py +242 -0
  474. crackerjack-0.45.2.dist-info/METADATA +1678 -0
  475. crackerjack-0.45.2.dist-info/RECORD +478 -0
  476. {crackerjack-0.18.2.dist-info → crackerjack-0.45.2.dist-info}/WHEEL +1 -1
  477. crackerjack-0.45.2.dist-info/entry_points.txt +2 -0
  478. crackerjack/.gitignore +0 -14
  479. crackerjack/.libcst.codemod.yaml +0 -18
  480. crackerjack/.pdm.toml +0 -1
  481. crackerjack/.pre-commit-config.yaml +0 -91
  482. crackerjack/.pytest_cache/.gitignore +0 -2
  483. crackerjack/.pytest_cache/CACHEDIR.TAG +0 -4
  484. crackerjack/.pytest_cache/README.md +0 -8
  485. crackerjack/.pytest_cache/v/cache/nodeids +0 -1
  486. crackerjack/.pytest_cache/v/cache/stepwise +0 -1
  487. crackerjack/.ruff_cache/.gitignore +0 -1
  488. crackerjack/.ruff_cache/0.1.11/3256171999636029978 +0 -0
  489. crackerjack/.ruff_cache/0.1.14/602324811142551221 +0 -0
  490. crackerjack/.ruff_cache/0.1.4/10355199064880463147 +0 -0
  491. crackerjack/.ruff_cache/0.1.6/15140459877605758699 +0 -0
  492. crackerjack/.ruff_cache/0.1.7/1790508110482614856 +0 -0
  493. crackerjack/.ruff_cache/0.1.9/17041001205004563469 +0 -0
  494. crackerjack/.ruff_cache/0.11.2/4070660268492669020 +0 -0
  495. crackerjack/.ruff_cache/0.11.3/9818742842212983150 +0 -0
  496. crackerjack/.ruff_cache/0.11.4/9818742842212983150 +0 -0
  497. crackerjack/.ruff_cache/0.11.6/3557596832929915217 +0 -0
  498. crackerjack/.ruff_cache/0.11.7/10386934055395314831 +0 -0
  499. crackerjack/.ruff_cache/0.11.7/3557596832929915217 +0 -0
  500. crackerjack/.ruff_cache/0.11.8/530407680854991027 +0 -0
  501. crackerjack/.ruff_cache/0.2.0/10047773857155985907 +0 -0
  502. crackerjack/.ruff_cache/0.2.1/8522267973936635051 +0 -0
  503. crackerjack/.ruff_cache/0.2.2/18053836298936336950 +0 -0
  504. crackerjack/.ruff_cache/0.3.0/12548816621480535786 +0 -0
  505. crackerjack/.ruff_cache/0.3.3/11081883392474770722 +0 -0
  506. crackerjack/.ruff_cache/0.3.4/676973378459347183 +0 -0
  507. crackerjack/.ruff_cache/0.3.5/16311176246009842383 +0 -0
  508. crackerjack/.ruff_cache/0.5.7/1493622539551733492 +0 -0
  509. crackerjack/.ruff_cache/0.5.7/6231957614044513175 +0 -0
  510. crackerjack/.ruff_cache/0.5.7/9932762556785938009 +0 -0
  511. crackerjack/.ruff_cache/0.6.0/11982804814124138945 +0 -0
  512. crackerjack/.ruff_cache/0.6.0/12055761203849489982 +0 -0
  513. crackerjack/.ruff_cache/0.6.2/1206147804896221174 +0 -0
  514. crackerjack/.ruff_cache/0.6.4/1206147804896221174 +0 -0
  515. crackerjack/.ruff_cache/0.6.5/1206147804896221174 +0 -0
  516. crackerjack/.ruff_cache/0.6.7/3657366982708166874 +0 -0
  517. crackerjack/.ruff_cache/0.6.9/285614542852677309 +0 -0
  518. crackerjack/.ruff_cache/0.7.1/1024065805990144819 +0 -0
  519. crackerjack/.ruff_cache/0.7.1/285614542852677309 +0 -0
  520. crackerjack/.ruff_cache/0.7.3/16061516852537040135 +0 -0
  521. crackerjack/.ruff_cache/0.8.4/16354268377385700367 +0 -0
  522. crackerjack/.ruff_cache/0.9.10/12813592349865671909 +0 -0
  523. crackerjack/.ruff_cache/0.9.10/923908772239632759 +0 -0
  524. crackerjack/.ruff_cache/0.9.3/13948373885254993391 +0 -0
  525. crackerjack/.ruff_cache/0.9.9/12813592349865671909 +0 -0
  526. crackerjack/.ruff_cache/0.9.9/8843823720003377982 +0 -0
  527. crackerjack/.ruff_cache/CACHEDIR.TAG +0 -1
  528. crackerjack/crackerjack.py +0 -855
  529. crackerjack/pyproject.toml +0 -214
  530. crackerjack-0.18.2.dist-info/METADATA +0 -420
  531. crackerjack-0.18.2.dist-info/RECORD +0 -59
  532. crackerjack-0.18.2.dist-info/entry_points.txt +0 -4
  533. {crackerjack-0.18.2.dist-info → crackerjack-0.45.2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,793 @@
1
+ from pathlib import Path
2
+
3
+ from ..services.regex_patterns import SAFE_PATTERNS
4
+ from .base import (
5
+ AgentContext,
6
+ FixResult,
7
+ Issue,
8
+ IssueType,
9
+ SubAgent,
10
+ agent_registry,
11
+ )
12
+
13
+
14
+ class SecurityAgent(SubAgent):
15
+ def __init__(self, context: AgentContext) -> None:
16
+ super().__init__(context)
17
+
18
+ def get_supported_types(self) -> set[IssueType]:
19
+ return {IssueType.SECURITY, IssueType.REGEX_VALIDATION}
20
+
21
+ async def can_handle(self, issue: Issue) -> float:
22
+ if issue.type not in self.get_supported_types():
23
+ return 0.0
24
+
25
+ message_lower = issue.message.lower()
26
+
27
+ if issue.type == IssueType.REGEX_VALIDATION:
28
+ return 0.95
29
+
30
+ if any(
31
+ keyword in message_lower
32
+ for keyword in (
33
+ "validate-regex-patterns",
34
+ "raw regex",
35
+ "regex pattern",
36
+ r"\g<",
37
+ "replacement",
38
+ "unsafe regex",
39
+ "regex vulnerability",
40
+ "redos",
41
+ )
42
+ ):
43
+ return 0.95
44
+
45
+ if any(
46
+ keyword in message_lower
47
+ for keyword in (
48
+ "bandit",
49
+ "security",
50
+ "vulnerability",
51
+ "hardcoded",
52
+ "shell=true",
53
+ "b108",
54
+ "b602",
55
+ "b301",
56
+ "b506",
57
+ "unsafe",
58
+ "injection",
59
+ "pickle",
60
+ "yaml.load",
61
+ "md5",
62
+ "sha1",
63
+ "jwt_secret",
64
+ )
65
+ ):
66
+ return 0.9
67
+
68
+ enhanced_patterns = [
69
+ "detect_security_keywords",
70
+ "detect_crypto_weak_algorithms",
71
+ "detect_hardcoded_credentials_advanced",
72
+ "detect_subprocess_shell_injection",
73
+ "detect_unsafe_pickle_usage",
74
+ ]
75
+
76
+ for pattern_name in enhanced_patterns:
77
+ if SAFE_PATTERNS[pattern_name].test(issue.message):
78
+ return 0.9
79
+
80
+ if issue.file_path and any(
81
+ keyword in issue.file_path.lower()
82
+ for keyword in ("security", "auth", "crypto", "password", "token", "jwt")
83
+ ):
84
+ return 0.7
85
+
86
+ if issue.type == IssueType.SECURITY:
87
+ return 0.6
88
+
89
+ return 0.0
90
+
91
+ async def analyze_and_fix(self, issue: Issue) -> FixResult:
92
+ self.log(f"Analyzing security issue: {issue.message}")
93
+
94
+ fixes_applied: list[str] = []
95
+ files_modified: list[str] = []
96
+ recommendations: list[str] = []
97
+
98
+ try:
99
+ vulnerability_type = self._identify_vulnerability_type(issue)
100
+ self.log(f"Identified vulnerability type: {vulnerability_type}")
101
+
102
+ fixes_applied, files_modified = await self._apply_vulnerability_fixes(
103
+ vulnerability_type,
104
+ issue,
105
+ fixes_applied,
106
+ files_modified,
107
+ )
108
+
109
+ fixes_applied, files_modified = await self._apply_additional_fixes(
110
+ issue,
111
+ fixes_applied,
112
+ files_modified,
113
+ )
114
+
115
+ success = len(fixes_applied) > 0
116
+ confidence = 0.95 if success else 0.4
117
+
118
+ if not success:
119
+ recommendations = self._get_security_recommendations()
120
+
121
+ return FixResult(
122
+ success=success,
123
+ confidence=confidence,
124
+ fixes_applied=fixes_applied,
125
+ files_modified=files_modified,
126
+ recommendations=recommendations,
127
+ )
128
+
129
+ except Exception as e:
130
+ self.log(f"Error fixing security issue: {e}", "ERROR")
131
+ return self._create_error_fix_result(e)
132
+
133
+ async def _apply_vulnerability_fixes(
134
+ self,
135
+ vulnerability_type: str,
136
+ issue: Issue,
137
+ fixes_applied: list[str],
138
+ files_modified: list[str],
139
+ ) -> tuple[list[str], list[str]]:
140
+ vulnerability_fix_map = {
141
+ "regex_validation": self._fix_regex_validation_issues,
142
+ "hardcoded_temp_paths": self._fix_hardcoded_temp_paths,
143
+ "shell_injection": self._fix_shell_injection,
144
+ "hardcoded_secrets": self._fix_hardcoded_secrets,
145
+ "unsafe_yaml": self._fix_unsafe_yaml,
146
+ "eval_usage": self._fix_eval_usage,
147
+ "weak_crypto": self._fix_weak_crypto,
148
+ "jwt_secrets": self._fix_jwt_secrets,
149
+ "pickle_usage": self._fix_pickle_usage,
150
+ "insecure_random": self._fix_insecure_random,
151
+ }
152
+
153
+ if (fix_method := vulnerability_fix_map.get(vulnerability_type)) is not None:
154
+ fixes = await fix_method(issue)
155
+ fixes_applied.extend(fixes["fixes"])
156
+ files_modified.extend(fixes["files"])
157
+
158
+ return fixes_applied, files_modified
159
+
160
+ async def _apply_additional_fixes(
161
+ self,
162
+ issue: Issue,
163
+ fixes_applied: list[str],
164
+ files_modified: list[str],
165
+ ) -> tuple[list[str], list[str]]:
166
+ if not fixes_applied:
167
+ bandit_fixes = await self._run_bandit_analysis()
168
+ fixes_applied.extend(bandit_fixes)
169
+
170
+ if issue.file_path:
171
+ file_fixes = await self._fix_file_security_issues(issue.file_path)
172
+ fixes_applied.extend(file_fixes["fixes"])
173
+ if file_fixes["fixes"]:
174
+ files_modified.append(issue.file_path)
175
+
176
+ return fixes_applied, files_modified
177
+
178
+ def _get_security_recommendations(self) -> list[str]:
179
+ return [
180
+ "Use centralized SAFE_PATTERNS for regex operations to prevent ReDoS attacks",
181
+ "Avoid raw regex patterns with vulnerable replacement syntax like \\g<1>",
182
+ "Use tempfile module for temporary file creation instead of hardcoded paths",
183
+ "Avoid shell=True in subprocess calls to prevent command injection",
184
+ "Store secrets in environment variables using os.getenv(), never hardcode them",
185
+ "Replace weak cryptographic algorithms (MD5, SHA1, DES, RC4) with stronger alternatives",
186
+ "Use secrets module instead of random for cryptographically secure operations",
187
+ "Replace unsafe yaml.load() with yaml.safe_load() to prevent code execution",
188
+ "Avoid pickle.load() with untrusted data as it can execute arbitrary code",
189
+ "Use JWT secrets from environment variables, never hardcode them",
190
+ "Implement proper input validation and sanitization for all user inputs",
191
+ "Add security comments to document potential risks in legacy code",
192
+ "Run bandit security scanner regularly to identify new vulnerabilities",
193
+ "Review all subprocess calls for potential injection vulnerabilities",
194
+ "Ensure all cryptographic operations use secure algorithms and proper key management",
195
+ ]
196
+
197
+ def _create_error_fix_result(self, error: Exception) -> FixResult:
198
+ return FixResult(
199
+ success=False,
200
+ confidence=0.0,
201
+ remaining_issues=[f"Failed to fix security issue: {error}"],
202
+ recommendations=[
203
+ "Manual security review may be required",
204
+ "Consider running bandit security scanner",
205
+ "Review code for common security anti-patterns",
206
+ ],
207
+ )
208
+
209
+ def _identify_vulnerability_type(self, issue: Issue) -> str:
210
+ message = issue.message
211
+
212
+ if self._is_regex_validation_issue(issue):
213
+ return "regex_validation"
214
+
215
+ pattern_checks = self._check_enhanced_patterns(message)
216
+ if pattern_checks:
217
+ return pattern_checks
218
+
219
+ bandit_checks = self._check_bandit_patterns(message)
220
+ if bandit_checks:
221
+ return bandit_checks
222
+
223
+ legacy_checks = self._check_legacy_patterns(message)
224
+ if legacy_checks:
225
+ return legacy_checks
226
+
227
+ if self._is_jwt_secret_issue(message):
228
+ return "jwt_secrets"
229
+
230
+ return "unknown"
231
+
232
+ def _is_regex_validation_issue(self, issue: Issue) -> bool:
233
+ if issue.type == IssueType.REGEX_VALIDATION:
234
+ return True
235
+
236
+ message_lower = issue.message.lower()
237
+ return any(
238
+ keyword in message_lower
239
+ for keyword in (
240
+ "validate-regex-patterns",
241
+ "raw regex",
242
+ "unsafe regex",
243
+ r"\g<",
244
+ "redos",
245
+ )
246
+ )
247
+
248
+ def _check_enhanced_patterns(self, message: str) -> str | None:
249
+ pattern_map = {
250
+ "detect_crypto_weak_algorithms": "weak_crypto",
251
+ "detect_hardcoded_credentials_advanced": "hardcoded_secrets",
252
+ "detect_subprocess_shell_injection": "shell_injection",
253
+ "detect_unsafe_pickle_usage": "pickle_usage",
254
+ "detect_regex_redos_vulnerable": "regex_validation",
255
+ }
256
+
257
+ for pattern_name, vulnerability_type in pattern_map.items():
258
+ if SAFE_PATTERNS[pattern_name].test(message):
259
+ return vulnerability_type
260
+
261
+ return None
262
+
263
+ def _check_bandit_patterns(self, message: str) -> str | None:
264
+ if "B108" in message:
265
+ return "hardcoded_temp_paths"
266
+ if "B602" in message or "shell=True" in message:
267
+ return "shell_injection"
268
+ if "B301" in message or "pickle" in message.lower():
269
+ return "pickle_usage"
270
+ if "B506" in message or "yaml.load" in message:
271
+ return "unsafe_yaml"
272
+ if any(crypto in message.lower() for crypto in ("md5", "sha1", "des", "rc4")):
273
+ return "weak_crypto"
274
+
275
+ return None
276
+
277
+ def _check_legacy_patterns(self, message: str) -> str | None:
278
+ pattern_map = {
279
+ "detect_hardcoded_temp_paths_basic": "hardcoded_temp_paths",
280
+ "detect_hardcoded_secrets": "hardcoded_secrets",
281
+ "detect_insecure_random_usage": "insecure_random",
282
+ }
283
+
284
+ for pattern_name, vulnerability_type in pattern_map.items():
285
+ if SAFE_PATTERNS[pattern_name].test(message):
286
+ return vulnerability_type
287
+
288
+ return None
289
+
290
+ def _is_jwt_secret_issue(self, message: str) -> bool:
291
+ message_lower = message.lower()
292
+ return "jwt" in message_lower and (
293
+ "secret" in message_lower or "hardcoded" in message_lower
294
+ )
295
+
296
+ async def _fix_regex_validation_issues(self, issue: Issue) -> dict[str, list[str]]:
297
+ fixes: list[str] = []
298
+ files: list[str] = []
299
+
300
+ if not issue.file_path:
301
+ await self._fix_regex_patterns_project_wide(fixes, files)
302
+ return {"fixes": fixes, "files": files}
303
+
304
+ file_path = Path(issue.file_path)
305
+ if not file_path.exists():
306
+ return {"fixes": fixes, "files": files}
307
+
308
+ content = self.context.get_file_content(file_path)
309
+ if not content:
310
+ return {"fixes": fixes, "files": files}
311
+
312
+ original_content = content
313
+ content = await self._apply_regex_pattern_fixes(content)
314
+
315
+ if content != original_content:
316
+ if self.context.write_file_content(file_path, content):
317
+ fixes.append(f"Fixed unsafe regex patterns in {issue.file_path}")
318
+ files.append(str(file_path))
319
+ self.log(f"Fixed regex patterns in {issue.file_path}")
320
+
321
+ return {"fixes": fixes, "files": files}
322
+
323
+ async def _fix_regex_patterns_project_wide(
324
+ self, fixes: list[str], files: list[str]
325
+ ) -> None:
326
+ try:
327
+ python_files = self._get_python_files_for_security_scan()
328
+ await self._process_python_files_for_regex_fixes(python_files, fixes, files)
329
+ except Exception as e:
330
+ self.log(f"Error during project-wide regex fixes: {e}", "ERROR")
331
+
332
+ def _get_python_files_for_security_scan(self) -> list[Path]:
333
+ python_files = list(self.context.project_path.rglob("*.py"))
334
+ return [
335
+ f for f in python_files if not self._should_skip_file_for_security_scan(f)
336
+ ]
337
+
338
+ def _should_skip_file_for_security_scan(self, file_path: Path) -> bool:
339
+ skip_patterns = [".venv", "__pycache__", ".git"]
340
+ return any(part in str(file_path) for part in skip_patterns)
341
+
342
+ async def _process_python_files_for_regex_fixes(
343
+ self, python_files: list[Path], fixes: list[str], files: list[str]
344
+ ) -> None:
345
+ for file_path in python_files:
346
+ await self._process_single_file_for_regex_fixes(file_path, fixes, files)
347
+
348
+ async def _process_single_file_for_regex_fixes(
349
+ self, file_path: Path, fixes: list[str], files: list[str]
350
+ ) -> None:
351
+ content = self.context.get_file_content(file_path)
352
+ if not content:
353
+ return
354
+
355
+ original_content = content
356
+ content = await self._apply_regex_pattern_fixes(content)
357
+
358
+ if self._should_save_regex_fixes(content, original_content):
359
+ await self._save_regex_fixes_to_file(file_path, content, fixes, files)
360
+
361
+ def _should_save_regex_fixes(self, content: str, original_content: str) -> bool:
362
+ return content != original_content
363
+
364
+ async def _save_regex_fixes_to_file(
365
+ self, file_path: Path, content: str, fixes: list[str], files: list[str]
366
+ ) -> None:
367
+ if self.context.write_file_content(file_path, content):
368
+ fixes.append(f"Fixed unsafe regex patterns in {file_path}")
369
+ files.append(str(file_path))
370
+ self.log(f"Fixed regex patterns in {file_path}")
371
+
372
+ async def _apply_regex_pattern_fixes(self, content: str) -> str:
373
+ from crackerjack.services.regex_utils import (
374
+ replace_unsafe_regex_with_safe_patterns,
375
+ )
376
+
377
+ try:
378
+ fixed_content = replace_unsafe_regex_with_safe_patterns(content)
379
+ return fixed_content
380
+ except Exception as e:
381
+ self.log(f"Error applying regex fixes: {e}", "ERROR")
382
+ return content
383
+
384
+ async def _fix_hardcoded_temp_paths(self, issue: Issue) -> dict[str, list[str]]:
385
+ fixes: list[str] = []
386
+ files: list[str] = []
387
+
388
+ if not issue.file_path:
389
+ return {"fixes": fixes, "files": files}
390
+
391
+ file_path = Path(issue.file_path)
392
+ if not file_path.exists():
393
+ return {"fixes": fixes, "files": files}
394
+
395
+ content = self.context.get_file_content(file_path)
396
+ if not content:
397
+ return {"fixes": fixes, "files": files}
398
+
399
+ lines = content.split("\n")
400
+ lines, modified = self._process_temp_path_fixes(lines)
401
+
402
+ if modified:
403
+ if self.context.write_file_content(file_path, "\n".join(lines)):
404
+ fixes.append(f"Fixed hardcoded temp paths in {issue.file_path}")
405
+ files.append(str(file_path))
406
+ self.log(f"Fixed hardcoded temp paths in {issue.file_path}")
407
+
408
+ return {"fixes": fixes, "files": files}
409
+
410
+ def _process_temp_path_fixes(self, lines: list[str]) -> tuple[list[str], bool]:
411
+ modified = False
412
+
413
+ lines, import_added = self._ensure_tempfile_import(lines)
414
+ if import_added:
415
+ modified = True
416
+
417
+ lines, paths_replaced = self._replace_hardcoded_temp_paths(lines)
418
+ if paths_replaced:
419
+ modified = True
420
+
421
+ return lines, modified
422
+
423
+ def _ensure_tempfile_import(self, lines: list[str]) -> tuple[list[str], bool]:
424
+ has_tempfile_import = any("import tempfile" in line for line in lines)
425
+ if has_tempfile_import:
426
+ return lines, False
427
+
428
+ import_section_end = 0
429
+ for i, line in enumerate(lines):
430
+ if line.strip().startswith(("import ", "from ")):
431
+ import_section_end = i + 1
432
+ elif line.strip() == "" and import_section_end > 0:
433
+ break
434
+
435
+ lines.insert(import_section_end, "import tempfile")
436
+ return lines, True
437
+
438
+ def _replace_hardcoded_temp_paths(self, lines: list[str]) -> tuple[list[str], bool]:
439
+ new_content = "\n".join(lines)
440
+
441
+ if SAFE_PATTERNS["detect_hardcoded_temp_paths_basic"].test(new_content):
442
+ new_content = SAFE_PATTERNS["replace_hardcoded_temp_paths"].apply(
443
+ new_content
444
+ )
445
+ new_content = SAFE_PATTERNS["replace_hardcoded_temp_strings"].apply(
446
+ new_content
447
+ )
448
+ new_content = SAFE_PATTERNS["replace_hardcoded_temp_single_quotes"].apply(
449
+ new_content
450
+ )
451
+ new_content = SAFE_PATTERNS["replace_test_path_patterns"].apply(new_content)
452
+ lines = new_content.split("\n")
453
+ return lines, True
454
+
455
+ return lines, False
456
+
457
+ async def _fix_shell_injection(self, issue: Issue) -> dict[str, list[str]]:
458
+ fixes: list[str] = []
459
+ files: list[str] = []
460
+
461
+ if not issue.file_path:
462
+ return {"fixes": fixes, "files": files}
463
+
464
+ file_path = Path(issue.file_path)
465
+ content = self.context.get_file_content(file_path)
466
+ if not content:
467
+ return {"fixes": fixes, "files": files}
468
+
469
+ original_content = content
470
+
471
+ from crackerjack.services.regex_patterns import apply_security_fixes
472
+
473
+ content = apply_security_fixes(content)
474
+
475
+ if content != original_content:
476
+ if self.context.write_file_content(file_path, content):
477
+ fixes.append(
478
+ f"Fixed shell injection vulnerability in {issue.file_path}",
479
+ )
480
+ files.append(str(file_path))
481
+ self.log(f"Fixed shell injection in {issue.file_path}")
482
+
483
+ return {"fixes": fixes, "files": files}
484
+
485
+ async def _fix_hardcoded_secrets(self, issue: Issue) -> dict[str, list[str]]:
486
+ fixes: list[str] = []
487
+ files: list[str] = []
488
+
489
+ if not issue.file_path:
490
+ return {"fixes": fixes, "files": files}
491
+
492
+ file_path = Path(issue.file_path)
493
+ content = self.context.get_file_content(file_path)
494
+ if not content:
495
+ return {"fixes": fixes, "files": files}
496
+
497
+ lines = content.split("\n")
498
+ lines, modified = self._process_hardcoded_secrets_in_lines(lines)
499
+
500
+ if modified:
501
+ if self.context.write_file_content(file_path, "\n".join(lines)):
502
+ fixes.append(f"Fixed hardcoded secrets in {issue.file_path}")
503
+ files.append(str(file_path))
504
+ self.log(f"Fixed hardcoded secrets in {issue.file_path}")
505
+
506
+ return {"fixes": fixes, "files": files}
507
+
508
+ def _process_hardcoded_secrets_in_lines(
509
+ self,
510
+ lines: list[str],
511
+ ) -> tuple[list[str], bool]:
512
+ modified = False
513
+
514
+ lines, import_added = self._ensure_os_import(lines)
515
+ if import_added:
516
+ modified = True
517
+
518
+ for i, line in enumerate(lines):
519
+ if self._line_contains_hardcoded_secret(line):
520
+ new_line = self._replace_hardcoded_secret_with_env_var(line)
521
+ if new_line != line:
522
+ lines[i] = new_line
523
+ modified = True
524
+
525
+ return lines, modified
526
+
527
+ def _ensure_os_import(self, lines: list[str]) -> tuple[list[str], bool]:
528
+ has_os_import = any("import os" in line for line in lines)
529
+ if has_os_import:
530
+ return lines, False
531
+
532
+ for i, line in enumerate(lines):
533
+ if line.strip().startswith(("import ", "from ")):
534
+ lines.insert(i, "import os")
535
+ return lines, True
536
+
537
+ return lines, False
538
+
539
+ def _line_contains_hardcoded_secret(self, line: str) -> bool:
540
+ return SAFE_PATTERNS["detect_hardcoded_secrets"].test(line)
541
+
542
+ def _replace_hardcoded_secret_with_env_var(self, line: str) -> str:
543
+ var_name_result = SAFE_PATTERNS["extract_variable_name_from_assignment"].apply(
544
+ line
545
+ )
546
+ if var_name_result != line: # Pattern matched and extracted variable name
547
+ var_name = var_name_result
548
+ env_var_name = var_name.upper()
549
+ return f"{var_name} = os.getenv('{env_var_name}', '')"
550
+ return line
551
+
552
+ async def _fix_unsafe_yaml(self, issue: Issue) -> dict[str, list[str]]:
553
+ fixes: list[str] = []
554
+ files: list[str] = []
555
+
556
+ if not issue.file_path:
557
+ return {"fixes": fixes, "files": files}
558
+
559
+ file_path = Path(issue.file_path)
560
+ content = self.context.get_file_content(file_path)
561
+ if not content:
562
+ return {"fixes": fixes, "files": files}
563
+
564
+ original_content = content
565
+
566
+ from crackerjack.services.regex_patterns import SAFE_PATTERNS
567
+
568
+ content = SAFE_PATTERNS["fix_unsafe_yaml_load"].apply(content)
569
+
570
+ if content != original_content:
571
+ if self.context.write_file_content(file_path, content):
572
+ fixes.append(f"Fixed unsafe YAML loading in {issue.file_path}")
573
+ files.append(str(file_path))
574
+ self.log(f"Fixed unsafe YAML loading in {issue.file_path}")
575
+
576
+ return {"fixes": fixes, "files": files}
577
+
578
+ async def _fix_eval_usage(self, issue: Issue) -> dict[str, list[str]]:
579
+ fixes: list[str] = []
580
+ files: list[str] = []
581
+
582
+ fixes.append(
583
+ f"Identified eval() usage in {issue.file_path} - manual review required",
584
+ )
585
+
586
+ return {"fixes": fixes, "files": files}
587
+
588
+ async def _fix_weak_crypto(self, issue: Issue) -> dict[str, list[str]]:
589
+ fixes: list[str] = []
590
+ files: list[str] = []
591
+
592
+ if not issue.file_path:
593
+ return {"fixes": fixes, "files": files}
594
+
595
+ file_path = Path(issue.file_path)
596
+ content = self.context.get_file_content(file_path)
597
+ if not content:
598
+ return {"fixes": fixes, "files": files}
599
+
600
+ original_content = content
601
+
602
+ from crackerjack.services.regex_patterns import SAFE_PATTERNS
603
+
604
+ content = SAFE_PATTERNS["fix_weak_md5_hash"].apply(content)
605
+ content = SAFE_PATTERNS["fix_weak_sha1_hash"].apply(content)
606
+
607
+ if content != original_content:
608
+ if self.context.write_file_content(file_path, content):
609
+ fixes.append(f"Upgraded weak cryptographic hashes in {issue.file_path}")
610
+ files.append(str(file_path))
611
+ self.log(f"Fixed weak crypto in {issue.file_path}")
612
+
613
+ return {"fixes": fixes, "files": files}
614
+
615
+ async def _fix_jwt_secrets(self, issue: Issue) -> dict[str, list[str]]:
616
+ fixes: list[str] = []
617
+ files: list[str] = []
618
+
619
+ if not issue.file_path:
620
+ return {"fixes": fixes, "files": files}
621
+
622
+ file_path = Path(issue.file_path)
623
+ content = self.context.get_file_content(file_path)
624
+ if not content:
625
+ return {"fixes": fixes, "files": files}
626
+
627
+ original_content = content
628
+
629
+ content = SAFE_PATTERNS["fix_hardcoded_jwt_secret"].apply(content)
630
+
631
+ if "os.getenv" in content and "import os" not in content:
632
+ lines = content.split("\n")
633
+ import_index = 0
634
+ for i, line in enumerate(lines):
635
+ if line.strip().startswith(("import ", "from ")):
636
+ import_index = i + 1
637
+ lines.insert(import_index, "import os")
638
+ content = "\n".join(lines)
639
+
640
+ if content != original_content:
641
+ if self.context.write_file_content(file_path, content):
642
+ fixes.append(f"Fixed hardcoded JWT secrets in {issue.file_path}")
643
+ files.append(str(file_path))
644
+ self.log(f"Fixed JWT secrets in {issue.file_path}")
645
+
646
+ return {"fixes": fixes, "files": files}
647
+
648
+ async def _fix_pickle_usage(self, issue: Issue) -> dict[str, list[str]]:
649
+ fixes: list[str] = []
650
+ files: list[str] = []
651
+
652
+ if not issue.file_path:
653
+ return {"fixes": fixes, "files": files}
654
+
655
+ file_path = Path(issue.file_path)
656
+ content = self.context.get_file_content(file_path)
657
+ if not content:
658
+ return {"fixes": fixes, "files": files}
659
+
660
+ fixes.append(
661
+ f"Documented unsafe pickle usage in {issue.file_path} - manual review required"
662
+ )
663
+
664
+ if "pickle.load" in content:
665
+ lines = content.split("\n")
666
+ for i, line in enumerate(lines):
667
+ if "pickle.load" in line and "# SECURITY: " not in line:
668
+ lines[i] = (
669
+ line + " # SECURITY: pickle.load is unsafe with untrusted data"
670
+ )
671
+ if self.context.write_file_content(file_path, "\n".join(lines)):
672
+ fixes.append(
673
+ f"Added security warning for pickle usage in {issue.file_path}"
674
+ )
675
+ files.append(str(file_path))
676
+ self.log(
677
+ f"Added security warning for pickle in {issue.file_path}"
678
+ )
679
+ break
680
+
681
+ return {"fixes": fixes, "files": files}
682
+
683
+ async def _fix_insecure_random(self, issue: Issue) -> dict[str, list[str]]:
684
+ fixes: list[str] = []
685
+ files: list[str] = []
686
+
687
+ if not issue.file_path:
688
+ return {"fixes": fixes, "files": files}
689
+
690
+ file_path = Path(issue.file_path)
691
+ content = self.context.get_file_content(file_path)
692
+ if not content:
693
+ return {"fixes": fixes, "files": files}
694
+
695
+ original_content = content
696
+
697
+ content = SAFE_PATTERNS["fix_insecure_random_choice"].apply(content)
698
+
699
+ if "secrets.choice" in content and "import secrets" not in content:
700
+ lines = content.split("\n")
701
+ import_index = 0
702
+ for i, line in enumerate(lines):
703
+ if line.strip().startswith(("import ", "from ")):
704
+ import_index = i + 1
705
+ lines.insert(import_index, "import secrets")
706
+ content = "\n".join(lines)
707
+
708
+ if content != original_content:
709
+ if self.context.write_file_content(file_path, content):
710
+ fixes.append(f"Fixed insecure random usage in {issue.file_path}")
711
+ files.append(str(file_path))
712
+ self.log(f"Fixed insecure random usage in {issue.file_path}")
713
+
714
+ return {"fixes": fixes, "files": files}
715
+
716
+ async def _run_bandit_analysis(self) -> list[str]:
717
+ fixes: list[str] = []
718
+
719
+ try:
720
+ returncode, _, _ = await self.run_command(
721
+ ["uv", "run", "bandit", "-r", "crackerjack/", "-f", "txt"],
722
+ )
723
+
724
+ if returncode == 0:
725
+ fixes.append("Bandit security scan completed successfully")
726
+ else:
727
+ fixes.append("Bandit identified security issues for review")
728
+
729
+ except Exception as e:
730
+ self.log(f"Bandit analysis failed: {e}", "WARN")
731
+
732
+ return fixes
733
+
734
+ async def _fix_file_security_issues(self, file_path: str) -> dict[str, list[str]]:
735
+ fixes: list[str] = []
736
+ files: list[str] = []
737
+
738
+ try:
739
+ path = Path(file_path)
740
+ if not self._is_valid_file_path(path):
741
+ return {"fixes": fixes, "files": files}
742
+
743
+ content = self.context.get_file_content(path)
744
+ if not content:
745
+ return {"fixes": fixes, "files": files}
746
+
747
+ original_content = content
748
+ content = await self._apply_security_fixes_to_content(content)
749
+
750
+ if content != original_content:
751
+ if self.context.write_file_content(path, content):
752
+ fixes.append(f"Applied general security fixes to {file_path}")
753
+ files.append(file_path)
754
+ self.log(f"Applied security fixes to {file_path}")
755
+
756
+ except Exception as e:
757
+ self.log(f"Error fixing file security issues in {file_path}: {e}", "ERROR")
758
+
759
+ return {"fixes": fixes, "files": files}
760
+
761
+ def _is_valid_file_path(self, path: Path) -> bool:
762
+ return path.exists() and path.is_file()
763
+
764
+ async def _apply_security_fixes_to_content(self, content: str) -> str:
765
+ content = await self._fix_insecure_random_usage(content)
766
+ return self._remove_debug_prints_with_secrets(content)
767
+
768
+ async def _fix_insecure_random_usage(self, content: str) -> str:
769
+ if not SAFE_PATTERNS["detect_insecure_random_usage"].test(content):
770
+ return content
771
+
772
+ content = self._add_secrets_import_if_needed(content)
773
+
774
+ return SAFE_PATTERNS["fix_insecure_random_choice"].apply(content)
775
+
776
+ def _add_secrets_import_if_needed(self, content: str) -> str:
777
+ if "import secrets" in content:
778
+ return content
779
+
780
+ lines = content.split("\n")
781
+ for i, line in enumerate(lines):
782
+ if line.strip().startswith(("import ", "from ")):
783
+ lines.insert(i + 1, "import secrets")
784
+ break
785
+ return "\n".join(lines)
786
+
787
+ def _remove_debug_prints_with_secrets(self, content: str) -> str:
788
+ from crackerjack.services.regex_patterns import SAFE_PATTERNS
789
+
790
+ return SAFE_PATTERNS["remove_debug_prints_with_secrets"].apply(content)
791
+
792
+
793
+ agent_registry.register(SecurityAgent)