rego-engine
Validates CloudFormation templates using Rego policies evaluated by the Regorus
interpreter. Implements the ValidationEngine trait. Custom builtins bridge Rego
policies to the SemanticModel for deep template introspection that pure Rego cannot
express.
Architecture
Rules are organized into Rego packages by category:
| Package |
Eval Path |
Category |
structure |
data.structure.violation |
Template structure |
intrinsics |
data.intrinsics.violation |
Intrinsic functions |
references |
data.references.violation |
Cross-resource refs |
best_practices |
data.best_practices.violation |
Best practices |
resources |
data.resources.violation |
Resource-specific |
Rules come from four sources: handwritten Rego policies embedded by this crate's build script, generated shared data
embedded by data-source, user-provided custom Rego policies, and Guard DSL files. Guard files are not translated to
Rego: they are evaluated by the shared Guard evaluator in validation-engine, which
every engine calls, so the same Guard rule yields the same findings in every engine.
Custom Builtins
These builtins are registered with the Regorus interpreter and called as bare functions in Rego policies - there is no
namespace prefix. For example, a policy calls resolve(name, "Properties.BucketName"), not cfn.resolve(...).
Template Resolution
| Builtin |
Signature |
Purpose |
resolve |
(resource_id, path) → value |
Resolve a property value through intrinsic functions; a reference is rendered per the evaluating package, see below |
resolve_all |
(resource_id, path) → [values] |
Resolve all scenario values for a property |
resolve_scenarios |
(resource_id, path) → [{value, conditions}] |
Resolve all (value, condition_map) pairs |
resolve_ref_target |
(resource_id, path) → {resourceType, condition, properties} |
Resolve the target of a reference |
resolve_type |
(resource_id, path) → type_string |
Get the resolved value type |
is_dynamic |
(resource_id, path) → bool |
Check if a property contains unresolvable content |
is_from_parameter |
(resource_id, path) → bool |
Check if a property originates from a parameter |
is_from_intrinsic |
(resource_id, path) → bool |
Check if a property originates from an intrinsic |
follow_ref |
(resource_id, path) → target_id |
Follow a Ref/GetAtt to its target resource |
flatten_list |
(resource_id, path) → [{value, index}] |
Flatten nested arrays |
Reference rendering
A Ref/Fn::GetAtt to a template resource has no literal before deployment, and resolve (and a reference inside a
list returned by resolve_all) renders it according to the package being evaluated:
- Handwritten built-in policies receive the
{"__ref": target} marker object, the same shape the input document
uses. It is never a bare string, so a format or enum check that guards with is_string skips the reference instead of
judging a logical ID as if it were the value, while a presence check still sees a value.
- Custom rules receive the target's logical ID as a plain string, the contract they were written against; a custom
rule may look the target up in
input.resources or compare it with another logical ID. Rules that validate literal
content should exclude a logical ID with not input.resources[value], or read the reference explicitly with
follow_ref or authored_form.
The rendering is selected per package around each eval_rule query, so the two kinds evaluate on one engine instance
without observing each other's rendering. Guard rules are not affected: they never evaluate through Rego.
Resource Queries
| Builtin |
Signature |
Purpose |
get_resource |
(resource_id) → resource_object |
Get full resolved resource data |
has_property |
(resource_id, path) → bool |
Check if a property is authored, even when its value is only known at deployment |
resources_of_type |
(type_name) → [resource_ids] |
Get all logical IDs of a resource type |
has_transform |
(transform_name) → bool |
Check if a transform is declared |
Graph Queries
| Builtin |
Signature |
Purpose |
ref_targets |
(resource_id) → [target_ids] |
Outgoing reference targets |
ref_sources |
(resource_id) → [source_ids] |
Incoming reference sources |
depends_on |
(resource_a, resource_b) → bool |
Transitive dependency check |
edges_from |
(resource_id) → [edge_objects] |
Detailed outgoing edges |
edges_to |
(resource_id) → [edge_objects] |
Detailed incoming edges |
pipeline_artifacts |
(resource_id) → {issues: [{message}]} |
Extract CodePipeline artifact relationships |
Condition Analysis
| Builtin |
Signature |
Purpose |
conditions_compatible |
(resource_a, resource_b) → bool |
Can both resources' conditions be true simultaneously? |
condition_implies |
(cond_a, cond_b) → bool |
Does cond_a=true force cond_b=true? |
conjunction_implies |
(guard1, guard2, target) → bool |
Does the conjunction of two guards imply target? |
resource_condition |
(resource_id) → condition_name |
Get the Condition on a resource |
is_satisfiable |
(assumptions) → bool |
Is a set of condition assumptions satisfiable? |
unreachable_if_branches |
(resource_id) → [{resourceId, path, message}] |
Find unreachable Fn::If branches in a resource |
Parameter / Mapping
| Builtin |
Signature |
Purpose |
param_allowed_values |
(param_name) → [values] |
Get AllowedValues for a parameter |
param_type |
(param_name) → type_string |
Get the declared Type of a parameter |
mapping_value |
(map, key1, key2) → value |
Look up a value in Mappings |
Schema Introspection
| Builtin |
Signature |
Purpose |
schema_properties |
(resource_type) → [property_names] |
List schema-defined properties |
schema_required |
(resource_type) → [required_names] |
List required properties |
schema_type |
(resource_type, property) → type_string |
Primary schema type (first declared when several) |
schema_enum |
(resource_type, property) → [values] |
Allowed values (incl. case-insensitive enums) |
attribute_type |
(resource_type, property) → type_string |
Get schema attribute type |
getatt_return_type |
(resource_type, attribute) → type_string |
Get GetAtt return type |
schema_string_length |
(resource_type, property) → {minLength?, maxLength?} |
Get string length constraints |
schema_requires_unique_items |
(resource_type, property) → bool |
True when a property schema sets uniqueItems |
Diagnostic Construction
| Builtin |
Signature |
Purpose |
make_diag |
(rule_id, severity, resource_id, message) → diag |
Create a basic diagnostic |
make_diag_at |
(rule_id, severity, resource_id, prop_path, message) → diag |
Diagnostic with property path |
make_diag_full |
(rule_id, severity, resource_id, prop_path, message, fix, doc_url) → diag |
Full diagnostic with fix and URL |
make_diag_related |
(rule_id, severity, resource_id, prop_path, message, related_locations) → diag |
Diagnostic with related locations |
make_diag_conditional |
(rule_id, severity, resource_id, prop_path, message, conditions) → diag |
Diagnostic with condition context |
Utilities
| Builtin |
Signature |
Purpose |
arn_matches |
(arn, pattern) → bool |
Match an ARN against a pattern with wildcards |
ip_overlaps |
(cidr_a, cidr_b) → bool |
Check if two CIDR blocks overlap |
ip_subnet_of |
(subnet, supernet) → bool |
Check if a CIDR is a subnet of another |
is_valid_cidr_strict |
(cidr) → bool |
Validate CIDR notation |
ensure_list |
(value) → [value] |
Wrap scalar in array, pass arrays through |
input_region |
() → region_string |
Get the configured AWS region |
region_flat_invalid |
(region_map, value) → message |
Diagnostic message when a flat instance/node-type value is invalid for the effective scope (configured region, or union of all regions when unset), else undefined |
region_conditional_invalid |
(region_map, target_prop, normalize_engine_case, value, props) → message |
Diagnostic message when a conditional RDS instance-class value is invalid for the effective scope, else undefined |
coerce_to_number |
(value) → number |
CloudFormation-style number coercion |
coerce_to_string |
(value) → string |
CloudFormation-style string coercion |
cfn_type_compatible |
(value, expected_type) → bool |
Check CFN type compatibility with coercion |
estimated_string_length_bounds |
(resource_id, path) → {shortest, longest} |
Shortest and longest resolved string length; undefined when the length cannot be pinned for every possibility |