ricecoder_agents/agents/
devops.rs

1//! DevOps Agent
2//!
3//! This module provides a specialized agent for DevOps tasks,
4//! including CI/CD pipeline recommendations, Infrastructure as Code guidance,
5//! containerization recommendations, observability infrastructure guidance,
6//! security scanning setup recommendations, and auto-scaling configuration guidance.
7
8use 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/// DevOps Agent
16///
17/// A specialized agent for DevOps that provides recommendations for:
18/// - CI/CD pipeline setup (GitHub Actions, GitLab CI, Jenkins)
19/// - Infrastructure as Code (Terraform, CloudFormation, Ansible)
20/// - Containerization (Docker, Kubernetes)
21/// - Observability infrastructure (monitoring, logging, alerting)
22/// - Security scanning setup
23/// - Auto-scaling configuration
24///
25/// # Examples
26///
27/// ```ignore
28/// use ricecoder_agents::agents::DevOpsAgent;
29///
30/// let agent = DevOpsAgent::new();
31/// assert_eq!(agent.id(), "devops-agent");
32/// assert_eq!(agent.domain(), "devops");
33/// ```
34#[derive(Debug, Clone)]
35pub struct DevOpsAgent {
36    domain_agent: DomainAgent,
37}
38
39impl DevOpsAgent {
40    /// Create a new DevOps Agent
41    ///
42    /// Initializes the agent with DevOps-specific capabilities and knowledge.
43    ///
44    /// # Returns
45    ///
46    /// A new `DevOpsAgent` instance
47    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    /// Get the domain of this agent
402    pub fn domain(&self) -> &str {
403        &self.domain_agent.domain
404    }
405
406    /// Get the capabilities of this agent
407    pub fn capabilities(&self) -> &[DomainCapability] {
408        &self.domain_agent.capabilities
409    }
410
411    /// Get the knowledge of this agent
412    pub fn knowledge(&self) -> &DomainKnowledge {
413        &self.domain_agent.knowledge
414    }
415
416    /// Get the underlying domain agent
417    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        // DevOps agent supports code review and other DevOps-related tasks
444        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        // For now, return a basic output
455        // This will be enhanced with actual DevOps-specific logic
456        let mut output = AgentOutput::default();
457
458        // Add findings based on the task type
459        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        // Check first capability
496        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        // Check Kubernetes recommendation
523        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}