Skip to main content

rules/
registry.rs

1use crate::category::Category;
2use crate::severity::Severity;
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5use std::fmt;
6use std::sync::LazyLock;
7
8/// Static definition of a validation rule in the registry.
9#[derive(Debug, Clone)]
10pub struct RuleDefinition {
11    pub id: &'static str,
12    pub category: Category,
13    pub description: &'static str,
14    pub origin: RuleOrigin,
15}
16
17/// Metadata describing a validation rule.
18#[derive(Debug, Clone, Serialize, Deserialize)]
19#[cfg_attr(feature = "wasm-bindings", derive(tsify::Tsify))]
20#[cfg_attr(feature = "uniffi-bindings", derive(uniffi::Record))]
21#[serde(rename_all = "camelCase")]
22pub struct RuleInfo {
23    pub id: String,
24    pub severity: Severity,
25    #[serde(default, skip_serializing_if = "Option::is_none")]
26    #[cfg_attr(feature = "uniffi-bindings", uniffi(default))]
27    pub category: Option<String>,
28    pub description: String,
29    pub origin: RuleOrigin,
30}
31
32/// Where a rule's logic originates.
33#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Hash)]
34#[cfg_attr(feature = "wasm-bindings", derive(tsify::Tsify))]
35#[cfg_attr(feature = "uniffi-bindings", derive(uniffi::Enum))]
36#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
37pub enum RuleOrigin {
38    /// From CloudFormation's own definitions: the resource provider schemas or
39    /// the template language's structural/syntax/shape rules - anything
40    /// CloudFormation itself rejects, regardless of whether cfn-lint also
41    /// implements the check
42    Schema,
43    /// Lint judgment ported from cfn-lint
44    CfnLint,
45    /// Implemented in this validation engine
46    Engine,
47    /// User supplied custom rule
48    Custom,
49    /// User supplied CloudFormation Guard rule
50    Guard,
51}
52
53impl RuleOrigin {
54    pub const fn as_str(&self) -> &'static str {
55        match self {
56            RuleOrigin::Schema => "SCHEMA",
57            RuleOrigin::CfnLint => "CFN_LINT",
58            RuleOrigin::Engine => "ENGINE",
59            RuleOrigin::Custom => "CUSTOM",
60            RuleOrigin::Guard => "GUARD",
61        }
62    }
63}
64
65impl fmt::Display for RuleOrigin {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        f.write_str(self.as_str())
68    }
69}
70
71impl RuleDefinition {
72    /// Derive severity from the first character of the rule ID.
73    /// Panics if the rule ID is empty - every registered rule must have a valid ID.
74    pub fn severity(&self) -> Severity {
75        let prefix = self.id.chars().next().unwrap_or_else(|| panic!("RuleDefinition has empty ID"));
76        Severity::from_prefix(prefix)
77    }
78
79    pub fn to_rule_info(&self) -> RuleInfo {
80        RuleInfo::from(self)
81    }
82}
83
84impl From<&RuleDefinition> for RuleInfo {
85    fn from(rule: &RuleDefinition) -> Self {
86        RuleInfo {
87            id: rule.id.to_string(),
88            severity: rule.severity(),
89            category: Some(rule.category.as_str().into()),
90            description: rule.description.to_string(),
91            origin: rule.origin,
92        }
93    }
94}
95
96/// Owned metadata for a single rule, used in engine metadata maps.
97#[derive(Debug, Clone, PartialEq)]
98pub struct RuleMetadataEntry {
99    pub category: Option<String>,
100    pub description: String,
101    pub severity: Severity,
102    pub origin: RuleOrigin,
103}
104
105/// Index keyed by rule ID over [`RULE_REGISTRY`] for O(1) lookups. The
106/// schema validator routes every fatal/error/warn/info diagnostic through
107/// [`lookup_rule`] via the shared `RegisteredDiagnostic` builder, so a per-
108/// diagnostic linear scan over so many rules turned construction from O(N) into
109/// O(N × R). The registry is `&'static`, so the index borrows directly.
110static RULE_REGISTRY_BY_ID: LazyLock<HashMap<&'static str, &'static RuleDefinition>> =
111    LazyLock::new(|| RULE_REGISTRY.iter().map(|r| (r.id, r)).collect());
112
113/// Find a rule definition by its ID, or `None` if not registered.
114pub fn lookup_rule(id: &str) -> Option<&'static RuleDefinition> {
115    RULE_REGISTRY_BY_ID.get(id).copied()
116}
117
118/// Build a map of rule ID → metadata for all registered rules.
119pub fn build_rule_metadata_map() -> HashMap<String, RuleMetadataEntry> {
120    RULE_REGISTRY
121        .iter()
122        .map(|r| {
123            (
124                r.id.to_string(),
125                RuleMetadataEntry {
126                    category: Some(r.category.as_str().into()),
127                    description: r.description.to_string(),
128                    severity: r.severity(),
129                    origin: r.origin,
130                },
131            )
132        })
133        .collect()
134}
135
136pub const RULE_REGISTRY: &[RuleDefinition] = &[
137    RuleDefinition {
138        id: "F0000",
139        category: Category::Structure,
140        description: "Duplicate key in template",
141        origin: RuleOrigin::Schema,
142    },
143    RuleDefinition {
144        id: "F0001",
145        category: Category::Structure,
146        description: "Resources section must exist and be non-empty",
147        origin: RuleOrigin::Schema,
148    },
149    RuleDefinition {
150        id: "E0001",
151        category: Category::Structure,
152        description: "SAM (AWS::Serverless) transform would reject the template",
153        origin: RuleOrigin::CfnLint,
154    },
155    RuleDefinition {
156        id: "F0002",
157        category: Category::Structure,
158        description: "AWSTemplateFormatVersion must be 2010-09-09",
159        origin: RuleOrigin::Schema,
160    },
161    RuleDefinition {
162        id: "F0003",
163        category: Category::Structure,
164        description: "Maximum 200 parameters",
165        origin: RuleOrigin::Schema,
166    },
167    RuleDefinition {
168        id: "F0004",
169        category: Category::Structure,
170        description: "Maximum 200 outputs",
171        origin: RuleOrigin::Schema,
172    },
173    RuleDefinition {
174        id: "F0005",
175        category: Category::Structure,
176        description: "Top-level keys must be valid section names",
177        origin: RuleOrigin::Schema,
178    },
179    RuleDefinition {
180        id: "F0006",
181        category: Category::Structure,
182        description: "Logical IDs must be alphanumeric",
183        origin: RuleOrigin::Schema,
184    },
185    RuleDefinition {
186        id: "F0007",
187        category: Category::Structure,
188        description: "Maximum 500 resources",
189        origin: RuleOrigin::Schema,
190    },
191    RuleDefinition {
192        id: "F0008",
193        category: Category::Structure,
194        description: "Maximum 200 mappings",
195        origin: RuleOrigin::Schema,
196    },
197    RuleDefinition {
198        id: "F0009",
199        category: Category::Structure,
200        description: "Maximum 200 conditions",
201        origin: RuleOrigin::Schema,
202    },
203    RuleDefinition {
204        id: "F0010",
205        category: Category::Intrinsic,
206        description: "Fn::Sub second argument must be a map",
207        origin: RuleOrigin::Schema,
208    },
209    RuleDefinition {
210        id: "F0011",
211        category: Category::Structure,
212        description: "Description exceeds maximum 1024 characters",
213        origin: RuleOrigin::Schema,
214    },
215    RuleDefinition {
216        id: "F0013",
217        category: Category::Intrinsic,
218        description: "Fn::If must have exactly 3 elements",
219        origin: RuleOrigin::Schema,
220    },
221    RuleDefinition {
222        id: "F0014",
223        category: Category::Intrinsic,
224        description: "Boolean condition function (Fn::Equals/Fn::And/Fn::Or/Fn::Not) has invalid structure",
225        origin: RuleOrigin::Schema,
226    },
227    RuleDefinition {
228        id: "F0015",
229        category: Category::Parameter,
230        description: "Default value must match parameter Type",
231        origin: RuleOrigin::Schema,
232    },
233    RuleDefinition {
234        id: "F0016",
235        category: Category::Parameter,
236        description: "AllowedValues entries must match parameter Type",
237        origin: RuleOrigin::Schema,
238    },
239    RuleDefinition {
240        id: "F0017",
241        category: Category::Structure,
242        description: "Mapping level must be a map",
243        origin: RuleOrigin::Schema,
244    },
245    RuleDefinition {
246        id: "F1004",
247        category: Category::Structure,
248        description: "Description must be a string",
249        origin: RuleOrigin::Schema,
250    },
251    RuleDefinition {
252        id: "F0040",
253        category: Category::Structure,
254        description: "Output must have Value property",
255        origin: RuleOrigin::Schema,
256    },
257    RuleDefinition {
258        id: "F0050",
259        category: Category::Structure,
260        description: "Mapping must have valid 3-level structure",
261        origin: RuleOrigin::Schema,
262    },
263    RuleDefinition {
264        id: "E2001",
265        category: Category::Parameter,
266        description: "Parameters have appropriate properties",
267        origin: RuleOrigin::CfnLint,
268    },
269    RuleDefinition {
270        id: "F2002",
271        category: Category::Parameter,
272        description: "Parameter Type must be valid",
273        origin: RuleOrigin::Schema,
274    },
275    RuleDefinition {
276        id: "F2003",
277        category: Category::Parameter,
278        description: "Parameter name must be alphanumeric",
279        origin: RuleOrigin::Schema,
280    },
281    RuleDefinition {
282        id: "F2011",
283        category: Category::Parameter,
284        description: "Parameter name exceeds maximum length",
285        origin: RuleOrigin::Schema,
286    },
287    RuleDefinition {
288        id: "F2012",
289        category: Category::Parameter,
290        description: "Parameter Default must be in AllowedValues",
291        origin: RuleOrigin::Schema,
292    },
293    RuleDefinition {
294        id: "F3007",
295        category: Category::Structure,
296        description: "Logical ID used as both parameter and resource",
297        origin: RuleOrigin::Schema,
298    },
299    RuleDefinition {
300        id: "F3016",
301        category: Category::Structure,
302        description: "DeletionPolicy must be valid",
303        origin: RuleOrigin::Schema,
304    },
305    RuleDefinition {
306        id: "F0018",
307        category: Category::Structure,
308        description: "UpdateReplacePolicy must be valid",
309        origin: RuleOrigin::Schema,
310    },
311    RuleDefinition {
312        id: "E3038",
313        category: Category::Structure,
314        description: "Check if Serverless Resources have Serverless Transform",
315        origin: RuleOrigin::CfnLint,
316    },
317    RuleDefinition {
318        id: "E5001",
319        category: Category::Structure,
320        description: "Check that Modules resources are valid",
321        origin: RuleOrigin::CfnLint,
322    },
323    RuleDefinition {
324        id: "F6004",
325        category: Category::Structure,
326        description: "Output name must be alphanumeric",
327        origin: RuleOrigin::Schema,
328    },
329    RuleDefinition {
330        id: "F6005",
331        category: Category::Structure,
332        description: "Output Export name validation",
333        origin: RuleOrigin::Schema,
334    },
335    RuleDefinition {
336        id: "F6011",
337        category: Category::Structure,
338        description: "Output name exceeds maximum length",
339        origin: RuleOrigin::Schema,
340    },
341    RuleDefinition {
342        id: "F6101",
343        category: Category::Structure,
344        description: "Output value must be a string",
345        origin: RuleOrigin::Schema,
346    },
347    RuleDefinition {
348        id: "F7002",
349        category: Category::Structure,
350        description: "Mapping name exceeds maximum length",
351        origin: RuleOrigin::Schema,
352    },
353    RuleDefinition {
354        id: "E8002",
355        category: Category::Structure,
356        description: "Condition referenced by resource is not defined",
357        origin: RuleOrigin::Schema,
358    },
359    RuleDefinition {
360        id: "I1003",
361        category: Category::Structure,
362        description: "Validate if we are approaching the max size of a description",
363        origin: RuleOrigin::CfnLint,
364    },
365    RuleDefinition {
366        id: "I2010",
367        category: Category::Structure,
368        description: "Parameter limit",
369        origin: RuleOrigin::CfnLint,
370    },
371    RuleDefinition {
372        id: "I2011",
373        category: Category::Structure,
374        description: "Parameter name limit",
375        origin: RuleOrigin::CfnLint,
376    },
377    RuleDefinition {
378        id: "I3012",
379        category: Category::Structure,
380        description: "Resource name limit",
381        origin: RuleOrigin::CfnLint,
382    },
383    RuleDefinition {
384        id: "I6010",
385        category: Category::Structure,
386        description: "Output limit",
387        origin: RuleOrigin::CfnLint,
388    },
389    RuleDefinition {
390        id: "I6011",
391        category: Category::Structure,
392        description: "Output name limit",
393        origin: RuleOrigin::CfnLint,
394    },
395    RuleDefinition {
396        id: "I7002",
397        category: Category::Structure,
398        description: "Mapping name limit",
399        origin: RuleOrigin::CfnLint,
400    },
401    RuleDefinition {
402        id: "I7010",
403        category: Category::Structure,
404        description: "Mapping limit",
405        origin: RuleOrigin::CfnLint,
406    },
407    RuleDefinition {
408        id: "W2001",
409        category: Category::BestPractice,
410        description: "Check if Parameters are Used",
411        origin: RuleOrigin::CfnLint,
412    },
413    RuleDefinition {
414        id: "W2002",
415        category: Category::BestPractice,
416        description: "Parameter type is not officially supported by CloudFormation",
417        origin: RuleOrigin::CfnLint,
418    },
419    RuleDefinition {
420        id: "W7001",
421        category: Category::BestPractice,
422        description: "Check if Mappings are Used",
423        origin: RuleOrigin::CfnLint,
424    },
425    RuleDefinition {
426        id: "E8001",
427        category: Category::Structure,
428        description: "Conditions section must have valid structure",
429        origin: RuleOrigin::Schema,
430    },
431    RuleDefinition {
432        id: "E8003",
433        category: Category::Intrinsic,
434        description: "Fn::Equals must take exactly two scalar operands",
435        origin: RuleOrigin::Schema,
436    },
437    RuleDefinition {
438        id: "E8004",
439        category: Category::Intrinsic,
440        description: "Fn::And must take between 2 and 10 boolean conditions",
441        origin: RuleOrigin::Schema,
442    },
443    RuleDefinition {
444        id: "E8005",
445        category: Category::Intrinsic,
446        description: "Fn::Not must take exactly one boolean condition",
447        origin: RuleOrigin::Schema,
448    },
449    RuleDefinition {
450        id: "E8006",
451        category: Category::Intrinsic,
452        description: "Fn::Or must take between 2 and 10 boolean conditions",
453        origin: RuleOrigin::Schema,
454    },
455    RuleDefinition {
456        id: "W8001",
457        category: Category::BestPractice,
458        description: "Check if Conditions are Used",
459        origin: RuleOrigin::CfnLint,
460    },
461    RuleDefinition {
462        id: "W8003",
463        category: Category::BestPractice,
464        description: "Fn::Equals will always return true or false",
465        origin: RuleOrigin::CfnLint,
466    },
467    RuleDefinition {
468        id: "E8007",
469        category: Category::Intrinsic,
470        description: "Condition function value must be a string referencing a defined condition",
471        origin: RuleOrigin::Schema,
472    },
473    RuleDefinition {
474        id: "F8600",
475        category: Category::Structure,
476        description: "Rules section must be an object",
477        origin: RuleOrigin::Schema,
478    },
479    RuleDefinition {
480        id: "F8601",
481        category: Category::Structure,
482        description: "Rule must be an object",
483        origin: RuleOrigin::Schema,
484    },
485    RuleDefinition {
486        id: "F8603",
487        category: Category::Structure,
488        description: "Rule missing required Assertions property",
489        origin: RuleOrigin::Schema,
490    },
491    RuleDefinition {
492        id: "F8604",
493        category: Category::Structure,
494        description: "Rule Assertions must be an array",
495        origin: RuleOrigin::Schema,
496    },
497    RuleDefinition {
498        id: "F8605",
499        category: Category::Structure,
500        description: "Rule Assertions must not be empty",
501        origin: RuleOrigin::Schema,
502    },
503    RuleDefinition {
504        id: "F8606",
505        category: Category::Structure,
506        description: "Rule RuleCondition must be a condition function",
507        origin: RuleOrigin::Schema,
508    },
509    RuleDefinition {
510        id: "F8607",
511        category: Category::Structure,
512        description: "Rule assertion must be an object",
513        origin: RuleOrigin::Schema,
514    },
515    RuleDefinition {
516        id: "F8609",
517        category: Category::Structure,
518        description: "Rule assertion missing required Assert property",
519        origin: RuleOrigin::Schema,
520    },
521    RuleDefinition {
522        id: "F8610",
523        category: Category::Structure,
524        description: "Rule assertion Assert must be a condition function",
525        origin: RuleOrigin::Schema,
526    },
527    RuleDefinition {
528        id: "F8611",
529        category: Category::Structure,
530        description: "Disallowed function in Rules section",
531        origin: RuleOrigin::Schema,
532    },
533    RuleDefinition {
534        id: "W8602",
535        category: Category::BestPractice,
536        description: "Rule has unknown property",
537        origin: RuleOrigin::Engine,
538    },
539    RuleDefinition {
540        id: "W8608",
541        category: Category::BestPractice,
542        description: "Rule assertion has unknown property",
543        origin: RuleOrigin::Engine,
544    },
545    RuleDefinition {
546        id: "F1010",
547        category: Category::Intrinsic,
548        description: "Ref target must exist",
549        origin: RuleOrigin::Schema,
550    },
551    RuleDefinition {
552        id: "F1012",
553        category: Category::Intrinsic,
554        description: "FindInMap map name must exist in Mappings",
555        origin: RuleOrigin::Schema,
556    },
557    RuleDefinition {
558        id: "E9003",
559        category: Category::Intrinsic,
560        description: "GetAtt return type may not match usage context",
561        origin: RuleOrigin::CfnLint,
562    },
563    RuleDefinition {
564        id: "F1018",
565        category: Category::Intrinsic,
566        description: "Sub variables must resolve",
567        origin: RuleOrigin::Schema,
568    },
569    RuleDefinition {
570        id: "F1020",
571        category: Category::Intrinsic,
572        description: "Ref/GetAtt target must exist",
573        origin: RuleOrigin::Schema,
574    },
575    RuleDefinition {
576        id: "E9004",
577        category: Category::Intrinsic,
578        description: "GetAtt attribute must exist on target resource type",
579        origin: RuleOrigin::Schema,
580    },
581    RuleDefinition {
582        id: "E1029",
583        category: Category::Intrinsic,
584        description: "Substitution variable ${X} requires Fn::Sub",
585        origin: RuleOrigin::CfnLint,
586    },
587    RuleDefinition {
588        id: "E1040",
589        category: Category::Intrinsic,
590        description: "Check if GetAtt matches destination format",
591        origin: RuleOrigin::CfnLint,
592    },
593    RuleDefinition {
594        id: "E1041",
595        category: Category::Intrinsic,
596        description: "Check if Ref matches destination format",
597        origin: RuleOrigin::CfnLint,
598    },
599    RuleDefinition {
600        id: "F1050",
601        category: Category::Intrinsic,
602        description: "Select index must be non-negative",
603        origin: RuleOrigin::Schema,
604    },
605    RuleDefinition {
606        id: "E1028",
607        category: Category::Intrinsic,
608        description: "Fn::If condition must exist in Conditions section",
609        origin: RuleOrigin::Schema,
610    },
611    RuleDefinition {
612        id: "E1050",
613        category: Category::Intrinsic,
614        description: "Dynamic reference must match the SSM, ssm-secure, or Secrets Manager format",
615        origin: RuleOrigin::CfnLint,
616    },
617    RuleDefinition {
618        id: "W1019",
619        category: Category::Intrinsic,
620        description: "Parameter in Fn::Sub variable map is not used in the template string",
621        origin: RuleOrigin::CfnLint,
622    },
623    RuleDefinition {
624        id: "W1051",
625        category: Category::Intrinsic,
626        description: "Dynamic reference resolves secret value but property expects the secret ARN",
627        origin: RuleOrigin::CfnLint,
628    },
629    RuleDefinition {
630        id: "W1054",
631        category: Category::Intrinsic,
632        description: "String value matches a pseudo parameter; use Ref instead",
633        origin: RuleOrigin::CfnLint,
634    },
635    RuleDefinition {
636        id: "W1100",
637        category: Category::Structure,
638        description: "YAML merge key '<<' is not supported by CloudFormation",
639        origin: RuleOrigin::CfnLint,
640    },
641    RuleDefinition {
642        id: "E9101",
643        category: Category::Intrinsic,
644        description: "Invalid nesting of intrinsic functions",
645        origin: RuleOrigin::Schema,
646    },
647    RuleDefinition {
648        id: "E9106",
649        category: Category::Structure,
650        description: "Circular dependency in condition definitions",
651        origin: RuleOrigin::Schema,
652    },
653    RuleDefinition {
654        id: "F1101",
655        category: Category::Structure,
656        description: "Invalid YAML/JSON syntax",
657        origin: RuleOrigin::Schema,
658    },
659    RuleDefinition {
660        id: "W1102",
661        category: Category::BestPractice,
662        description: "Invalid intrinsic function usage",
663        origin: RuleOrigin::Engine,
664    },
665    RuleDefinition {
666        id: "W1103",
667        category: Category::Intrinsic,
668        description: "Unknown intrinsic function name",
669        origin: RuleOrigin::Engine,
670    },
671    RuleDefinition {
672        id: "E1103",
673        category: Category::Intrinsic,
674        description: "Validate the format of a value",
675        origin: RuleOrigin::CfnLint,
676    },
677    RuleDefinition {
678        id: "E1150",
679        category: Category::Intrinsic,
680        description: "Validate security group format",
681        origin: RuleOrigin::CfnLint,
682    },
683    RuleDefinition {
684        id: "E1151",
685        category: Category::Intrinsic,
686        description: "Validate VPC id format",
687        origin: RuleOrigin::CfnLint,
688    },
689    RuleDefinition {
690        id: "E1152",
691        category: Category::Intrinsic,
692        description: "Validate AMI id format",
693        origin: RuleOrigin::CfnLint,
694    },
695    RuleDefinition {
696        id: "E1153",
697        category: Category::Intrinsic,
698        description: "Validate security group name",
699        origin: RuleOrigin::CfnLint,
700    },
701    RuleDefinition {
702        id: "E1154",
703        category: Category::Intrinsic,
704        description: "Validate VPC subnet id format",
705        origin: RuleOrigin::CfnLint,
706    },
707    RuleDefinition {
708        id: "E1155",
709        category: Category::Intrinsic,
710        description: "Validate CloudWatch logs group name",
711        origin: RuleOrigin::CfnLint,
712    },
713    RuleDefinition {
714        id: "E1156",
715        category: Category::Intrinsic,
716        description: "Validate IAM role ARN format",
717        origin: RuleOrigin::CfnLint,
718    },
719    RuleDefinition {
720        id: "I1022",
721        category: Category::Intrinsic,
722        description: "Use Sub instead of Join",
723        origin: RuleOrigin::CfnLint,
724    },
725    RuleDefinition {
726        id: "W1020",
727        category: Category::BestPractice,
728        description: "Sub isn't needed if it doesn't have a variable defined",
729        origin: RuleOrigin::CfnLint,
730    },
731    RuleDefinition {
732        id: "F2015",
733        category: Category::Parameter,
734        description: "Default value is within parameter constraints",
735        origin: RuleOrigin::Schema,
736    },
737    RuleDefinition {
738        id: "W2506",
739        category: Category::BestPractice,
740        description: "Check if ImageId Parameters have the correct type",
741        origin: RuleOrigin::CfnLint,
742    },
743    RuleDefinition {
744        id: "F3004",
745        category: Category::Reference,
746        description: "Circular dependency detected",
747        origin: RuleOrigin::Schema,
748    },
749    RuleDefinition {
750        id: "E3005",
751        category: Category::Reference,
752        description: "Check DependsOn values for Resources",
753        origin: RuleOrigin::CfnLint,
754    },
755    RuleDefinition {
756        id: "W1001",
757        category: Category::BestPractice,
758        description: "Ref/GetAtt to resource that is available when conditions are applied",
759        origin: RuleOrigin::CfnLint,
760    },
761    RuleDefinition {
762        id: "W3005",
763        category: Category::BestPractice,
764        description: "Check obsolete DependsOn configuration for Resources",
765        origin: RuleOrigin::CfnLint,
766    },
767    RuleDefinition {
768        id: "W2503",
769        category: Category::BestPractice,
770        description: "Resource references conditional resource with mutually exclusive condition",
771        origin: RuleOrigin::Engine,
772    },
773    RuleDefinition {
774        id: "E2504",
775        category: Category::Resource,
776        description: "FIFO queue name must end with .fifo",
777        origin: RuleOrigin::Engine,
778    },
779    RuleDefinition {
780        id: "E2529",
781        category: Category::Resource,
782        description: "Check for SubscriptionFilters beyond 2 attachments to a CloudWatch Log Group",
783        origin: RuleOrigin::CfnLint,
784    },
785    RuleDefinition {
786        id: "E2530",
787        category: Category::Resource,
788        description: "SnapStart supports the configured runtime",
789        origin: RuleOrigin::CfnLint,
790    },
791    RuleDefinition {
792        id: "E3001",
793        category: Category::Resource,
794        description: "Basic CloudFormation Resource Check",
795        origin: RuleOrigin::CfnLint,
796    },
797    RuleDefinition {
798        id: "E3003",
799        category: Category::Resource,
800        description: "Required Resource properties are missing",
801        origin: RuleOrigin::CfnLint,
802    },
803    RuleDefinition {
804        id: "E3010",
805        category: Category::Resource,
806        description: "Resource limit not exceeded",
807        origin: RuleOrigin::CfnLint,
808    },
809    RuleDefinition {
810        id: "E3013",
811        category: Category::Resource,
812        description: "CloudFront Aliases",
813        origin: RuleOrigin::CfnLint,
814    },
815    RuleDefinition {
816        id: "E3016",
817        category: Category::Resource,
818        description: "Check UpdatePolicy values for Resources",
819        origin: RuleOrigin::CfnLint,
820    },
821    RuleDefinition {
822        id: "E3019",
823        category: Category::Resource,
824        description: "Validate that all resources have unique primary identifiers",
825        origin: RuleOrigin::CfnLint,
826    },
827    RuleDefinition {
828        id: "E3022",
829        category: Category::Resource,
830        description: "Resource SubnetRouteTableAssociation Properties",
831        origin: RuleOrigin::CfnLint,
832    },
833    RuleDefinition {
834        id: "E3024",
835        category: Category::Resource,
836        description: "Validate tag configuration",
837        origin: RuleOrigin::CfnLint,
838    },
839    RuleDefinition {
840        id: "E3025",
841        category: Category::Resource,
842        description: "Validates RDS DB Instance Class",
843        origin: RuleOrigin::CfnLint,
844    },
845    RuleDefinition {
846        id: "W9006",
847        category: Category::BestPractice,
848        description: "String length estimation through Fn::Sub",
849        origin: RuleOrigin::Engine,
850    },
851    RuleDefinition {
852        id: "W9007",
853        category: Category::BestPractice,
854        description: "Array items must be unique when required",
855        origin: RuleOrigin::Engine,
856    },
857    RuleDefinition {
858        id: "W9012",
859        category: Category::BestPractice,
860        description: "Provided pseudo-parameter override value is not a valid AWS value",
861        origin: RuleOrigin::Engine,
862    },
863    RuleDefinition {
864        id: "F3006",
865        category: Category::Schema,
866        description: "AWS resource type must be recognized and available in the configured region",
867        origin: RuleOrigin::Schema,
868    },
869    RuleDefinition {
870        id: "E3039",
871        category: Category::Resource,
872        description: "AttributeDefinitions / KeySchemas mismatch",
873        origin: RuleOrigin::CfnLint,
874    },
875    RuleDefinition {
876        id: "E3041",
877        category: Category::Resource,
878        description: "RecordSet HostedZoneName is a superdomain of or equal to Name",
879        origin: RuleOrigin::CfnLint,
880    },
881    RuleDefinition {
882        id: "E3042",
883        category: Category::Resource,
884        description: "Validate at least one essential container is specified",
885        origin: RuleOrigin::CfnLint,
886    },
887    RuleDefinition {
888        id: "E3048",
889        category: Category::Resource,
890        description: "Validate ECS Fargate tasks have required properties and values",
891        origin: RuleOrigin::CfnLint,
892    },
893    RuleDefinition {
894        id: "E3044",
895        category: Category::Resource,
896        description: "ECS service using FARGATE or EXTERNAL cannot use DAEMON scheduling",
897        origin: RuleOrigin::CfnLint,
898    },
899    RuleDefinition {
900        id: "E3045",
901        category: Category::Resource,
902        description: "Validate AccessControl are set with OwnershipControls",
903        origin: RuleOrigin::CfnLint,
904    },
905    RuleDefinition {
906        id: "E9002",
907        category: Category::Resource,
908        description: "SecurityGroup FromPort must be <= ToPort for the TCP and UDP protocols",
909        origin: RuleOrigin::Engine,
910    },
911    RuleDefinition {
912        id: "E3047",
913        category: Category::Resource,
914        description: "Validate ECS Fargate tasks have the right combination of CPU and memory",
915        origin: RuleOrigin::CfnLint,
916    },
917    RuleDefinition {
918        id: "W3049",
919        category: Category::BestPractice,
920        description: "ELB target group health check uses a fixed port that will not follow an ECS dynamic host port",
921        origin: RuleOrigin::CfnLint,
922    },
923    RuleDefinition {
924        id: "I3049",
925        category: Category::BestPractice,
926        description: "ELB target group relies on the default traffic-port health check for an ECS dynamic host port",
927        origin: RuleOrigin::CfnLint,
928    },
929    RuleDefinition {
930        id: "E3050",
931        category: Category::Resource,
932        description: "Check if REFing to a IAM resource with path set",
933        origin: RuleOrigin::CfnLint,
934    },
935    RuleDefinition {
936        id: "E3051",
937        category: Category::Resource,
938        description: "Validate the structure of a SSM document",
939        origin: RuleOrigin::CfnLint,
940    },
941    RuleDefinition {
942        id: "E3052",
943        category: Category::Resource,
944        description: "Validate ECS service requires NetworkConfiguration",
945        origin: RuleOrigin::CfnLint,
946    },
947    RuleDefinition {
948        id: "E3053",
949        category: Category::Resource,
950        description: "Validate ECS task definition has correct values for HostPort",
951        origin: RuleOrigin::CfnLint,
952    },
953    RuleDefinition {
954        id: "E3054",
955        category: Category::Resource,
956        description: "Validate ECS service using Fargate uses TaskDefinition that allows Fargate",
957        origin: RuleOrigin::CfnLint,
958    },
959    RuleDefinition {
960        id: "E3055",
961        category: Category::Resource,
962        description: "Check CreationPolicy values for Resources",
963        origin: RuleOrigin::CfnLint,
964    },
965    RuleDefinition {
966        id: "E3057",
967        category: Category::Resource,
968        description: "Validate that CloudFront TargetOriginId is a specified Origin",
969        origin: RuleOrigin::CfnLint,
970    },
971    RuleDefinition {
972        id: "E3059",
973        category: Category::Resource,
974        description: "Validate subnet CIDRs are within the CIDRs of the VPC",
975        origin: RuleOrigin::CfnLint,
976    },
977    RuleDefinition {
978        id: "E3060",
979        category: Category::Resource,
980        description: "Validate subnet CIDRs do not overlap with other subnets",
981        origin: RuleOrigin::CfnLint,
982    },
983    RuleDefinition {
984        id: "E3061",
985        category: Category::Resource,
986        description: "Validate the days for tierings in IntelligentTieringConfigurations",
987        origin: RuleOrigin::CfnLint,
988    },
989    RuleDefinition {
990        id: "E3677",
991        category: Category::Resource,
992        description: "Lambda ZipFile requires nodejs or python runtime",
993        origin: RuleOrigin::CfnLint,
994    },
995    RuleDefinition {
996        id: "E3501",
997        category: Category::Resource,
998        description: "Validate SQS queue properties are valid",
999        origin: RuleOrigin::CfnLint,
1000    },
1001    RuleDefinition {
1002        id: "E3502",
1003        category: Category::Resource,
1004        description: "Validate SQS DLQ queues are the same type",
1005        origin: RuleOrigin::CfnLint,
1006    },
1007    RuleDefinition {
1008        id: "E3504",
1009        category: Category::Resource,
1010        description: "Check minimum 90 period is met between BackupPlan cold and delete",
1011        origin: RuleOrigin::CfnLint,
1012    },
1013    RuleDefinition {
1014        id: "E3505",
1015        category: Category::Resource,
1016        description: "Validate SQS VisibilityTimeout is greater than a function's Timeout",
1017        origin: RuleOrigin::CfnLint,
1018    },
1019    RuleDefinition {
1020        id: "E3510",
1021        category: Category::Resource,
1022        description: "Validate identity based IAM policies",
1023        origin: RuleOrigin::CfnLint,
1024    },
1025    RuleDefinition {
1026        id: "E3511",
1027        category: Category::Resource,
1028        description: "Validate IAM role arn pattern",
1029        origin: RuleOrigin::CfnLint,
1030    },
1031    RuleDefinition {
1032        id: "E3512",
1033        category: Category::Resource,
1034        description: "Validate resource based IAM policies",
1035        origin: RuleOrigin::CfnLint,
1036    },
1037    RuleDefinition {
1038        id: "E3513",
1039        category: Category::Resource,
1040        description: "Validate ECR repository policy",
1041        origin: RuleOrigin::CfnLint,
1042    },
1043    RuleDefinition {
1044        id: "E3530",
1045        category: Category::Resource,
1046        description: "Validate IAM trust policies",
1047        origin: RuleOrigin::CfnLint,
1048    },
1049    RuleDefinition {
1050        id: "E3601",
1051        category: Category::Resource,
1052        description: "Validate the structure of a StateMachine definition",
1053        origin: RuleOrigin::CfnLint,
1054    },
1055    RuleDefinition {
1056        id: "E3628",
1057        category: Category::Resource,
1058        description: "Validate EC2 instance types based on region",
1059        origin: RuleOrigin::CfnLint,
1060    },
1061    RuleDefinition {
1062        id: "E3635",
1063        category: Category::Resource,
1064        description: "Validate Neptune DB instance class",
1065        origin: RuleOrigin::CfnLint,
1066    },
1067    RuleDefinition {
1068        id: "E3636",
1069        category: Category::Resource,
1070        description: "Validate CodeBuild projects using S3 also have Location",
1071        origin: RuleOrigin::CfnLint,
1072    },
1073    RuleDefinition {
1074        id: "E3639",
1075        category: Category::Resource,
1076        description: "Validate DynamoDB table ProvisionedThroughput is set when BillingMode is PROVISIONED",
1077        origin: RuleOrigin::CfnLint,
1078    },
1079    RuleDefinition {
1080        id: "E3641",
1081        category: Category::Resource,
1082        description: "Validate GameLift Fleet EC2 instance type",
1083        origin: RuleOrigin::CfnLint,
1084    },
1085    RuleDefinition {
1086        id: "E3660",
1087        category: Category::Resource,
1088        description: "RestApi requires a name when not using an OpenAPI specification",
1089        origin: RuleOrigin::CfnLint,
1090    },
1091    RuleDefinition {
1092        id: "E3663",
1093        category: Category::Resource,
1094        description: "Validate Lambda environment variable names aren't reserved",
1095        origin: RuleOrigin::CfnLint,
1096    },
1097    RuleDefinition {
1098        id: "E3667",
1099        category: Category::Resource,
1100        description: "Validate Redshift cluster node type",
1101        origin: RuleOrigin::CfnLint,
1102    },
1103    RuleDefinition {
1104        id: "E3670",
1105        category: Category::Resource,
1106        description: "Validate the instance types for an AmazonMQ Broker",
1107        origin: RuleOrigin::CfnLint,
1108    },
1109    RuleDefinition {
1110        id: "E3671",
1111        category: Category::Resource,
1112        description: "Validate block device mapping configuration",
1113        origin: RuleOrigin::CfnLint,
1114    },
1115    RuleDefinition {
1116        id: "E3675",
1117        category: Category::Resource,
1118        description: "Validate EMR cluster instance type",
1119        origin: RuleOrigin::CfnLint,
1120    },
1121    RuleDefinition {
1122        id: "E3676",
1123        category: Category::Resource,
1124        description: "Validate ELBv2 protocols that require certificates have a certificate specified",
1125        origin: RuleOrigin::CfnLint,
1126    },
1127    RuleDefinition {
1128        id: "E3679",
1129        category: Category::Resource,
1130        description: "Validate ELB protocols that require certificates have a certificate specified",
1131        origin: RuleOrigin::CfnLint,
1132    },
1133    RuleDefinition {
1134        id: "E3680",
1135        category: Category::Resource,
1136        description: "Application load balancers require at least 2 subnets",
1137        origin: RuleOrigin::CfnLint,
1138    },
1139    RuleDefinition {
1140        id: "E3685",
1141        category: Category::Resource,
1142        description: "Container image functions cannot use Handler, Runtime, or Layers",
1143        origin: RuleOrigin::CfnLint,
1144    },
1145    RuleDefinition {
1146        id: "E9006",
1147        category: Category::Schema,
1148        description: "Property value not valid for conditional extension enum",
1149        origin: RuleOrigin::CfnLint,
1150    },
1151    RuleDefinition {
1152        id: "E3698",
1153        category: Category::Resource,
1154        description: "API Gateway Stage and Deployment must use the same RestApi",
1155        origin: RuleOrigin::CfnLint,
1156    },
1157    RuleDefinition {
1158        id: "E3699",
1159        category: Category::Resource,
1160        description: "API Gateway Method and Authorizer must use the same RestApi",
1161        origin: RuleOrigin::CfnLint,
1162    },
1163    RuleDefinition {
1164        id: "E3700",
1165        category: Category::Resource,
1166        description: "Validate CodePipeline Source actions are only in the first stage",
1167        origin: RuleOrigin::CfnLint,
1168    },
1169    RuleDefinition {
1170        id: "E3701",
1171        category: Category::Resource,
1172        description: "Validate input and output artifact names are used properly",
1173        origin: RuleOrigin::CfnLint,
1174    },
1175    RuleDefinition {
1176        id: "E3702",
1177        category: Category::Resource,
1178        description: "Validate the number of input and output artifacts in a CodePipeline",
1179        origin: RuleOrigin::CfnLint,
1180    },
1181    RuleDefinition {
1182        id: "E3703",
1183        category: Category::Resource,
1184        description: "Validate the configuration of a pipeline action",
1185        origin: RuleOrigin::CfnLint,
1186    },
1187    RuleDefinition {
1188        id: "E3704",
1189        category: Category::Resource,
1190        description: "Validate TransitEncryptionEnabled is set when using Valkey engine",
1191        origin: RuleOrigin::CfnLint,
1192    },
1193    RuleDefinition {
1194        id: "E3705",
1195        category: Category::Resource,
1196        description: "Validate SQS FIFO queue EventSourceMapping BatchSize is at most 10",
1197        origin: RuleOrigin::CfnLint,
1198    },
1199    RuleDefinition {
1200        id: "E3706",
1201        category: Category::Resource,
1202        description: "MaxSize must be greater than or equal to MinSize",
1203        origin: RuleOrigin::CfnLint,
1204    },
1205    RuleDefinition {
1206        id: "E3707",
1207        category: Category::Resource,
1208        description: "Validate RDS DBInstance Engine matches DBCluster Engine",
1209        origin: RuleOrigin::CfnLint,
1210    },
1211    RuleDefinition {
1212        id: "E3708",
1213        category: Category::Resource,
1214        description: "API Gateway Method AuthorizationType must match Authorizer Type",
1215        origin: RuleOrigin::CfnLint,
1216    },
1217    RuleDefinition {
1218        id: "I9002",
1219        category: Category::BestPractice,
1220        description: "Property is ignored in this configuration (from extension)",
1221        origin: RuleOrigin::Engine,
1222    },
1223    RuleDefinition {
1224        id: "I9003",
1225        category: Category::BestPractice,
1226        description: "Region-scoped values validated against all regions because no region was supplied",
1227        origin: RuleOrigin::Engine,
1228    },
1229    RuleDefinition {
1230        id: "I3037",
1231        category: Category::BestPractice,
1232        description: "Check if a list that allows duplicates has any duplicates",
1233        origin: RuleOrigin::CfnLint,
1234    },
1235    RuleDefinition {
1236        id: "I3510",
1237        category: Category::Security,
1238        description: "Validate statement resources match the actions",
1239        origin: RuleOrigin::CfnLint,
1240    },
1241    RuleDefinition {
1242        id: "W1028",
1243        category: Category::BestPractice,
1244        description: "Check Fn::If has a path that cannot be reached",
1245        origin: RuleOrigin::CfnLint,
1246    },
1247    RuleDefinition {
1248        id: "W1030",
1249        category: Category::BestPractice,
1250        description: "Validate the values that come from a Ref function",
1251        origin: RuleOrigin::CfnLint,
1252    },
1253    RuleDefinition {
1254        id: "W1053",
1255        category: Category::BestPractice,
1256        description: "Dynamic references should not contain spaces",
1257        origin: RuleOrigin::CfnLint,
1258    },
1259    RuleDefinition {
1260        id: "W2010",
1261        category: Category::Security,
1262        description: "NoEcho parameters are not masked when used in Metadata and Outputs",
1263        origin: RuleOrigin::CfnLint,
1264    },
1265    RuleDefinition {
1266        id: "W2502",
1267        category: Category::BestPractice,
1268        description: "DependsOn conditional resource without matching condition",
1269        origin: RuleOrigin::Engine,
1270    },
1271    RuleDefinition {
1272        id: "W2530",
1273        category: Category::BestPractice,
1274        description: "Validate that SnapStart is properly configured",
1275        origin: RuleOrigin::CfnLint,
1276    },
1277    RuleDefinition {
1278        id: "W2533",
1279        category: Category::BestPractice,
1280        description: "Check required properties for Lambda if the deployment package is a .zip file",
1281        origin: RuleOrigin::CfnLint,
1282    },
1283    RuleDefinition {
1284        id: "W3010",
1285        category: Category::BestPractice,
1286        description: "Availability zone properties should not be hardcoded",
1287        origin: RuleOrigin::CfnLint,
1288    },
1289    RuleDefinition {
1290        id: "W1011",
1291        category: Category::Security,
1292        description: "Instead of REFing a parameter for a secret use a dynamic reference",
1293        origin: RuleOrigin::CfnLint,
1294    },
1295    RuleDefinition {
1296        id: "W2501",
1297        category: Category::Security,
1298        description: "Check if Password Properties are correctly configured",
1299        origin: RuleOrigin::CfnLint,
1300    },
1301    RuleDefinition {
1302        id: "W2508",
1303        category: Category::Security,
1304        description: "Security group allows open access to sensitive port",
1305        origin: RuleOrigin::Engine,
1306    },
1307    RuleDefinition {
1308        id: "W2509",
1309        category: Category::Security,
1310        description: "Password parameter should have NoEcho",
1311        origin: RuleOrigin::Engine,
1312    },
1313    RuleDefinition {
1314        id: "W2511",
1315        category: Category::Security,
1316        description: "Check IAM Resource Policies syntax",
1317        origin: RuleOrigin::CfnLint,
1318    },
1319    RuleDefinition {
1320        id: "W2512",
1321        category: Category::Security,
1322        description: "IAM policy with NotAction",
1323        origin: RuleOrigin::Engine,
1324    },
1325    RuleDefinition {
1326        id: "W9008",
1327        category: Category::Security,
1328        description: "RDS instance should have StorageEncrypted",
1329        origin: RuleOrigin::Engine,
1330    },
1331    RuleDefinition {
1332        id: "W9011",
1333        category: Category::Security,
1334        description: "RDS instance PubliclyAccessible is true",
1335        origin: RuleOrigin::Engine,
1336    },
1337    RuleDefinition {
1338        id: "W3663",
1339        category: Category::Security,
1340        description: "Validate SourceAccount is required property",
1341        origin: RuleOrigin::CfnLint,
1342    },
1343    RuleDefinition {
1344        id: "E3687",
1345        category: Category::Resource,
1346        description: "Validate to and from ports based on the protocol",
1347        origin: RuleOrigin::CfnLint,
1348    },
1349    RuleDefinition {
1350        id: "W3687",
1351        category: Category::BestPractice,
1352        description: "Validate that ports aren't specified for certain protocols",
1353        origin: RuleOrigin::CfnLint,
1354    },
1355    RuleDefinition {
1356        id: "I2530",
1357        category: Category::BestPractice,
1358        description: "Validate that SnapStart is configured for >= Java11 runtimes",
1359        origin: RuleOrigin::CfnLint,
1360    },
1361    RuleDefinition {
1362        id: "I3011",
1363        category: Category::BestPractice,
1364        description: "Check stateful resources have a set UpdateReplacePolicy/DeletionPolicy",
1365        origin: RuleOrigin::CfnLint,
1366    },
1367    RuleDefinition {
1368        id: "I3013",
1369        category: Category::BestPractice,
1370        description: "Check resources with auto expiring content have explicit retention period",
1371        origin: RuleOrigin::CfnLint,
1372    },
1373    RuleDefinition {
1374        id: "I9040",
1375        category: Category::BestPractice,
1376        description: "Resource should have Tags",
1377        origin: RuleOrigin::Engine,
1378    },
1379    RuleDefinition {
1380        id: "I3042",
1381        category: Category::BestPractice,
1382        description: "ARNs should use correctly placed Pseudo Parameters",
1383        origin: RuleOrigin::CfnLint,
1384    },
1385    RuleDefinition {
1386        id: "I3100",
1387        category: Category::BestPractice,
1388        description: "Checks for legacy instance type generations",
1389        origin: RuleOrigin::CfnLint,
1390    },
1391    RuleDefinition {
1392        id: "W9010",
1393        category: Category::Security,
1394        description: "Hardcoded AMI ID",
1395        origin: RuleOrigin::Engine,
1396    },
1397    RuleDefinition {
1398        id: "W9013",
1399        category: Category::Security,
1400        description: "Hardcoded account ID in ARN",
1401        origin: RuleOrigin::Engine,
1402    },
1403    RuleDefinition {
1404        id: "W9053",
1405        category: Category::BestPractice,
1406        description: "Conditions are semantically equivalent and can be consolidated",
1407        origin: RuleOrigin::Engine,
1408    },
1409    RuleDefinition {
1410        id: "W9052",
1411        category: Category::Structure,
1412        description: "Deterministic validation budgets were exhausted; see report metadata for completeness impact",
1413        origin: RuleOrigin::Engine,
1414    },
1415    RuleDefinition {
1416        id: "W9002",
1417        category: Category::BestPractice,
1418        description: "Hardcoded ARN property",
1419        origin: RuleOrigin::Engine,
1420    },
1421    RuleDefinition {
1422        id: "W3011",
1423        category: Category::BestPractice,
1424        description: "Check resources with UpdateReplacePolicy/DeletionPolicy have both",
1425        origin: RuleOrigin::CfnLint,
1426    },
1427    RuleDefinition {
1428        id: "E2531",
1429        category: Category::Deprecation,
1430        description: "Check if Lambda Function Runtimes are blocked for create",
1431        origin: RuleOrigin::CfnLint,
1432    },
1433    RuleDefinition {
1434        id: "E2533",
1435        category: Category::Deprecation,
1436        description: "Check if Lambda Function Runtimes are updatable",
1437        origin: RuleOrigin::CfnLint,
1438    },
1439    RuleDefinition {
1440        id: "E3710",
1441        category: Category::Deprecation,
1442        description: "Resource type is from a service that has been shut down",
1443        origin: RuleOrigin::CfnLint,
1444    },
1445    RuleDefinition {
1446        id: "W2531",
1447        category: Category::Deprecation,
1448        description: "Check if EOL Lambda Function Runtimes are used",
1449        origin: RuleOrigin::CfnLint,
1450    },
1451    RuleDefinition {
1452        id: "W3045",
1453        category: Category::Deprecation,
1454        description: "Controlling access to an S3 bucket should be done with bucket policies",
1455        origin: RuleOrigin::CfnLint,
1456    },
1457    RuleDefinition {
1458        id: "W3696",
1459        category: Category::Deprecation,
1460        description: "Resource type is from a service that is sunsetting",
1461        origin: RuleOrigin::CfnLint,
1462    },
1463    RuleDefinition {
1464        id: "W3697",
1465        category: Category::Deprecation,
1466        description: "Resource type is from a service in maintenance mode",
1467        origin: RuleOrigin::CfnLint,
1468    },
1469    RuleDefinition {
1470        id: "E6001",
1471        category: Category::Structure,
1472        description: "Outputs have appropriate properties",
1473        origin: RuleOrigin::CfnLint,
1474    },
1475    RuleDefinition {
1476        id: "E6003",
1477        category: Category::Structure,
1478        description: "Outputs section must be an object of named output definitions",
1479        origin: RuleOrigin::CfnLint,
1480    },
1481    RuleDefinition {
1482        id: "E6005",
1483        category: Category::Structure,
1484        description: "Condition referenced by an output must exist in the Conditions section",
1485        origin: RuleOrigin::Schema,
1486    },
1487    RuleDefinition {
1488        id: "E7001",
1489        category: Category::Structure,
1490        description: "Mappings are appropriately configured",
1491        origin: RuleOrigin::CfnLint,
1492    },
1493    RuleDefinition {
1494        id: "E3002",
1495        category: Category::Schema,
1496        description: "Resource properties are invalid",
1497        origin: RuleOrigin::CfnLint,
1498    },
1499    RuleDefinition {
1500        id: "E3012",
1501        category: Category::Schema,
1502        description: "Check resource properties values",
1503        origin: RuleOrigin::CfnLint,
1504    },
1505    RuleDefinition {
1506        id: "E3030",
1507        category: Category::Schema,
1508        description: "Check if properties have a valid value",
1509        origin: RuleOrigin::CfnLint,
1510    },
1511    RuleDefinition {
1512        id: "E3031",
1513        category: Category::Schema,
1514        description: "Check if property values adhere to a specific pattern",
1515        origin: RuleOrigin::CfnLint,
1516    },
1517    RuleDefinition {
1518        id: "E3032",
1519        category: Category::Schema,
1520        description: "Check if an array has between min and max number of values",
1521        origin: RuleOrigin::CfnLint,
1522    },
1523    RuleDefinition {
1524        id: "E3034",
1525        category: Category::Schema,
1526        description: "Check if a number is between min and max",
1527        origin: RuleOrigin::CfnLint,
1528    },
1529    RuleDefinition {
1530        id: "F3002",
1531        category: Category::Schema,
1532        description: "Additional properties are not allowed",
1533        origin: RuleOrigin::Schema,
1534    },
1535    RuleDefinition {
1536        id: "F3003",
1537        category: Category::Schema,
1538        description: "Required property missing",
1539        origin: RuleOrigin::Schema,
1540    },
1541    RuleDefinition {
1542        id: "F3012",
1543        category: Category::Schema,
1544        description: "Property type mismatch",
1545        origin: RuleOrigin::Schema,
1546    },
1547    RuleDefinition {
1548        id: "F3014",
1549        category: Category::Schema,
1550        description: "Exactly one of properties required (requiredXor)",
1551        origin: RuleOrigin::Schema,
1552    },
1553    RuleDefinition {
1554        id: "F3017",
1555        category: Category::Schema,
1556        description: "Value not valid under anyOf",
1557        origin: RuleOrigin::Schema,
1558    },
1559    RuleDefinition {
1560        id: "F3018",
1561        category: Category::Schema,
1562        description: "Value not valid under oneOf",
1563        origin: RuleOrigin::Schema,
1564    },
1565    RuleDefinition {
1566        id: "F3020",
1567        category: Category::Schema,
1568        description: "Mutually exclusive properties",
1569        origin: RuleOrigin::Schema,
1570    },
1571    RuleDefinition {
1572        id: "F3021",
1573        category: Category::Schema,
1574        description: "Dependent property required",
1575        origin: RuleOrigin::Schema,
1576    },
1577    RuleDefinition {
1578        id: "F3030",
1579        category: Category::Schema,
1580        description: "Value does not match the required constant",
1581        origin: RuleOrigin::Schema,
1582    },
1583    RuleDefinition {
1584        id: "W3030",
1585        category: Category::Schema,
1586        description: "Value not in allowed enum",
1587        origin: RuleOrigin::CfnLint,
1588    },
1589    RuleDefinition {
1590        id: "F3031",
1591        category: Category::Schema,
1592        description: "Value does not match pattern",
1593        origin: RuleOrigin::Schema,
1594    },
1595    RuleDefinition {
1596        id: "F3032",
1597        category: Category::Schema,
1598        description: "Array item count out of bounds",
1599        origin: RuleOrigin::Schema,
1600    },
1601    RuleDefinition {
1602        id: "F3033",
1603        category: Category::Schema,
1604        description: "String length out of bounds",
1605        origin: RuleOrigin::Schema,
1606    },
1607    RuleDefinition {
1608        id: "F3034",
1609        category: Category::Schema,
1610        description: "Numeric value out of bounds",
1611        origin: RuleOrigin::Schema,
1612    },
1613    RuleDefinition {
1614        id: "F3037",
1615        category: Category::Schema,
1616        description: "Array items not unique",
1617        origin: RuleOrigin::Schema,
1618    },
1619    RuleDefinition {
1620        id: "E3040",
1621        category: Category::Schema,
1622        description: "Read only property should not be specified",
1623        origin: RuleOrigin::CfnLint,
1624    },
1625    RuleDefinition {
1626        id: "W9054",
1627        category: Category::BestPractice,
1628        description: "Write-only property referenced in output",
1629        origin: RuleOrigin::Engine,
1630    },
1631    RuleDefinition {
1632        id: "F3058",
1633        category: Category::Schema,
1634        description: "One of properties required (requiredOr)",
1635        origin: RuleOrigin::Schema,
1636    },
1637    RuleDefinition {
1638        id: "I9001",
1639        category: Category::BestPractice,
1640        description: "Create-only property updated triggers resource replacement",
1641        origin: RuleOrigin::Engine,
1642    },
1643    RuleDefinition {
1644        id: "W9003",
1645        category: Category::BestPractice,
1646        description: "Property type coercion warning",
1647        origin: RuleOrigin::CfnLint,
1648    },
1649    RuleDefinition {
1650        id: "W9009",
1651        category: Category::Deprecation,
1652        description: "Resource type sunset or shutdown",
1653        origin: RuleOrigin::Engine,
1654    },
1655    RuleDefinition {
1656        id: "E1002",
1657        category: Category::Structure,
1658        description: "Validate if a template size is too large",
1659        origin: RuleOrigin::CfnLint,
1660    },
1661    RuleDefinition {
1662        id: "E1005",
1663        category: Category::Structure,
1664        description: "Validate Transform configuration",
1665        origin: RuleOrigin::CfnLint,
1666    },
1667    RuleDefinition {
1668        id: "E1015",
1669        category: Category::Intrinsic,
1670        description: "GetAz validation of parameters",
1671        origin: RuleOrigin::Schema,
1672    },
1673    RuleDefinition {
1674        id: "E1016",
1675        category: Category::Intrinsic,
1676        description: "ImportValue validation of parameters",
1677        origin: RuleOrigin::Schema,
1678    },
1679    RuleDefinition {
1680        id: "E1011",
1681        category: Category::Intrinsic,
1682        description: "Fn::FindInMap operands must be strings or one of Ref/Fn::FindInMap",
1683        origin: RuleOrigin::Schema,
1684    },
1685    RuleDefinition {
1686        id: "E1017",
1687        category: Category::Intrinsic,
1688        description: "Fn::Select requires exactly two operands and a list source",
1689        origin: RuleOrigin::Schema,
1690    },
1691    RuleDefinition {
1692        id: "E1018",
1693        category: Category::Intrinsic,
1694        description: "Fn::Split source must be a string or a string-producing intrinsic",
1695        origin: RuleOrigin::Schema,
1696    },
1697    RuleDefinition {
1698        id: "E1019",
1699        category: Category::Intrinsic,
1700        description: "Fn::Sub variable map values must be strings or string-producing intrinsics",
1701        origin: RuleOrigin::Schema,
1702    },
1703    RuleDefinition {
1704        id: "E1021",
1705        category: Category::Intrinsic,
1706        description: "Fn::Base64 argument must be a string or a string-producing intrinsic",
1707        origin: RuleOrigin::Schema,
1708    },
1709    RuleDefinition {
1710        id: "E1022",
1711        category: Category::Intrinsic,
1712        description: "Fn::Join requires a string delimiter and a list of strings or string-producing intrinsics",
1713        origin: RuleOrigin::Schema,
1714    },
1715    RuleDefinition {
1716        id: "E1024",
1717        category: Category::Intrinsic,
1718        description: "Fn::Cidr requires a CIDR-format ipBlock string and integer count/cidrBits",
1719        origin: RuleOrigin::Schema,
1720    },
1721    RuleDefinition {
1722        id: "E1027",
1723        category: Category::Intrinsic,
1724        description: "Check dynamic references secure strings are in supported locations",
1725        origin: RuleOrigin::CfnLint,
1726    },
1727    RuleDefinition {
1728        id: "E1030",
1729        category: Category::Intrinsic,
1730        description: "Fn::Length argument must be an array or a list-producing function",
1731        origin: RuleOrigin::Schema,
1732    },
1733    RuleDefinition {
1734        id: "E1031",
1735        category: Category::Intrinsic,
1736        description: "Fn::ToJsonString argument must be a non-empty array/object or a supported function",
1737        origin: RuleOrigin::Schema,
1738    },
1739    RuleDefinition {
1740        id: "F1030",
1741        category: Category::Intrinsic,
1742        description: "Fn::Length requires the AWS::LanguageExtensions transform",
1743        origin: RuleOrigin::Schema,
1744    },
1745    RuleDefinition {
1746        id: "F1031",
1747        category: Category::Intrinsic,
1748        description: "Fn::ToJsonString requires the AWS::LanguageExtensions transform",
1749        origin: RuleOrigin::Schema,
1750    },
1751    RuleDefinition {
1752        id: "F1032",
1753        category: Category::Intrinsic,
1754        description: "Fn::ForEach requires the AWS::LanguageExtensions transform",
1755        origin: RuleOrigin::Schema,
1756    },
1757    RuleDefinition {
1758        id: "E1033",
1759        category: Category::Intrinsic,
1760        description: "GetStackOutput validation of parameters",
1761        origin: RuleOrigin::Schema,
1762    },
1763    RuleDefinition {
1764        id: "E1051",
1765        category: Category::Intrinsic,
1766        description: "Validate dynamic references to secrets manager are only in resource properties",
1767        origin: RuleOrigin::CfnLint,
1768    },
1769    RuleDefinition {
1770        id: "E1052",
1771        category: Category::Intrinsic,
1772        description: "Validate dynamic references to SSM are in a valid location",
1773        origin: RuleOrigin::CfnLint,
1774    },
1775    RuleDefinition {
1776        id: "E3011",
1777        category: Category::Resource,
1778        description: "Check property names in Resources",
1779        origin: RuleOrigin::CfnLint,
1780    },
1781    RuleDefinition {
1782        id: "E3023",
1783        category: Category::Resource,
1784        description: "Validate Route53 RecordSets",
1785        origin: RuleOrigin::CfnLint,
1786    },
1787    RuleDefinition {
1788        id: "E3026",
1789        category: Category::Resource,
1790        description: "Check Elastic Cache Redis Cluster settings",
1791        origin: RuleOrigin::CfnLint,
1792    },
1793    RuleDefinition {
1794        id: "E3027",
1795        category: Category::Resource,
1796        description: "Validate AWS Event ScheduleExpression format",
1797        origin: RuleOrigin::CfnLint,
1798    },
1799    RuleDefinition {
1800        id: "E3029",
1801        category: Category::Resource,
1802        description: "Validate Route53 record set aliases",
1803        origin: RuleOrigin::CfnLint,
1804    },
1805    RuleDefinition {
1806        id: "E3062",
1807        category: Category::Resource,
1808        description: "Validates RDS DB Instance Class based on Engine and EngineVersion",
1809        origin: RuleOrigin::CfnLint,
1810    },
1811    RuleDefinition {
1812        id: "E3617",
1813        category: Category::Resource,
1814        description: "Validate ManagedBlockchain instance type",
1815        origin: RuleOrigin::CfnLint,
1816    },
1817    RuleDefinition {
1818        id: "E3620",
1819        category: Category::Resource,
1820        description: "Validate a DocDB DB Instance class",
1821        origin: RuleOrigin::CfnLint,
1822    },
1823    RuleDefinition {
1824        id: "E3621",
1825        category: Category::Resource,
1826        description: "Validate the instance types for AppStream Fleet",
1827        origin: RuleOrigin::CfnLint,
1828    },
1829    RuleDefinition {
1830        id: "E3647",
1831        category: Category::Resource,
1832        description: "Validate ElastiCache cluster cache node type",
1833        origin: RuleOrigin::CfnLint,
1834    },
1835    RuleDefinition {
1836        id: "E3672",
1837        category: Category::Resource,
1838        description: "Validate the cluster node type for a DAX Cluster",
1839        origin: RuleOrigin::CfnLint,
1840    },
1841    RuleDefinition {
1842        id: "E3694",
1843        category: Category::Resource,
1844        description: "Validates RDS DB Cluster instance class",
1845        origin: RuleOrigin::CfnLint,
1846    },
1847    RuleDefinition {
1848        id: "E3640",
1849        category: Category::Resource,
1850        description: "Validate SageMaker processing instance types based on region",
1851        origin: RuleOrigin::CfnLint,
1852    },
1853    RuleDefinition {
1854        id: "E3642",
1855        category: Category::Resource,
1856        description: "Validate SageMaker hosting instance types based on region",
1857        origin: RuleOrigin::CfnLint,
1858    },
1859    RuleDefinition {
1860        id: "E3643",
1861        category: Category::Resource,
1862        description: "Validate SageMaker transform instance types based on region",
1863        origin: RuleOrigin::CfnLint,
1864    },
1865    RuleDefinition {
1866        id: "E3644",
1867        category: Category::Resource,
1868        description: "Validate SageMaker cluster instance types based on region",
1869        origin: RuleOrigin::CfnLint,
1870    },
1871    RuleDefinition {
1872        id: "E3652",
1873        category: Category::Resource,
1874        description: "Validate Elasticsearch domain cluster instance",
1875        origin: RuleOrigin::CfnLint,
1876    },
1877    RuleDefinition {
1878        id: "E3653",
1879        category: Category::Resource,
1880        description: "Validate OpenSearch domain cluster instance type",
1881        origin: RuleOrigin::CfnLint,
1882    },
1883    RuleDefinition {
1884        id: "I2003",
1885        category: Category::Structure,
1886        description: "Validate AllowedPattern is a valid regex",
1887        origin: RuleOrigin::CfnLint,
1888    },
1889    RuleDefinition {
1890        id: "W3002",
1891        category: Category::BestPractice,
1892        description: "Warn when properties are configured to only work with the package command",
1893        origin: RuleOrigin::CfnLint,
1894    },
1895    RuleDefinition {
1896        id: "W3037",
1897        category: Category::Security,
1898        description: "Check IAM Permission configuration",
1899        origin: RuleOrigin::CfnLint,
1900    },
1901    RuleDefinition {
1902        id: "W3660",
1903        category: Category::BestPractice,
1904        description: "Validate if multiple resources are modifying a Rest API definition",
1905        origin: RuleOrigin::CfnLint,
1906    },
1907    RuleDefinition {
1908        id: "W3664",
1909        category: Category::BestPractice,
1910        description: "Validate Lambda permission Principal matches SourceArn resource type",
1911        origin: RuleOrigin::CfnLint,
1912    },
1913    RuleDefinition {
1914        id: "W3671",
1915        category: Category::BestPractice,
1916        description: "Iops is ignored for certain EBS volume types",
1917        origin: RuleOrigin::CfnLint,
1918    },
1919    RuleDefinition {
1920        id: "W3688",
1921        category: Category::BestPractice,
1922        description: "When restoring DBCluster certain properties are ignored",
1923        origin: RuleOrigin::CfnLint,
1924    },
1925    RuleDefinition {
1926        id: "W3689",
1927        category: Category::BestPractice,
1928        description: "When using a source DB certain properties are ignored",
1929        origin: RuleOrigin::CfnLint,
1930    },
1931    RuleDefinition {
1932        id: "W3693",
1933        category: Category::BestPractice,
1934        description: "Validate Aurora DB cluster configuration for ignored properties",
1935        origin: RuleOrigin::CfnLint,
1936    },
1937    RuleDefinition {
1938        id: "W3694",
1939        category: Category::BestPractice,
1940        description: "SNS Subscription Endpoint should match Protocol",
1941        origin: RuleOrigin::CfnLint,
1942    },
1943    RuleDefinition {
1944        id: "E3715",
1945        category: Category::Resource,
1946        description: "VirtualName must use ephemeral device format when Ebs is absent",
1947        origin: RuleOrigin::CfnLint,
1948    },
1949    RuleDefinition {
1950        id: "W3698",
1951        category: Category::BestPractice,
1952        description: "VirtualName is ignored when Ebs is specified",
1953        origin: RuleOrigin::CfnLint,
1954    },
1955];
1956
1957#[cfg(test)]
1958mod tests {
1959    use super::*;
1960    use std::collections::HashSet;
1961
1962    #[test]
1963    fn severity_matches_id_prefix_for_all_rules() {
1964        for rule in RULE_REGISTRY {
1965            let prefix = rule.id.chars().next().unwrap();
1966            let expected = Severity::from_prefix(prefix);
1967            assert_eq!(rule.severity(), expected, "Rule {} severity mismatch", rule.id);
1968        }
1969    }
1970
1971    #[test]
1972    fn registry_contains_no_duplicate_ids() {
1973        let mut seen = HashSet::new();
1974        for rule in RULE_REGISTRY {
1975            assert!(seen.insert(rule.id), "Duplicate rule ID: {}", rule.id);
1976        }
1977    }
1978
1979    #[test]
1980    fn lookup_rule_returns_definition_for_registered_id() {
1981        let rule = lookup_rule("E9002").expect("E9002 should exist");
1982        assert_eq!(rule.category, Category::Resource);
1983    }
1984
1985    #[test]
1986    fn lookup_rule_returns_none_for_unregistered_id() {
1987        assert!(lookup_rule("Z9999").is_none(), "unregistered rule ID Z9999 should return None");
1988    }
1989
1990    #[test]
1991    fn lookup_rule_index_covers_every_registered_rule() {
1992        for rule in RULE_REGISTRY {
1993            let looked_up =
1994                lookup_rule(rule.id).unwrap_or_else(|| panic!("registered rule {} is missing from the index", rule.id));
1995            assert_eq!(looked_up.id, rule.id);
1996            assert_eq!(looked_up.category, rule.category, "category mismatch for rule {}", rule.id);
1997            assert_eq!(looked_up.origin, rule.origin, "origin mismatch for rule {}", rule.id);
1998        }
1999        assert_eq!(
2000            RULE_REGISTRY_BY_ID.len(),
2001            RULE_REGISTRY.len(),
2002            "the lookup index must contain exactly one entry per registered rule"
2003        );
2004    }
2005
2006    #[test]
2007    fn to_rule_info_populates_all_fields_from_definition() {
2008        let rule = lookup_rule("F0001").unwrap();
2009        let info = rule.to_rule_info();
2010        assert_eq!(info.id, "F0001");
2011        assert_eq!(info.severity, Severity::Fatal);
2012        assert_eq!(info.category.as_deref(), Some(Category::Structure.as_str()));
2013        assert_eq!(info.origin, RuleOrigin::Schema);
2014    }
2015
2016    #[test]
2017    fn metadata_map_contains_entry_for_every_registered_rule() {
2018        let map = build_rule_metadata_map();
2019        assert_eq!(map.len(), RULE_REGISTRY.len());
2020        for rule in RULE_REGISTRY {
2021            assert!(map.contains_key(rule.id), "Missing rule: {}", rule.id);
2022        }
2023    }
2024
2025    #[test]
2026    fn rule_origin_as_str_returns_screaming_snake_case() {
2027        assert_eq!(RuleOrigin::Schema.as_str(), "SCHEMA");
2028        assert_eq!(RuleOrigin::CfnLint.as_str(), "CFN_LINT");
2029        assert_eq!(RuleOrigin::Engine.as_str(), "ENGINE");
2030        assert_eq!(RuleOrigin::Custom.as_str(), "CUSTOM");
2031        assert_eq!(RuleOrigin::Guard.as_str(), "GUARD");
2032    }
2033
2034    #[test]
2035    fn rule_origin_serde_round_trips() {
2036        for origin in
2037            [RuleOrigin::Schema, RuleOrigin::CfnLint, RuleOrigin::Engine, RuleOrigin::Custom, RuleOrigin::Guard]
2038        {
2039            let json = serde_json::to_string(&origin).unwrap();
2040            let deserialized: RuleOrigin = serde_json::from_str(&json).unwrap();
2041            assert_eq!(deserialized, origin, "round-trip failed for {:?}", origin);
2042        }
2043    }
2044
2045    #[test]
2046    fn rule_info_serde_round_trips() {
2047        let rule = lookup_rule("E3012").unwrap();
2048        let info = rule.to_rule_info();
2049        let json = serde_json::to_string(&info).unwrap();
2050        let deserialized: RuleInfo = serde_json::from_str(&json).unwrap();
2051        assert_eq!(deserialized.id, info.id);
2052        assert_eq!(deserialized.severity, info.severity);
2053        assert_eq!(deserialized.category, info.category);
2054        assert_eq!(deserialized.description, info.description);
2055        assert_eq!(deserialized.origin, info.origin);
2056    }
2057
2058    #[test]
2059    fn rule_ids_match_expected_format() {
2060        let id_re = regex::Regex::new(r"^[FEWID]\d{4}$").unwrap();
2061        for rule in RULE_REGISTRY {
2062            assert!(id_re.is_match(rule.id), "Rule ID '{}' does not match [FEWID]NNNN format", rule.id);
2063        }
2064    }
2065
2066    #[test]
2067    fn no_empty_descriptions() {
2068        for rule in RULE_REGISTRY {
2069            assert!(!rule.description.trim().is_empty(), "Rule {} has empty description", rule.id);
2070        }
2071    }
2072}