tfmcp/terraform/
model.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Serialize, Deserialize)]
4pub struct TerraformAnalysis {
5    pub project_directory: String,
6    pub file_count: usize,
7    pub resources: Vec<TerraformResource>,
8    pub variables: Vec<TerraformVariable>,
9    pub outputs: Vec<TerraformOutput>,
10    pub providers: Vec<TerraformProvider>,
11}
12
13#[derive(Debug, Serialize, Deserialize)]
14pub struct TerraformResource {
15    pub resource_type: String,
16    pub name: String,
17    pub file: String,
18    pub provider: String,
19}
20
21#[derive(Debug, Serialize, Deserialize)]
22#[allow(dead_code)]
23pub struct TerraformPlan {
24    pub changes: TerraformChanges,
25    pub raw_output: String,
26}
27
28#[derive(Debug, Serialize, Deserialize)]
29#[allow(dead_code)]
30pub struct TerraformChanges {
31    pub add: usize,
32    pub change: usize,
33    pub destroy: usize,
34}
35
36#[derive(Debug, Serialize, Deserialize)]
37#[allow(dead_code)]
38pub struct TerraformState {
39    pub resources: Vec<TerraformStateResource>,
40    pub version: String,
41}
42
43#[derive(Debug, Serialize, Deserialize)]
44#[allow(dead_code)]
45pub struct TerraformStateResource {
46    pub name: String,
47    pub type_: String,
48    pub provider: String,
49    pub instances: Vec<TerraformResourceInstance>,
50}
51
52#[derive(Debug, Serialize, Deserialize)]
53#[allow(dead_code)]
54pub struct TerraformResourceInstance {
55    pub id: String,
56    pub attributes: serde_json::Value,
57}
58
59#[derive(Debug, Serialize, Deserialize, Clone)]
60pub struct TerraformValidateOutput {
61    pub valid: bool,
62    pub error_count: i32,
63    pub warning_count: i32,
64    pub diagnostics: Vec<TerraformDiagnostic>,
65}
66
67#[derive(Debug, Serialize, Deserialize, Clone)]
68pub struct TerraformDiagnostic {
69    pub severity: String,
70    pub summary: String,
71    pub detail: Option<String>,
72    pub range: Option<DiagnosticRange>,
73}
74
75#[derive(Debug, Serialize, Deserialize, Clone)]
76pub struct DiagnosticRange {
77    pub filename: String,
78    pub start: Position,
79    pub end: Position,
80}
81
82#[derive(Debug, Serialize, Deserialize, Clone)]
83pub struct Position {
84    pub line: i32,
85    pub column: i32,
86    pub byte: i32,
87}
88
89#[derive(Debug, Serialize, Deserialize)]
90pub struct DetailedValidationResult {
91    pub valid: bool,
92    pub error_count: i32,
93    pub warning_count: i32,
94    pub diagnostics: Vec<TerraformDiagnostic>,
95    pub additional_warnings: Vec<String>,
96    pub suggestions: Vec<String>,
97    pub checked_files: usize,
98    /// Future Architect guideline compliance checks
99    pub guideline_checks: Option<GuidelineCheckResult>,
100}
101
102/// Results from Future Architect Terraform guideline compliance checks
103#[derive(Debug, Serialize, Deserialize, Default)]
104pub struct GuidelineCheckResult {
105    /// Overall compliance score (0-100)
106    pub compliance_score: u8,
107    /// Variables missing type definition
108    pub variables_missing_type: Vec<String>,
109    /// Variables missing description
110    pub variables_missing_description: Vec<String>,
111    /// Outputs missing description
112    pub outputs_missing_description: Vec<String>,
113    /// Resources using count instead of for_each (not for 0/1 toggle)
114    pub count_instead_of_foreach: Vec<CountUsageWarning>,
115    /// Variables using 'any' type (discouraged)
116    pub any_type_usage: Vec<String>,
117    /// Providers missing version constraint
118    pub providers_missing_version: Vec<String>,
119    /// Resources missing default_tags (AWS)
120    pub missing_default_tags: bool,
121    /// Detected hardcoded secrets
122    pub hardcoded_secrets: Vec<SecretDetection>,
123    /// Resources missing lifecycle prevent_destroy for critical resources
124    pub missing_lifecycle_protection: Vec<String>,
125}
126
127/// Warning for count usage that should be for_each
128#[derive(Debug, Serialize, Deserialize)]
129pub struct CountUsageWarning {
130    pub resource_name: String,
131    pub resource_type: String,
132    pub suggestion: String,
133}
134
135/// Detected potential secret in code
136#[derive(Debug, Serialize, Deserialize)]
137pub struct SecretDetection {
138    pub file: String,
139    pub line: usize,
140    pub pattern: String,
141    pub severity: String,
142}
143
144#[derive(Debug, Serialize, Deserialize)]
145pub struct TerraformVariable {
146    pub name: String,
147    pub description: Option<String>,
148    pub type_: Option<String>,
149    pub default: Option<serde_json::Value>,
150}
151
152#[derive(Debug, Serialize, Deserialize)]
153pub struct TerraformOutput {
154    pub name: String,
155    pub description: Option<String>,
156    pub value: Option<serde_json::Value>,
157}
158
159#[derive(Debug, Serialize, Deserialize)]
160pub struct TerraformProvider {
161    pub name: String,
162    pub version: Option<String>,
163}
164
165// ==================== Module Health Analysis Models ====================
166// Based on the whitebox approach to Infrastructure as Code
167// Reference: "インフラコードはホワイトボックス的利用が必要"
168
169/// Module health analysis result
170#[derive(Debug, Serialize, Deserialize)]
171pub struct ModuleHealthAnalysis {
172    pub module_path: String,
173    pub metrics: ModuleMetrics,
174    pub health_score: u8, // 0-100
175    pub issues: Vec<ModuleIssue>,
176    pub recommendations: Vec<String>,
177    pub cohesion_analysis: CohesionAnalysis,
178    pub coupling_analysis: CouplingAnalysis,
179}
180
181/// Quantitative metrics for module analysis
182#[derive(Debug, Serialize, Deserialize)]
183pub struct ModuleMetrics {
184    pub variable_count: usize,
185    pub output_count: usize,
186    pub resource_count: usize,
187    pub resource_type_count: usize, // Number of distinct resource types
188    pub provider_count: usize,
189    pub data_source_count: usize,
190    pub local_count: usize,
191    pub module_call_count: usize, // Number of module blocks
192    pub file_count: usize,
193    pub lines_of_code: usize,
194    pub hierarchy_depth: usize, // Depth of nested modules
195    pub variables_with_defaults: usize,
196    pub variables_without_description: usize,
197}
198
199/// Issue severity levels
200#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
201pub enum IssueSeverity {
202    Critical,
203    Warning,
204    Info,
205}
206
207/// Module issue detected during analysis
208#[derive(Debug, Serialize, Deserialize)]
209pub struct ModuleIssue {
210    pub severity: IssueSeverity,
211    pub category: IssueCategory,
212    pub message: String,
213    pub file: Option<String>,
214    pub line: Option<usize>,
215}
216
217/// Categories of module issues
218#[derive(Debug, Clone, Serialize, Deserialize)]
219pub enum IssueCategory {
220    LogicalCohesion,      // Too many unrelated resource types
221    ExcessiveVariables,   // Too many variables exposed
222    DeepHierarchy,        // Too many nested module levels
223    MissingDocumentation, // Variables/outputs without descriptions
224    ControlCoupling,      // Excessive conditional logic
225    ModelCoupling,        // Internal model exposed through variables
226    NamingConvention,     // Poor file/resource naming
227    PublicModuleRisk,     // Using public registry modules without wrappers
228}
229
230/// Cohesion type analysis (based on software engineering principles)
231#[derive(Debug, Serialize, Deserialize)]
232pub struct CohesionAnalysis {
233    pub cohesion_type: CohesionType,
234    pub score: u8, // 0-100, higher is better
235    pub resource_type_groups: Vec<ResourceTypeGroup>,
236    pub explanation: String,
237}
238
239/// Types of module cohesion
240#[derive(Debug, Clone, Serialize, Deserialize)]
241pub enum CohesionType {
242    Functional,      // Best: Single, well-defined purpose
243    Sequential,      // Good: Output of one feeds into another
244    Communicational, // OK: Operates on same data
245    Procedural,      // Weak: Steps that must happen in order
246    Temporal,        // Weak: Things that happen at the same time
247    Logical,         // Poor: Only related by category (e.g., "network things")
248    Coincidental,    // Worst: No meaningful relationship
249}
250
251/// Group of related resource types
252#[derive(Debug, Serialize, Deserialize)]
253pub struct ResourceTypeGroup {
254    pub name: String,
255    pub resource_types: Vec<String>,
256    pub resource_count: usize,
257}
258
259/// Coupling analysis between modules
260#[derive(Debug, Serialize, Deserialize)]
261pub struct CouplingAnalysis {
262    pub coupling_type: CouplingType,
263    pub score: u8, // 0-100, lower coupling is better
264    pub dependencies: Vec<ModuleDependency>,
265    pub explanation: String,
266}
267
268/// Types of module coupling
269#[derive(Debug, Clone, Serialize, Deserialize)]
270pub enum CouplingType {
271    Data,    // Best: Only data passed between modules
272    Stamp,   // OK: Structured data passed
273    Control, // Poor: Flags/conditionals control behavior
274    Common,  // Poor: Shared global data
275    Content, // Worst: One module modifies another's internal data
276}
277
278/// Dependency information between modules
279#[derive(Debug, Serialize, Deserialize)]
280pub struct ModuleDependency {
281    pub source_module: String,
282    pub target_module: String,
283    pub dependency_type: String,
284    pub variables_passed: Vec<String>,
285}
286
287/// Resource dependency graph for visualization
288#[derive(Debug, Serialize, Deserialize)]
289pub struct ResourceDependencyGraph {
290    pub nodes: Vec<ResourceNode>,
291    pub edges: Vec<ResourceEdge>,
292    pub module_boundaries: Vec<ModuleBoundary>,
293}
294
295/// A node in the resource dependency graph
296#[derive(Debug, Serialize, Deserialize)]
297pub struct ResourceNode {
298    pub id: String,
299    pub resource_type: String,
300    pub resource_name: String,
301    pub module_path: String,
302    pub file: String,
303    pub provider: String,
304}
305
306/// An edge in the resource dependency graph
307#[derive(Debug, Serialize, Deserialize)]
308pub struct ResourceEdge {
309    pub source: String,
310    pub target: String,
311    pub dependency_type: DependencyType,
312    pub attribute: Option<String>,
313}
314
315/// Types of resource dependencies
316#[derive(Debug, Clone, Serialize, Deserialize)]
317pub enum DependencyType {
318    Explicit,     // depends_on
319    Implicit,     // Reference to another resource
320    DataSource,   // Data source reference
321    ModuleOutput, // Reference to module output
322}
323
324/// Module boundary for visualization
325#[derive(Debug, Serialize, Deserialize)]
326pub struct ModuleBoundary {
327    pub module_path: String,
328    pub resource_ids: Vec<String>,
329}
330
331/// Refactoring suggestion
332#[derive(Debug, Serialize, Deserialize)]
333pub struct RefactoringSuggestion {
334    pub suggestion_type: RefactoringType,
335    pub priority: IssueSeverity,
336    pub description: String,
337    pub affected_resources: Vec<String>,
338    pub proposed_structure: Option<ProposedModuleStructure>,
339    pub migration_steps: Vec<String>,
340}
341
342/// Types of refactoring suggestions
343#[derive(Debug, Clone, Serialize, Deserialize)]
344pub enum RefactoringType {
345    SplitModule,           // Extract resources to new module
346    MergeModules,          // Combine small modules
347    ExtractSubmodule,      // Create submodule for related resources
348    FlattenHierarchy,      // Reduce nesting depth
349    WrapPublicModule,      // Create wrapper for public module
350    RemoveUnusedVariables, // Clean up unused inputs
351    AddDescriptions,       // Document variables/outputs
352}
353
354/// Proposed new module structure
355#[derive(Debug, Serialize, Deserialize)]
356pub struct ProposedModuleStructure {
357    pub module_name: String,
358    pub resources: Vec<String>,
359    pub variables: Vec<String>,
360    pub outputs: Vec<String>,
361}