empathy-framework 3.7.0__py3-none-any.whl → 3.7.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (267) hide show
  1. coach_wizards/code_reviewer_README.md +60 -0
  2. coach_wizards/code_reviewer_wizard.py +180 -0
  3. {empathy_framework-3.7.0.dist-info → empathy_framework-3.7.1.dist-info}/METADATA +20 -2
  4. empathy_framework-3.7.1.dist-info/RECORD +327 -0
  5. {empathy_framework-3.7.0.dist-info → empathy_framework-3.7.1.dist-info}/top_level.txt +5 -1
  6. empathy_healthcare_plugin/monitors/__init__.py +9 -0
  7. empathy_healthcare_plugin/monitors/clinical_protocol_monitor.py +315 -0
  8. empathy_healthcare_plugin/monitors/monitoring/__init__.py +44 -0
  9. empathy_healthcare_plugin/monitors/monitoring/protocol_checker.py +300 -0
  10. empathy_healthcare_plugin/monitors/monitoring/protocol_loader.py +214 -0
  11. empathy_healthcare_plugin/monitors/monitoring/sensor_parsers.py +306 -0
  12. empathy_healthcare_plugin/monitors/monitoring/trajectory_analyzer.py +389 -0
  13. empathy_llm_toolkit/agent_factory/__init__.py +53 -0
  14. empathy_llm_toolkit/agent_factory/adapters/__init__.py +85 -0
  15. empathy_llm_toolkit/agent_factory/adapters/autogen_adapter.py +312 -0
  16. empathy_llm_toolkit/agent_factory/adapters/crewai_adapter.py +454 -0
  17. empathy_llm_toolkit/agent_factory/adapters/haystack_adapter.py +298 -0
  18. empathy_llm_toolkit/agent_factory/adapters/langchain_adapter.py +362 -0
  19. empathy_llm_toolkit/agent_factory/adapters/langgraph_adapter.py +333 -0
  20. empathy_llm_toolkit/agent_factory/adapters/native.py +228 -0
  21. empathy_llm_toolkit/agent_factory/adapters/wizard_adapter.py +426 -0
  22. empathy_llm_toolkit/agent_factory/base.py +305 -0
  23. empathy_llm_toolkit/agent_factory/crews/__init__.py +67 -0
  24. empathy_llm_toolkit/agent_factory/crews/code_review.py +1113 -0
  25. empathy_llm_toolkit/agent_factory/crews/health_check.py +1246 -0
  26. empathy_llm_toolkit/agent_factory/crews/refactoring.py +1128 -0
  27. empathy_llm_toolkit/agent_factory/crews/security_audit.py +1018 -0
  28. empathy_llm_toolkit/agent_factory/decorators.py +286 -0
  29. empathy_llm_toolkit/agent_factory/factory.py +558 -0
  30. empathy_llm_toolkit/agent_factory/framework.py +192 -0
  31. empathy_llm_toolkit/agent_factory/memory_integration.py +324 -0
  32. empathy_llm_toolkit/agent_factory/resilient.py +320 -0
  33. empathy_llm_toolkit/cli/__init__.py +8 -0
  34. empathy_llm_toolkit/cli/sync_claude.py +487 -0
  35. empathy_llm_toolkit/code_health.py +150 -3
  36. empathy_llm_toolkit/config/__init__.py +29 -0
  37. empathy_llm_toolkit/config/unified.py +295 -0
  38. empathy_llm_toolkit/routing/__init__.py +32 -0
  39. empathy_llm_toolkit/routing/model_router.py +362 -0
  40. empathy_llm_toolkit/security/IMPLEMENTATION_SUMMARY.md +413 -0
  41. empathy_llm_toolkit/security/PHASE2_COMPLETE.md +384 -0
  42. empathy_llm_toolkit/security/PHASE2_SECRETS_DETECTOR_COMPLETE.md +271 -0
  43. empathy_llm_toolkit/security/QUICK_REFERENCE.md +316 -0
  44. empathy_llm_toolkit/security/README.md +262 -0
  45. empathy_llm_toolkit/security/__init__.py +62 -0
  46. empathy_llm_toolkit/security/audit_logger.py +929 -0
  47. empathy_llm_toolkit/security/audit_logger_example.py +152 -0
  48. empathy_llm_toolkit/security/pii_scrubber.py +640 -0
  49. empathy_llm_toolkit/security/secrets_detector.py +678 -0
  50. empathy_llm_toolkit/security/secrets_detector_example.py +304 -0
  51. empathy_llm_toolkit/security/secure_memdocs.py +1192 -0
  52. empathy_llm_toolkit/security/secure_memdocs_example.py +278 -0
  53. empathy_llm_toolkit/wizards/__init__.py +38 -0
  54. empathy_llm_toolkit/wizards/base_wizard.py +364 -0
  55. empathy_llm_toolkit/wizards/customer_support_wizard.py +190 -0
  56. empathy_llm_toolkit/wizards/healthcare_wizard.py +362 -0
  57. empathy_llm_toolkit/wizards/patient_assessment_README.md +64 -0
  58. empathy_llm_toolkit/wizards/patient_assessment_wizard.py +193 -0
  59. empathy_llm_toolkit/wizards/technology_wizard.py +194 -0
  60. empathy_os/__init__.py +52 -52
  61. empathy_os/adaptive/__init__.py +13 -0
  62. empathy_os/adaptive/task_complexity.py +127 -0
  63. empathy_os/cli.py +118 -8
  64. empathy_os/cli_unified.py +121 -1
  65. empathy_os/config/__init__.py +63 -0
  66. empathy_os/config/xml_config.py +239 -0
  67. empathy_os/dashboard/__init__.py +15 -0
  68. empathy_os/dashboard/server.py +743 -0
  69. empathy_os/memory/__init__.py +195 -0
  70. empathy_os/memory/claude_memory.py +466 -0
  71. empathy_os/memory/config.py +224 -0
  72. empathy_os/memory/control_panel.py +1298 -0
  73. empathy_os/memory/edges.py +179 -0
  74. empathy_os/memory/graph.py +567 -0
  75. empathy_os/memory/long_term.py +1193 -0
  76. empathy_os/memory/nodes.py +179 -0
  77. empathy_os/memory/redis_bootstrap.py +540 -0
  78. empathy_os/memory/security/__init__.py +31 -0
  79. empathy_os/memory/security/audit_logger.py +930 -0
  80. empathy_os/memory/security/pii_scrubber.py +640 -0
  81. empathy_os/memory/security/secrets_detector.py +678 -0
  82. empathy_os/memory/short_term.py +2119 -0
  83. empathy_os/memory/storage/__init__.py +15 -0
  84. empathy_os/memory/summary_index.py +583 -0
  85. empathy_os/memory/unified.py +619 -0
  86. empathy_os/metrics/__init__.py +12 -0
  87. empathy_os/metrics/prompt_metrics.py +190 -0
  88. empathy_os/models/__init__.py +136 -0
  89. empathy_os/models/__main__.py +13 -0
  90. empathy_os/models/cli.py +655 -0
  91. empathy_os/models/empathy_executor.py +354 -0
  92. empathy_os/models/executor.py +252 -0
  93. empathy_os/models/fallback.py +671 -0
  94. empathy_os/models/provider_config.py +563 -0
  95. empathy_os/models/registry.py +382 -0
  96. empathy_os/models/tasks.py +302 -0
  97. empathy_os/models/telemetry.py +548 -0
  98. empathy_os/models/token_estimator.py +378 -0
  99. empathy_os/models/validation.py +274 -0
  100. empathy_os/monitoring/__init__.py +52 -0
  101. empathy_os/monitoring/alerts.py +23 -0
  102. empathy_os/monitoring/alerts_cli.py +268 -0
  103. empathy_os/monitoring/multi_backend.py +271 -0
  104. empathy_os/monitoring/otel_backend.py +363 -0
  105. empathy_os/optimization/__init__.py +19 -0
  106. empathy_os/optimization/context_optimizer.py +272 -0
  107. empathy_os/plugins/__init__.py +28 -0
  108. empathy_os/plugins/base.py +361 -0
  109. empathy_os/plugins/registry.py +268 -0
  110. empathy_os/project_index/__init__.py +30 -0
  111. empathy_os/project_index/cli.py +335 -0
  112. empathy_os/project_index/crew_integration.py +430 -0
  113. empathy_os/project_index/index.py +425 -0
  114. empathy_os/project_index/models.py +501 -0
  115. empathy_os/project_index/reports.py +473 -0
  116. empathy_os/project_index/scanner.py +538 -0
  117. empathy_os/prompts/__init__.py +61 -0
  118. empathy_os/prompts/config.py +77 -0
  119. empathy_os/prompts/context.py +177 -0
  120. empathy_os/prompts/parser.py +285 -0
  121. empathy_os/prompts/registry.py +313 -0
  122. empathy_os/prompts/templates.py +208 -0
  123. empathy_os/resilience/__init__.py +56 -0
  124. empathy_os/resilience/circuit_breaker.py +256 -0
  125. empathy_os/resilience/fallback.py +179 -0
  126. empathy_os/resilience/health.py +300 -0
  127. empathy_os/resilience/retry.py +209 -0
  128. empathy_os/resilience/timeout.py +135 -0
  129. empathy_os/routing/__init__.py +43 -0
  130. empathy_os/routing/chain_executor.py +433 -0
  131. empathy_os/routing/classifier.py +217 -0
  132. empathy_os/routing/smart_router.py +234 -0
  133. empathy_os/routing/wizard_registry.py +307 -0
  134. empathy_os/trust/__init__.py +28 -0
  135. empathy_os/trust/circuit_breaker.py +579 -0
  136. empathy_os/validation/__init__.py +19 -0
  137. empathy_os/validation/xml_validator.py +281 -0
  138. empathy_os/wizard_factory_cli.py +170 -0
  139. empathy_os/workflows/__init__.py +360 -0
  140. empathy_os/workflows/base.py +1530 -0
  141. empathy_os/workflows/bug_predict.py +962 -0
  142. empathy_os/workflows/code_review.py +960 -0
  143. empathy_os/workflows/code_review_adapters.py +310 -0
  144. empathy_os/workflows/code_review_pipeline.py +720 -0
  145. empathy_os/workflows/config.py +600 -0
  146. empathy_os/workflows/dependency_check.py +648 -0
  147. empathy_os/workflows/document_gen.py +1069 -0
  148. empathy_os/workflows/documentation_orchestrator.py +1205 -0
  149. empathy_os/workflows/health_check.py +679 -0
  150. empathy_os/workflows/keyboard_shortcuts/__init__.py +39 -0
  151. empathy_os/workflows/keyboard_shortcuts/generators.py +386 -0
  152. empathy_os/workflows/keyboard_shortcuts/parsers.py +414 -0
  153. empathy_os/workflows/keyboard_shortcuts/prompts.py +295 -0
  154. empathy_os/workflows/keyboard_shortcuts/schema.py +193 -0
  155. empathy_os/workflows/keyboard_shortcuts/workflow.py +505 -0
  156. empathy_os/workflows/manage_documentation.py +804 -0
  157. empathy_os/workflows/new_sample_workflow1.py +146 -0
  158. empathy_os/workflows/new_sample_workflow1_README.md +150 -0
  159. empathy_os/workflows/perf_audit.py +687 -0
  160. empathy_os/workflows/pr_review.py +748 -0
  161. empathy_os/workflows/progress.py +445 -0
  162. empathy_os/workflows/progress_server.py +322 -0
  163. empathy_os/workflows/refactor_plan.py +691 -0
  164. empathy_os/workflows/release_prep.py +808 -0
  165. empathy_os/workflows/research_synthesis.py +404 -0
  166. empathy_os/workflows/secure_release.py +585 -0
  167. empathy_os/workflows/security_adapters.py +297 -0
  168. empathy_os/workflows/security_audit.py +1050 -0
  169. empathy_os/workflows/step_config.py +234 -0
  170. empathy_os/workflows/test5.py +125 -0
  171. empathy_os/workflows/test5_README.md +158 -0
  172. empathy_os/workflows/test_gen.py +1855 -0
  173. empathy_os/workflows/test_lifecycle.py +526 -0
  174. empathy_os/workflows/test_maintenance.py +626 -0
  175. empathy_os/workflows/test_maintenance_cli.py +590 -0
  176. empathy_os/workflows/test_maintenance_crew.py +821 -0
  177. empathy_os/workflows/xml_enhanced_crew.py +285 -0
  178. empathy_software_plugin/cli/__init__.py +120 -0
  179. empathy_software_plugin/cli/inspect.py +362 -0
  180. empathy_software_plugin/cli.py +3 -1
  181. empathy_software_plugin/wizards/__init__.py +42 -0
  182. empathy_software_plugin/wizards/advanced_debugging_wizard.py +392 -0
  183. empathy_software_plugin/wizards/agent_orchestration_wizard.py +511 -0
  184. empathy_software_plugin/wizards/ai_collaboration_wizard.py +503 -0
  185. empathy_software_plugin/wizards/ai_context_wizard.py +441 -0
  186. empathy_software_plugin/wizards/ai_documentation_wizard.py +503 -0
  187. empathy_software_plugin/wizards/base_wizard.py +288 -0
  188. empathy_software_plugin/wizards/book_chapter_wizard.py +519 -0
  189. empathy_software_plugin/wizards/code_review_wizard.py +606 -0
  190. empathy_software_plugin/wizards/debugging/__init__.py +50 -0
  191. empathy_software_plugin/wizards/debugging/bug_risk_analyzer.py +414 -0
  192. empathy_software_plugin/wizards/debugging/config_loaders.py +442 -0
  193. empathy_software_plugin/wizards/debugging/fix_applier.py +469 -0
  194. empathy_software_plugin/wizards/debugging/language_patterns.py +383 -0
  195. empathy_software_plugin/wizards/debugging/linter_parsers.py +470 -0
  196. empathy_software_plugin/wizards/debugging/verification.py +369 -0
  197. empathy_software_plugin/wizards/enhanced_testing_wizard.py +537 -0
  198. empathy_software_plugin/wizards/memory_enhanced_debugging_wizard.py +816 -0
  199. empathy_software_plugin/wizards/multi_model_wizard.py +501 -0
  200. empathy_software_plugin/wizards/pattern_extraction_wizard.py +422 -0
  201. empathy_software_plugin/wizards/pattern_retriever_wizard.py +400 -0
  202. empathy_software_plugin/wizards/performance/__init__.py +9 -0
  203. empathy_software_plugin/wizards/performance/bottleneck_detector.py +221 -0
  204. empathy_software_plugin/wizards/performance/profiler_parsers.py +278 -0
  205. empathy_software_plugin/wizards/performance/trajectory_analyzer.py +429 -0
  206. empathy_software_plugin/wizards/performance_profiling_wizard.py +305 -0
  207. empathy_software_plugin/wizards/prompt_engineering_wizard.py +425 -0
  208. empathy_software_plugin/wizards/rag_pattern_wizard.py +461 -0
  209. empathy_software_plugin/wizards/security/__init__.py +32 -0
  210. empathy_software_plugin/wizards/security/exploit_analyzer.py +290 -0
  211. empathy_software_plugin/wizards/security/owasp_patterns.py +241 -0
  212. empathy_software_plugin/wizards/security/vulnerability_scanner.py +604 -0
  213. empathy_software_plugin/wizards/security_analysis_wizard.py +322 -0
  214. empathy_software_plugin/wizards/security_learning_wizard.py +740 -0
  215. empathy_software_plugin/wizards/tech_debt_wizard.py +726 -0
  216. empathy_software_plugin/wizards/testing/__init__.py +27 -0
  217. empathy_software_plugin/wizards/testing/coverage_analyzer.py +459 -0
  218. empathy_software_plugin/wizards/testing/quality_analyzer.py +531 -0
  219. empathy_software_plugin/wizards/testing/test_suggester.py +533 -0
  220. empathy_software_plugin/wizards/testing_wizard.py +274 -0
  221. hot_reload/README.md +473 -0
  222. hot_reload/__init__.py +62 -0
  223. hot_reload/config.py +84 -0
  224. hot_reload/integration.py +228 -0
  225. hot_reload/reloader.py +298 -0
  226. hot_reload/watcher.py +179 -0
  227. hot_reload/websocket.py +176 -0
  228. scaffolding/README.md +589 -0
  229. scaffolding/__init__.py +35 -0
  230. scaffolding/__main__.py +14 -0
  231. scaffolding/cli.py +240 -0
  232. test_generator/__init__.py +38 -0
  233. test_generator/__main__.py +14 -0
  234. test_generator/cli.py +226 -0
  235. test_generator/generator.py +325 -0
  236. test_generator/risk_analyzer.py +216 -0
  237. workflow_patterns/__init__.py +33 -0
  238. workflow_patterns/behavior.py +249 -0
  239. workflow_patterns/core.py +76 -0
  240. workflow_patterns/output.py +99 -0
  241. workflow_patterns/registry.py +255 -0
  242. workflow_patterns/structural.py +288 -0
  243. workflow_scaffolding/__init__.py +11 -0
  244. workflow_scaffolding/__main__.py +12 -0
  245. workflow_scaffolding/cli.py +206 -0
  246. workflow_scaffolding/generator.py +265 -0
  247. agents/code_inspection/patterns/inspection/recurring_B112.json +0 -18
  248. agents/code_inspection/patterns/inspection/recurring_F541.json +0 -16
  249. agents/code_inspection/patterns/inspection/recurring_FORMAT.json +0 -25
  250. agents/code_inspection/patterns/inspection/recurring_bug_20250822_def456.json +0 -16
  251. agents/code_inspection/patterns/inspection/recurring_bug_20250915_abc123.json +0 -16
  252. agents/code_inspection/patterns/inspection/recurring_bug_20251212_3c5b9951.json +0 -16
  253. agents/code_inspection/patterns/inspection/recurring_bug_20251212_97c0f72f.json +0 -16
  254. agents/code_inspection/patterns/inspection/recurring_bug_20251212_a0871d53.json +0 -16
  255. agents/code_inspection/patterns/inspection/recurring_bug_20251212_a9b6ec41.json +0 -16
  256. agents/code_inspection/patterns/inspection/recurring_bug_null_001.json +0 -16
  257. agents/code_inspection/patterns/inspection/recurring_builtin.json +0 -16
  258. agents/compliance_anticipation_agent.py +0 -1422
  259. agents/compliance_db.py +0 -339
  260. agents/epic_integration_wizard.py +0 -530
  261. agents/notifications.py +0 -291
  262. agents/trust_building_behaviors.py +0 -872
  263. empathy_framework-3.7.0.dist-info/RECORD +0 -105
  264. {empathy_framework-3.7.0.dist-info → empathy_framework-3.7.1.dist-info}/WHEEL +0 -0
  265. {empathy_framework-3.7.0.dist-info → empathy_framework-3.7.1.dist-info}/entry_points.txt +0 -0
  266. {empathy_framework-3.7.0.dist-info → empathy_framework-3.7.1.dist-info}/licenses/LICENSE +0 -0
  267. /empathy_os/{monitoring.py → agent_monitoring.py} +0 -0
@@ -0,0 +1,585 @@
1
+ """Secure Release Pipeline
2
+
3
+ A comprehensive security pipeline that composes multiple security workflows
4
+ for maximum coverage before release approval.
5
+
6
+ Orchestrates:
7
+ 1. SecurityAuditCrew (optional, parallel) - 5-agent multi-agent security crew
8
+ 2. SecurityAuditWorkflow - OWASP-focused vulnerability scanning
9
+ 3. CodeReviewWorkflow - Security-aware code review (optional)
10
+ 4. ReleasePreparationWorkflow - Pre-release quality gate
11
+
12
+ Copyright 2025 Smart-AI-Memory
13
+ Licensed under Fair Source License 0.9
14
+ """
15
+
16
+ import asyncio
17
+ import logging
18
+ from dataclasses import dataclass, field
19
+ from datetime import datetime
20
+ from typing import Any
21
+
22
+ from .base import WorkflowResult
23
+
24
+ logger = logging.getLogger(__name__)
25
+
26
+
27
+ @dataclass
28
+ class SecureReleaseResult:
29
+ """Result from SecureReleasePipeline execution."""
30
+
31
+ success: bool
32
+ go_no_go: str # "GO", "NO_GO", "CONDITIONAL"
33
+
34
+ # Individual workflow results
35
+ crew_report: dict | None = None
36
+ security_audit: WorkflowResult | None = None
37
+ code_review: WorkflowResult | None = None
38
+ release_prep: WorkflowResult | None = None
39
+
40
+ # Unified metrics
41
+ combined_risk_score: float = 0.0
42
+ total_findings: int = 0
43
+ critical_count: int = 0
44
+ high_count: int = 0
45
+
46
+ # Cost tracking
47
+ total_cost: float = 0.0
48
+ total_duration_ms: int = 0
49
+
50
+ # Recommendations
51
+ blockers: list[str] = field(default_factory=list)
52
+ warnings: list[str] = field(default_factory=list)
53
+ recommendations: list[str] = field(default_factory=list)
54
+
55
+ # Metadata
56
+ mode: str = "full"
57
+ crew_enabled: bool = False
58
+
59
+ def to_dict(self) -> dict:
60
+ """Convert result to dictionary."""
61
+ return {
62
+ "success": self.success,
63
+ "go_no_go": self.go_no_go,
64
+ "combined_risk_score": self.combined_risk_score,
65
+ "total_findings": self.total_findings,
66
+ "critical_count": self.critical_count,
67
+ "high_count": self.high_count,
68
+ "total_cost": self.total_cost,
69
+ "total_duration_ms": self.total_duration_ms,
70
+ "blockers": self.blockers,
71
+ "warnings": self.warnings,
72
+ "recommendations": self.recommendations,
73
+ "mode": self.mode,
74
+ "crew_enabled": self.crew_enabled,
75
+ }
76
+
77
+ @property
78
+ def formatted_report(self) -> str:
79
+ """Generate human-readable report."""
80
+ return format_secure_release_report(self)
81
+
82
+
83
+ class SecureReleasePipeline:
84
+ """Comprehensive security pipeline for release preparation.
85
+
86
+ This pipeline composes multiple security workflows to provide
87
+ maximum coverage before release approval.
88
+
89
+ Execution modes:
90
+ - "full": Run all workflows (SecurityAuditCrew + all workflows) [DEFAULT]
91
+ - "standard": Skip crew, run all workflows (fallback when crew unavailable)
92
+
93
+ Note: For quick release checks without full security audit, use the
94
+ ReleasePreparationWorkflow directly instead.
95
+
96
+ Usage:
97
+ pipeline = SecureReleasePipeline(mode="full")
98
+ result = await pipeline.execute(
99
+ path="./src",
100
+ diff="...",
101
+ files_changed=[...]
102
+ )
103
+
104
+ if result.go_no_go == "GO":
105
+ print("Ready for release!")
106
+ else:
107
+ for blocker in result.blockers:
108
+ print(f"BLOCKER: {blocker}")
109
+ """
110
+
111
+ name = "secure-release"
112
+ description = "Comprehensive security pipeline composing multiple workflows"
113
+
114
+ def __init__(
115
+ self,
116
+ mode: str = "full", # "full" or "standard"
117
+ use_crew: bool | None = None, # Override mode's crew setting
118
+ parallel_crew: bool = True, # Run crew in parallel with first workflow
119
+ crew_config: dict | None = None,
120
+ **kwargs: Any,
121
+ ):
122
+ """Initialize secure release pipeline.
123
+
124
+ Args:
125
+ mode: Execution mode - "full" (with crew, DEFAULT) or "standard" (skip crew)
126
+ use_crew: Override crew setting (None uses mode default: full=True, standard=False)
127
+ parallel_crew: Run SecurityAuditCrew in parallel with first workflow
128
+ crew_config: Configuration for SecurityAuditCrew
129
+ **kwargs: Additional arguments passed to child workflows
130
+
131
+ """
132
+ # Validate mode
133
+ if mode not in ("full", "standard"):
134
+ raise ValueError(f"Invalid mode '{mode}'. Must be 'full' or 'standard'.")
135
+
136
+ self.mode = mode
137
+ self.use_crew = use_crew if use_crew is not None else (mode == "full")
138
+ self.parallel_crew = parallel_crew
139
+ self.crew_config = crew_config or {}
140
+ self.kwargs = kwargs
141
+
142
+ async def execute(
143
+ self,
144
+ path: str = ".",
145
+ diff: str = "",
146
+ files_changed: list[str] | None = None,
147
+ since: str = "1 week ago",
148
+ **kwargs: Any,
149
+ ) -> SecureReleaseResult:
150
+ """Execute the secure release pipeline.
151
+
152
+ Args:
153
+ path: Path to codebase to analyze
154
+ diff: Git diff for code review (optional)
155
+ files_changed: List of changed files (optional)
156
+ since: Period for changelog generation
157
+ **kwargs: Additional arguments
158
+
159
+ Returns:
160
+ SecureReleaseResult with combined analysis
161
+
162
+ """
163
+ from .security_adapters import (
164
+ _check_crew_available,
165
+ _get_crew_audit,
166
+ crew_report_to_workflow_format,
167
+ )
168
+
169
+ started_at = datetime.now()
170
+
171
+ crew_report = None
172
+ security_result = None
173
+ code_review_result = None
174
+ release_result = None
175
+
176
+ total_cost = 0.0
177
+ blockers: list[str] = []
178
+ warnings: list[str] = []
179
+ recommendations: list[str] = []
180
+
181
+ try:
182
+ # Step 1: SecurityAuditCrew (parallel or first)
183
+ crew_task = None
184
+ crew_enabled = self.use_crew and _check_crew_available()
185
+
186
+ if crew_enabled:
187
+ if self.parallel_crew:
188
+ # Start crew in parallel
189
+ crew_task = asyncio.create_task(_get_crew_audit(path, self.crew_config))
190
+ else:
191
+ # Run crew first, then proceed
192
+ crew_report_obj = await _get_crew_audit(path, self.crew_config)
193
+ if crew_report_obj:
194
+ crew_report = crew_report_to_workflow_format(crew_report_obj)
195
+
196
+ # Step 2: SecurityAuditWorkflow
197
+ from .security_audit import SecurityAuditWorkflow
198
+
199
+ security_workflow = SecurityAuditWorkflow(**self.kwargs)
200
+ security_result = await security_workflow.execute(path=path)
201
+ total_cost += security_result.cost_report.total_cost
202
+
203
+ # Collect crew results if running in parallel
204
+ if crew_task:
205
+ try:
206
+ crew_report_obj = await asyncio.wait_for(crew_task, timeout=300.0)
207
+ if crew_report_obj:
208
+ crew_report = crew_report_to_workflow_format(crew_report_obj)
209
+ except asyncio.TimeoutError:
210
+ logger.warning("SecurityAuditCrew timed out")
211
+ warnings.append("SecurityAuditCrew timed out - results not included")
212
+
213
+ # Step 3: CodeReviewWorkflow (if diff provided)
214
+ if diff:
215
+ from .code_review import CodeReviewWorkflow
216
+
217
+ code_workflow = CodeReviewWorkflow(**self.kwargs)
218
+
219
+ # Pass crew findings as external audit if available
220
+ code_input: dict = {
221
+ "diff": diff,
222
+ "files_changed": files_changed or [],
223
+ }
224
+ if crew_report:
225
+ code_input["external_audit_results"] = crew_report
226
+
227
+ code_review_result = await code_workflow.execute(**code_input)
228
+ total_cost += code_review_result.cost_report.total_cost
229
+
230
+ # Step 4: ReleasePreparationWorkflow
231
+ from .release_prep import ReleasePreparationWorkflow
232
+
233
+ release_workflow = ReleasePreparationWorkflow(**self.kwargs)
234
+ release_result = await release_workflow.execute(path=path, since=since)
235
+ total_cost += release_result.cost_report.total_cost
236
+
237
+ # Aggregate results
238
+ combined_risk_score = self._calculate_combined_risk(
239
+ crew_report,
240
+ security_result,
241
+ code_review_result,
242
+ release_result,
243
+ )
244
+
245
+ findings = self._aggregate_findings(crew_report, security_result, code_review_result)
246
+
247
+ # Determine go/no-go
248
+ go_no_go = self._determine_go_no_go(combined_risk_score, findings, release_result)
249
+
250
+ blockers, warnings, recommendations = self._generate_recommendations(
251
+ crew_report,
252
+ security_result,
253
+ code_review_result,
254
+ release_result,
255
+ )
256
+
257
+ except Exception as e:
258
+ logger.error(f"Secure release pipeline failed: {e}")
259
+ blockers.append(f"Pipeline failed: {e!s}")
260
+ go_no_go = "NO_GO"
261
+ combined_risk_score = 100.0
262
+ findings = {"critical": 0, "high": 0, "total": 0}
263
+
264
+ completed_at = datetime.now()
265
+ duration_ms = int((completed_at - started_at).total_seconds() * 1000)
266
+
267
+ return SecureReleaseResult(
268
+ success=go_no_go != "NO_GO",
269
+ go_no_go=go_no_go,
270
+ crew_report=crew_report,
271
+ security_audit=security_result,
272
+ code_review=code_review_result,
273
+ release_prep=release_result,
274
+ combined_risk_score=combined_risk_score,
275
+ total_findings=findings.get("total", 0),
276
+ critical_count=findings.get("critical", 0),
277
+ high_count=findings.get("high", 0),
278
+ total_cost=total_cost,
279
+ total_duration_ms=duration_ms,
280
+ blockers=blockers,
281
+ warnings=warnings,
282
+ recommendations=recommendations,
283
+ mode=self.mode,
284
+ crew_enabled=crew_report is not None,
285
+ )
286
+
287
+ def _calculate_combined_risk(
288
+ self,
289
+ crew_report: dict | None,
290
+ security_result: WorkflowResult | None,
291
+ code_review_result: WorkflowResult | None,
292
+ release_result: WorkflowResult | None,
293
+ ) -> float:
294
+ """Calculate combined risk score from all sources."""
295
+ scores = []
296
+ weights = []
297
+
298
+ if crew_report:
299
+ scores.append(crew_report.get("risk_score", 0))
300
+ weights.append(1.5) # Crew gets higher weight
301
+
302
+ if security_result and security_result.final_output:
303
+ assessment = security_result.final_output.get("assessment", {})
304
+ scores.append(assessment.get("risk_score", 0))
305
+ weights.append(1.0)
306
+
307
+ if code_review_result and code_review_result.final_output:
308
+ security_score = code_review_result.final_output.get("security_score", 90)
309
+ # Convert to risk (100 - security_score)
310
+ scores.append(100 - security_score)
311
+ weights.append(0.8)
312
+
313
+ if not scores:
314
+ return 0.0
315
+
316
+ weighted_sum = sum(s * w for s, w in zip(scores, weights, strict=False))
317
+ return float(min(100.0, weighted_sum / sum(weights)))
318
+
319
+ def _aggregate_findings(
320
+ self,
321
+ crew_report: dict | None,
322
+ security_result: WorkflowResult | None,
323
+ code_review_result: WorkflowResult | None,
324
+ ) -> dict:
325
+ """Aggregate findings from all sources."""
326
+ critical = 0
327
+ high = 0
328
+ total = 0
329
+
330
+ if crew_report:
331
+ assessment = crew_report.get("assessment", {})
332
+ critical += len(assessment.get("critical_findings", []))
333
+ high += len(assessment.get("high_findings", []))
334
+ total += crew_report.get("finding_count", 0)
335
+
336
+ if security_result and security_result.final_output:
337
+ assessment = security_result.final_output.get("assessment", {})
338
+ severity = assessment.get("severity_breakdown", {})
339
+ critical = max(critical, severity.get("critical", 0))
340
+ high = max(high, severity.get("high", 0))
341
+ total = max(
342
+ total,
343
+ sum(severity.values()) if severity else 0,
344
+ )
345
+
346
+ if code_review_result and code_review_result.final_output:
347
+ if code_review_result.final_output.get("has_critical_issues"):
348
+ critical = max(critical, 1)
349
+
350
+ return {"critical": critical, "high": high, "total": total}
351
+
352
+ def _determine_go_no_go(
353
+ self,
354
+ risk_score: float,
355
+ findings: dict,
356
+ release_result: WorkflowResult | None,
357
+ ) -> str:
358
+ """Determine go/no-go decision."""
359
+ # Critical findings = immediate NO_GO
360
+ if findings.get("critical", 0) > 0:
361
+ return "NO_GO"
362
+
363
+ # Very high risk = NO_GO
364
+ if risk_score >= 75:
365
+ return "NO_GO"
366
+
367
+ # High findings or elevated risk = CONDITIONAL
368
+ if findings.get("high", 0) > 3 or risk_score >= 50:
369
+ return "CONDITIONAL"
370
+
371
+ # Release workflow not approved = CONDITIONAL
372
+ if release_result and release_result.final_output:
373
+ if not release_result.final_output.get("approved", True):
374
+ return "CONDITIONAL"
375
+
376
+ return "GO"
377
+
378
+ def _generate_recommendations(
379
+ self,
380
+ crew_report: dict | None,
381
+ security_result: WorkflowResult | None,
382
+ code_review_result: WorkflowResult | None,
383
+ release_result: WorkflowResult | None,
384
+ ) -> tuple[list[str], list[str], list[str]]:
385
+ """Generate blockers, warnings, and recommendations."""
386
+ blockers = []
387
+ warnings = []
388
+ recommendations = []
389
+
390
+ # Crew findings
391
+ if crew_report:
392
+ critical = crew_report.get("assessment", {}).get("critical_findings", [])
393
+ for f in critical:
394
+ blockers.append(f"Critical: {f.get('title', 'Unknown issue')}")
395
+
396
+ high = crew_report.get("assessment", {}).get("high_findings", [])
397
+ for f in high[:3]: # Top 3
398
+ warnings.append(f"High: {f.get('title', 'Unknown issue')}")
399
+
400
+ # Security audit findings
401
+ if security_result and security_result.final_output:
402
+ assessment = security_result.final_output.get("assessment", {})
403
+ if assessment.get("risk_level") == "critical":
404
+ blockers.append("Security audit identified critical risk level")
405
+ elif assessment.get("risk_level") == "high":
406
+ warnings.append("Security audit identified high risk level")
407
+
408
+ # Code review verdict
409
+ if code_review_result and code_review_result.final_output:
410
+ verdict = code_review_result.final_output.get("verdict", "")
411
+ if verdict == "reject":
412
+ blockers.append("Code review: Changes rejected")
413
+ elif verdict == "request_changes":
414
+ warnings.append("Code review: Changes requested")
415
+
416
+ # Release prep blockers
417
+ if release_result and release_result.final_output:
418
+ for b in release_result.final_output.get("blockers", []):
419
+ blockers.append(f"Release: {b}")
420
+ for w in release_result.final_output.get("warnings", []):
421
+ warnings.append(f"Release: {w}")
422
+
423
+ # General recommendations
424
+ if not blockers and not warnings:
425
+ recommendations.append("All checks passed - ready for release")
426
+ elif blockers:
427
+ recommendations.append("Address all blockers before release")
428
+ recommendations.append("Consider running security audit on fixes")
429
+ elif warnings:
430
+ recommendations.append("Review warnings before release")
431
+ recommendations.append("Document accepted risks if proceeding")
432
+
433
+ return blockers, warnings, recommendations
434
+
435
+ @classmethod
436
+ def for_pr_review(cls, files_changed: int = 0) -> "SecureReleasePipeline":
437
+ """Create pipeline optimized for PR review."""
438
+ return cls(
439
+ mode="standard" if files_changed < 10 else "full",
440
+ parallel_crew=True,
441
+ )
442
+
443
+ @classmethod
444
+ def for_release(cls) -> "SecureReleasePipeline":
445
+ """Create pipeline for release preparation."""
446
+ return cls(
447
+ mode="full",
448
+ crew_config={"scan_depth": "thorough"},
449
+ )
450
+
451
+
452
+ def format_secure_release_report(result: SecureReleaseResult) -> str:
453
+ """Format secure release result as a human-readable report.
454
+
455
+ Args:
456
+ result: The SecureReleaseResult object
457
+
458
+ Returns:
459
+ Formatted report string
460
+
461
+ """
462
+ lines = []
463
+
464
+ # Header with go/no-go decision
465
+ go_no_go = result.go_no_go
466
+
467
+ if go_no_go == "GO":
468
+ status_icon = "✅"
469
+ status_text = "READY FOR RELEASE"
470
+ elif go_no_go == "CONDITIONAL":
471
+ status_icon = "⚠️"
472
+ status_text = "CONDITIONAL APPROVAL"
473
+ else:
474
+ status_icon = "❌"
475
+ status_text = "RELEASE BLOCKED"
476
+
477
+ lines.append("=" * 60)
478
+ lines.append("SECURE RELEASE REPORT")
479
+ lines.append("=" * 60)
480
+ lines.append("")
481
+ lines.append(f"Decision: {status_icon} {go_no_go} - {status_text}")
482
+ lines.append(f"Risk Score: {result.combined_risk_score:.1f}/100")
483
+ lines.append(f"Pipeline Mode: {result.mode.upper()}")
484
+ lines.append(f"Crew Enabled: {'Yes' if result.crew_enabled else 'No'}")
485
+ lines.append("")
486
+
487
+ # Findings summary
488
+ lines.append("-" * 60)
489
+ lines.append("FINDINGS SUMMARY")
490
+ lines.append("-" * 60)
491
+ lines.append(f"Total Findings: {result.total_findings}")
492
+ lines.append(f" 🔴 Critical: {result.critical_count}")
493
+ lines.append(f" 🟠 High: {result.high_count}")
494
+ lines.append("")
495
+
496
+ # Blockers
497
+ if result.blockers:
498
+ lines.append("-" * 60)
499
+ lines.append("🚫 BLOCKERS (Must Fix Before Release)")
500
+ lines.append("-" * 60)
501
+ for blocker in result.blockers:
502
+ lines.append(f" • {blocker}")
503
+ lines.append("")
504
+
505
+ # Warnings
506
+ if result.warnings:
507
+ lines.append("-" * 60)
508
+ lines.append("⚠️ WARNINGS")
509
+ lines.append("-" * 60)
510
+ for warning in result.warnings:
511
+ lines.append(f" • {warning}")
512
+ lines.append("")
513
+
514
+ # Recommendations
515
+ if result.recommendations:
516
+ lines.append("-" * 60)
517
+ lines.append("💡 RECOMMENDATIONS")
518
+ lines.append("-" * 60)
519
+ for rec in result.recommendations:
520
+ lines.append(f" • {rec}")
521
+ lines.append("")
522
+
523
+ # Individual workflow summaries
524
+ lines.append("-" * 60)
525
+ lines.append("WORKFLOW RESULTS")
526
+ lines.append("-" * 60)
527
+
528
+ # Crew results
529
+ if result.crew_report:
530
+ crew_risk = result.crew_report.get("risk_score", 0)
531
+ crew_findings = result.crew_report.get("finding_count", 0)
532
+ crew_icon = "✅" if crew_risk < 50 else "⚠️" if crew_risk < 75 else "❌"
533
+ lines.append(
534
+ f" {crew_icon} SecurityAuditCrew: {crew_findings} findings, risk {crew_risk}/100",
535
+ )
536
+ elif result.crew_enabled:
537
+ lines.append(" ⏭️ SecurityAuditCrew: Skipped or failed")
538
+
539
+ # Security audit
540
+ if result.security_audit:
541
+ sec_output = result.security_audit.final_output or {}
542
+ assessment = sec_output.get("assessment", {})
543
+ sec_risk = assessment.get("risk_score", 0)
544
+ sec_level = assessment.get("risk_level", "unknown")
545
+ sec_icon = "✅" if sec_risk < 50 else "⚠️" if sec_risk < 75 else "❌"
546
+ lines.append(f" {sec_icon} SecurityAudit: {sec_level} risk ({sec_risk}/100)")
547
+
548
+ # Code review
549
+ if result.code_review:
550
+ cr_output = result.code_review.final_output or {}
551
+ verdict = cr_output.get("verdict", "unknown")
552
+ cr_icon = "✅" if verdict == "approve" else "⚠️" if verdict == "request_changes" else "❌"
553
+ lines.append(f" {cr_icon} CodeReview: {verdict}")
554
+
555
+ # Release prep
556
+ if result.release_prep:
557
+ rp_output = result.release_prep.final_output or {}
558
+ approved = rp_output.get("approved", False)
559
+ confidence = rp_output.get("confidence", "unknown")
560
+ rp_icon = "✅" if approved else "❌"
561
+ lines.append(
562
+ f" {rp_icon} ReleasePrep: {'Approved' if approved else 'Not Approved'} ({confidence} confidence)",
563
+ )
564
+
565
+ lines.append("")
566
+
567
+ # Cost and duration
568
+ lines.append("-" * 60)
569
+ lines.append("EXECUTION DETAILS")
570
+ lines.append("-" * 60)
571
+ lines.append(f"Total Cost: ${result.total_cost:.4f}")
572
+ lines.append(f"Duration: {result.total_duration_ms:.0f}ms")
573
+ lines.append("")
574
+
575
+ # Footer
576
+ lines.append("=" * 60)
577
+ if go_no_go == "GO":
578
+ lines.append("All security checks passed. Proceed with release.")
579
+ elif go_no_go == "CONDITIONAL":
580
+ lines.append("Review warnings before proceeding with release.")
581
+ else:
582
+ lines.append("Address all blockers before release can proceed.")
583
+ lines.append("=" * 60)
584
+
585
+ return "\n".join(lines)