1use crate::agents::Agent;
9use crate::domain::{DomainAgent, DomainCapability, DomainKnowledge, TechRecommendation};
10use crate::error::Result;
11use crate::models::{AgentInput, AgentOutput, Finding, Severity, TaskType};
12use async_trait::async_trait;
13use uuid::Uuid;
14
15#[derive(Debug, Clone)]
35pub struct DevOpsAgent {
36 domain_agent: DomainAgent,
37}
38
39impl DevOpsAgent {
40 pub fn new() -> Self {
48 let capabilities = vec![
49 DomainCapability {
50 name: "CI/CD Pipeline Setup".to_string(),
51 description: "Recommendations for GitHub Actions, GitLab CI, or Jenkins"
52 .to_string(),
53 technologies: vec![
54 "GitHub Actions".to_string(),
55 "GitLab CI".to_string(),
56 "Jenkins".to_string(),
57 ],
58 patterns: vec![],
59 },
60 DomainCapability {
61 name: "Infrastructure as Code".to_string(),
62 description: "Recommendations for Terraform, CloudFormation, or Ansible"
63 .to_string(),
64 technologies: vec![
65 "Terraform".to_string(),
66 "CloudFormation".to_string(),
67 "Ansible".to_string(),
68 ],
69 patterns: vec![],
70 },
71 DomainCapability {
72 name: "Containerization".to_string(),
73 description: "Recommendations for Docker and Kubernetes configuration"
74 .to_string(),
75 technologies: vec!["Docker".to_string(), "Kubernetes".to_string()],
76 patterns: vec![],
77 },
78 DomainCapability {
79 name: "Observability Infrastructure".to_string(),
80 description: "Recommendations for monitoring, logging, and alerting"
81 .to_string(),
82 technologies: vec![
83 "Prometheus".to_string(),
84 "Grafana".to_string(),
85 "ELK Stack".to_string(),
86 ],
87 patterns: vec![],
88 },
89 DomainCapability {
90 name: "Security Scanning".to_string(),
91 description: "Recommendations for vulnerability scanning and compliance"
92 .to_string(),
93 technologies: vec![
94 "Trivy".to_string(),
95 "Snyk".to_string(),
96 "SonarQube".to_string(),
97 ],
98 patterns: vec![],
99 },
100 DomainCapability {
101 name: "Auto-Scaling".to_string(),
102 description: "Recommendations for scaling policies and resource management"
103 .to_string(),
104 technologies: vec![
105 "Kubernetes".to_string(),
106 "AWS Auto Scaling".to_string(),
107 "Docker Swarm".to_string(),
108 ],
109 patterns: vec![],
110 },
111 ];
112
113 let knowledge = DomainKnowledge {
114 best_practices: vec![],
115 technology_recommendations: vec![
116 TechRecommendation {
117 technology: "GitHub Actions".to_string(),
118 domain: "devops".to_string(),
119 use_cases: vec![
120 "GitHub-hosted CI/CD".to_string(),
121 "Automated testing".to_string(),
122 "Deployment automation".to_string(),
123 ],
124 pros: vec![
125 "Native GitHub integration".to_string(),
126 "Free for public repos".to_string(),
127 "Easy to set up".to_string(),
128 ],
129 cons: vec![
130 "Limited to GitHub".to_string(),
131 "Execution time limits".to_string(),
132 ],
133 alternatives: vec!["GitLab CI".to_string(), "Jenkins".to_string()],
134 },
135 TechRecommendation {
136 technology: "GitLab CI".to_string(),
137 domain: "devops".to_string(),
138 use_cases: vec![
139 "GitLab-hosted CI/CD".to_string(),
140 "Self-hosted runners".to_string(),
141 "Complex pipelines".to_string(),
142 ],
143 pros: vec![
144 "Powerful pipeline features".to_string(),
145 "Self-hosted runners".to_string(),
146 "Integrated with GitLab".to_string(),
147 ],
148 cons: vec![
149 "Limited to GitLab".to_string(),
150 "Steeper learning curve".to_string(),
151 ],
152 alternatives: vec!["GitHub Actions".to_string(), "Jenkins".to_string()],
153 },
154 TechRecommendation {
155 technology: "Jenkins".to_string(),
156 domain: "devops".to_string(),
157 use_cases: vec![
158 "Self-hosted CI/CD".to_string(),
159 "Complex pipelines".to_string(),
160 "Legacy systems".to_string(),
161 ],
162 pros: vec![
163 "Highly customizable".to_string(),
164 "Large plugin ecosystem".to_string(),
165 "Self-hosted".to_string(),
166 ],
167 cons: vec![
168 "Complex setup".to_string(),
169 "Maintenance overhead".to_string(),
170 "Older technology".to_string(),
171 ],
172 alternatives: vec!["GitHub Actions".to_string(), "GitLab CI".to_string()],
173 },
174 TechRecommendation {
175 technology: "Terraform".to_string(),
176 domain: "devops".to_string(),
177 use_cases: vec![
178 "Infrastructure as Code".to_string(),
179 "Multi-cloud deployments".to_string(),
180 "Reproducible infrastructure".to_string(),
181 ],
182 pros: vec![
183 "Declarative syntax".to_string(),
184 "Multi-cloud support".to_string(),
185 "State management".to_string(),
186 ],
187 cons: vec![
188 "State management complexity".to_string(),
189 "Learning curve".to_string(),
190 ],
191 alternatives: vec!["CloudFormation".to_string(), "Ansible".to_string()],
192 },
193 TechRecommendation {
194 technology: "CloudFormation".to_string(),
195 domain: "devops".to_string(),
196 use_cases: vec![
197 "AWS Infrastructure as Code".to_string(),
198 "AWS-specific deployments".to_string(),
199 ],
200 pros: vec![
201 "Native AWS integration".to_string(),
202 "No additional tools needed".to_string(),
203 "Good documentation".to_string(),
204 ],
205 cons: vec![
206 "AWS-only".to_string(),
207 "Verbose syntax".to_string(),
208 "Limited multi-cloud support".to_string(),
209 ],
210 alternatives: vec!["Terraform".to_string(), "Ansible".to_string()],
211 },
212 TechRecommendation {
213 technology: "Ansible".to_string(),
214 domain: "devops".to_string(),
215 use_cases: vec![
216 "Configuration management".to_string(),
217 "Infrastructure automation".to_string(),
218 "Agentless automation".to_string(),
219 ],
220 pros: vec![
221 "Agentless".to_string(),
222 "Easy to learn".to_string(),
223 "Flexible".to_string(),
224 ],
225 cons: vec![
226 "Slower than alternatives".to_string(),
227 "Less suitable for IaC".to_string(),
228 ],
229 alternatives: vec!["Terraform".to_string(), "Chef".to_string()],
230 },
231 TechRecommendation {
232 technology: "Docker".to_string(),
233 domain: "devops".to_string(),
234 use_cases: vec![
235 "Containerization".to_string(),
236 "Application packaging".to_string(),
237 "Development environments".to_string(),
238 ],
239 pros: vec![
240 "Lightweight containers".to_string(),
241 "Easy to use".to_string(),
242 "Large ecosystem".to_string(),
243 ],
244 cons: vec![
245 "Learning curve".to_string(),
246 "Security considerations".to_string(),
247 ],
248 alternatives: vec!["Podman".to_string(), "containerd".to_string()],
249 },
250 TechRecommendation {
251 technology: "Kubernetes".to_string(),
252 domain: "devops".to_string(),
253 use_cases: vec![
254 "Container orchestration".to_string(),
255 "Microservices".to_string(),
256 "High availability".to_string(),
257 ],
258 pros: vec![
259 "Powerful orchestration".to_string(),
260 "Auto-scaling".to_string(),
261 "Self-healing".to_string(),
262 ],
263 cons: vec![
264 "Complex setup".to_string(),
265 "Steep learning curve".to_string(),
266 "Operational overhead".to_string(),
267 ],
268 alternatives: vec!["Docker Swarm".to_string(), "AWS ECS".to_string()],
269 },
270 TechRecommendation {
271 technology: "Prometheus".to_string(),
272 domain: "devops".to_string(),
273 use_cases: vec![
274 "Metrics collection".to_string(),
275 "Monitoring".to_string(),
276 "Alerting".to_string(),
277 ],
278 pros: vec![
279 "Time-series database".to_string(),
280 "Powerful query language".to_string(),
281 "Easy to set up".to_string(),
282 ],
283 cons: vec![
284 "Limited long-term storage".to_string(),
285 "Requires additional tools".to_string(),
286 ],
287 alternatives: vec!["Grafana Loki".to_string(), "InfluxDB".to_string()],
288 },
289 TechRecommendation {
290 technology: "Grafana".to_string(),
291 domain: "devops".to_string(),
292 use_cases: vec![
293 "Metrics visualization".to_string(),
294 "Dashboards".to_string(),
295 "Alerting".to_string(),
296 ],
297 pros: vec![
298 "Beautiful dashboards".to_string(),
299 "Multiple data sources".to_string(),
300 "Easy to use".to_string(),
301 ],
302 cons: vec![
303 "Requires data source".to_string(),
304 "Learning curve for advanced features".to_string(),
305 ],
306 alternatives: vec!["Kibana".to_string(), "Datadog".to_string()],
307 },
308 TechRecommendation {
309 technology: "ELK Stack".to_string(),
310 domain: "devops".to_string(),
311 use_cases: vec![
312 "Log aggregation".to_string(),
313 "Log analysis".to_string(),
314 "Centralized logging".to_string(),
315 ],
316 pros: vec![
317 "Powerful search".to_string(),
318 "Scalable".to_string(),
319 "Open source".to_string(),
320 ],
321 cons: vec![
322 "Complex setup".to_string(),
323 "Resource intensive".to_string(),
324 "Operational overhead".to_string(),
325 ],
326 alternatives: vec!["Splunk".to_string(), "Datadog".to_string()],
327 },
328 TechRecommendation {
329 technology: "Trivy".to_string(),
330 domain: "devops".to_string(),
331 use_cases: vec![
332 "Vulnerability scanning".to_string(),
333 "Container scanning".to_string(),
334 "CI/CD integration".to_string(),
335 ],
336 pros: vec![
337 "Fast scanning".to_string(),
338 "Easy to use".to_string(),
339 "Comprehensive database".to_string(),
340 ],
341 cons: vec![
342 "False positives".to_string(),
343 "Limited remediation guidance".to_string(),
344 ],
345 alternatives: vec!["Snyk".to_string(), "Grype".to_string()],
346 },
347 TechRecommendation {
348 technology: "Snyk".to_string(),
349 domain: "devops".to_string(),
350 use_cases: vec![
351 "Vulnerability management".to_string(),
352 "Dependency scanning".to_string(),
353 "Container scanning".to_string(),
354 ],
355 pros: vec![
356 "Developer-friendly".to_string(),
357 "Remediation guidance".to_string(),
358 "Multiple scanning types".to_string(),
359 ],
360 cons: vec![
361 "Paid service".to_string(),
362 "Limited free tier".to_string(),
363 ],
364 alternatives: vec!["Trivy".to_string(), "Dependabot".to_string()],
365 },
366 TechRecommendation {
367 technology: "SonarQube".to_string(),
368 domain: "devops".to_string(),
369 use_cases: vec![
370 "Code quality analysis".to_string(),
371 "Security scanning".to_string(),
372 "Technical debt tracking".to_string(),
373 ],
374 pros: vec![
375 "Comprehensive analysis".to_string(),
376 "Multiple languages".to_string(),
377 "Good reporting".to_string(),
378 ],
379 cons: vec![
380 "Complex setup".to_string(),
381 "Resource intensive".to_string(),
382 "Expensive for large teams".to_string(),
383 ],
384 alternatives: vec!["CodeClimate".to_string(), "Codacy".to_string()],
385 },
386 ],
387 patterns: vec![],
388 anti_patterns: vec![],
389 };
390
391 let domain_agent = DomainAgent {
392 id: "devops-agent".to_string(),
393 domain: "devops".to_string(),
394 capabilities,
395 knowledge,
396 };
397
398 DevOpsAgent { domain_agent }
399 }
400
401 pub fn domain(&self) -> &str {
403 &self.domain_agent.domain
404 }
405
406 pub fn capabilities(&self) -> &[DomainCapability] {
408 &self.domain_agent.capabilities
409 }
410
411 pub fn knowledge(&self) -> &DomainKnowledge {
413 &self.domain_agent.knowledge
414 }
415
416 pub fn domain_agent(&self) -> &DomainAgent {
418 &self.domain_agent
419 }
420}
421
422impl Default for DevOpsAgent {
423 fn default() -> Self {
424 Self::new()
425 }
426}
427
428#[async_trait]
429impl Agent for DevOpsAgent {
430 fn id(&self) -> &str {
431 &self.domain_agent.id
432 }
433
434 fn name(&self) -> &str {
435 "DevOps Agent"
436 }
437
438 fn description(&self) -> &str {
439 "Specialized agent for DevOps with expertise in CI/CD pipelines, Infrastructure as Code, containerization, observability, security scanning, and auto-scaling"
440 }
441
442 fn supports(&self, task_type: TaskType) -> bool {
443 matches!(
445 task_type,
446 TaskType::CodeReview
447 | TaskType::Refactoring
448 | TaskType::Documentation
449 | TaskType::SecurityAnalysis
450 )
451 }
452
453 async fn execute(&self, input: AgentInput) -> Result<AgentOutput> {
454 let mut output = AgentOutput::default();
457
458 match input.task.task_type {
460 TaskType::CodeReview => {
461 output.findings.push(Finding {
462 id: Uuid::new_v4().to_string(),
463 severity: Severity::Info,
464 category: "devops-best-practices".to_string(),
465 message: "DevOps best practices applied".to_string(),
466 location: None,
467 suggestion: None,
468 });
469 }
470 _ => {}
471 }
472
473 Ok(output)
474 }
475}
476
477#[cfg(test)]
478mod tests {
479 use super::*;
480
481 #[test]
482 fn test_devops_agent_creation() {
483 let agent = DevOpsAgent::new();
484 assert_eq!(agent.id(), "devops-agent");
485 assert_eq!(agent.domain(), "devops");
486 assert_eq!(agent.name(), "DevOps Agent");
487 }
488
489 #[test]
490 fn test_devops_agent_capabilities() {
491 let agent = DevOpsAgent::new();
492 let capabilities = agent.capabilities();
493 assert_eq!(capabilities.len(), 6);
494
495 assert_eq!(capabilities[0].name, "CI/CD Pipeline Setup");
497 assert_eq!(capabilities[0].technologies.len(), 3);
498 assert!(capabilities[0]
499 .technologies
500 .contains(&"GitHub Actions".to_string()));
501 assert!(capabilities[0]
502 .technologies
503 .contains(&"GitLab CI".to_string()));
504 assert!(capabilities[0]
505 .technologies
506 .contains(&"Jenkins".to_string()));
507 }
508
509 #[test]
510 fn test_devops_agent_knowledge() {
511 let agent = DevOpsAgent::new();
512 let knowledge = agent.knowledge();
513 assert!(!knowledge.technology_recommendations.is_empty());
514 assert_eq!(knowledge.technology_recommendations.len(), 14);
515 }
516
517 #[test]
518 fn test_devops_agent_technology_recommendations() {
519 let agent = DevOpsAgent::new();
520 let knowledge = agent.knowledge();
521
522 let k8s_rec = knowledge
524 .technology_recommendations
525 .iter()
526 .find(|r| r.technology == "Kubernetes")
527 .expect("Kubernetes recommendation not found");
528
529 assert_eq!(k8s_rec.domain, "devops");
530 assert!(!k8s_rec.use_cases.is_empty());
531 assert!(!k8s_rec.pros.is_empty());
532 assert!(!k8s_rec.cons.is_empty());
533 assert!(!k8s_rec.alternatives.is_empty());
534 }
535
536 #[test]
537 fn test_devops_agent_supports_task_types() {
538 let agent = DevOpsAgent::new();
539 assert!(agent.supports(TaskType::CodeReview));
540 assert!(agent.supports(TaskType::Refactoring));
541 assert!(agent.supports(TaskType::Documentation));
542 assert!(agent.supports(TaskType::SecurityAnalysis));
543 assert!(!agent.supports(TaskType::TestGeneration));
544 }
545
546 #[test]
547 fn test_devops_agent_default() {
548 let agent1 = DevOpsAgent::new();
549 let agent2 = DevOpsAgent::default();
550 assert_eq!(agent1.id(), agent2.id());
551 assert_eq!(agent1.domain(), agent2.domain());
552 }
553
554 #[test]
555 fn test_devops_agent_clone() {
556 let agent1 = DevOpsAgent::new();
557 let agent2 = agent1.clone();
558 assert_eq!(agent1.id(), agent2.id());
559 assert_eq!(agent1.domain(), agent2.domain());
560 assert_eq!(agent1.capabilities().len(), agent2.capabilities().len());
561 }
562
563 #[test]
564 fn test_devops_agent_all_cicd_tools_present() {
565 let agent = DevOpsAgent::new();
566 let knowledge = agent.knowledge();
567
568 let cicd_tools = vec!["GitHub Actions", "GitLab CI", "Jenkins"];
569 for tool in cicd_tools {
570 let found = knowledge
571 .technology_recommendations
572 .iter()
573 .any(|r| r.technology == tool);
574 assert!(found, "CI/CD tool {} not found in recommendations", tool);
575 }
576 }
577
578 #[test]
579 fn test_devops_agent_all_iac_tools_present() {
580 let agent = DevOpsAgent::new();
581 let knowledge = agent.knowledge();
582
583 let iac_tools = vec!["Terraform", "CloudFormation", "Ansible"];
584 for tool in iac_tools {
585 let found = knowledge
586 .technology_recommendations
587 .iter()
588 .any(|r| r.technology == tool);
589 assert!(found, "IaC tool {} not found in recommendations", tool);
590 }
591 }
592
593 #[test]
594 fn test_devops_agent_all_container_tools_present() {
595 let agent = DevOpsAgent::new();
596 let knowledge = agent.knowledge();
597
598 let container_tools = vec!["Docker", "Kubernetes"];
599 for tool in container_tools {
600 let found = knowledge
601 .technology_recommendations
602 .iter()
603 .any(|r| r.technology == tool);
604 assert!(found, "Container tool {} not found in recommendations", tool);
605 }
606 }
607
608 #[test]
609 fn test_devops_agent_all_observability_tools_present() {
610 let agent = DevOpsAgent::new();
611 let knowledge = agent.knowledge();
612
613 let observability_tools = vec!["Prometheus", "Grafana", "ELK Stack"];
614 for tool in observability_tools {
615 let found = knowledge
616 .technology_recommendations
617 .iter()
618 .any(|r| r.technology == tool);
619 assert!(
620 found,
621 "Observability tool {} not found in recommendations",
622 tool
623 );
624 }
625 }
626
627 #[test]
628 fn test_devops_agent_all_security_tools_present() {
629 let agent = DevOpsAgent::new();
630 let knowledge = agent.knowledge();
631
632 let security_tools = vec!["Trivy", "Snyk", "SonarQube"];
633 for tool in security_tools {
634 let found = knowledge
635 .technology_recommendations
636 .iter()
637 .any(|r| r.technology == tool);
638 assert!(found, "Security tool {} not found in recommendations", tool);
639 }
640 }
641
642 #[test]
643 fn test_devops_agent_terraform_alternatives() {
644 let agent = DevOpsAgent::new();
645 let knowledge = agent.knowledge();
646
647 let terraform_rec = knowledge
648 .technology_recommendations
649 .iter()
650 .find(|r| r.technology == "Terraform")
651 .expect("Terraform recommendation not found");
652
653 assert!(terraform_rec
654 .alternatives
655 .contains(&"CloudFormation".to_string()));
656 assert!(terraform_rec
657 .alternatives
658 .contains(&"Ansible".to_string()));
659 }
660
661 #[test]
662 fn test_devops_agent_kubernetes_alternatives() {
663 let agent = DevOpsAgent::new();
664 let knowledge = agent.knowledge();
665
666 let k8s_rec = knowledge
667 .technology_recommendations
668 .iter()
669 .find(|r| r.technology == "Kubernetes")
670 .expect("Kubernetes recommendation not found");
671
672 assert!(k8s_rec
673 .alternatives
674 .contains(&"Docker Swarm".to_string()));
675 assert!(k8s_rec.alternatives.contains(&"AWS ECS".to_string()));
676 }
677
678 #[test]
679 fn test_devops_agent_github_actions_alternatives() {
680 let agent = DevOpsAgent::new();
681 let knowledge = agent.knowledge();
682
683 let github_rec = knowledge
684 .technology_recommendations
685 .iter()
686 .find(|r| r.technology == "GitHub Actions")
687 .expect("GitHub Actions recommendation not found");
688
689 assert!(github_rec
690 .alternatives
691 .contains(&"GitLab CI".to_string()));
692 assert!(github_rec.alternatives.contains(&"Jenkins".to_string()));
693 }
694
695 #[tokio::test]
696 async fn test_devops_agent_execute() {
697 use crate::models::{
698 AgentConfig, AgentTask, ProjectContext, TaskOptions, TaskScope, TaskTarget,
699 };
700 use std::path::PathBuf;
701
702 let agent = DevOpsAgent::new();
703 let input = AgentInput {
704 task: AgentTask {
705 id: "task-1".to_string(),
706 task_type: TaskType::CodeReview,
707 target: TaskTarget {
708 files: vec![PathBuf::from("Dockerfile")],
709 scope: TaskScope::File,
710 },
711 options: TaskOptions::default(),
712 },
713 context: ProjectContext {
714 name: "devops-project".to_string(),
715 root: PathBuf::from("/tmp/devops-project"),
716 },
717 config: AgentConfig::default(),
718 };
719
720 let result = agent.execute(input).await;
721 assert!(result.is_ok());
722
723 let output = result.unwrap();
724 assert!(!output.findings.is_empty());
725 }
726}