Files
regorus/tests/azure_policy/parser_tests/cases/expressions.yaml
Anand Krishnamoorthi 687be2850b feat: add Azure Policy constraint parser (#658)
Add constraint.rs module that parses Azure Policy JSON constraints
into span-annotated AST nodes:

- Logical combinators: allOf, anyOf, not
- Leaf conditions: field/value with all 19 operators
- Count blocks: field-count and value-count with where clauses

Public API: parse_constraint() parses a standalone constraint from JSON.

Includes YAML-driven test suite with 6 test files covering operators,
fields, expressions, logical combinators, count, and parse errors.
2026-04-03 19:09:51 -05:00

555 lines
14 KiB
YAML

# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# ARM Template Expressions Test Suite
# Tests [parameters(...)], [concat(...)], [field(...)], [if(...)], and other
# ARM template expression patterns in field, value, and effect positions.
cases:
# =========================================================================
# parameters() references
# =========================================================================
- note: expr_parameters_in_value
policy_rule: |
{
"if": {
"value": "[parameters('environment')]",
"equals": "production"
},
"then": { "effect": "deny" }
}
parameters:
environment: "production"
resource:
type: "any"
want_effect: "deny"
- note: expr_parameters_in_rhs
policy_rule: |
{
"if": {
"field": "location",
"in": "[parameters('allowedLocations')]"
},
"then": { "effect": "deny" }
}
parameters:
allowedLocations:
- "eastus"
- "westus"
resource:
location: "eastus"
want_effect: "deny"
- note: expr_parameters_in_effect
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": {
"effect": "[parameters('effect')]"
}
}
parameters:
effect: "deny"
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "deny"
# =========================================================================
# concat()
# =========================================================================
- note: expr_concat_strings
policy_rule: |
{
"if": {
"value": "[concat('Microsoft.Compute/', 'virtualMachines')]",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: expr_concat_with_parameters
policy_rule: |
{
"if": {
"value": "[concat(parameters('prefix'), '-vm')]",
"equals": "prod-vm"
},
"then": { "effect": "audit" }
}
parameters:
prefix: "prod"
resource:
type: "any"
want_effect: "audit"
- note: expr_concat_nested
policy_rule: |
{
"if": {
"value": "[concat(concat('a', 'b'), 'c')]",
"equals": "abc"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
# =========================================================================
# field() function
# =========================================================================
- note: expr_field_function
policy_rule: |
{
"if": {
"value": "[field('name')]",
"contains": "prod"
},
"then": { "effect": "audit" }
}
resource:
name: "my-prod-vm"
want_effect: "audit"
- note: expr_field_in_concat
policy_rule: |
{
"if": {
"value": "[concat(field('type'), '/', field('name'))]",
"contains": "Microsoft.Compute"
},
"then": { "effect": "audit" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
name: "vm1"
want_effect: "audit"
# =========================================================================
# if() conditional
# =========================================================================
- note: expr_if_conditional
policy_rule: |
{
"if": {
"value": "[if(equals(parameters('env'), 'prod'), 'deny', 'audit')]",
"equals": "deny"
},
"then": { "effect": "audit" }
}
parameters:
env: "prod"
resource:
type: "any"
want_effect: "audit"
# =========================================================================
# String functions
# =========================================================================
- note: expr_toLower
policy_rule: |
{
"if": {
"value": "[toLower(field('name'))]",
"equals": "my-vm"
},
"then": { "effect": "audit" }
}
resource:
name: "My-VM"
want_effect: "audit"
- note: expr_toUpper
policy_rule: |
{
"if": {
"value": "[toUpper(parameters('prefix'))]",
"equals": "PROD"
},
"then": { "effect": "audit" }
}
parameters:
prefix: "prod"
resource:
type: "any"
want_effect: "audit"
- note: expr_replace
policy_rule: |
{
"if": {
"value": "[replace(field('name'), '-', '_')]",
"equals": "my_prod_vm"
},
"then": { "effect": "audit" }
}
resource:
name: "my-prod-vm"
want_effect: "audit"
- note: expr_substring
policy_rule: |
{
"if": {
"value": "[substring(field('name'), 0, 4)]",
"equals": "prod"
},
"then": { "effect": "audit" }
}
resource:
name: "prod-vm-01"
want_effect: "audit"
# =========================================================================
# Numeric functions
# =========================================================================
- note: expr_length
policy_rule: |
{
"if": {
"value": "[length(parameters('allowedLocations'))]",
"greater": 0
},
"then": { "effect": "audit" }
}
parameters:
allowedLocations:
- "eastus"
- "westus"
resource:
type: "any"
want_effect: "audit"
- note: expr_add
policy_rule: |
{
"if": {
"value": "[add(parameters('base'), 1)]",
"greater": 5
},
"then": { "effect": "audit" }
}
parameters:
base: 10
resource:
type: "any"
want_effect: "audit"
# =========================================================================
# Context functions
# =========================================================================
- note: expr_resourceGroup
policy_rule: |
{
"if": {
"value": "[resourceGroup().location]",
"notIn": "[parameters('allowedLocations')]"
},
"then": { "effect": "deny" }
}
parameters:
allowedLocations:
- "westus2"
- "centralus"
resource:
type: "any"
want_effect: "deny"
- note: expr_subscription
policy_rule: |
{
"if": {
"value": "[subscription().subscriptionId]",
"equals": "00000000-0000-0000-0000-000000000000"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: expr_requestContext_apiVersion
policy_rule: |
{
"if": {
"value": "[requestContext().apiVersion]",
"greaterOrEquals": "2021-04-01"
},
"then": { "effect": "deny" }
}
context:
resourceGroup:
name: "myResourceGroup"
location: "eastus"
subscription:
subscriptionId: "00000000-0000-0000-0000-000000000000"
requestContext:
apiVersion: "2023-01-01"
resource:
type: "any"
want_effect: "deny"
- note: expr_requestContext_apiVersion_older
policy_rule: |
{
"if": {
"value": "[requestContext().apiVersion]",
"greaterOrEquals": "2024-06-01"
},
"then": { "effect": "deny" }
}
context:
resourceGroup:
name: "myResourceGroup"
location: "eastus"
subscription:
subscriptionId: "00000000-0000-0000-0000-000000000000"
requestContext:
apiVersion: "2023-01-01"
resource:
type: "any"
want_undefined: true
- note: expr_policy_assignmentId
policy_rule: |
{
"if": {
"value": "[policy().assignmentId]",
"equals": "/subscriptions/sub1/providers/Microsoft.Authorization/policyAssignments/myAssignment"
},
"then": { "effect": "audit" }
}
context:
resourceGroup:
name: "myResourceGroup"
location: "eastus"
subscription:
subscriptionId: "00000000-0000-0000-0000-000000000000"
policy:
assignmentId: "/subscriptions/sub1/providers/Microsoft.Authorization/policyAssignments/myAssignment"
definitionId: "/providers/Microsoft.Authorization/policyDefinitions/myDefinition"
setDefinitionId: ""
definitionReferenceId: ""
resource:
type: "any"
want_effect: "audit"
- note: expr_policy_definitionId
policy_rule: |
{
"if": {
"value": "[policy().definitionId]",
"contains": "myDefinition"
},
"then": { "effect": "deny" }
}
context:
resourceGroup:
name: "myResourceGroup"
location: "eastus"
subscription:
subscriptionId: "00000000-0000-0000-0000-000000000000"
policy:
assignmentId: "/subscriptions/sub1/providers/Microsoft.Authorization/policyAssignments/myAssignment"
definitionId: "/providers/Microsoft.Authorization/policyDefinitions/myDefinition"
resource:
type: "any"
want_effect: "deny"
# =========================================================================
# current() in count contexts
# =========================================================================
- note: expr_current_in_value_count
policy_rule: |
{
"if": {
"count": {
"value": "[parameters('requiredTags')]",
"name": "tagName",
"where": {
"value": "[current('tagName')]",
"notEquals": ""
}
},
"greater": 0
},
"then": { "effect": "audit" }
}
parameters:
requiredTags:
- "environment"
- "costCenter"
resource:
type: "any"
want_effect: "audit"
# =========================================================================
# Dot and index access in expressions
# =========================================================================
- note: expr_dot_access
policy_rule: |
{
"if": {
"value": "[resourceGroup().name]",
"equals": "myResourceGroup"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: expr_index_access
policy_rule: |
{
"if": {
"value": "[parameters('allowedLocations')[0]]",
"equals": "eastus"
},
"then": { "effect": "audit" }
}
parameters:
allowedLocations:
- "eastus"
- "westus"
resource:
type: "any"
want_effect: "audit"
# =========================================================================
# Escaped bracket literals (not expressions)
# =========================================================================
- note: escaped_bracket_literal
policy_rule: |
{
"if": {
"field": "name",
"equals": "[[not-an-expression]"
},
"then": { "effect": "audit" }
}
resource:
name: "[not-an-expression]"
want_effect: "audit"
# =========================================================================
# Complex nested expressions
# =========================================================================
- note: expr_complex_nested
policy_rule: |
{
"if": {
"value": "[if(contains(toLower(field('location')), 'us'), 'allowed', 'blocked')]",
"equals": "blocked"
},
"then": { "effect": "deny" }
}
resource:
location: "northeurope"
want_effect: "deny"
- note: expr_multiple_expression_fields
policy_rule: |
{
"if": {
"allOf": [
{
"value": "[parameters('environment')]",
"equals": "production"
},
{
"value": "[concat(parameters('prefix'), '-', parameters('suffix'))]",
"notEquals": ""
},
{
"value": "[length(parameters('allowedLocations'))]",
"greater": 0
}
]
},
"then": { "effect": "deny" }
}
parameters:
environment: "production"
prefix: "prod"
suffix: "01"
allowedLocations:
- "eastus"
resource:
type: "any"
want_effect: "deny"
# =========================================================================
# Unary minus for negative number literals
# =========================================================================
- note: expr_unary_minus_literal
policy_rule: |
{
"if": {
"value": "[add(-1, 5)]",
"equals": 4
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
- note: expr_unary_minus_float
policy_rule: |
{
"if": {
"value": "[add(-2.5, 3.5)]",
"equals": 1
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
- note: expr_unary_minus_sub_expression
policy_rule: |
{
"if": {
"value": "[sub(10, -3)]",
"equals": 13
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
- note: expr_zero_arg_function_call
policy_rule: |
{
"if": {
"value": "[concat()]",
"equals": ""
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"