# cel-engine
Validates CloudFormation templates using a three-tier evaluation strategy: native Rust rule functions for built-in
rules, a generated rule registry for data-driven rules, and
the [cel-interpreter](https://crates.io/crates/cel-interpreter) for user-provided custom rules. Implements
the [ValidationEngine](../validation-engine/README.md) trait.
## Architecture
```
CelEngine::evaluate_rules(model, config)
│
├── Tier 1: Native Rust functions (built-in rules, max performance)
├── Tier 2: Generated rule descriptors (data-driven rules from schemas)
├── Tier 3: Custom CEL expressions (user-provided)
└── Guard DSL rules (shared Guard evaluator, identical in every engine)
│
▼
Vec<Diagnostic>
```
- **Tier 1** - Native Rust functions organized by implementation area (structure, intrinsics, references,
best-practices, resources, and conditions); a module can emit several registry categories. They access the
`SemanticModel` directly with no serialization overhead.
- **Tier 2** - JSON rule descriptors generated by data-source, evaluated natively against
the `SemanticModel`. Indexed by resource type for efficient lookup.
- **Tier 3** - User-provided CEL expressions, compiled at engine init and evaluated via the CEL interpreter at
runtime.
- **Guard DSL rules** are not translated to CEL. They are evaluated by the shared Guard evaluator in
[validation-engine](../validation-engine/README.md), which every engine calls, so the same Guard rule yields the same
findings in every engine.
## Custom CEL Rules
Custom rules are provided as JSON:
```json
{
"rules": [
{
"rule_id": "CUSTOM001",
"severity": "ERROR",
"category": "custom",
"resource_type": "AWS::S3::Bucket",
"expression": "!has(properties.BucketEncryption)",
"message": "S3 bucket {name} must have encryption enabled",
"prop_path": "Properties.BucketEncryption",
"suggested_fix": "Add BucketEncryption configuration"
}
]
}
```
For resource-scoped rules (`resource_type` set), the engine iterates over all resources of that type and evaluates the
CEL expression with resource-specific context. For global rules (no `resource_type`), the expression is evaluated once.
### CEL Context Variables
| `resources` | map | Global | All resolved resources keyed by logical ID |
| `parameters` | map | Global | All parameters with metadata |
| `conditions` | map | Global | All conditions |
| `outputs` | map | Global | All outputs |
| `mappings` | map | Global | All mappings |
| `template` | map | Global | Template metadata (transforms, format version, description) |
| `name` | string | Per-resource | Current resource's logical ID |
| `resource` | map | Per-resource | Current resource's full resolved data |
| `properties` | map | Per-resource | Current resource's resolved properties |
| `resolved_properties` | map | Per-resource | Properties with intrinsic functions fully resolved to values |