attune-ai 2.0.0__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.
- attune/__init__.py +358 -0
- attune/adaptive/__init__.py +13 -0
- attune/adaptive/task_complexity.py +127 -0
- attune/agent_monitoring.py +414 -0
- attune/cache/__init__.py +117 -0
- attune/cache/base.py +166 -0
- attune/cache/dependency_manager.py +256 -0
- attune/cache/hash_only.py +251 -0
- attune/cache/hybrid.py +457 -0
- attune/cache/storage.py +285 -0
- attune/cache_monitor.py +356 -0
- attune/cache_stats.py +298 -0
- attune/cli/__init__.py +152 -0
- attune/cli/__main__.py +12 -0
- attune/cli/commands/__init__.py +1 -0
- attune/cli/commands/batch.py +264 -0
- attune/cli/commands/cache.py +248 -0
- attune/cli/commands/help.py +331 -0
- attune/cli/commands/info.py +140 -0
- attune/cli/commands/inspect.py +436 -0
- attune/cli/commands/inspection.py +57 -0
- attune/cli/commands/memory.py +48 -0
- attune/cli/commands/metrics.py +92 -0
- attune/cli/commands/orchestrate.py +184 -0
- attune/cli/commands/patterns.py +207 -0
- attune/cli/commands/profiling.py +202 -0
- attune/cli/commands/provider.py +98 -0
- attune/cli/commands/routing.py +285 -0
- attune/cli/commands/setup.py +96 -0
- attune/cli/commands/status.py +235 -0
- attune/cli/commands/sync.py +166 -0
- attune/cli/commands/tier.py +121 -0
- attune/cli/commands/utilities.py +114 -0
- attune/cli/commands/workflow.py +579 -0
- attune/cli/core.py +32 -0
- attune/cli/parsers/__init__.py +68 -0
- attune/cli/parsers/batch.py +118 -0
- attune/cli/parsers/cache.py +65 -0
- attune/cli/parsers/help.py +41 -0
- attune/cli/parsers/info.py +26 -0
- attune/cli/parsers/inspect.py +66 -0
- attune/cli/parsers/metrics.py +42 -0
- attune/cli/parsers/orchestrate.py +61 -0
- attune/cli/parsers/patterns.py +54 -0
- attune/cli/parsers/provider.py +40 -0
- attune/cli/parsers/routing.py +110 -0
- attune/cli/parsers/setup.py +42 -0
- attune/cli/parsers/status.py +47 -0
- attune/cli/parsers/sync.py +31 -0
- attune/cli/parsers/tier.py +33 -0
- attune/cli/parsers/workflow.py +77 -0
- attune/cli/utils/__init__.py +1 -0
- attune/cli/utils/data.py +242 -0
- attune/cli/utils/helpers.py +68 -0
- attune/cli_legacy.py +3957 -0
- attune/cli_minimal.py +1159 -0
- attune/cli_router.py +437 -0
- attune/cli_unified.py +814 -0
- attune/config/__init__.py +66 -0
- attune/config/xml_config.py +286 -0
- attune/config.py +545 -0
- attune/coordination.py +870 -0
- attune/core.py +1511 -0
- attune/core_modules/__init__.py +15 -0
- attune/cost_tracker.py +626 -0
- attune/dashboard/__init__.py +41 -0
- attune/dashboard/app.py +512 -0
- attune/dashboard/simple_server.py +435 -0
- attune/dashboard/standalone_server.py +547 -0
- attune/discovery.py +306 -0
- attune/emergence.py +306 -0
- attune/exceptions.py +123 -0
- attune/feedback_loops.py +373 -0
- attune/hot_reload/README.md +473 -0
- attune/hot_reload/__init__.py +62 -0
- attune/hot_reload/config.py +83 -0
- attune/hot_reload/integration.py +229 -0
- attune/hot_reload/reloader.py +298 -0
- attune/hot_reload/watcher.py +183 -0
- attune/hot_reload/websocket.py +177 -0
- attune/levels.py +577 -0
- attune/leverage_points.py +441 -0
- attune/logging_config.py +261 -0
- attune/mcp/__init__.py +10 -0
- attune/mcp/server.py +506 -0
- attune/memory/__init__.py +237 -0
- attune/memory/claude_memory.py +469 -0
- attune/memory/config.py +224 -0
- attune/memory/control_panel.py +1290 -0
- attune/memory/control_panel_support.py +145 -0
- attune/memory/cross_session.py +845 -0
- attune/memory/edges.py +179 -0
- attune/memory/encryption.py +159 -0
- attune/memory/file_session.py +770 -0
- attune/memory/graph.py +570 -0
- attune/memory/long_term.py +913 -0
- attune/memory/long_term_types.py +99 -0
- attune/memory/mixins/__init__.py +25 -0
- attune/memory/mixins/backend_init_mixin.py +249 -0
- attune/memory/mixins/capabilities_mixin.py +208 -0
- attune/memory/mixins/handoff_mixin.py +208 -0
- attune/memory/mixins/lifecycle_mixin.py +49 -0
- attune/memory/mixins/long_term_mixin.py +352 -0
- attune/memory/mixins/promotion_mixin.py +109 -0
- attune/memory/mixins/short_term_mixin.py +182 -0
- attune/memory/nodes.py +179 -0
- attune/memory/redis_bootstrap.py +540 -0
- attune/memory/security/__init__.py +31 -0
- attune/memory/security/audit_logger.py +932 -0
- attune/memory/security/pii_scrubber.py +640 -0
- attune/memory/security/secrets_detector.py +678 -0
- attune/memory/short_term.py +2192 -0
- attune/memory/simple_storage.py +302 -0
- attune/memory/storage/__init__.py +15 -0
- attune/memory/storage_backend.py +167 -0
- attune/memory/summary_index.py +583 -0
- attune/memory/types.py +446 -0
- attune/memory/unified.py +182 -0
- attune/meta_workflows/__init__.py +74 -0
- attune/meta_workflows/agent_creator.py +248 -0
- attune/meta_workflows/builtin_templates.py +567 -0
- attune/meta_workflows/cli_commands/__init__.py +56 -0
- attune/meta_workflows/cli_commands/agent_commands.py +321 -0
- attune/meta_workflows/cli_commands/analytics_commands.py +442 -0
- attune/meta_workflows/cli_commands/config_commands.py +232 -0
- attune/meta_workflows/cli_commands/memory_commands.py +182 -0
- attune/meta_workflows/cli_commands/template_commands.py +354 -0
- attune/meta_workflows/cli_commands/workflow_commands.py +382 -0
- attune/meta_workflows/cli_meta_workflows.py +59 -0
- attune/meta_workflows/form_engine.py +292 -0
- attune/meta_workflows/intent_detector.py +409 -0
- attune/meta_workflows/models.py +569 -0
- attune/meta_workflows/pattern_learner.py +738 -0
- attune/meta_workflows/plan_generator.py +384 -0
- attune/meta_workflows/session_context.py +397 -0
- attune/meta_workflows/template_registry.py +229 -0
- attune/meta_workflows/workflow.py +984 -0
- attune/metrics/__init__.py +12 -0
- attune/metrics/collector.py +31 -0
- attune/metrics/prompt_metrics.py +194 -0
- attune/models/__init__.py +172 -0
- attune/models/__main__.py +13 -0
- attune/models/adaptive_routing.py +437 -0
- attune/models/auth_cli.py +444 -0
- attune/models/auth_strategy.py +450 -0
- attune/models/cli.py +655 -0
- attune/models/empathy_executor.py +354 -0
- attune/models/executor.py +257 -0
- attune/models/fallback.py +762 -0
- attune/models/provider_config.py +282 -0
- attune/models/registry.py +472 -0
- attune/models/tasks.py +359 -0
- attune/models/telemetry/__init__.py +71 -0
- attune/models/telemetry/analytics.py +594 -0
- attune/models/telemetry/backend.py +196 -0
- attune/models/telemetry/data_models.py +431 -0
- attune/models/telemetry/storage.py +489 -0
- attune/models/token_estimator.py +420 -0
- attune/models/validation.py +280 -0
- attune/monitoring/__init__.py +52 -0
- attune/monitoring/alerts.py +946 -0
- attune/monitoring/alerts_cli.py +448 -0
- attune/monitoring/multi_backend.py +271 -0
- attune/monitoring/otel_backend.py +362 -0
- attune/optimization/__init__.py +19 -0
- attune/optimization/context_optimizer.py +272 -0
- attune/orchestration/__init__.py +67 -0
- attune/orchestration/agent_templates.py +707 -0
- attune/orchestration/config_store.py +499 -0
- attune/orchestration/execution_strategies.py +2111 -0
- attune/orchestration/meta_orchestrator.py +1168 -0
- attune/orchestration/pattern_learner.py +696 -0
- attune/orchestration/real_tools.py +931 -0
- attune/pattern_cache.py +187 -0
- attune/pattern_library.py +542 -0
- attune/patterns/debugging/all_patterns.json +81 -0
- attune/patterns/debugging/workflow_20260107_1770825e.json +77 -0
- attune/patterns/refactoring_memory.json +89 -0
- attune/persistence.py +564 -0
- attune/platform_utils.py +265 -0
- attune/plugins/__init__.py +28 -0
- attune/plugins/base.py +361 -0
- attune/plugins/registry.py +268 -0
- attune/project_index/__init__.py +32 -0
- attune/project_index/cli.py +335 -0
- attune/project_index/index.py +667 -0
- attune/project_index/models.py +504 -0
- attune/project_index/reports.py +474 -0
- attune/project_index/scanner.py +777 -0
- attune/project_index/scanner_parallel.py +291 -0
- attune/prompts/__init__.py +61 -0
- attune/prompts/config.py +77 -0
- attune/prompts/context.py +177 -0
- attune/prompts/parser.py +285 -0
- attune/prompts/registry.py +313 -0
- attune/prompts/templates.py +208 -0
- attune/redis_config.py +302 -0
- attune/redis_memory.py +799 -0
- attune/resilience/__init__.py +56 -0
- attune/resilience/circuit_breaker.py +256 -0
- attune/resilience/fallback.py +179 -0
- attune/resilience/health.py +300 -0
- attune/resilience/retry.py +209 -0
- attune/resilience/timeout.py +135 -0
- attune/routing/__init__.py +43 -0
- attune/routing/chain_executor.py +433 -0
- attune/routing/classifier.py +217 -0
- attune/routing/smart_router.py +234 -0
- attune/routing/workflow_registry.py +343 -0
- attune/scaffolding/README.md +589 -0
- attune/scaffolding/__init__.py +35 -0
- attune/scaffolding/__main__.py +14 -0
- attune/scaffolding/cli.py +240 -0
- attune/scaffolding/templates/base_wizard.py.jinja2 +121 -0
- attune/scaffolding/templates/coach_wizard.py.jinja2 +321 -0
- attune/scaffolding/templates/domain_wizard.py.jinja2 +408 -0
- attune/scaffolding/templates/linear_flow_wizard.py.jinja2 +203 -0
- attune/socratic/__init__.py +256 -0
- attune/socratic/ab_testing.py +958 -0
- attune/socratic/blueprint.py +533 -0
- attune/socratic/cli.py +703 -0
- attune/socratic/collaboration.py +1114 -0
- attune/socratic/domain_templates.py +924 -0
- attune/socratic/embeddings.py +738 -0
- attune/socratic/engine.py +794 -0
- attune/socratic/explainer.py +682 -0
- attune/socratic/feedback.py +772 -0
- attune/socratic/forms.py +629 -0
- attune/socratic/generator.py +732 -0
- attune/socratic/llm_analyzer.py +637 -0
- attune/socratic/mcp_server.py +702 -0
- attune/socratic/session.py +312 -0
- attune/socratic/storage.py +667 -0
- attune/socratic/success.py +730 -0
- attune/socratic/visual_editor.py +860 -0
- attune/socratic/web_ui.py +958 -0
- attune/telemetry/__init__.py +39 -0
- attune/telemetry/agent_coordination.py +475 -0
- attune/telemetry/agent_tracking.py +367 -0
- attune/telemetry/approval_gates.py +545 -0
- attune/telemetry/cli.py +1231 -0
- attune/telemetry/commands/__init__.py +14 -0
- attune/telemetry/commands/dashboard_commands.py +696 -0
- attune/telemetry/event_streaming.py +409 -0
- attune/telemetry/feedback_loop.py +567 -0
- attune/telemetry/usage_tracker.py +591 -0
- attune/templates.py +754 -0
- attune/test_generator/__init__.py +38 -0
- attune/test_generator/__main__.py +14 -0
- attune/test_generator/cli.py +234 -0
- attune/test_generator/generator.py +355 -0
- attune/test_generator/risk_analyzer.py +216 -0
- attune/test_generator/templates/unit_test.py.jinja2 +272 -0
- attune/tier_recommender.py +384 -0
- attune/tools.py +183 -0
- attune/trust/__init__.py +28 -0
- attune/trust/circuit_breaker.py +579 -0
- attune/trust_building.py +527 -0
- attune/validation/__init__.py +19 -0
- attune/validation/xml_validator.py +281 -0
- attune/vscode_bridge.py +173 -0
- attune/workflow_commands.py +780 -0
- attune/workflow_patterns/__init__.py +33 -0
- attune/workflow_patterns/behavior.py +249 -0
- attune/workflow_patterns/core.py +76 -0
- attune/workflow_patterns/output.py +99 -0
- attune/workflow_patterns/registry.py +255 -0
- attune/workflow_patterns/structural.py +288 -0
- attune/workflows/__init__.py +539 -0
- attune/workflows/autonomous_test_gen.py +1268 -0
- attune/workflows/base.py +2667 -0
- attune/workflows/batch_processing.py +342 -0
- attune/workflows/bug_predict.py +1084 -0
- attune/workflows/builder.py +273 -0
- attune/workflows/caching.py +253 -0
- attune/workflows/code_review.py +1048 -0
- attune/workflows/code_review_adapters.py +312 -0
- attune/workflows/code_review_pipeline.py +722 -0
- attune/workflows/config.py +645 -0
- attune/workflows/dependency_check.py +644 -0
- attune/workflows/document_gen/__init__.py +25 -0
- attune/workflows/document_gen/config.py +30 -0
- attune/workflows/document_gen/report_formatter.py +162 -0
- attune/workflows/document_gen/workflow.py +1426 -0
- attune/workflows/document_manager.py +216 -0
- attune/workflows/document_manager_README.md +134 -0
- attune/workflows/documentation_orchestrator.py +1205 -0
- attune/workflows/history.py +510 -0
- attune/workflows/keyboard_shortcuts/__init__.py +39 -0
- attune/workflows/keyboard_shortcuts/generators.py +391 -0
- attune/workflows/keyboard_shortcuts/parsers.py +416 -0
- attune/workflows/keyboard_shortcuts/prompts.py +295 -0
- attune/workflows/keyboard_shortcuts/schema.py +193 -0
- attune/workflows/keyboard_shortcuts/workflow.py +509 -0
- attune/workflows/llm_base.py +363 -0
- attune/workflows/manage_docs.py +87 -0
- attune/workflows/manage_docs_README.md +134 -0
- attune/workflows/manage_documentation.py +821 -0
- attune/workflows/new_sample_workflow1.py +149 -0
- attune/workflows/new_sample_workflow1_README.md +150 -0
- attune/workflows/orchestrated_health_check.py +849 -0
- attune/workflows/orchestrated_release_prep.py +600 -0
- attune/workflows/output.py +413 -0
- attune/workflows/perf_audit.py +863 -0
- attune/workflows/pr_review.py +762 -0
- attune/workflows/progress.py +785 -0
- attune/workflows/progress_server.py +322 -0
- attune/workflows/progressive/README 2.md +454 -0
- attune/workflows/progressive/README.md +454 -0
- attune/workflows/progressive/__init__.py +82 -0
- attune/workflows/progressive/cli.py +219 -0
- attune/workflows/progressive/core.py +488 -0
- attune/workflows/progressive/orchestrator.py +723 -0
- attune/workflows/progressive/reports.py +520 -0
- attune/workflows/progressive/telemetry.py +274 -0
- attune/workflows/progressive/test_gen.py +495 -0
- attune/workflows/progressive/workflow.py +589 -0
- attune/workflows/refactor_plan.py +694 -0
- attune/workflows/release_prep.py +895 -0
- attune/workflows/release_prep_crew.py +969 -0
- attune/workflows/research_synthesis.py +404 -0
- attune/workflows/routing.py +168 -0
- attune/workflows/secure_release.py +593 -0
- attune/workflows/security_adapters.py +297 -0
- attune/workflows/security_audit.py +1329 -0
- attune/workflows/security_audit_phase3.py +355 -0
- attune/workflows/seo_optimization.py +633 -0
- attune/workflows/step_config.py +234 -0
- attune/workflows/telemetry_mixin.py +269 -0
- attune/workflows/test5.py +125 -0
- attune/workflows/test5_README.md +158 -0
- attune/workflows/test_coverage_boost_crew.py +849 -0
- attune/workflows/test_gen/__init__.py +52 -0
- attune/workflows/test_gen/ast_analyzer.py +249 -0
- attune/workflows/test_gen/config.py +88 -0
- attune/workflows/test_gen/data_models.py +38 -0
- attune/workflows/test_gen/report_formatter.py +289 -0
- attune/workflows/test_gen/test_templates.py +381 -0
- attune/workflows/test_gen/workflow.py +655 -0
- attune/workflows/test_gen.py +54 -0
- attune/workflows/test_gen_behavioral.py +477 -0
- attune/workflows/test_gen_parallel.py +341 -0
- attune/workflows/test_lifecycle.py +526 -0
- attune/workflows/test_maintenance.py +627 -0
- attune/workflows/test_maintenance_cli.py +590 -0
- attune/workflows/test_maintenance_crew.py +840 -0
- attune/workflows/test_runner.py +622 -0
- attune/workflows/tier_tracking.py +531 -0
- attune/workflows/xml_enhanced_crew.py +285 -0
- attune_ai-2.0.0.dist-info/METADATA +1026 -0
- attune_ai-2.0.0.dist-info/RECORD +457 -0
- attune_ai-2.0.0.dist-info/WHEEL +5 -0
- attune_ai-2.0.0.dist-info/entry_points.txt +26 -0
- attune_ai-2.0.0.dist-info/licenses/LICENSE +201 -0
- attune_ai-2.0.0.dist-info/licenses/LICENSE_CHANGE_ANNOUNCEMENT.md +101 -0
- attune_ai-2.0.0.dist-info/top_level.txt +5 -0
- attune_healthcare/__init__.py +13 -0
- attune_healthcare/monitors/__init__.py +9 -0
- attune_healthcare/monitors/clinical_protocol_monitor.py +315 -0
- attune_healthcare/monitors/monitoring/__init__.py +44 -0
- attune_healthcare/monitors/monitoring/protocol_checker.py +300 -0
- attune_healthcare/monitors/monitoring/protocol_loader.py +214 -0
- attune_healthcare/monitors/monitoring/sensor_parsers.py +306 -0
- attune_healthcare/monitors/monitoring/trajectory_analyzer.py +389 -0
- attune_llm/README.md +553 -0
- attune_llm/__init__.py +28 -0
- attune_llm/agent_factory/__init__.py +53 -0
- attune_llm/agent_factory/adapters/__init__.py +85 -0
- attune_llm/agent_factory/adapters/autogen_adapter.py +312 -0
- attune_llm/agent_factory/adapters/crewai_adapter.py +483 -0
- attune_llm/agent_factory/adapters/haystack_adapter.py +298 -0
- attune_llm/agent_factory/adapters/langchain_adapter.py +362 -0
- attune_llm/agent_factory/adapters/langgraph_adapter.py +333 -0
- attune_llm/agent_factory/adapters/native.py +228 -0
- attune_llm/agent_factory/adapters/wizard_adapter.py +423 -0
- attune_llm/agent_factory/base.py +305 -0
- attune_llm/agent_factory/crews/__init__.py +67 -0
- attune_llm/agent_factory/crews/code_review.py +1113 -0
- attune_llm/agent_factory/crews/health_check.py +1262 -0
- attune_llm/agent_factory/crews/refactoring.py +1128 -0
- attune_llm/agent_factory/crews/security_audit.py +1018 -0
- attune_llm/agent_factory/decorators.py +287 -0
- attune_llm/agent_factory/factory.py +558 -0
- attune_llm/agent_factory/framework.py +193 -0
- attune_llm/agent_factory/memory_integration.py +328 -0
- attune_llm/agent_factory/resilient.py +320 -0
- attune_llm/agents_md/__init__.py +22 -0
- attune_llm/agents_md/loader.py +218 -0
- attune_llm/agents_md/parser.py +271 -0
- attune_llm/agents_md/registry.py +307 -0
- attune_llm/claude_memory.py +466 -0
- attune_llm/cli/__init__.py +8 -0
- attune_llm/cli/sync_claude.py +487 -0
- attune_llm/code_health.py +1313 -0
- attune_llm/commands/__init__.py +51 -0
- attune_llm/commands/context.py +375 -0
- attune_llm/commands/loader.py +301 -0
- attune_llm/commands/models.py +231 -0
- attune_llm/commands/parser.py +371 -0
- attune_llm/commands/registry.py +429 -0
- attune_llm/config/__init__.py +29 -0
- attune_llm/config/unified.py +291 -0
- attune_llm/context/__init__.py +22 -0
- attune_llm/context/compaction.py +455 -0
- attune_llm/context/manager.py +434 -0
- attune_llm/contextual_patterns.py +361 -0
- attune_llm/core.py +907 -0
- attune_llm/git_pattern_extractor.py +435 -0
- attune_llm/hooks/__init__.py +24 -0
- attune_llm/hooks/config.py +306 -0
- attune_llm/hooks/executor.py +289 -0
- attune_llm/hooks/registry.py +302 -0
- attune_llm/hooks/scripts/__init__.py +39 -0
- attune_llm/hooks/scripts/evaluate_session.py +201 -0
- attune_llm/hooks/scripts/first_time_init.py +285 -0
- attune_llm/hooks/scripts/pre_compact.py +207 -0
- attune_llm/hooks/scripts/session_end.py +183 -0
- attune_llm/hooks/scripts/session_start.py +163 -0
- attune_llm/hooks/scripts/suggest_compact.py +225 -0
- attune_llm/learning/__init__.py +30 -0
- attune_llm/learning/evaluator.py +438 -0
- attune_llm/learning/extractor.py +514 -0
- attune_llm/learning/storage.py +560 -0
- attune_llm/levels.py +227 -0
- attune_llm/pattern_confidence.py +414 -0
- attune_llm/pattern_resolver.py +272 -0
- attune_llm/pattern_summary.py +350 -0
- attune_llm/providers.py +967 -0
- attune_llm/routing/__init__.py +32 -0
- attune_llm/routing/model_router.py +362 -0
- attune_llm/security/IMPLEMENTATION_SUMMARY.md +413 -0
- attune_llm/security/PHASE2_COMPLETE.md +384 -0
- attune_llm/security/PHASE2_SECRETS_DETECTOR_COMPLETE.md +271 -0
- attune_llm/security/QUICK_REFERENCE.md +316 -0
- attune_llm/security/README.md +262 -0
- attune_llm/security/__init__.py +62 -0
- attune_llm/security/audit_logger.py +929 -0
- attune_llm/security/audit_logger_example.py +152 -0
- attune_llm/security/pii_scrubber.py +640 -0
- attune_llm/security/secrets_detector.py +678 -0
- attune_llm/security/secrets_detector_example.py +304 -0
- attune_llm/security/secure_memdocs.py +1192 -0
- attune_llm/security/secure_memdocs_example.py +278 -0
- attune_llm/session_status.py +745 -0
- attune_llm/state.py +246 -0
- attune_llm/utils/__init__.py +5 -0
- attune_llm/utils/tokens.py +349 -0
- attune_software/SOFTWARE_PLUGIN_README.md +57 -0
- attune_software/__init__.py +13 -0
- attune_software/cli/__init__.py +120 -0
- attune_software/cli/inspect.py +362 -0
- attune_software/cli.py +574 -0
- attune_software/plugin.py +188 -0
- workflow_scaffolding/__init__.py +11 -0
- workflow_scaffolding/__main__.py +12 -0
- workflow_scaffolding/cli.py +206 -0
- workflow_scaffolding/generator.py +265 -0
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
"""Security Adapters for SecurityAuditCrew Integration
|
|
2
|
+
|
|
3
|
+
Provides format conversion functions between SecurityAuditCrew output
|
|
4
|
+
and workflow dict formats used by existing workflows.
|
|
5
|
+
|
|
6
|
+
Copyright 2025 Smart-AI-Memory
|
|
7
|
+
Licensed under Fair Source License 0.9
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import asyncio
|
|
11
|
+
import logging
|
|
12
|
+
from typing import TYPE_CHECKING
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from attune_llm.agent_factory.crews import SecurityReport
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _check_crew_available() -> bool:
|
|
21
|
+
"""Check if SecurityAuditCrew is available.
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
True if the crew module can be imported, False otherwise.
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
try:
|
|
28
|
+
from attune_llm.agent_factory.crews import SecurityAuditCrew # noqa: F401
|
|
29
|
+
|
|
30
|
+
return True
|
|
31
|
+
except ImportError:
|
|
32
|
+
return False
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
async def _get_crew_audit(
|
|
36
|
+
target: str,
|
|
37
|
+
config: dict | None = None,
|
|
38
|
+
timeout: float = 300.0,
|
|
39
|
+
) -> "SecurityReport | None":
|
|
40
|
+
"""Get SecurityAuditCrew audit results with graceful fallback.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
target: Path to codebase to audit
|
|
44
|
+
config: Optional SecurityAuditConfig parameters as dict
|
|
45
|
+
timeout: Maximum time to wait for audit (default 5 minutes)
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
SecurityReport if successful, None if crew unavailable or audit failed.
|
|
49
|
+
|
|
50
|
+
"""
|
|
51
|
+
if not _check_crew_available():
|
|
52
|
+
logger.debug("SecurityAuditCrew not available, returning None")
|
|
53
|
+
return None
|
|
54
|
+
|
|
55
|
+
try:
|
|
56
|
+
from attune_llm.agent_factory.crews import SecurityAuditConfig, SecurityAuditCrew
|
|
57
|
+
|
|
58
|
+
# Build config from dict
|
|
59
|
+
crew_config = SecurityAuditConfig(**(config or {}))
|
|
60
|
+
crew = SecurityAuditCrew(config=crew_config)
|
|
61
|
+
|
|
62
|
+
# Run with timeout
|
|
63
|
+
report = await asyncio.wait_for(crew.audit(target), timeout=timeout)
|
|
64
|
+
return report
|
|
65
|
+
|
|
66
|
+
except asyncio.TimeoutError:
|
|
67
|
+
logger.warning(f"SecurityAuditCrew audit timed out after {timeout}s")
|
|
68
|
+
return None
|
|
69
|
+
except Exception as e:
|
|
70
|
+
logger.warning(f"SecurityAuditCrew audit failed: {e}")
|
|
71
|
+
return None
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def crew_report_to_workflow_format(report: "SecurityReport") -> dict:
|
|
75
|
+
"""Convert SecurityReport to workflow dict format.
|
|
76
|
+
|
|
77
|
+
This converts the crew's structured output to the format expected
|
|
78
|
+
by existing workflows (matching SecurityAuditWorkflow output).
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
report: SecurityReport from SecurityAuditCrew
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
Dict in workflow format with findings, assessment, etc.
|
|
85
|
+
|
|
86
|
+
"""
|
|
87
|
+
findings: list[dict] = []
|
|
88
|
+
for finding in report.findings:
|
|
89
|
+
finding_dict = {
|
|
90
|
+
"type": finding.category.value if finding.category else "other",
|
|
91
|
+
"title": finding.title,
|
|
92
|
+
"description": finding.description,
|
|
93
|
+
"severity": finding.severity.value if finding.severity else "medium",
|
|
94
|
+
"file": finding.file_path,
|
|
95
|
+
"line": finding.line_number,
|
|
96
|
+
"match": finding.code_snippet[:100] if finding.code_snippet else None,
|
|
97
|
+
"remediation": finding.remediation,
|
|
98
|
+
"cwe_id": finding.cwe_id,
|
|
99
|
+
"cvss_score": finding.cvss_score,
|
|
100
|
+
"confidence": finding.confidence,
|
|
101
|
+
"owasp": _map_category_to_owasp(finding.category.value) if finding.category else None,
|
|
102
|
+
}
|
|
103
|
+
findings.append(finding_dict)
|
|
104
|
+
|
|
105
|
+
# Build severity breakdown
|
|
106
|
+
severity_counts = {
|
|
107
|
+
"critical": len([f for f in report.findings if f.severity.value == "critical"]),
|
|
108
|
+
"high": len([f for f in report.findings if f.severity.value == "high"]),
|
|
109
|
+
"medium": len([f for f in report.findings if f.severity.value == "medium"]),
|
|
110
|
+
"low": len([f for f in report.findings if f.severity.value == "low"]),
|
|
111
|
+
"info": len([f for f in report.findings if f.severity.value == "info"]),
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
# Build OWASP category breakdown
|
|
115
|
+
by_owasp: dict[str, int] = {}
|
|
116
|
+
for f_dict in findings:
|
|
117
|
+
owasp = f_dict.get("owasp", "Other")
|
|
118
|
+
by_owasp[owasp] = by_owasp.get(owasp, 0) + 1
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
"crew_enabled": True,
|
|
122
|
+
"findings": findings,
|
|
123
|
+
"finding_count": len(findings),
|
|
124
|
+
"risk_score": report.risk_score,
|
|
125
|
+
"risk_level": _score_to_level(report.risk_score),
|
|
126
|
+
"summary": report.summary,
|
|
127
|
+
"assessment": {
|
|
128
|
+
"risk_score": report.risk_score,
|
|
129
|
+
"risk_level": _score_to_level(report.risk_score),
|
|
130
|
+
"severity_breakdown": severity_counts,
|
|
131
|
+
"by_owasp_category": by_owasp,
|
|
132
|
+
"critical_findings": [f for f in findings if f["severity"] == "critical"],
|
|
133
|
+
"high_findings": [f for f in findings if f["severity"] == "high"],
|
|
134
|
+
},
|
|
135
|
+
"agents_used": report.agents_used,
|
|
136
|
+
"memory_graph_hits": report.memory_graph_hits,
|
|
137
|
+
"audit_duration_seconds": report.audit_duration_seconds,
|
|
138
|
+
"metadata": report.metadata,
|
|
139
|
+
# Pass through cost if tracked by crew (future enhancement)
|
|
140
|
+
"cost": report.metadata.get("cost", 0.0),
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def workflow_findings_to_crew_format(findings: list[dict]) -> list[dict]:
|
|
145
|
+
"""Convert workflow findings to SecurityFinding-compatible dicts.
|
|
146
|
+
|
|
147
|
+
This is useful when passing workflow findings to SecurityAuditCrew
|
|
148
|
+
for enhanced analysis.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
findings: List of finding dicts from workflow
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
List of dicts that can be used with SecurityAuditCrew context.
|
|
155
|
+
|
|
156
|
+
"""
|
|
157
|
+
crew_findings = []
|
|
158
|
+
for finding in findings:
|
|
159
|
+
crew_finding = {
|
|
160
|
+
"title": finding.get("title", finding.get("type", "Unknown")),
|
|
161
|
+
"description": finding.get("description", finding.get("match", "")),
|
|
162
|
+
"severity": finding.get("severity", "medium"),
|
|
163
|
+
"category": _map_type_to_category(finding.get("type", "other")),
|
|
164
|
+
"file_path": finding.get("file"),
|
|
165
|
+
"line_number": finding.get("line"),
|
|
166
|
+
"code_snippet": finding.get("match"),
|
|
167
|
+
"cwe_id": finding.get("cwe_id"),
|
|
168
|
+
"confidence": finding.get("confidence", 1.0),
|
|
169
|
+
}
|
|
170
|
+
crew_findings.append(crew_finding)
|
|
171
|
+
return crew_findings
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def merge_security_results(
|
|
175
|
+
crew_report: dict | None,
|
|
176
|
+
workflow_findings: dict | None,
|
|
177
|
+
) -> dict:
|
|
178
|
+
"""Merge SecurityAuditCrew and workflow security results.
|
|
179
|
+
|
|
180
|
+
Combines findings from both sources, deduplicating where possible,
|
|
181
|
+
and provides a unified assessment.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
crew_report: Crew results in workflow format (from crew_report_to_workflow_format)
|
|
185
|
+
workflow_findings: Workflow security results
|
|
186
|
+
|
|
187
|
+
Returns:
|
|
188
|
+
Merged dict with combined findings and assessment.
|
|
189
|
+
|
|
190
|
+
"""
|
|
191
|
+
# Handle None cases
|
|
192
|
+
if crew_report is None and workflow_findings is None:
|
|
193
|
+
return {"findings": [], "risk_score": 0, "merged": False}
|
|
194
|
+
|
|
195
|
+
if crew_report is None and workflow_findings is not None:
|
|
196
|
+
return {**workflow_findings, "merged": False, "crew_enabled": False}
|
|
197
|
+
|
|
198
|
+
if workflow_findings is None and crew_report is not None:
|
|
199
|
+
return {**crew_report, "merged": False}
|
|
200
|
+
|
|
201
|
+
# At this point, both should be non-None
|
|
202
|
+
assert crew_report is not None
|
|
203
|
+
assert workflow_findings is not None
|
|
204
|
+
|
|
205
|
+
# Merge findings (prefer crew findings for duplicates)
|
|
206
|
+
crew_findings = crew_report.get("findings", [])
|
|
207
|
+
wf_findings = workflow_findings.get("findings", [])
|
|
208
|
+
|
|
209
|
+
# Build set of crew finding keys for deduplication
|
|
210
|
+
crew_keys = set()
|
|
211
|
+
for f in crew_findings:
|
|
212
|
+
key = (f.get("file"), f.get("line"), f.get("type"))
|
|
213
|
+
crew_keys.add(key)
|
|
214
|
+
|
|
215
|
+
# Add non-duplicate workflow findings
|
|
216
|
+
merged_findings = list(crew_findings)
|
|
217
|
+
for f in wf_findings:
|
|
218
|
+
key = (f.get("file"), f.get("line"), f.get("type"))
|
|
219
|
+
if key not in crew_keys:
|
|
220
|
+
merged_findings.append(f)
|
|
221
|
+
|
|
222
|
+
# Calculate merged risk score (weighted average)
|
|
223
|
+
crew_score = crew_report.get("risk_score", 0)
|
|
224
|
+
wf_score = workflow_findings.get("assessment", {}).get("risk_score", 0)
|
|
225
|
+
# Give crew score higher weight (more comprehensive)
|
|
226
|
+
merged_score = (crew_score * 0.7 + wf_score * 0.3) if wf_score else crew_score
|
|
227
|
+
|
|
228
|
+
# Merge severity counts
|
|
229
|
+
crew_severity = crew_report.get("assessment", {}).get("severity_breakdown", {})
|
|
230
|
+
wf_severity = workflow_findings.get("assessment", {}).get("severity_breakdown", {})
|
|
231
|
+
merged_severity = {
|
|
232
|
+
"critical": max(crew_severity.get("critical", 0), wf_severity.get("critical", 0)),
|
|
233
|
+
"high": max(crew_severity.get("high", 0), wf_severity.get("high", 0)),
|
|
234
|
+
"medium": max(crew_severity.get("medium", 0), wf_severity.get("medium", 0)),
|
|
235
|
+
"low": max(crew_severity.get("low", 0), wf_severity.get("low", 0)),
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return {
|
|
239
|
+
"merged": True,
|
|
240
|
+
"crew_enabled": True,
|
|
241
|
+
"findings": merged_findings,
|
|
242
|
+
"finding_count": len(merged_findings),
|
|
243
|
+
"risk_score": merged_score,
|
|
244
|
+
"risk_level": _score_to_level(merged_score),
|
|
245
|
+
"assessment": {
|
|
246
|
+
"risk_score": merged_score,
|
|
247
|
+
"risk_level": _score_to_level(merged_score),
|
|
248
|
+
"severity_breakdown": merged_severity,
|
|
249
|
+
"critical_findings": [f for f in merged_findings if f.get("severity") == "critical"],
|
|
250
|
+
"high_findings": [f for f in merged_findings if f.get("severity") == "high"],
|
|
251
|
+
},
|
|
252
|
+
"crew_summary": crew_report.get("summary", ""),
|
|
253
|
+
"agents_used": crew_report.get("agents_used", []),
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def _score_to_level(score: float) -> str:
|
|
258
|
+
"""Convert risk score to risk level string."""
|
|
259
|
+
if score >= 75:
|
|
260
|
+
return "critical"
|
|
261
|
+
if score >= 50:
|
|
262
|
+
return "high"
|
|
263
|
+
if score >= 25:
|
|
264
|
+
return "medium"
|
|
265
|
+
if score > 0:
|
|
266
|
+
return "low"
|
|
267
|
+
return "none"
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def _map_category_to_owasp(category: str) -> str:
|
|
271
|
+
"""Map SecurityFinding category to OWASP category string."""
|
|
272
|
+
mapping = {
|
|
273
|
+
"injection": "A03:2021-Injection",
|
|
274
|
+
"broken_authentication": "A07:2021-Identification and Authentication Failures",
|
|
275
|
+
"sensitive_data_exposure": "A02:2021-Cryptographic Failures",
|
|
276
|
+
"xml_external_entities": "A05:2021-Security Misconfiguration",
|
|
277
|
+
"broken_access_control": "A01:2021-Broken Access Control",
|
|
278
|
+
"security_misconfiguration": "A05:2021-Security Misconfiguration",
|
|
279
|
+
"cross_site_scripting": "A03:2021-Injection",
|
|
280
|
+
"insecure_deserialization": "A08:2021-Software and Data Integrity Failures",
|
|
281
|
+
"vulnerable_components": "A06:2021-Vulnerable and Outdated Components",
|
|
282
|
+
"insufficient_logging": "A09:2021-Security Logging and Monitoring Failures",
|
|
283
|
+
}
|
|
284
|
+
return mapping.get(category, "Other")
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def _map_type_to_category(vuln_type: str) -> str:
|
|
288
|
+
"""Map workflow vulnerability type to crew category."""
|
|
289
|
+
mapping = {
|
|
290
|
+
"sql_injection": "injection",
|
|
291
|
+
"xss": "cross_site_scripting",
|
|
292
|
+
"command_injection": "injection",
|
|
293
|
+
"path_traversal": "broken_access_control",
|
|
294
|
+
"hardcoded_secret": "sensitive_data_exposure", # pragma: allowlist secret
|
|
295
|
+
"insecure_random": "security_misconfiguration",
|
|
296
|
+
}
|
|
297
|
+
return mapping.get(vuln_type, "other")
|