crackerjack 0.37.9__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.
- crackerjack/README.md +19 -0
- crackerjack/__init__.py +30 -1
- crackerjack/__main__.py +342 -1263
- crackerjack/adapters/README.md +18 -0
- crackerjack/adapters/__init__.py +27 -5
- crackerjack/adapters/_output_paths.py +167 -0
- crackerjack/adapters/_qa_adapter_base.py +309 -0
- crackerjack/adapters/_tool_adapter_base.py +706 -0
- crackerjack/adapters/ai/README.md +65 -0
- crackerjack/adapters/ai/__init__.py +5 -0
- crackerjack/adapters/ai/claude.py +853 -0
- crackerjack/adapters/complexity/README.md +53 -0
- crackerjack/adapters/complexity/__init__.py +10 -0
- crackerjack/adapters/complexity/complexipy.py +641 -0
- crackerjack/adapters/dependency/__init__.py +22 -0
- crackerjack/adapters/dependency/pip_audit.py +418 -0
- crackerjack/adapters/format/README.md +72 -0
- crackerjack/adapters/format/__init__.py +11 -0
- crackerjack/adapters/format/mdformat.py +313 -0
- crackerjack/adapters/format/ruff.py +516 -0
- crackerjack/adapters/lint/README.md +47 -0
- crackerjack/adapters/lint/__init__.py +11 -0
- crackerjack/adapters/lint/codespell.py +273 -0
- crackerjack/adapters/lsp/README.md +49 -0
- crackerjack/adapters/lsp/__init__.py +27 -0
- crackerjack/adapters/{rust_tool_manager.py → lsp/_manager.py} +3 -3
- crackerjack/adapters/{skylos_adapter.py → lsp/skylos.py} +59 -7
- crackerjack/adapters/{zuban_adapter.py → lsp/zuban.py} +3 -6
- crackerjack/adapters/refactor/README.md +59 -0
- crackerjack/adapters/refactor/__init__.py +12 -0
- crackerjack/adapters/refactor/creosote.py +318 -0
- crackerjack/adapters/refactor/refurb.py +406 -0
- crackerjack/adapters/refactor/skylos.py +494 -0
- crackerjack/adapters/sast/README.md +132 -0
- crackerjack/adapters/sast/__init__.py +32 -0
- crackerjack/adapters/sast/_base.py +201 -0
- crackerjack/adapters/sast/bandit.py +423 -0
- crackerjack/adapters/sast/pyscn.py +405 -0
- crackerjack/adapters/sast/semgrep.py +241 -0
- crackerjack/adapters/security/README.md +111 -0
- crackerjack/adapters/security/__init__.py +17 -0
- crackerjack/adapters/security/gitleaks.py +339 -0
- crackerjack/adapters/type/README.md +52 -0
- crackerjack/adapters/type/__init__.py +12 -0
- crackerjack/adapters/type/pyrefly.py +402 -0
- crackerjack/adapters/type/ty.py +402 -0
- crackerjack/adapters/type/zuban.py +522 -0
- crackerjack/adapters/utility/README.md +51 -0
- crackerjack/adapters/utility/__init__.py +10 -0
- crackerjack/adapters/utility/checks.py +884 -0
- crackerjack/agents/README.md +264 -0
- crackerjack/agents/__init__.py +40 -12
- crackerjack/agents/base.py +1 -0
- crackerjack/agents/claude_code_bridge.py +641 -0
- crackerjack/agents/coordinator.py +49 -53
- crackerjack/agents/dry_agent.py +187 -3
- crackerjack/agents/enhanced_coordinator.py +279 -0
- crackerjack/agents/enhanced_proactive_agent.py +185 -0
- crackerjack/agents/error_middleware.py +53 -0
- crackerjack/agents/formatting_agent.py +6 -8
- crackerjack/agents/helpers/__init__.py +9 -0
- crackerjack/agents/helpers/performance/__init__.py +22 -0
- crackerjack/agents/helpers/performance/performance_ast_analyzer.py +357 -0
- crackerjack/agents/helpers/performance/performance_pattern_detector.py +909 -0
- crackerjack/agents/helpers/performance/performance_recommender.py +572 -0
- crackerjack/agents/helpers/refactoring/__init__.py +22 -0
- crackerjack/agents/helpers/refactoring/code_transformer.py +536 -0
- crackerjack/agents/helpers/refactoring/complexity_analyzer.py +344 -0
- crackerjack/agents/helpers/refactoring/dead_code_detector.py +437 -0
- crackerjack/agents/helpers/test_creation/__init__.py +19 -0
- crackerjack/agents/helpers/test_creation/test_ast_analyzer.py +216 -0
- crackerjack/agents/helpers/test_creation/test_coverage_analyzer.py +643 -0
- crackerjack/agents/helpers/test_creation/test_template_generator.py +1031 -0
- crackerjack/agents/performance_agent.py +121 -1152
- crackerjack/agents/refactoring_agent.py +156 -655
- crackerjack/agents/semantic_agent.py +479 -0
- crackerjack/agents/semantic_helpers.py +356 -0
- crackerjack/agents/test_creation_agent.py +19 -1605
- crackerjack/api.py +5 -7
- crackerjack/cli/README.md +394 -0
- crackerjack/cli/__init__.py +1 -1
- crackerjack/cli/cache_handlers.py +23 -18
- crackerjack/cli/cache_handlers_enhanced.py +1 -4
- crackerjack/cli/facade.py +70 -8
- crackerjack/cli/formatting.py +13 -0
- crackerjack/cli/handlers/__init__.py +85 -0
- crackerjack/cli/handlers/advanced.py +103 -0
- crackerjack/cli/handlers/ai_features.py +62 -0
- crackerjack/cli/handlers/analytics.py +479 -0
- crackerjack/cli/handlers/changelog.py +271 -0
- crackerjack/cli/handlers/config_handlers.py +16 -0
- crackerjack/cli/handlers/coverage.py +84 -0
- crackerjack/cli/handlers/documentation.py +280 -0
- crackerjack/cli/handlers/main_handlers.py +497 -0
- crackerjack/cli/handlers/monitoring.py +371 -0
- crackerjack/cli/handlers.py +249 -49
- crackerjack/cli/interactive.py +8 -5
- crackerjack/cli/options.py +203 -110
- crackerjack/cli/semantic_handlers.py +292 -0
- crackerjack/cli/version.py +19 -0
- crackerjack/code_cleaner.py +60 -24
- crackerjack/config/README.md +472 -0
- crackerjack/config/__init__.py +256 -0
- crackerjack/config/global_lock_config.py +191 -54
- crackerjack/config/hooks.py +188 -16
- crackerjack/config/loader.py +239 -0
- crackerjack/config/settings.py +141 -0
- crackerjack/config/tool_commands.py +331 -0
- crackerjack/core/README.md +393 -0
- crackerjack/core/async_workflow_orchestrator.py +79 -53
- crackerjack/core/autofix_coordinator.py +22 -9
- crackerjack/core/container.py +10 -9
- crackerjack/core/enhanced_container.py +9 -9
- crackerjack/core/performance.py +1 -1
- crackerjack/core/performance_monitor.py +5 -3
- crackerjack/core/phase_coordinator.py +1018 -634
- crackerjack/core/proactive_workflow.py +3 -3
- crackerjack/core/retry.py +275 -0
- crackerjack/core/service_watchdog.py +167 -23
- crackerjack/core/session_coordinator.py +187 -382
- crackerjack/core/timeout_manager.py +161 -44
- crackerjack/core/workflow/__init__.py +21 -0
- crackerjack/core/workflow/workflow_ai_coordinator.py +863 -0
- crackerjack/core/workflow/workflow_event_orchestrator.py +1107 -0
- crackerjack/core/workflow/workflow_issue_parser.py +714 -0
- crackerjack/core/workflow/workflow_phase_executor.py +1158 -0
- crackerjack/core/workflow/workflow_security_gates.py +400 -0
- crackerjack/core/workflow_orchestrator.py +1247 -953
- crackerjack/data/README.md +11 -0
- crackerjack/data/__init__.py +8 -0
- crackerjack/data/models.py +79 -0
- crackerjack/data/repository.py +210 -0
- crackerjack/decorators/README.md +180 -0
- crackerjack/decorators/__init__.py +35 -0
- crackerjack/decorators/error_handling.py +649 -0
- crackerjack/decorators/error_handling_decorators.py +334 -0
- crackerjack/decorators/helpers.py +58 -0
- crackerjack/decorators/patterns.py +281 -0
- crackerjack/decorators/utils.py +58 -0
- crackerjack/docs/README.md +11 -0
- crackerjack/docs/generated/api/CLI_REFERENCE.md +1 -1
- crackerjack/documentation/README.md +11 -0
- crackerjack/documentation/ai_templates.py +1 -1
- crackerjack/documentation/dual_output_generator.py +11 -9
- crackerjack/documentation/reference_generator.py +104 -59
- crackerjack/dynamic_config.py +52 -61
- crackerjack/errors.py +1 -1
- crackerjack/events/README.md +11 -0
- crackerjack/events/__init__.py +16 -0
- crackerjack/events/telemetry.py +175 -0
- crackerjack/events/workflow_bus.py +346 -0
- crackerjack/exceptions/README.md +301 -0
- crackerjack/exceptions/__init__.py +5 -0
- crackerjack/exceptions/config.py +4 -0
- crackerjack/exceptions/tool_execution_error.py +245 -0
- crackerjack/executors/README.md +591 -0
- crackerjack/executors/__init__.py +2 -0
- crackerjack/executors/async_hook_executor.py +539 -77
- crackerjack/executors/cached_hook_executor.py +3 -3
- crackerjack/executors/hook_executor.py +967 -102
- crackerjack/executors/hook_lock_manager.py +31 -22
- crackerjack/executors/individual_hook_executor.py +66 -32
- crackerjack/executors/lsp_aware_hook_executor.py +136 -57
- crackerjack/executors/progress_hook_executor.py +282 -0
- crackerjack/executors/tool_proxy.py +23 -7
- crackerjack/hooks/README.md +485 -0
- crackerjack/hooks/lsp_hook.py +8 -9
- crackerjack/intelligence/README.md +557 -0
- crackerjack/interactive.py +37 -10
- crackerjack/managers/README.md +369 -0
- crackerjack/managers/async_hook_manager.py +41 -57
- crackerjack/managers/hook_manager.py +449 -79
- crackerjack/managers/publish_manager.py +81 -36
- crackerjack/managers/test_command_builder.py +290 -12
- crackerjack/managers/test_executor.py +93 -8
- crackerjack/managers/test_manager.py +1082 -75
- crackerjack/managers/test_progress.py +118 -26
- crackerjack/mcp/README.md +374 -0
- crackerjack/mcp/cache.py +25 -2
- crackerjack/mcp/client_runner.py +35 -18
- crackerjack/mcp/context.py +9 -9
- crackerjack/mcp/dashboard.py +24 -8
- crackerjack/mcp/enhanced_progress_monitor.py +34 -23
- crackerjack/mcp/file_monitor.py +27 -6
- crackerjack/mcp/progress_components.py +45 -34
- crackerjack/mcp/progress_monitor.py +6 -9
- crackerjack/mcp/rate_limiter.py +11 -7
- crackerjack/mcp/server.py +2 -0
- crackerjack/mcp/server_core.py +187 -55
- crackerjack/mcp/service_watchdog.py +12 -9
- crackerjack/mcp/task_manager.py +2 -2
- crackerjack/mcp/tools/README.md +27 -0
- crackerjack/mcp/tools/__init__.py +2 -0
- crackerjack/mcp/tools/core_tools.py +75 -52
- crackerjack/mcp/tools/execution_tools.py +87 -31
- crackerjack/mcp/tools/intelligence_tools.py +2 -2
- crackerjack/mcp/tools/proactive_tools.py +1 -1
- crackerjack/mcp/tools/semantic_tools.py +584 -0
- crackerjack/mcp/tools/utility_tools.py +180 -132
- crackerjack/mcp/tools/workflow_executor.py +87 -46
- crackerjack/mcp/websocket/README.md +31 -0
- crackerjack/mcp/websocket/app.py +11 -1
- crackerjack/mcp/websocket/event_bridge.py +188 -0
- crackerjack/mcp/websocket/jobs.py +27 -4
- crackerjack/mcp/websocket/monitoring/__init__.py +25 -0
- crackerjack/mcp/websocket/monitoring/api/__init__.py +19 -0
- crackerjack/mcp/websocket/monitoring/api/dependencies.py +141 -0
- crackerjack/mcp/websocket/monitoring/api/heatmap.py +154 -0
- crackerjack/mcp/websocket/monitoring/api/intelligence.py +199 -0
- crackerjack/mcp/websocket/monitoring/api/metrics.py +203 -0
- crackerjack/mcp/websocket/monitoring/api/telemetry.py +101 -0
- crackerjack/mcp/websocket/monitoring/dashboard.py +18 -0
- crackerjack/mcp/websocket/monitoring/factory.py +109 -0
- crackerjack/mcp/websocket/monitoring/filters.py +10 -0
- crackerjack/mcp/websocket/monitoring/metrics.py +64 -0
- crackerjack/mcp/websocket/monitoring/models.py +90 -0
- crackerjack/mcp/websocket/monitoring/utils.py +171 -0
- crackerjack/mcp/websocket/monitoring/websocket_manager.py +78 -0
- crackerjack/mcp/websocket/monitoring/websockets/__init__.py +17 -0
- crackerjack/mcp/websocket/monitoring/websockets/dependencies.py +126 -0
- crackerjack/mcp/websocket/monitoring/websockets/heatmap.py +176 -0
- crackerjack/mcp/websocket/monitoring/websockets/intelligence.py +291 -0
- crackerjack/mcp/websocket/monitoring/websockets/metrics.py +291 -0
- crackerjack/mcp/websocket/monitoring_endpoints.py +16 -2930
- crackerjack/mcp/websocket/server.py +1 -3
- crackerjack/mcp/websocket/websocket_handler.py +107 -6
- crackerjack/models/README.md +308 -0
- crackerjack/models/__init__.py +10 -1
- crackerjack/models/config.py +639 -22
- crackerjack/models/config_adapter.py +6 -6
- crackerjack/models/protocols.py +1167 -23
- crackerjack/models/pydantic_models.py +320 -0
- crackerjack/models/qa_config.py +145 -0
- crackerjack/models/qa_results.py +134 -0
- crackerjack/models/results.py +35 -0
- crackerjack/models/semantic_models.py +258 -0
- crackerjack/models/task.py +19 -3
- crackerjack/models/test_models.py +60 -0
- crackerjack/monitoring/README.md +11 -0
- crackerjack/monitoring/ai_agent_watchdog.py +5 -4
- crackerjack/monitoring/metrics_collector.py +4 -3
- crackerjack/monitoring/regression_prevention.py +4 -3
- crackerjack/monitoring/websocket_server.py +4 -241
- crackerjack/orchestration/README.md +340 -0
- crackerjack/orchestration/__init__.py +43 -0
- crackerjack/orchestration/advanced_orchestrator.py +20 -67
- crackerjack/orchestration/cache/README.md +312 -0
- crackerjack/orchestration/cache/__init__.py +37 -0
- crackerjack/orchestration/cache/memory_cache.py +338 -0
- crackerjack/orchestration/cache/tool_proxy_cache.py +340 -0
- crackerjack/orchestration/config.py +297 -0
- crackerjack/orchestration/coverage_improvement.py +13 -6
- crackerjack/orchestration/execution_strategies.py +6 -6
- crackerjack/orchestration/hook_orchestrator.py +1398 -0
- crackerjack/orchestration/strategies/README.md +401 -0
- crackerjack/orchestration/strategies/__init__.py +39 -0
- crackerjack/orchestration/strategies/adaptive_strategy.py +630 -0
- crackerjack/orchestration/strategies/parallel_strategy.py +237 -0
- crackerjack/orchestration/strategies/sequential_strategy.py +299 -0
- crackerjack/orchestration/test_progress_streamer.py +1 -1
- crackerjack/plugins/README.md +11 -0
- crackerjack/plugins/hooks.py +3 -2
- crackerjack/plugins/loader.py +3 -3
- crackerjack/plugins/managers.py +1 -1
- crackerjack/py313.py +191 -0
- crackerjack/security/README.md +11 -0
- crackerjack/services/README.md +374 -0
- crackerjack/services/__init__.py +8 -21
- crackerjack/services/ai/README.md +295 -0
- crackerjack/services/ai/__init__.py +7 -0
- crackerjack/services/ai/advanced_optimizer.py +878 -0
- crackerjack/services/{contextual_ai_assistant.py → ai/contextual_ai_assistant.py} +5 -3
- crackerjack/services/ai/embeddings.py +444 -0
- crackerjack/services/ai/intelligent_commit.py +328 -0
- crackerjack/services/ai/predictive_analytics.py +510 -0
- crackerjack/services/api_extractor.py +5 -3
- crackerjack/services/bounded_status_operations.py +45 -5
- crackerjack/services/cache.py +249 -318
- crackerjack/services/changelog_automation.py +7 -3
- crackerjack/services/command_execution_service.py +305 -0
- crackerjack/services/config_integrity.py +83 -39
- crackerjack/services/config_merge.py +9 -6
- crackerjack/services/config_service.py +198 -0
- crackerjack/services/config_template.py +13 -26
- crackerjack/services/coverage_badge_service.py +6 -4
- crackerjack/services/coverage_ratchet.py +53 -27
- crackerjack/services/debug.py +18 -7
- crackerjack/services/dependency_analyzer.py +4 -4
- crackerjack/services/dependency_monitor.py +13 -13
- crackerjack/services/documentation_generator.py +4 -2
- crackerjack/services/documentation_service.py +62 -33
- crackerjack/services/enhanced_filesystem.py +81 -27
- crackerjack/services/enterprise_optimizer.py +1 -1
- crackerjack/services/error_pattern_analyzer.py +10 -10
- crackerjack/services/file_filter.py +221 -0
- crackerjack/services/file_hasher.py +5 -7
- crackerjack/services/file_io_service.py +361 -0
- crackerjack/services/file_modifier.py +615 -0
- crackerjack/services/filesystem.py +80 -109
- crackerjack/services/git.py +99 -5
- crackerjack/services/health_metrics.py +4 -6
- crackerjack/services/heatmap_generator.py +12 -3
- crackerjack/services/incremental_executor.py +380 -0
- crackerjack/services/initialization.py +101 -49
- crackerjack/services/log_manager.py +2 -2
- crackerjack/services/logging.py +120 -68
- crackerjack/services/lsp_client.py +12 -12
- crackerjack/services/memory_optimizer.py +27 -22
- crackerjack/services/monitoring/README.md +30 -0
- crackerjack/services/monitoring/__init__.py +9 -0
- crackerjack/services/monitoring/dependency_monitor.py +678 -0
- crackerjack/services/monitoring/error_pattern_analyzer.py +676 -0
- crackerjack/services/monitoring/health_metrics.py +716 -0
- crackerjack/services/monitoring/metrics.py +587 -0
- crackerjack/services/{performance_benchmarks.py → monitoring/performance_benchmarks.py} +100 -14
- crackerjack/services/{performance_cache.py → monitoring/performance_cache.py} +21 -15
- crackerjack/services/{performance_monitor.py → monitoring/performance_monitor.py} +10 -6
- crackerjack/services/parallel_executor.py +166 -55
- crackerjack/services/patterns/__init__.py +142 -0
- crackerjack/services/patterns/agents.py +107 -0
- crackerjack/services/patterns/code/__init__.py +15 -0
- crackerjack/services/patterns/code/detection.py +118 -0
- crackerjack/services/patterns/code/imports.py +107 -0
- crackerjack/services/patterns/code/paths.py +159 -0
- crackerjack/services/patterns/code/performance.py +119 -0
- crackerjack/services/patterns/code/replacement.py +36 -0
- crackerjack/services/patterns/core.py +212 -0
- crackerjack/services/patterns/documentation/__init__.py +14 -0
- crackerjack/services/patterns/documentation/badges_markdown.py +96 -0
- crackerjack/services/patterns/documentation/comments_blocks.py +83 -0
- crackerjack/services/patterns/documentation/docstrings.py +89 -0
- crackerjack/services/patterns/formatting.py +226 -0
- crackerjack/services/patterns/operations.py +339 -0
- crackerjack/services/patterns/security/__init__.py +23 -0
- crackerjack/services/patterns/security/code_injection.py +122 -0
- crackerjack/services/patterns/security/credentials.py +190 -0
- crackerjack/services/patterns/security/path_traversal.py +221 -0
- crackerjack/services/patterns/security/unsafe_operations.py +216 -0
- crackerjack/services/patterns/templates.py +62 -0
- crackerjack/services/patterns/testing/__init__.py +18 -0
- crackerjack/services/patterns/testing/error_patterns.py +107 -0
- crackerjack/services/patterns/testing/pytest_output.py +126 -0
- crackerjack/services/patterns/tool_output/__init__.py +16 -0
- crackerjack/services/patterns/tool_output/bandit.py +72 -0
- crackerjack/services/patterns/tool_output/other.py +97 -0
- crackerjack/services/patterns/tool_output/pyright.py +67 -0
- crackerjack/services/patterns/tool_output/ruff.py +44 -0
- crackerjack/services/patterns/url_sanitization.py +114 -0
- crackerjack/services/patterns/utilities.py +42 -0
- crackerjack/services/patterns/utils.py +339 -0
- crackerjack/services/patterns/validation.py +46 -0
- crackerjack/services/patterns/versioning.py +62 -0
- crackerjack/services/predictive_analytics.py +21 -8
- crackerjack/services/profiler.py +280 -0
- crackerjack/services/quality/README.md +415 -0
- crackerjack/services/quality/__init__.py +11 -0
- crackerjack/services/quality/anomaly_detector.py +392 -0
- crackerjack/services/quality/pattern_cache.py +333 -0
- crackerjack/services/quality/pattern_detector.py +479 -0
- crackerjack/services/quality/qa_orchestrator.py +491 -0
- crackerjack/services/{quality_baseline.py → quality/quality_baseline.py} +163 -2
- crackerjack/services/{quality_baseline_enhanced.py → quality/quality_baseline_enhanced.py} +4 -1
- crackerjack/services/{quality_intelligence.py → quality/quality_intelligence.py} +180 -16
- crackerjack/services/regex_patterns.py +58 -2987
- crackerjack/services/regex_utils.py +55 -29
- crackerjack/services/secure_status_formatter.py +42 -15
- crackerjack/services/secure_subprocess.py +35 -2
- crackerjack/services/security.py +16 -8
- crackerjack/services/server_manager.py +40 -51
- crackerjack/services/smart_scheduling.py +46 -6
- crackerjack/services/status_authentication.py +3 -3
- crackerjack/services/thread_safe_status_collector.py +1 -0
- crackerjack/services/tool_filter.py +368 -0
- crackerjack/services/tool_version_service.py +9 -5
- crackerjack/services/unified_config.py +43 -351
- crackerjack/services/vector_store.py +689 -0
- crackerjack/services/version_analyzer.py +6 -4
- crackerjack/services/version_checker.py +14 -8
- crackerjack/services/zuban_lsp_service.py +5 -4
- crackerjack/slash_commands/README.md +11 -0
- crackerjack/slash_commands/init.md +2 -12
- crackerjack/slash_commands/run.md +84 -50
- crackerjack/tools/README.md +11 -0
- crackerjack/tools/__init__.py +30 -0
- crackerjack/tools/_git_utils.py +105 -0
- crackerjack/tools/check_added_large_files.py +139 -0
- crackerjack/tools/check_ast.py +105 -0
- crackerjack/tools/check_json.py +103 -0
- crackerjack/tools/check_jsonschema.py +297 -0
- crackerjack/tools/check_toml.py +103 -0
- crackerjack/tools/check_yaml.py +110 -0
- crackerjack/tools/codespell_wrapper.py +72 -0
- crackerjack/tools/end_of_file_fixer.py +202 -0
- crackerjack/tools/format_json.py +128 -0
- crackerjack/tools/mdformat_wrapper.py +114 -0
- crackerjack/tools/trailing_whitespace.py +198 -0
- crackerjack/tools/validate_regex_patterns.py +7 -3
- crackerjack/ui/README.md +11 -0
- crackerjack/ui/dashboard_renderer.py +28 -0
- crackerjack/ui/templates/README.md +11 -0
- crackerjack/utils/console_utils.py +13 -0
- crackerjack/utils/dependency_guard.py +230 -0
- crackerjack/utils/retry_utils.py +275 -0
- crackerjack/workflows/README.md +590 -0
- crackerjack/workflows/__init__.py +46 -0
- crackerjack/workflows/actions.py +811 -0
- crackerjack/workflows/auto_fix.py +444 -0
- crackerjack/workflows/container_builder.py +499 -0
- crackerjack/workflows/definitions.py +443 -0
- crackerjack/workflows/engine.py +177 -0
- crackerjack/workflows/event_bridge.py +242 -0
- {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/METADATA +678 -98
- crackerjack-0.45.2.dist-info/RECORD +478 -0
- {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/WHEEL +1 -1
- crackerjack/managers/test_manager_backup.py +0 -1075
- crackerjack/mcp/tools/execution_tools_backup.py +0 -1011
- crackerjack/mixins/__init__.py +0 -3
- crackerjack/mixins/error_handling.py +0 -145
- crackerjack/services/config.py +0 -358
- crackerjack/ui/server_panels.py +0 -125
- crackerjack-0.37.9.dist-info/RECORD +0 -231
- /crackerjack/adapters/{rust_tool_adapter.py → lsp/_base.py} +0 -0
- /crackerjack/adapters/{lsp_client.py → lsp/_client.py} +0 -0
- {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/entry_points.txt +0 -0
- {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"""SAST (Static Application Security Testing) adapter protocol and base classes.
|
|
2
|
+
|
|
3
|
+
This module defines the protocol interface that all SAST adapters must implement,
|
|
4
|
+
providing a consistent API for static security analysis tools.
|
|
5
|
+
|
|
6
|
+
SAST tools analyze source code for:
|
|
7
|
+
- Security vulnerabilities (SQL injection, XSS, etc.)
|
|
8
|
+
- Security anti-patterns and insecure practices
|
|
9
|
+
- Weak cryptography implementations
|
|
10
|
+
- Authentication/authorization flaws
|
|
11
|
+
- Potential injection vulnerabilities
|
|
12
|
+
|
|
13
|
+
Protocol-based design ensures:
|
|
14
|
+
- Type safety via runtime_checkable protocol
|
|
15
|
+
- Loose coupling for testing and mocking
|
|
16
|
+
- Consistent interface across all SAST tools
|
|
17
|
+
- Integration with ACB dependency injection
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import typing as t
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
from typing import Protocol, runtime_checkable
|
|
25
|
+
from uuid import UUID
|
|
26
|
+
|
|
27
|
+
from crackerjack.adapters._tool_adapter_base import (
|
|
28
|
+
ToolAdapterSettings,
|
|
29
|
+
ToolExecutionResult,
|
|
30
|
+
ToolIssue,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
if t.TYPE_CHECKING:
|
|
34
|
+
from crackerjack.models.qa_config import QACheckConfig
|
|
35
|
+
from crackerjack.models.qa_results import QACheckType
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@runtime_checkable
|
|
39
|
+
class SASTAdapterProtocol(Protocol):
|
|
40
|
+
"""Protocol for SAST (Static Application Security Testing) adapters.
|
|
41
|
+
|
|
42
|
+
All SAST adapters must implement this protocol to ensure consistent
|
|
43
|
+
behavior and integration with the Crackerjack quality assurance framework.
|
|
44
|
+
|
|
45
|
+
SAST tools focus on finding security vulnerabilities in source code through
|
|
46
|
+
static analysis, complementing secret detection (gitleaks) which prevents
|
|
47
|
+
credential leaks.
|
|
48
|
+
|
|
49
|
+
Attributes:
|
|
50
|
+
settings: Tool-specific settings (severity thresholds, rulesets, etc.)
|
|
51
|
+
adapter_name: Human-readable adapter name (e.g., "Semgrep (SAST)")
|
|
52
|
+
module_id: Unique UUID7 identifier for this adapter module
|
|
53
|
+
tool_name: CLI tool name for command execution
|
|
54
|
+
|
|
55
|
+
Example:
|
|
56
|
+
```python
|
|
57
|
+
from crackerjack.adapters.sast import SemgrepAdapter
|
|
58
|
+
|
|
59
|
+
adapter: SASTAdapterProtocol = SemgrepAdapter()
|
|
60
|
+
await adapter.init()
|
|
61
|
+
result = await adapter.check(files=[Path("src/")])
|
|
62
|
+
```
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
settings: ToolAdapterSettings | None
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def adapter_name(self) -> str:
|
|
69
|
+
"""Human-readable adapter name.
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
Name identifying the adapter (e.g., "Bandit (SAST)", "Semgrep (SAST)")
|
|
73
|
+
"""
|
|
74
|
+
...
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def module_id(self) -> UUID:
|
|
78
|
+
"""Unique module identifier.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
UUID7 for reproducible module identity (ACB registration)
|
|
82
|
+
"""
|
|
83
|
+
...
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def tool_name(self) -> str:
|
|
87
|
+
"""CLI tool name.
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
Command-line tool name for subprocess execution
|
|
91
|
+
"""
|
|
92
|
+
...
|
|
93
|
+
|
|
94
|
+
async def init(self) -> None:
|
|
95
|
+
"""Initialize adapter with settings and dependencies.
|
|
96
|
+
|
|
97
|
+
Must be called before using check() or other operations.
|
|
98
|
+
Sets up default settings if not provided during construction.
|
|
99
|
+
|
|
100
|
+
Raises:
|
|
101
|
+
RuntimeError: If initialization fails
|
|
102
|
+
"""
|
|
103
|
+
...
|
|
104
|
+
|
|
105
|
+
def build_command(
|
|
106
|
+
self,
|
|
107
|
+
files: list[Path],
|
|
108
|
+
config: QACheckConfig | None = None,
|
|
109
|
+
) -> list[str]:
|
|
110
|
+
"""Build tool command for execution.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
files: Files or directories to scan for vulnerabilities
|
|
114
|
+
config: Optional configuration override
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
Command as list of strings for subprocess execution
|
|
118
|
+
|
|
119
|
+
Example:
|
|
120
|
+
```python
|
|
121
|
+
cmd = adapter.build_command(
|
|
122
|
+
files=[Path("src/")],
|
|
123
|
+
config=None,
|
|
124
|
+
)
|
|
125
|
+
# Returns: ["semgrep", "scan", "--json", "--config", "p/security-audit", "src/"]
|
|
126
|
+
```
|
|
127
|
+
"""
|
|
128
|
+
...
|
|
129
|
+
|
|
130
|
+
async def check(
|
|
131
|
+
self,
|
|
132
|
+
files: list[Path],
|
|
133
|
+
config: QACheckConfig | None = None,
|
|
134
|
+
) -> ToolExecutionResult:
|
|
135
|
+
"""Execute SAST scan on specified files.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
files: Files or directories to analyze for security issues
|
|
139
|
+
config: Optional configuration override
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
Execution result with parsed issues, timing, and metadata
|
|
143
|
+
|
|
144
|
+
Example:
|
|
145
|
+
```python
|
|
146
|
+
result = await adapter.check(files=[Path("src/")])
|
|
147
|
+
for issue in result.issues:
|
|
148
|
+
print(f"{issue.file_path}:{issue.line_number} - {issue.message}")
|
|
149
|
+
```
|
|
150
|
+
"""
|
|
151
|
+
...
|
|
152
|
+
|
|
153
|
+
async def parse_output(
|
|
154
|
+
self,
|
|
155
|
+
result: ToolExecutionResult,
|
|
156
|
+
) -> list[ToolIssue]:
|
|
157
|
+
"""Parse tool output into standardized issues.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
result: Raw execution result from SAST tool
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
List of parsed security issues with severity, location, and suggestions
|
|
164
|
+
|
|
165
|
+
Note:
|
|
166
|
+
Implementations should handle both JSON and text output formats,
|
|
167
|
+
with JSON preferred for structured parsing.
|
|
168
|
+
"""
|
|
169
|
+
...
|
|
170
|
+
|
|
171
|
+
def _get_check_type(self) -> QACheckType:
|
|
172
|
+
"""Return the check type for this adapter.
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
QACheckType.SAST for all SAST adapters
|
|
176
|
+
"""
|
|
177
|
+
...
|
|
178
|
+
|
|
179
|
+
def get_default_config(self) -> QACheckConfig:
|
|
180
|
+
"""Get default configuration for this SAST adapter.
|
|
181
|
+
|
|
182
|
+
Returns:
|
|
183
|
+
Default QACheckConfig with sensible defaults for the tool
|
|
184
|
+
|
|
185
|
+
Example:
|
|
186
|
+
```python
|
|
187
|
+
config = adapter.get_default_config()
|
|
188
|
+
assert config.check_type == QACheckType.SAST
|
|
189
|
+
assert config.stage == "comprehensive"
|
|
190
|
+
```
|
|
191
|
+
"""
|
|
192
|
+
...
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
# Type alias for convenience
|
|
196
|
+
SASTAdapter = SASTAdapterProtocol
|
|
197
|
+
|
|
198
|
+
__all__ = [
|
|
199
|
+
"SASTAdapterProtocol",
|
|
200
|
+
"SASTAdapter",
|
|
201
|
+
]
|
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
"""Bandit adapter for ACB QA framework - Python security linting.
|
|
2
|
+
|
|
3
|
+
Bandit is a security linter designed to find common security issues in Python code.
|
|
4
|
+
It performs static analysis to identify potential vulnerabilities like:
|
|
5
|
+
- SQL injection risks
|
|
6
|
+
- Hard-coded passwords/secrets
|
|
7
|
+
- Insecure use of eval/exec
|
|
8
|
+
- Weak cryptography
|
|
9
|
+
- And many more security anti-patterns
|
|
10
|
+
|
|
11
|
+
ACB Patterns:
|
|
12
|
+
- MODULE_ID and MODULE_STATUS at module level
|
|
13
|
+
- depends.set() registration after class definition
|
|
14
|
+
- Extends BaseToolAdapter for tool execution
|
|
15
|
+
- Async execution with JSON output parsing
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import json
|
|
21
|
+
import logging
|
|
22
|
+
import typing as t
|
|
23
|
+
from contextlib import suppress
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
from uuid import UUID
|
|
26
|
+
|
|
27
|
+
from acb.depends import depends
|
|
28
|
+
from pydantic import Field
|
|
29
|
+
|
|
30
|
+
from crackerjack.adapters._tool_adapter_base import (
|
|
31
|
+
BaseToolAdapter,
|
|
32
|
+
ToolAdapterSettings,
|
|
33
|
+
ToolExecutionResult,
|
|
34
|
+
ToolIssue,
|
|
35
|
+
)
|
|
36
|
+
from crackerjack.models.qa_results import QACheckType
|
|
37
|
+
|
|
38
|
+
if t.TYPE_CHECKING:
|
|
39
|
+
from crackerjack.models.qa_config import QACheckConfig
|
|
40
|
+
|
|
41
|
+
# ACB Module Registration (REQUIRED)
|
|
42
|
+
MODULE_ID = UUID(
|
|
43
|
+
"01937d86-4f2a-7b3c-8d9e-f3b4d3c2b1a0"
|
|
44
|
+
) # Static UUID7 for reproducible module identity
|
|
45
|
+
MODULE_STATUS = "stable"
|
|
46
|
+
|
|
47
|
+
# Module-level logger for structured logging
|
|
48
|
+
logger = logging.getLogger(__name__)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class BanditSettings(ToolAdapterSettings):
|
|
52
|
+
"""Settings for Bandit adapter."""
|
|
53
|
+
|
|
54
|
+
tool_name: str = "bandit"
|
|
55
|
+
use_json_output: bool = True
|
|
56
|
+
severity_level: str = "low" # low, medium, high
|
|
57
|
+
confidence_level: str = "low" # low, medium, high
|
|
58
|
+
exclude_tests: bool = True
|
|
59
|
+
skip_rules: list[str] = Field(default_factory=list)
|
|
60
|
+
tests_to_run: list[str] = Field(default_factory=list)
|
|
61
|
+
recursive: bool = True
|
|
62
|
+
timeout_seconds: int = (
|
|
63
|
+
1200 # 20 minutes to allow for comprehensive security scanning
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class BanditAdapter(BaseToolAdapter):
|
|
68
|
+
"""Adapter for Bandit - Python security linter.
|
|
69
|
+
|
|
70
|
+
Performs static security analysis to identify common vulnerabilities:
|
|
71
|
+
- SQL injection
|
|
72
|
+
- Hard-coded credentials
|
|
73
|
+
- Insecure cryptography
|
|
74
|
+
- Command injection
|
|
75
|
+
- Path traversal
|
|
76
|
+
- And 100+ more security checks
|
|
77
|
+
|
|
78
|
+
Features:
|
|
79
|
+
- JSON output for structured issue reporting
|
|
80
|
+
- Configurable severity and confidence thresholds
|
|
81
|
+
- Rule selection and exclusion
|
|
82
|
+
- Recursive directory scanning
|
|
83
|
+
- Test file exclusion
|
|
84
|
+
|
|
85
|
+
Example:
|
|
86
|
+
```python
|
|
87
|
+
settings = BanditSettings(
|
|
88
|
+
severity_level="medium",
|
|
89
|
+
confidence_level="medium",
|
|
90
|
+
exclude_tests=True,
|
|
91
|
+
skip_rules=["B101"], # Skip assert_used check
|
|
92
|
+
)
|
|
93
|
+
adapter = BanditAdapter(settings=settings)
|
|
94
|
+
await adapter.init()
|
|
95
|
+
result = await adapter.check(files=[Path("src/")])
|
|
96
|
+
```
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
settings: BanditSettings | None = None
|
|
100
|
+
|
|
101
|
+
def __init__(self, settings: BanditSettings | None = None) -> None:
|
|
102
|
+
"""Initialize Bandit adapter.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
settings: Optional settings override
|
|
106
|
+
"""
|
|
107
|
+
super().__init__(settings=settings)
|
|
108
|
+
logger.debug(
|
|
109
|
+
"BanditAdapter initialized", extra={"has_settings": settings is not None}
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
async def init(self) -> None:
|
|
113
|
+
"""Initialize adapter with default settings."""
|
|
114
|
+
if not self.settings:
|
|
115
|
+
self.settings = BanditSettings()
|
|
116
|
+
logger.info("Using default BanditSettings")
|
|
117
|
+
await super().init()
|
|
118
|
+
logger.debug(
|
|
119
|
+
"BanditAdapter initialization complete",
|
|
120
|
+
extra={
|
|
121
|
+
"severity": self.settings.severity_level,
|
|
122
|
+
"confidence": self.settings.confidence_level,
|
|
123
|
+
"exclude_tests": self.settings.exclude_tests,
|
|
124
|
+
},
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
@property
|
|
128
|
+
def adapter_name(self) -> str:
|
|
129
|
+
"""Human-readable adapter name."""
|
|
130
|
+
return "Bandit (Security)"
|
|
131
|
+
|
|
132
|
+
@property
|
|
133
|
+
def module_id(self) -> UUID:
|
|
134
|
+
"""Reference to module-level MODULE_ID."""
|
|
135
|
+
return MODULE_ID
|
|
136
|
+
|
|
137
|
+
@property
|
|
138
|
+
def tool_name(self) -> str:
|
|
139
|
+
"""CLI tool name."""
|
|
140
|
+
return "bandit"
|
|
141
|
+
|
|
142
|
+
def build_command(
|
|
143
|
+
self,
|
|
144
|
+
files: list[Path],
|
|
145
|
+
config: QACheckConfig | None = None,
|
|
146
|
+
) -> list[str]:
|
|
147
|
+
"""Build Bandit command.
|
|
148
|
+
|
|
149
|
+
Args:
|
|
150
|
+
files: Files/directories to scan
|
|
151
|
+
config: Optional configuration override
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
Command as list of strings
|
|
155
|
+
"""
|
|
156
|
+
if not self.settings:
|
|
157
|
+
raise RuntimeError("Settings not initialized")
|
|
158
|
+
|
|
159
|
+
cmd = [self.tool_name]
|
|
160
|
+
|
|
161
|
+
# Recursive scanning
|
|
162
|
+
if self.settings.recursive:
|
|
163
|
+
cmd.append("-r")
|
|
164
|
+
|
|
165
|
+
# Use HIGH severity and confidence to minimize issues that cause failures
|
|
166
|
+
cmd.extend(["-lll"]) # Use highest severity level (HIGH)
|
|
167
|
+
cmd.extend(["-iii"]) # Use highest confidence level (HIGH)
|
|
168
|
+
|
|
169
|
+
# Skip specific test IDs that are common false positives in development tools
|
|
170
|
+
# B101: assert_used (common in test/development tools)
|
|
171
|
+
# B110: try_except_pass (used in cleanup/error handling)
|
|
172
|
+
# B112: try_except_continue (used in scanning/parsing loops)
|
|
173
|
+
# B311: blacklist_random (used for jitter in retry mechanisms)
|
|
174
|
+
# B404: blacklist_import_subprocess (subprocess necessary for automation)
|
|
175
|
+
# B603: subprocess_without_shell_equals_true (common subprocess usage)
|
|
176
|
+
# B607: start_process_with_partial_path (necessary for many tools)
|
|
177
|
+
skip_rules = ["B101", "B110", "B112", "B311", "B404", "B603", "B607"]
|
|
178
|
+
cmd.extend(["-s", ",".join(skip_rules)])
|
|
179
|
+
|
|
180
|
+
# JSON output
|
|
181
|
+
if self.settings.use_json_output:
|
|
182
|
+
cmd.extend(["-f", "json"])
|
|
183
|
+
|
|
184
|
+
# Add targets
|
|
185
|
+
cmd.extend([str(f) for f in files])
|
|
186
|
+
|
|
187
|
+
logger.info(
|
|
188
|
+
"Built Bandit command with aggressive skip rules",
|
|
189
|
+
extra={
|
|
190
|
+
"file_count": len(files),
|
|
191
|
+
"severity": "high",
|
|
192
|
+
"confidence": "high",
|
|
193
|
+
"recursive": self.settings.recursive,
|
|
194
|
+
"skip_rules": skip_rules,
|
|
195
|
+
},
|
|
196
|
+
)
|
|
197
|
+
return cmd
|
|
198
|
+
|
|
199
|
+
async def parse_output(
|
|
200
|
+
self,
|
|
201
|
+
result: ToolExecutionResult,
|
|
202
|
+
) -> list[ToolIssue]:
|
|
203
|
+
"""Parse Bandit JSON output into standardized issues.
|
|
204
|
+
|
|
205
|
+
Args:
|
|
206
|
+
result: Raw execution result from Bandit
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
List of parsed issues
|
|
210
|
+
"""
|
|
211
|
+
if not result.raw_output:
|
|
212
|
+
logger.debug("No output to parse")
|
|
213
|
+
return []
|
|
214
|
+
|
|
215
|
+
try:
|
|
216
|
+
data = json.loads(result.raw_output)
|
|
217
|
+
logger.debug(
|
|
218
|
+
"Parsed Bandit JSON output",
|
|
219
|
+
extra={"results_count": len(data.get("results", []))},
|
|
220
|
+
)
|
|
221
|
+
except json.JSONDecodeError as e:
|
|
222
|
+
# Fallback to text parsing if JSON fails
|
|
223
|
+
logger.debug(
|
|
224
|
+
"JSON parse failed, falling back to text parsing",
|
|
225
|
+
extra={"error": str(e), "output_preview": result.raw_output[:200]},
|
|
226
|
+
)
|
|
227
|
+
return self._parse_text_output(result.raw_output)
|
|
228
|
+
|
|
229
|
+
issues = []
|
|
230
|
+
|
|
231
|
+
# Bandit JSON format:
|
|
232
|
+
# {
|
|
233
|
+
# "results": [
|
|
234
|
+
# {
|
|
235
|
+
# "code": "...",
|
|
236
|
+
# "filename": "path/to/file.py",
|
|
237
|
+
# "issue_confidence": "HIGH",
|
|
238
|
+
# "issue_severity": "HIGH",
|
|
239
|
+
# "issue_text": "...",
|
|
240
|
+
# "line_number": 42,
|
|
241
|
+
# "line_range": [42, 43],
|
|
242
|
+
# "more_info": "https://...",
|
|
243
|
+
# "test_id": "B201",
|
|
244
|
+
# "test_name": "flask_debug_true"
|
|
245
|
+
# }
|
|
246
|
+
# ],
|
|
247
|
+
# "metrics": {...}
|
|
248
|
+
# }
|
|
249
|
+
|
|
250
|
+
for item in data.get("results", []):
|
|
251
|
+
file_path = Path(item.get("filename", ""))
|
|
252
|
+
|
|
253
|
+
# Map Bandit severity to our severity levels
|
|
254
|
+
severity_mapping = {
|
|
255
|
+
"HIGH": "error",
|
|
256
|
+
"MEDIUM": "warning",
|
|
257
|
+
"LOW": "warning",
|
|
258
|
+
}
|
|
259
|
+
bandit_severity = item.get("issue_severity", "MEDIUM")
|
|
260
|
+
severity = severity_mapping.get(bandit_severity.upper(), "warning")
|
|
261
|
+
|
|
262
|
+
issue = ToolIssue(
|
|
263
|
+
file_path=file_path,
|
|
264
|
+
line_number=item.get("line_number"),
|
|
265
|
+
message=item.get("issue_text", ""),
|
|
266
|
+
code=item.get("test_id"),
|
|
267
|
+
severity=severity,
|
|
268
|
+
suggestion=f"Confidence: {item.get('issue_confidence', 'UNKNOWN')}, "
|
|
269
|
+
f"See: {item.get('more_info', '')}",
|
|
270
|
+
)
|
|
271
|
+
issues.append(issue)
|
|
272
|
+
|
|
273
|
+
logger.info(
|
|
274
|
+
"Parsed Bandit output",
|
|
275
|
+
extra={
|
|
276
|
+
"total_issues": len(issues),
|
|
277
|
+
"high_severity": sum(1 for i in issues if i.severity == "error"),
|
|
278
|
+
"files_affected": len({str(i.file_path) for i in issues}),
|
|
279
|
+
},
|
|
280
|
+
)
|
|
281
|
+
return issues
|
|
282
|
+
|
|
283
|
+
def _parse_text_output(self, output: str) -> list[ToolIssue]:
|
|
284
|
+
"""Parse Bandit text output (fallback).
|
|
285
|
+
|
|
286
|
+
Args:
|
|
287
|
+
output: Text output from Bandit
|
|
288
|
+
|
|
289
|
+
Returns:
|
|
290
|
+
List of ToolIssue objects
|
|
291
|
+
"""
|
|
292
|
+
issues = []
|
|
293
|
+
lines = output.strip().split("\n")
|
|
294
|
+
|
|
295
|
+
current_file: Path | None = None
|
|
296
|
+
current_line: int | None = None
|
|
297
|
+
|
|
298
|
+
for line in lines:
|
|
299
|
+
line = line.strip()
|
|
300
|
+
|
|
301
|
+
# Parse file path lines
|
|
302
|
+
if line.startswith(">>"):
|
|
303
|
+
try:
|
|
304
|
+
file_str = line.split(">>")[1].strip()
|
|
305
|
+
current_file = Path(file_str)
|
|
306
|
+
except (IndexError, ValueError):
|
|
307
|
+
continue
|
|
308
|
+
|
|
309
|
+
# Parse issue lines
|
|
310
|
+
elif line.startswith("Issue:") and current_file:
|
|
311
|
+
message = line.replace("Issue:", "").strip()
|
|
312
|
+
issue = ToolIssue(
|
|
313
|
+
file_path=current_file,
|
|
314
|
+
line_number=current_line,
|
|
315
|
+
message=message,
|
|
316
|
+
severity="warning",
|
|
317
|
+
)
|
|
318
|
+
issues.append(issue)
|
|
319
|
+
|
|
320
|
+
# Parse line numbers
|
|
321
|
+
elif "Line:" in line:
|
|
322
|
+
with suppress(IndexError, ValueError):
|
|
323
|
+
line_num_str = line.split("Line:")[1].strip()
|
|
324
|
+
current_line = int(line_num_str)
|
|
325
|
+
|
|
326
|
+
logger.info(
|
|
327
|
+
"Parsed Bandit text output (fallback)",
|
|
328
|
+
extra={
|
|
329
|
+
"total_issues": len(issues),
|
|
330
|
+
"files_with_issues": len(
|
|
331
|
+
{str(i.file_path) for i in issues if i.file_path}
|
|
332
|
+
),
|
|
333
|
+
},
|
|
334
|
+
)
|
|
335
|
+
return issues
|
|
336
|
+
|
|
337
|
+
def _get_check_type(self) -> QACheckType:
|
|
338
|
+
"""Return SAST check type."""
|
|
339
|
+
return QACheckType.SAST
|
|
340
|
+
|
|
341
|
+
def _detect_package_directory(self) -> str:
|
|
342
|
+
"""Detect the package directory name from pyproject.toml.
|
|
343
|
+
|
|
344
|
+
Returns:
|
|
345
|
+
Package directory name (e.g., 'crackerjack', 'session_mgmt_mcp')
|
|
346
|
+
"""
|
|
347
|
+
from contextlib import suppress
|
|
348
|
+
|
|
349
|
+
current_dir = Path.cwd()
|
|
350
|
+
|
|
351
|
+
# Try to read package name from pyproject.toml
|
|
352
|
+
pyproject_path = current_dir / "pyproject.toml"
|
|
353
|
+
if pyproject_path.exists():
|
|
354
|
+
with suppress(Exception):
|
|
355
|
+
import tomllib
|
|
356
|
+
|
|
357
|
+
with pyproject_path.open("rb") as f:
|
|
358
|
+
data = tomllib.load(f)
|
|
359
|
+
|
|
360
|
+
if "project" in data and "name" in data["project"]:
|
|
361
|
+
# Convert package name to directory name (replace - with _)
|
|
362
|
+
package_name = str(data["project"]["name"]).replace("-", "_")
|
|
363
|
+
|
|
364
|
+
# Verify directory exists
|
|
365
|
+
if (current_dir / package_name).exists():
|
|
366
|
+
return package_name
|
|
367
|
+
|
|
368
|
+
# Fallback to directory name if package dir exists
|
|
369
|
+
if (current_dir / current_dir.name).exists():
|
|
370
|
+
return current_dir.name
|
|
371
|
+
|
|
372
|
+
# Default fallback
|
|
373
|
+
return "src"
|
|
374
|
+
|
|
375
|
+
def get_default_config(self) -> QACheckConfig:
|
|
376
|
+
"""Get default configuration for Bandit adapter.
|
|
377
|
+
|
|
378
|
+
Returns:
|
|
379
|
+
QACheckConfig with sensible defaults
|
|
380
|
+
"""
|
|
381
|
+
from crackerjack.models.qa_config import QACheckConfig
|
|
382
|
+
|
|
383
|
+
# Dynamically detect package directory
|
|
384
|
+
package_dir = self._detect_package_directory()
|
|
385
|
+
|
|
386
|
+
return QACheckConfig(
|
|
387
|
+
check_id=MODULE_ID,
|
|
388
|
+
check_name=self.adapter_name,
|
|
389
|
+
check_type=QACheckType.SAST,
|
|
390
|
+
enabled=True,
|
|
391
|
+
file_patterns=[
|
|
392
|
+
f"{package_dir}/**/*.py"
|
|
393
|
+
], # Dynamically detected package directory
|
|
394
|
+
exclude_patterns=[
|
|
395
|
+
"**/test_*.py",
|
|
396
|
+
"**/tests/**",
|
|
397
|
+
"**/.venv/**",
|
|
398
|
+
"**/venv/**",
|
|
399
|
+
"**/build/**",
|
|
400
|
+
"**/dist/**",
|
|
401
|
+
"**/__pycache__/**",
|
|
402
|
+
"**/.git/**",
|
|
403
|
+
"**/node_modules/**",
|
|
404
|
+
"**/.tox/**",
|
|
405
|
+
"**/.pytest_cache/**",
|
|
406
|
+
"**/htmlcov/**",
|
|
407
|
+
"**/.coverage*",
|
|
408
|
+
],
|
|
409
|
+
timeout_seconds=1200, # Match the timeout in BanditSettings
|
|
410
|
+
parallel_safe=True,
|
|
411
|
+
stage="comprehensive", # Security checks in comprehensive stage
|
|
412
|
+
settings={
|
|
413
|
+
"severity_level": "low", # Will be overridden in command builder anyway
|
|
414
|
+
"confidence_level": "low", # Will be overridden in command builder anyway
|
|
415
|
+
"exclude_tests": True,
|
|
416
|
+
"skip_rules": [], # Handled in command builder with more aggressive set
|
|
417
|
+
},
|
|
418
|
+
)
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
# ACB Registration (REQUIRED at module level)
|
|
422
|
+
with suppress(Exception):
|
|
423
|
+
depends.set(BanditAdapter)
|