test(azure_policy): add foundation test cases (#698)

YAML-driven test cases for the core Azure Policy compiler. These cover
alias resolution, field conditions, logical operators, type coercion,
count expressions, template functions, effect compilation, and policy
definition parsing. 24 files, each a self-contained scenario exercised
by the test runner in the companion code PR.

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Anand Krishnamoorthi
2026-04-28 11:03:39 -05:00
committed by GitHub
parent afdb894d85
commit 7f42115b63
24 changed files with 14295 additions and 0 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,482 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Complex Policies Test Suite
# Tests realistic, multi-layer Azure Policy definitions covering combinations of
# operators, logical combinators, expressions, fields, counts, and effects.
cases:
# =========================================================================
# Require HTTPS for storage accounts
# =========================================================================
- note: require_https_storage
policy_rule: |
{
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
},
{
"field": "properties.supportsHttpsTrafficOnly",
"notEquals": true
}
]
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Storage/storageAccounts"
properties:
supportsHttpsTrafficOnly: false
want_effect: "deny"
# =========================================================================
# Allowed locations with parameterized effect
# =========================================================================
- note: allowed_locations_parameterized
policy_rule: |
{
"if": {
"allOf": [
{
"field": "location",
"notIn": "[parameters('allowedLocations')]"
},
{
"field": "location",
"notEquals": "global"
},
{
"field": "type",
"notEquals": "Microsoft.AzureActiveDirectory/b2cDirectories"
}
]
},
"then": {
"effect": "[parameters('effect')]"
}
}
parameters:
allowedLocations:
- "eastus"
- "westus"
effect: "deny"
resource:
type: "Microsoft.Compute/virtualMachines"
location: "northeurope"
want_effect: "deny"
# =========================================================================
# Require tags with parameter-driven enforcement
# =========================================================================
- note: require_tag_environment
policy_rule: |
{
"if": {
"allOf": [
{
"field": "type",
"notEquals": "Microsoft.Resources/subscriptions"
},
{
"field": "[concat('tags[', parameters('tagName'), ']')]",
"exists": false
}
]
},
"then": {
"effect": "deny",
"details": {
"message": "Required tag is missing"
}
}
}
parameters:
tagName: "environment"
resource:
type: "Microsoft.Compute/virtualMachines"
tags: {}
want_effect: "deny"
# =========================================================================
# NSG rule restriction — deny risky inbound ports
# =========================================================================
- note: deny_risky_inbound_nsg
policy_rule: |
{
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Network/networkSecurityGroups/securityRules"
},
{
"field": "properties.direction",
"equals": "Inbound"
},
{
"field": "properties.access",
"equals": "Allow"
},
{
"anyOf": [
{
"field": "properties.destinationPortRange",
"in": ["22", "3389", "*"]
},
{
"field": "properties.sourceAddressPrefix",
"in": ["*", "Internet", "0.0.0.0/0"]
}
]
}
]
},
"then": {
"effect": "deny",
"details": {
"message": "Risky inbound NSG rules are not allowed"
}
}
}
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
properties:
direction: "Inbound"
access: "Allow"
destinationPortRange: "22"
sourceAddressPrefix: "*"
want_effect: "deny"
# =========================================================================
# Modify — add tags if missing
# =========================================================================
- note: modify_add_tags
policy_rule: |
{
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
{
"anyOf": [
{ "field": "tags.environment", "exists": false },
{ "field": "tags.costCenter", "exists": false }
]
}
]
},
"then": {
"effect": "modify",
"details": {
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
],
"operations": [
{
"operation": "addOrReplace",
"field": "tags['environment']",
"value": "[if(empty(field('tags.environment')), 'unknown', field('tags.environment'))]"
},
{
"operation": "addOrReplace",
"field": "tags['costCenter']",
"value": "[if(empty(field('tags.costCenter')), 'unassigned', field('tags.costCenter'))]"
}
]
}
}
}
resource:
type: "Microsoft.Compute/virtualMachines"
tags:
environment: "prod"
want_effect: "modify"
# =========================================================================
# Count — deny if too many open NSG rules
# =========================================================================
- note: deny_excessive_open_nsg_rules
policy_rule: |
{
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Network/networkSecurityGroups"
},
{
"count": {
"field": "securityRules[*]",
"where": {
"allOf": [
{
"field": "securityRules[*].access",
"equals": "Allow"
},
{
"field": "securityRules[*].direction",
"equals": "Inbound"
},
{
"field": "securityRules[*].sourceAddressPrefix",
"equals": "*"
}
]
}
},
"greater": 0
}
]
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Network/networkSecurityGroups"
securityRules:
-
access: "Allow"
direction: "Inbound"
sourceAddressPrefix: "*"
want_effect: "deny"
# =========================================================================
# AuditIfNotExists — require diagnostics settings
# =========================================================================
- note: audit_diagnostics_settings
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.KeyVault/vaults"
},
"then": {
"effect": "auditIfNotExists",
"details": {
"type": "Microsoft.Insights/diagnosticSettings",
"existenceCondition": {
"allOf": [
{
"field": "properties.logs.enabled",
"equals": true
},
{
"field": "properties.logs.retentionPolicy.enabled",
"equals": true
},
{
"field": "properties.logs.retentionPolicy.days",
"greaterOrEquals": 90
}
]
}
}
}
}
resource:
type: "Microsoft.KeyVault/vaults"
host_await:
- key:
operation: "lookup_related_resources"
type: "Microsoft.Insights/diagnosticSettings"
response: null
want_effect: "auditIfNotExists"
# =========================================================================
# DeployIfNotExists — deploy monitoring agent
# =========================================================================
- note: deploy_monitoring_agent
policy_rule: |
{
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
{
"field": "properties.storageProfile.imageReference.publisher",
"equals": "Canonical"
}
]
},
"then": {
"effect": "deployIfNotExists",
"details": {
"type": "Microsoft.Compute/virtualMachines/extensions",
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/9980e02c-c2be-4d73-94e8-173b1dc7cf3c"
],
"existenceCondition": {
"allOf": [
{
"field": "properties.publisher",
"equals": "Microsoft.Azure.Monitor"
},
{
"field": "properties.type",
"equals": "AzureMonitorLinuxAgent"
}
]
},
"deployment": {
"properties": {
"mode": "incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"resources": []
}
}
}
}
}
}
resource:
type: "Microsoft.Compute/virtualMachines"
properties:
storageProfile:
imageReference:
publisher: "Canonical"
host_await:
- response: null
want_effect: "deployIfNotExists"
# =========================================================================
# Value count with complex where — required tags
# =========================================================================
- note: required_tags_value_count
policy_rule: |
{
"if": {
"allOf": [
{
"field": "type",
"notEquals": "Microsoft.Resources/subscriptions"
},
{
"count": {
"value": "[parameters('requiredTags')]",
"name": "tagName",
"where": {
"field": "[concat('tags[', current('tagName'), ']')]",
"exists": true
}
},
"notEquals": "[length(parameters('requiredTags'))]"
}
]
},
"then": {
"effect": "deny",
"details": {
"message": "Not all required tags are present"
}
}
}
parameters:
requiredTags:
- "environment"
- "costCenter"
- "owner"
resource:
type: "Microsoft.Compute/virtualMachines"
tags:
environment: "prod"
costCenter: "12345"
want_effect: "deny"
# =========================================================================
# Multi-resource type policy with not
# =========================================================================
- note: multi_type_with_not
policy_rule: |
{
"if": {
"allOf": [
{
"not": {
"anyOf": [
{ "field": "type", "equals": "Microsoft.Resources/subscriptions" },
{ "field": "type", "equals": "Microsoft.Resources/subscriptions/resourceGroups" },
{ "field": "type", "equals": "Microsoft.Authorization/roleAssignments" }
]
}
},
{
"field": "location",
"notIn": "[parameters('allowedLocations')]"
}
]
},
"then": {
"effect": "[parameters('effect')]",
"details": {
"message": "Resource location is not in the allowed list"
}
}
}
parameters:
allowedLocations:
- "eastus"
- "westus"
- "centralus"
effect: "deny"
resource:
type: "Microsoft.Compute/virtualMachines"
location: "southeastasia"
want_effect: "deny"
# =========================================================================
# Condition-free policy (always true if block is trivially satisfied)
# =========================================================================
- note: trivial_allOf_empty
policy_rule: |
{
"if": {
"allOf": []
},
"then": { "effect": "audit" }
}
resource:
type: "anything"
want_effect: "audit"
# =========================================================================
# Exists mixed with value comparisons
# =========================================================================
- note: exists_and_value_check
policy_rule: |
{
"if": {
"allOf": [
{ "field": "type", "equals": "Microsoft.Storage/storageAccounts" },
{ "field": "properties.networkAcls", "exists": true },
{ "field": "properties.networkAcls.defaultAction", "notEquals": "Deny" }
]
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Storage/storageAccounts"
properties:
networkAcls:
defaultAction: "Allow"
want_effect: "deny"

View File

@@ -0,0 +1,617 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Count Expressions Test Suite
# Tests field count and value count with optional where clauses and name bindings.
cases:
# =========================================================================
# Field count — direct path (core subset, no alias resolution)
# =========================================================================
- note: field_count_direct_path_core
policy_rule: |
{
"if": {
"count": {
"field": "securityRules[*]"
},
"greater": 2
},
"then": { "effect": "deny" }
}
resource:
securityRules:
- { "name": "r1" }
- { "name": "r2" }
- { "name": "r3" }
want_effect: "deny"
- note: field_count_direct_path_where_core
policy_rule: |
{
"if": {
"count": {
"field": "securityRules[*]",
"where": {
"field": "securityRules[*].access",
"equals": "Allow"
}
},
"equals": 2
},
"then": { "effect": "audit" }
}
resource:
securityRules:
- { "access": "Allow" }
- { "access": "Deny" }
- { "access": "Allow" }
want_effect: "audit"
# =========================================================================
# Field count — basic
# =========================================================================
- note: field_count_basic
policy_rule: |
{
"if": {
"count": {
"field": "securityRules[*]"
},
"greater": 10
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Network/networkSecurityGroups"
securityRules:
- { "name": "r1" }
- { "name": "r2" }
- { "name": "r3" }
- { "name": "r4" }
- { "name": "r5" }
- { "name": "r6" }
- { "name": "r7" }
- { "name": "r8" }
- { "name": "r9" }
- { "name": "r10" }
- { "name": "r11" }
want_effect: "deny"
- note: field_count_equals_zero
policy_rule: |
{
"if": {
"count": {
"field": "storageProfile.dataDisks[*]"
},
"equals": 0
},
"then": { "effect": "audit" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "audit"
# =========================================================================
# Field count — with where clause
# =========================================================================
- note: field_count_with_where
policy_rule: |
{
"if": {
"count": {
"field": "securityRules[*]",
"where": {
"field": "securityRules[*].access",
"equals": "Allow"
}
},
"greater": 5
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Network/networkSecurityGroups"
securityRules:
- { "access": "Allow" }
- { "access": "Allow" }
- { "access": "Allow" }
- { "access": "Allow" }
- { "access": "Allow" }
- { "access": "Allow" }
want_effect: "deny"
- note: field_count_where_allOf
policy_rule: |
{
"if": {
"count": {
"field": "securityRules[*]",
"where": {
"allOf": [
{
"field": "securityRules[*].access",
"equals": "Allow"
},
{
"field": "securityRules[*].direction",
"equals": "Inbound"
}
]
}
},
"greaterOrEquals": 1
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Network/networkSecurityGroups"
securityRules:
- { "access": "Allow", "direction": "Inbound" }
- { "access": "Deny", "direction": "Outbound" }
want_effect: "deny"
- note: field_count_where_anyOf
policy_rule: |
{
"if": {
"count": {
"field": "securityRules[*]",
"where": {
"anyOf": [
{
"field": "securityRules[*].destinationPortRange",
"equals": "22"
},
{
"field": "securityRules[*].destinationPortRange",
"equals": "3389"
}
]
}
},
"notEquals": 0
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Network/networkSecurityGroups"
securityRules:
- { "destinationPortRange": "22" }
- { "destinationPortRange": "443" }
want_effect: "deny"
- note: field_count_where_not
policy_rule: |
{
"if": {
"count": {
"field": "securityRules[*]",
"where": {
"not": {
"field": "securityRules[*].access",
"equals": "Deny"
}
}
},
"greater": 0
},
"then": { "effect": "audit" }
}
resource:
type: "Microsoft.Network/networkSecurityGroups"
securityRules:
- { "access": "Allow" }
- { "access": "Deny" }
want_effect: "audit"
# =========================================================================
# Value count
# =========================================================================
- note: value_count_basic
policy_rule: |
{
"if": {
"count": {
"value": ["eastus", "westus", "centralus"]
},
"equals": 3
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: value_count_with_name
policy_rule: |
{
"if": {
"count": {
"value": ["eastus", "westus", "centralus"],
"name": "location"
},
"greater": 0
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: value_count_with_name_and_where
policy_rule: |
{
"if": {
"count": {
"value": ["eastus", "westus", "centralus", "northeurope"],
"name": "loc",
"where": {
"value": "[current('loc')]",
"like": "*us"
}
},
"equals": 3
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: value_count_expression
policy_rule: |
{
"if": {
"count": {
"value": "[parameters('allowedLocations')]",
"name": "loc"
},
"greater": 0
},
"then": { "effect": "audit" }
}
parameters:
allowedLocations:
- "eastus"
- "westus"
resource:
type: "any"
want_effect: "audit"
# =========================================================================
# Count in allOf/anyOf
# =========================================================================
- note: count_in_allOf
policy_rule: |
{
"if": {
"allOf": [
{ "field": "type", "equals": "Microsoft.Network/networkSecurityGroups" },
{
"count": {
"field": "securityRules[*]",
"where": {
"field": "securityRules[*].access",
"equals": "Allow"
}
},
"greater": 10
}
]
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Network/networkSecurityGroups"
securityRules:
- { "access": "Allow" }
- { "access": "Allow" }
- { "access": "Allow" }
- { "access": "Allow" }
- { "access": "Allow" }
- { "access": "Allow" }
- { "access": "Allow" }
- { "access": "Allow" }
- { "access": "Allow" }
- { "access": "Allow" }
- { "access": "Allow" }
want_effect: "deny"
- note: count_in_not
policy_rule: |
{
"if": {
"not": {
"count": {
"field": "storageProfile.dataDisks[*]"
},
"lessOrEquals": 4
}
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
storageProfile:
dataDisks:
- { "name": "d1" }
- { "name": "d2" }
- { "name": "d3" }
- { "name": "d4" }
- { "name": "d5" }
want_effect: "deny"
# =========================================================================
# Count with nested where containing count
# =========================================================================
- note: value_count_nested_where
policy_rule: |
{
"if": {
"count": {
"value": "[parameters('requiredTags')]",
"name": "tag",
"where": {
"field": "[concat('tags[', current('tag'), ']')]",
"exists": true
}
},
"notEquals": "[length(parameters('requiredTags'))]"
},
"then": { "effect": "deny" }
}
parameters:
requiredTags:
- "environment"
- "costCenter"
resource:
type: "Microsoft.Compute/virtualMachines"
tags:
environment: "prod"
want_effect: "deny"
# =========================================================================
# Alias field refs inside count resolve to current loop element
# =========================================================================
- note: field_count_multiple_alias_refs_same_element
policy_rule: |
{
"if": {
"count": {
"field": "securityRules[*]",
"where": {
"allOf": [
{ "field": "securityRules[*].access", "equals": "Allow" },
{ "field": "securityRules[*].direction", "equals": "Inbound" },
{ "field": "securityRules[*].protocol", "equals": "Tcp" }
]
}
},
"equals": 1
},
"then": { "effect": "audit" }
}
resource:
securityRules:
- { "access": "Allow", "direction": "Inbound", "protocol": "Tcp" }
- { "access": "Allow", "direction": "Outbound", "protocol": "Tcp" }
- { "access": "Deny", "direction": "Inbound", "protocol": "Tcp" }
want_effect: "audit"
- note: field_count_nested_field_access
policy_rule: |
{
"if": {
"count": {
"field": "storageProfile.dataDisks[*]",
"where": {
"field": "storageProfile.dataDisks[*].managedDisk.storageAccountType",
"notEquals": "Premium_LRS"
}
},
"greater": 0
},
"then": { "effect": "deny" }
}
resource:
storageProfile:
dataDisks:
- { "name": "d1", "managedDisk": { "storageAccountType": "Premium_LRS" } }
- { "name": "d2", "managedDisk": { "storageAccountType": "Standard_LRS" } }
want_effect: "deny"
- note: field_count_where_zero_matches
policy_rule: |
{
"if": {
"count": {
"field": "items[*]",
"where": {
"field": "items[*].status",
"equals": "failed"
}
},
"equals": 0
},
"then": { "effect": "audit" }
}
resource:
items:
- { "status": "ok" }
- { "status": "ok" }
- { "status": "ok" }
want_effect: "audit"
# =========================================================================
# Nested count: count inside another count's where clause
# =========================================================================
- note: nested_field_and_value_count
policy_rule: |
{
"if": {
"count": {
"value": "[parameters('requiredPorts')]",
"name": "port",
"where": {
"count": {
"field": "securityRules[*]",
"where": {
"allOf": [
{ "field": "securityRules[*].destinationPortRange", "equals": "[current('port')]" },
{ "field": "securityRules[*].access", "equals": "Allow" }
]
}
},
"greater": 0
}
},
"equals": "[length(parameters('requiredPorts'))]"
},
"then": { "effect": "audit" }
}
parameters:
requiredPorts:
- "443"
- "80"
resource:
securityRules:
- { "destinationPortRange": "443", "access": "Allow" }
- { "destinationPortRange": "80", "access": "Allow" }
- { "destinationPortRange": "22", "access": "Deny" }
want_effect: "audit"
- note: nested_field_and_value_count_fail
policy_rule: |
{
"if": {
"count": {
"value": "[parameters('requiredPorts')]",
"name": "port",
"where": {
"count": {
"field": "securityRules[*]",
"where": {
"allOf": [
{ "field": "securityRules[*].destinationPortRange", "equals": "[current('port')]" },
{ "field": "securityRules[*].access", "equals": "Allow" }
]
}
},
"greater": 0
}
},
"equals": "[length(parameters('requiredPorts'))]"
},
"then": { "effect": "deny" }
}
parameters:
requiredPorts:
- "443"
- "80"
- "8080"
resource:
securityRules:
- { "destinationPortRange": "443", "access": "Allow" }
- { "destinationPortRange": "80", "access": "Allow" }
- { "destinationPortRange": "22", "access": "Deny" }
want_effect: ~
# =========================================================================
# current() — zero-arg form (innermost count element)
# =========================================================================
- note: current_zero_arg_value_count
policy_rule: |
{
"if": {
"count": {
"value": ["Allow", "Allow", "Deny"],
"name": "access",
"where": {
"value": "[current()]",
"equals": "Allow"
}
},
"equals": 2
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
- note: current_zero_arg_field_count
policy_rule: |
{
"if": {
"count": {
"field": "items[*]",
"where": {
"value": "[current()]",
"equals": "yes"
}
},
"equals": 2
},
"then": { "effect": "deny" }
}
resource:
items: ["yes", "no", "yes"]
want_effect: "deny"
- note: current_zero_arg_with_function
policy_rule: |
{
"if": {
"count": {
"value": ["HELLO", "WORLD"],
"name": "word",
"where": {
"value": "[startsWith(current(), 'HE')]",
"equals": true
}
},
"equals": 1
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
- note: current_zero_arg_nested_innermost
policy_rule: |
{
"if": {
"count": {
"value": ["a", "b"],
"name": "outer",
"where": {
"count": {
"value": ["x", "y"],
"name": "inner",
"where": {
"value": "[current()]",
"equals": "x"
}
},
"greater": 0
}
},
"greater": 0
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"

View File

@@ -0,0 +1,684 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Deep Nesting & Edge-Case Test Suite
# Tests deeply nested logical combinators, nested ARM expressions,
# nested count loops, and edge cases around condition-no-match paths.
cases:
# =========================================================================
# Deep logical combinator nesting (4+ levels)
# =========================================================================
- note: four_level_nesting
policy_rule: |
{
"if": {
"allOf": [
{
"anyOf": [
{
"not": {
"allOf": [
{ "field": "type", "equals": "Microsoft.Compute/virtualMachines" },
{ "field": "location", "equals": "westus" }
]
}
},
{
"field": "kind", "equals": "linux"
}
]
},
{ "field": "name", "notEquals": "" }
]
},
"then": { "effect": "audit" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
location: "eastus"
kind: "windows"
name: "my-vm"
want_effect: "audit"
- note: four_level_nesting_no_match
policy_rule: |
{
"if": {
"allOf": [
{
"anyOf": [
{
"not": {
"allOf": [
{ "field": "type", "equals": "Microsoft.Compute/virtualMachines" },
{ "field": "location", "equals": "eastus" }
]
}
},
{
"field": "kind", "equals": "linux"
}
]
},
{ "field": "name", "notEquals": "" }
]
},
"then": { "effect": "audit" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
location: "eastus"
kind: "windows"
name: "my-vm"
want_undefined: true
- note: five_level_nesting
policy_rule: |
{
"if": {
"not": {
"allOf": [
{
"anyOf": [
{
"not": {
"allOf": [
{ "field": "type", "equals": "Microsoft.Storage/storageAccounts" },
{ "field": "properties.supportsHttpsTrafficOnly", "equals": true }
]
}
}
]
}
]
}
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Storage/storageAccounts"
properties:
supportsHttpsTrafficOnly: true
want_effect: "deny"
# =========================================================================
# Deeply nested ARM template expressions
# =========================================================================
- note: nested_toLower_concat
policy_rule: |
{
"if": {
"value": "[toLower(concat(parameters('prefix'), '-', field('name')))]",
"equals": "prod-myvm"
},
"then": { "effect": "audit" }
}
parameters:
prefix: "PROD"
resource:
name: "MYVM"
want_effect: "audit"
- note: nested_if_equals_contains
policy_rule: |
{
"if": {
"value": "[if(contains(field('location'), 'us'), 'allowed', 'blocked')]",
"equals": "blocked"
},
"then": { "effect": "deny" }
}
resource:
location: "northeurope"
want_effect: "deny"
- note: nested_if_equals_allowed
policy_rule: |
{
"if": {
"value": "[if(contains(field('location'), 'us'), 'allowed', 'blocked')]",
"equals": "blocked"
},
"then": { "effect": "deny" }
}
resource:
location: "eastus"
want_undefined: true
- note: nested_length_of_concat
policy_rule: |
{
"if": {
"value": "[length(concat(parameters('a'), parameters('b')))]",
"greater": 6
},
"then": { "effect": "audit" }
}
parameters:
a: "hello"
b: "world"
resource:
type: "any"
want_effect: "audit"
- note: nested_add_length_length
policy_rule: |
{
"if": {
"value": "[add(length(parameters('list1')), length(parameters('list2')))]",
"equals": 5
},
"then": { "effect": "audit" }
}
parameters:
list1: ["a", "b"]
list2: ["c", "d", "e"]
resource:
type: "any"
want_effect: "audit"
- note: triple_nested_replace_toLower
policy_rule: |
{
"if": {
"value": "[replace(toLower(field('name')), '-', '_')]",
"equals": "my_vm"
},
"then": { "effect": "audit" }
}
resource:
name: "My-VM"
want_effect: "audit"
- note: triple_nested_substring_concat
policy_rule: |
{
"if": {
"value": "[substring(concat(parameters('prefix'), '-', field('name')), 0, 4)]",
"equals": "prod"
},
"then": { "effect": "audit" }
}
parameters:
prefix: "prod"
resource:
name: "myvm"
want_effect: "audit"
# =========================================================================
# Count inside anyOf (not just allOf)
# =========================================================================
- note: count_inside_anyOf
policy_rule: |
{
"if": {
"anyOf": [
{
"count": {
"field": "securityRules[*]",
"where": {
"field": "securityRules[*].access",
"equals": "Allow"
}
},
"greater": 5
},
{
"field": "type",
"equals": "something-else"
}
]
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Network/networkSecurityGroups"
securityRules:
- { access: "Allow" }
- { access: "Allow" }
- { access: "Allow" }
- { access: "Allow" }
- { access: "Allow" }
- { access: "Allow" }
want_effect: "deny"
# =========================================================================
# Count edge cases
# =========================================================================
- note: field_count_empty_array
policy_rule: |
{
"if": {
"count": {
"field": "items[*]"
},
"equals": 0
},
"then": { "effect": "audit" }
}
resource:
items: []
want_effect: "audit"
- note: field_count_where_matches_none
policy_rule: |
{
"if": {
"count": {
"field": "securityRules[*]",
"where": {
"field": "securityRules[*].access",
"equals": "SuperAllow"
}
},
"equals": 0
},
"then": { "effect": "audit" }
}
resource:
securityRules:
- { access: "Allow" }
- { access: "Deny" }
want_effect: "audit"
- note: field_count_where_matches_all
policy_rule: |
{
"if": {
"count": {
"field": "items[*]",
"where": {
"field": "items[*].enabled",
"equals": true
}
},
"equals": 3
},
"then": { "effect": "audit" }
}
resource:
items:
- { enabled: true }
- { enabled: true }
- { enabled: true }
want_effect: "audit"
- note: value_count_empty_parameter_array
policy_rule: |
{
"if": {
"count": {
"value": "[parameters('emptyList')]"
},
"equals": 0
},
"then": { "effect": "audit" }
}
parameters:
emptyList: []
resource:
type: "any"
want_effect: "audit"
- note: value_count_greater_no_match
policy_rule: |
{
"if": {
"count": {
"value": ["a", "b"]
},
"greater": 5
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_undefined: true
# =========================================================================
# Count with deeply nested where clauses
# =========================================================================
- note: count_where_allOf_nested_anyOf
policy_rule: |
{
"if": {
"count": {
"field": "rules[*]",
"where": {
"allOf": [
{ "field": "rules[*].enabled", "equals": true },
{
"anyOf": [
{ "field": "rules[*].priority", "equals": "high" },
{ "field": "rules[*].priority", "equals": "critical" }
]
}
]
}
},
"greater": 0
},
"then": { "effect": "deny" }
}
resource:
rules:
- { enabled: true, priority: "low" }
- { enabled: true, priority: "critical" }
- { enabled: false, priority: "high" }
want_effect: "deny"
- note: count_where_not_nested
policy_rule: |
{
"if": {
"count": {
"field": "items[*]",
"where": {
"not": {
"anyOf": [
{ "field": "items[*].status", "equals": "approved" },
{ "field": "items[*].status", "equals": "pending" }
]
}
}
},
"greater": 0
},
"then": { "effect": "deny" }
}
resource:
items:
- { status: "approved" }
- { status: "rejected" }
- { status: "pending" }
want_effect: "deny"
# =========================================================================
# Operators with missing/null fields
# =========================================================================
- note: greater_on_missing_field
policy_rule: |
{
"if": {
"field": "properties.missingProp",
"greater": 10
},
"then": { "effect": "deny" }
}
resource:
properties: {}
want_undefined: true
- note: less_on_missing_field
policy_rule: |
{
"if": {
"field": "properties.missingProp",
"less": 100
},
"then": { "effect": "deny" }
}
resource:
properties: {}
want_undefined: true
- note: contains_on_missing_field
policy_rule: |
{
"if": {
"field": "properties.missingProp",
"contains": "anything"
},
"then": { "effect": "deny" }
}
resource:
properties: {}
want_undefined: true
- note: in_on_missing_field
policy_rule: |
{
"if": {
"field": "properties.missingProp",
"in": ["a", "b", "c"]
},
"then": { "effect": "deny" }
}
resource:
properties: {}
want_undefined: true
- note: like_on_missing_field
policy_rule: |
{
"if": {
"field": "properties.missingProp",
"like": "any*"
},
"then": { "effect": "deny" }
}
resource:
properties: {}
want_undefined: true
- note: match_on_missing_field
policy_rule: |
{
"if": {
"field": "properties.missingProp",
"match": "test-##"
},
"then": { "effect": "deny" }
}
resource:
properties: {}
want_undefined: true
- note: notEquals_on_missing_field
policy_rule: |
{
"if": {
"field": "properties.missingProp",
"notEquals": "something"
},
"then": { "effect": "audit" }
}
resource:
properties: {}
want_effect: "audit"
- note: notIn_on_missing_field
policy_rule: |
{
"if": {
"field": "properties.missingProp",
"notIn": ["a", "b"]
},
"then": { "effect": "audit" }
}
resource:
properties: {}
want_effect: "audit"
- note: exists_true_on_missing_field
policy_rule: |
{
"if": {
"field": "properties.missingProp",
"exists": true
},
"then": { "effect": "deny" }
}
resource:
properties: {}
want_undefined: true
# =========================================================================
# ARM expression functions: equals() and contains() as function calls
# =========================================================================
- note: expr_func_equals
policy_rule: |
{
"if": {
"value": "[if(equals(field('type'), 'Microsoft.Compute/virtualMachines'), 'vm', 'other')]",
"equals": "vm"
},
"then": { "effect": "audit" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "audit"
- note: expr_func_contains_array
policy_rule: |
{
"if": {
"value": "[if(contains(parameters('allowedTypes'), field('type')), 'yes', 'no')]",
"equals": "no"
},
"then": { "effect": "deny" }
}
parameters:
allowedTypes:
- "Microsoft.Storage/storageAccounts"
- "Microsoft.Compute/virtualMachines"
resource:
type: "Microsoft.Network/virtualNetworks"
want_effect: "deny"
# =========================================================================
# Type coercion edge cases: greaterOrEquals, lessOrEquals, notEquals, notIn
# =========================================================================
- note: coercion_notEquals_string_number
policy_rule: |
{
"if": {
"field": "properties.port",
"notEquals": 443
},
"then": { "effect": "deny" }
}
resource:
properties:
port: "80"
want_effect: "deny"
- note: coercion_greaterOrEquals_string_number
policy_rule: |
{
"if": {
"field": "properties.port",
"greaterOrEquals": 80
},
"then": { "effect": "deny" }
}
resource:
properties:
port: "80"
want_effect: "deny"
- note: coercion_lessOrEquals_string_number
policy_rule: |
{
"if": {
"field": "properties.port",
"lessOrEquals": 443
},
"then": { "effect": "deny" }
}
resource:
properties:
port: "80"
want_effect: "deny"
- note: coercion_notIn_mixed_types
policy_rule: |
{
"if": {
"field": "properties.port",
"notIn": [80, 443]
},
"then": { "effect": "deny" }
}
resource:
properties:
port: "8080"
want_effect: "deny"
# =========================================================================
# Complex real-world: multiple count + combinator + expression
# =========================================================================
- note: complex_nsg_with_tag_and_count
policy_rule: |
{
"if": {
"allOf": [
{ "field": "type", "equals": "Microsoft.Network/networkSecurityGroups" },
{
"not": {
"field": "tags.exception",
"equals": "true"
}
},
{
"count": {
"field": "securityRules[*]",
"where": {
"allOf": [
{ "field": "securityRules[*].access", "equals": "Allow" },
{ "field": "securityRules[*].direction", "equals": "Inbound" },
{
"anyOf": [
{ "field": "securityRules[*].sourceAddressPrefix", "equals": "*" },
{ "field": "securityRules[*].sourceAddressPrefix", "equals": "Internet" }
]
}
]
}
},
"greater": 0
}
]
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Network/networkSecurityGroups"
tags:
environment: "prod"
securityRules:
- { access: "Allow", direction: "Inbound", sourceAddressPrefix: "Internet" }
- { access: "Deny", direction: "Outbound", sourceAddressPrefix: "10.0.0.0/8" }
want_effect: "deny"
- note: complex_value_count_with_expr_where
policy_rule: |
{
"if": {
"count": {
"value": "[parameters('requiredPorts')]",
"name": "port",
"where": {
"value": "[current('port')]",
"greater": 1024
}
},
"equals": 2
},
"then": { "effect": "audit" }
}
parameters:
requiredPorts: [80, 8080, 9090]
resource:
type: "any"
want_effect: "audit"

View File

@@ -0,0 +1,539 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Effect Details Test Suite
# Tests that effects produce structured result objects:
# { "effect": "<name>", "details": { ... } }
# and that want_details validation works correctly.
cases:
# =========================================================================
# Simple effects — structured result with no details
# =========================================================================
- note: deny_structured_result
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "deny"
- note: audit_structured_result
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": { "effect": "audit" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "audit"
# =========================================================================
# Modify — single operation
# =========================================================================
- note: modify_single_operation_details
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": {
"effect": "modify",
"details": {
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
],
"operations": [
{
"operation": "addOrReplace",
"field": "tags['environment']",
"value": "production"
}
]
}
}
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "modify"
want_details:
roleDefinitionIds:
- "/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
operations:
- operation: "addOrReplace"
field: "tags['environment']"
value: "production"
# =========================================================================
# Modify — multiple operations
# =========================================================================
- note: modify_multiple_operations_details
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": {
"effect": "modify",
"details": {
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
],
"operations": [
{
"operation": "addOrReplace",
"field": "tags['environment']",
"value": "production"
},
{
"operation": "add",
"field": "tags['managedBy']",
"value": "policy"
}
]
}
}
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "modify"
want_details:
roleDefinitionIds:
- "/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
operations:
- operation: "addOrReplace"
field: "tags['environment']"
value: "production"
- operation: "add"
field: "tags['managedBy']"
value: "policy"
# =========================================================================
# Modify — operation with condition
# =========================================================================
- note: modify_operation_with_condition
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": {
"effect": "modify",
"details": {
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
],
"operations": [
{
"operation": "addOrReplace",
"field": "tags['environment']",
"value": "production",
"condition": "[equals(field('tags.environment'), '')]"
}
]
}
}
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "modify"
want_details:
roleDefinitionIds:
- "/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
operations:
- operation: "addOrReplace"
field: "tags['environment']"
value: "production"
condition: "[equals(field('tags.environment'), '')]"
# =========================================================================
# Modify — template expression in value
# =========================================================================
- note: modify_template_expression_value
policy_rule: |
{
"if": {
"allOf": [
{ "field": "type", "equals": "Microsoft.Compute/virtualMachines" },
{ "field": "tags.environment", "exists": false }
]
},
"then": {
"effect": "modify",
"details": {
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
],
"operations": [
{
"operation": "addOrReplace",
"field": "tags['environment']",
"value": "[if(empty(field('tags.environment')), 'unknown', field('tags.environment'))]"
}
]
}
}
}
resource:
type: "Microsoft.Compute/virtualMachines"
tags: {}
want_effect: "modify"
want_details:
roleDefinitionIds:
- "/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
operations:
- operation: "addOrReplace"
field: "tags['environment']"
value: "unknown"
# =========================================================================
# Modify — template expression with existing tag value
# =========================================================================
- note: modify_template_expression_existing_value
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": {
"effect": "modify",
"details": {
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
],
"operations": [
{
"operation": "addOrReplace",
"field": "tags['environment']",
"value": "[if(empty(field('tags.environment')), 'unknown', field('tags.environment'))]"
}
]
}
}
}
resource:
type: "Microsoft.Compute/virtualMachines"
tags:
environment: "staging"
want_effect: "modify"
want_details:
roleDefinitionIds:
- "/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
operations:
- operation: "addOrReplace"
field: "tags['environment']"
value: "staging"
# =========================================================================
# Modify — no details (bare effect)
# =========================================================================
- note: modify_no_details
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": {
"effect": "modify"
}
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "modify"
# =========================================================================
# Append — single item
# =========================================================================
- note: append_single_item_details
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
},
"then": {
"effect": "append",
"details": [
{
"field": "properties.supportsHttpsTrafficOnly",
"value": true
}
]
}
}
resource:
type: "Microsoft.Storage/storageAccounts"
want_effect: "append"
want_details:
- field: "properties.supportsHttpsTrafficOnly"
value: true
# =========================================================================
# Append — multiple items
# =========================================================================
- note: append_multiple_items_details
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
},
"then": {
"effect": "append",
"details": [
{
"field": "properties.supportsHttpsTrafficOnly",
"value": true
},
{
"field": "properties.minimumTlsVersion",
"value": "TLS1_2"
}
]
}
}
resource:
type: "Microsoft.Storage/storageAccounts"
want_effect: "append"
want_details:
- field: "properties.supportsHttpsTrafficOnly"
value: true
- field: "properties.minimumTlsVersion"
value: "TLS1_2"
# =========================================================================
# Append — template expression in value
# =========================================================================
- note: append_template_expression_value
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
},
"then": {
"effect": "append",
"details": [
{
"field": "properties.networkAcls.defaultAction",
"value": "[toLower('Deny')]"
}
]
}
}
resource:
type: "Microsoft.Storage/storageAccounts"
want_effect: "append"
want_details:
- field: "properties.networkAcls.defaultAction"
value: "deny"
# =========================================================================
# Cross-resource effect — auditIfNotExists with details
# =========================================================================
- note: aine_structured_details
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": {
"effect": "auditIfNotExists",
"details": {
"type": "Microsoft.Compute/virtualMachines/extensions",
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/9980e02c-c2be-4d73-94e8-173b1dc7cf3c"
],
"existenceCondition": {
"field": "properties.publisher",
"equals": "Microsoft.Azure.Security"
}
}
}
}
resource:
type: "Microsoft.Compute/virtualMachines"
host_await:
- response: null
want_effect: "auditIfNotExists"
want_details:
roleDefinitionIds:
- "/providers/Microsoft.Authorization/roleDefinitions/9980e02c-c2be-4d73-94e8-173b1dc7cf3c"
type: "Microsoft.Compute/virtualMachines/extensions"
# =========================================================================
# Cross-resource effect — deployIfNotExists with details
# =========================================================================
- note: dine_structured_details
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": {
"effect": "deployIfNotExists",
"details": {
"type": "Microsoft.Compute/virtualMachines/extensions",
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/9980e02c-c2be-4d73-94e8-173b1dc7cf3c"
],
"existenceCondition": {
"field": "properties.publisher",
"equals": "Microsoft.Azure.Monitoring"
}
}
}
}
resource:
type: "Microsoft.Compute/virtualMachines"
host_await:
- response: null
want_effect: "deployIfNotExists"
want_details:
roleDefinitionIds:
- "/providers/Microsoft.Authorization/roleDefinitions/9980e02c-c2be-4d73-94e8-173b1dc7cf3c"
type: "Microsoft.Compute/virtualMachines/extensions"
# =========================================================================
# Parameterized effect resolving to Modify
# =========================================================================
- note: parameterized_modify_details
policy_definition: |
{
"properties": {
"parameters": {
"effect": {
"type": "String",
"defaultValue": "Modify"
}
},
"policyRule": {
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": {
"effect": "[parameters('effect')]",
"details": {
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
],
"operations": [
{
"operation": "addOrReplace",
"field": "tags['owner']",
"value": "platform-team"
}
]
}
}
}
}
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "Modify"
want_details:
roleDefinitionIds:
- "/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
operations:
- operation: "addOrReplace"
field: "tags['owner']"
value: "platform-team"
# =========================================================================
# Parameterized effect resolving to Append
# =========================================================================
- note: parameterized_append_details
policy_definition: |
{
"properties": {
"parameters": {
"effect": {
"type": "String",
"defaultValue": "Append"
}
},
"policyRule": {
"if": {
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
},
"then": {
"effect": "[parameters('effect')]",
"details": [
{
"field": "properties.supportsHttpsTrafficOnly",
"value": true
}
]
}
}
}
}
resource:
type: "Microsoft.Storage/storageAccounts"
want_effect: "Append"
want_details:
- field: "properties.supportsHttpsTrafficOnly"
value: true
# =========================================================================
# Condition not matching → undefined (no details)
# =========================================================================
- note: modify_condition_not_met
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": {
"effect": "modify",
"details": {
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
],
"operations": [
{
"operation": "addOrReplace",
"field": "tags['environment']",
"value": "production"
}
]
}
}
}
resource:
type: "Microsoft.Storage/storageAccounts"
want_undefined: true

View File

@@ -0,0 +1,428 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Effects Test Suite
# Tests all 9 Azure Policy effect types and parameterized effects.
cases:
# =========================================================================
# Simple effects
# =========================================================================
- note: effect_deny
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "deny"
- note: effect_audit
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": { "effect": "audit" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "audit"
- note: effect_disabled
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": { "effect": "disabled" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
# Azure Policy: "disabled" means the policy is inactive — no compliance
# result is produced. The compiler correctly returns undefined.
want_undefined: true
- note: effect_manual
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": { "effect": "manual" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "manual"
- note: effect_denyAction
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": {
"effect": "denyAction",
"details": {
"actionNames": ["delete"]
}
}
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "denyAction"
# =========================================================================
# Effects with details
# =========================================================================
- note: effect_deny_with_message
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
},
"then": {
"effect": "deny",
"details": {
"message": "Storage accounts must use HTTPS"
}
}
}
resource:
type: "Microsoft.Storage/storageAccounts"
want_effect: "deny"
- note: effect_append
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
},
"then": {
"effect": "append",
"details": [
{
"field": "properties.supportsHttpsTrafficOnly",
"value": true
}
]
}
}
resource:
type: "Microsoft.Storage/storageAccounts"
want_effect: "append"
- note: effect_modify
policy_rule: |
{
"if": {
"allOf": [
{ "field": "type", "equals": "Microsoft.Compute/virtualMachines" },
{ "field": "tags.environment", "exists": false }
]
},
"then": {
"effect": "modify",
"details": {
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
],
"operations": [
{
"operation": "addOrReplace",
"field": "tags['environment']",
"value": "production"
}
]
}
}
}
resource:
type: "Microsoft.Compute/virtualMachines"
tags: {}
want_effect: "modify"
- note: effect_modify_multiple_operations
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": {
"effect": "modify",
"details": {
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
],
"operations": [
{
"operation": "addOrReplace",
"field": "tags['environment']",
"value": "production"
},
{
"operation": "add",
"field": "tags['managedBy']",
"value": "policy"
}
]
}
}
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "modify"
- note: effect_auditIfNotExists
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": {
"effect": "auditIfNotExists",
"details": {
"type": "Microsoft.Compute/virtualMachines/extensions",
"existenceCondition": {
"allOf": [
{ "field": "properties.publisher", "equals": "Microsoft.Azure.Security" },
{ "field": "properties.type", "equals": "IaaSAntimalware" }
]
}
}
}
}
resource:
type: "Microsoft.Compute/virtualMachines"
host_await:
- key:
operation: "lookup_related_resources"
type: "Microsoft.Compute/virtualMachines/extensions"
response: null
want_effect: "auditIfNotExists"
# Related resource found and existenceCondition matches → compliant (undefined)
- note: effect_auditIfNotExists_compliant
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": {
"effect": "auditIfNotExists",
"details": {
"type": "Microsoft.Compute/virtualMachines/extensions",
"existenceCondition": {
"allOf": [
{ "field": "properties.publisher", "equals": "Microsoft.Azure.Security" },
{ "field": "properties.type", "equals": "IaaSAntimalware" }
]
}
}
}
}
resource:
type: "Microsoft.Compute/virtualMachines"
host_await:
- response:
properties:
publisher: "Microsoft.Azure.Security"
type: "IaaSAntimalware"
want_undefined: true
# Related resource found but existenceCondition fails → non-compliant
- note: effect_auditIfNotExists_condition_fails
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": {
"effect": "auditIfNotExists",
"details": {
"type": "Microsoft.Compute/virtualMachines/extensions",
"existenceCondition": {
"allOf": [
{ "field": "properties.publisher", "equals": "Microsoft.Azure.Security" },
{ "field": "properties.type", "equals": "IaaSAntimalware" }
]
}
}
}
}
resource:
type: "Microsoft.Compute/virtualMachines"
host_await:
- response:
properties:
publisher: "SomeOtherPublisher"
type: "SomeOtherExtension"
want_effect: "auditIfNotExists"
# No existenceCondition — just check if resource exists
- note: effect_auditIfNotExists_no_condition_exists
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": {
"effect": "auditIfNotExists",
"details": {
"type": "Microsoft.Compute/virtualMachines/extensions"
}
}
}
resource:
type: "Microsoft.Compute/virtualMachines"
host_await:
- response:
name: "some-extension"
properties: {}
want_undefined: true
# No existenceCondition, resource not found → non-compliant
- note: effect_auditIfNotExists_no_condition_missing
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": {
"effect": "auditIfNotExists",
"details": {
"type": "Microsoft.Compute/virtualMachines/extensions"
}
}
}
resource:
type: "Microsoft.Compute/virtualMachines"
host_await:
- response: null
want_effect: "auditIfNotExists"
- note: effect_deployIfNotExists
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": {
"effect": "deployIfNotExists",
"details": {
"type": "Microsoft.Compute/virtualMachines/extensions",
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/9980e02c-c2be-4d73-94e8-173b1dc7cf3c"
],
"existenceCondition": {
"field": "properties.publisher",
"equals": "Microsoft.Azure.Monitoring"
},
"deployment": {
"properties": {
"mode": "incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": []
}
}
}
}
}
}
resource:
type: "Microsoft.Compute/virtualMachines"
host_await:
- response: null
want_effect: "deployIfNotExists"
# =========================================================================
# Parameterized effects
# =========================================================================
- note: effect_parameterized
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": {
"effect": "[parameters('effect')]"
}
}
resource:
type: "Microsoft.Compute/virtualMachines"
parameters:
effect: "deny"
want_effect: "deny"
- note: effect_parameterized_with_details
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
},
"then": {
"effect": "[parameters('effect')]",
"details": {
"message": "HTTPS required for storage accounts"
}
}
}
resource:
type: "Microsoft.Storage/storageAccounts"
parameters:
effect: "audit"
want_effect: "audit"
# =========================================================================
# Case-insensitive effect names
# =========================================================================
- note: effect_case_insensitive_Deny
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": { "effect": "Deny" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "Deny"
- note: effect_case_insensitive_AUDIT
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": { "effect": "AUDIT" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "AUDIT"

View File

@@ -0,0 +1,463 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Exists Operator comprehensive tests
#
# Covers bare-field paths, dotted nested paths, null values, missing fields,
# object-valued fields, array-valued fields, and edge cases. These lock down
# the behaviour exercised by the external csharp-converted test suite.
cases:
# =========================================================================
# Basic exists true / false on properties path
# =========================================================================
- note: exists_true_field_present
policy_rule: |
{
"if": {
"field": "properties.setting",
"exists": true
},
"then": { "effect": "audit" }
}
resource:
properties:
setting: "hello"
want_effect: "audit"
- note: exists_true_field_absent
policy_rule: |
{
"if": {
"field": "properties.setting",
"exists": true
},
"then": { "effect": "audit" }
}
resource:
properties: {}
want_undefined: true
- note: exists_false_field_absent
policy_rule: |
{
"if": {
"field": "properties.setting",
"exists": false
},
"then": { "effect": "audit" }
}
resource:
properties: {}
want_effect: "audit"
- note: exists_false_field_present
policy_rule: |
{
"if": {
"field": "properties.setting",
"exists": false
},
"then": { "effect": "audit" }
}
resource:
properties:
setting: "hello"
want_undefined: true
# =========================================================================
# Null-valued fields
# =========================================================================
- note: exists_true_null_value
policy_rule: |
{
"if": {
"field": "properties.setting",
"exists": true
},
"then": { "effect": "audit" }
}
resource:
properties:
setting: null
want_undefined: true
- note: exists_false_null_value
policy_rule: |
{
"if": {
"field": "properties.setting",
"exists": false
},
"then": { "effect": "audit" }
}
resource:
properties:
setting: null
want_effect: "audit"
# =========================================================================
# Null parent object
# =========================================================================
- note: exists_true_null_parent
policy_rule: |
{
"if": {
"field": "properties.nested.value",
"exists": true
},
"then": { "effect": "audit" }
}
resource:
properties:
nested: null
want_undefined: true
- note: exists_false_null_parent
policy_rule: |
{
"if": {
"field": "properties.nested.value",
"exists": false
},
"then": { "effect": "audit" }
}
resource:
properties:
nested: null
want_effect: "audit"
# =========================================================================
# Object-valued fields (exists checks the field itself, not its children)
# =========================================================================
- note: exists_true_object_value
policy_rule: |
{
"if": {
"field": "properties.config",
"exists": true
},
"then": { "effect": "audit" }
}
resource:
properties:
config:
enabled: true
want_effect: "audit"
- note: exists_false_object_value
policy_rule: |
{
"if": {
"field": "properties.config",
"exists": false
},
"then": { "effect": "audit" }
}
resource:
properties:
config:
enabled: true
want_undefined: true
- note: exists_true_empty_object
policy_rule: |
{
"if": {
"field": "properties.config",
"exists": true
},
"then": { "effect": "audit" }
}
resource:
properties:
config: {}
want_effect: "audit"
# =========================================================================
# Array-valued fields
# =========================================================================
- note: exists_true_array_value
policy_rule: |
{
"if": {
"field": "properties.items",
"exists": true
},
"then": { "effect": "audit" }
}
resource:
properties:
items:
- "a"
- "b"
want_effect: "audit"
- note: exists_true_empty_array
policy_rule: |
{
"if": {
"field": "properties.items",
"exists": true
},
"then": { "effect": "audit" }
}
resource:
properties:
items: []
want_effect: "audit"
- note: exists_false_array_absent
policy_rule: |
{
"if": {
"field": "properties.items",
"exists": false
},
"then": { "effect": "audit" }
}
resource:
properties: {}
want_effect: "audit"
# =========================================================================
# Deeply nested dotted paths
# =========================================================================
- note: exists_true_deep_path
policy_rule: |
{
"if": {
"field": "properties.network.subnet.cidr",
"exists": true
},
"then": { "effect": "audit" }
}
resource:
properties:
network:
subnet:
cidr: "10.0.0.0/24"
want_effect: "audit"
- note: exists_false_deep_path_missing_leaf
policy_rule: |
{
"if": {
"field": "properties.network.subnet.cidr",
"exists": false
},
"then": { "effect": "audit" }
}
resource:
properties:
network:
subnet: {}
want_effect: "audit"
- note: exists_false_deep_path_missing_intermediate
policy_rule: |
{
"if": {
"field": "properties.network.subnet.cidr",
"exists": false
},
"then": { "effect": "audit" }
}
resource:
properties:
network: {}
want_effect: "audit"
# =========================================================================
# Root-level fields (type, name, location, etc.)
# =========================================================================
- note: exists_true_root_type
policy_rule: |
{
"if": {
"field": "type",
"exists": true
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "deny"
- note: exists_false_root_location_absent
policy_rule: |
{
"if": {
"field": "location",
"exists": false
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "deny"
- note: exists_true_root_tags
policy_rule: |
{
"if": {
"field": "tags",
"exists": true
},
"then": { "effect": "audit" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
tags:
env: "prod"
want_effect: "audit"
- note: exists_false_root_tags_absent
policy_rule: |
{
"if": {
"field": "tags",
"exists": false
},
"then": { "effect": "audit" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "audit"
# =========================================================================
# Numeric & boolean values (non-null truthy values ⇒ exists true)
# =========================================================================
- note: exists_true_zero
policy_rule: |
{
"if": {
"field": "properties.count",
"exists": true
},
"then": { "effect": "audit" }
}
resource:
properties:
count: 0
want_effect: "audit"
- note: exists_true_false_boolean
policy_rule: |
{
"if": {
"field": "properties.enabled",
"exists": true
},
"then": { "effect": "audit" }
}
resource:
properties:
enabled: false
want_effect: "audit"
- note: exists_true_empty_string
policy_rule: |
{
"if": {
"field": "properties.label",
"exists": true
},
"then": { "effect": "audit" }
}
resource:
properties:
label: ""
want_effect: "audit"
# =========================================================================
# Combined with allOf / anyOf
# =========================================================================
- note: exists_allof_both_present
policy_rule: |
{
"if": {
"allOf": [
{ "field": "properties.a", "exists": true },
{ "field": "properties.b", "exists": true }
]
},
"then": { "effect": "audit" }
}
resource:
properties:
a: 1
b: 2
want_effect: "audit"
- note: exists_allof_one_missing
policy_rule: |
{
"if": {
"allOf": [
{ "field": "properties.a", "exists": true },
{ "field": "properties.b", "exists": true }
]
},
"then": { "effect": "audit" }
}
resource:
properties:
a: 1
want_undefined: true
- note: exists_anyof_one_present
policy_rule: |
{
"if": {
"anyOf": [
{ "field": "properties.a", "exists": true },
{ "field": "properties.b", "exists": true }
]
},
"then": { "effect": "audit" }
}
resource:
properties:
b: "yes"
want_effect: "audit"
# =========================================================================
# exists with string value ("true"/"false") must behave same as boolean
# =========================================================================
- note: exists_string_false_field_absent
policy_rule: |
{
"if": {
"field": "properties.setting",
"exists": "false"
},
"then": { "effect": "audit" }
}
resource:
properties: {}
want_effect: "audit"
- note: exists_string_false_field_present
policy_rule: |
{
"if": {
"field": "properties.setting",
"exists": "false"
},
"then": { "effect": "audit" }
}
resource:
properties:
setting: "val"
want_undefined: true

View File

@@ -0,0 +1,541 @@
# 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"

View File

@@ -0,0 +1,253 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Field Wildcard Collection Test Suite
# Tests field('path[*]') and field('path[*].prop') as value expressions
# that return arrays, including missing-array → empty-array handling.
cases:
# =========================================================================
# field('path[*]') — collect all elements
# =========================================================================
- note: field_wildcard_collect_all_elements
policy_rule: |
{
"if": {
"value": "[length(field('items[*]'))]",
"equals": 3
},
"then": { "effect": "deny" }
}
resource:
items:
- "a"
- "b"
- "c"
want_effect: "deny"
- note: field_wildcard_collect_all_elements_no_match
policy_rule: |
{
"if": {
"value": "[length(field('items[*]'))]",
"equals": 5
},
"then": { "effect": "deny" }
}
resource:
items:
- "a"
- "b"
- "c"
want_undefined: true
# =========================================================================
# field('path[*].prop') — collect property from each element
# =========================================================================
- note: field_wildcard_collect_property
policy_rule: |
{
"if": {
"value": "[first(field('rules[*].action'))]",
"equals": "Allow"
},
"then": { "effect": "deny" }
}
resource:
rules:
- { "action": "Allow", "priority": 100 }
- { "action": "Deny", "priority": 200 }
want_effect: "deny"
- note: field_wildcard_collect_property_length
policy_rule: |
{
"if": {
"value": "[length(field('securityRules[*].access'))]",
"equals": 4
},
"then": { "effect": "audit" }
}
resource:
securityRules:
- { "access": "Allow" }
- { "access": "Deny" }
- { "access": "Allow" }
- { "access": "Deny" }
want_effect: "audit"
# =========================================================================
# Nested property path after [*]
# =========================================================================
- note: field_wildcard_nested_property
policy_rule: |
{
"if": {
"value": "[length(field('rules[*].target.name'))]",
"greater": 0
},
"then": { "effect": "deny" }
}
resource:
rules:
- target:
name: "web-app"
- target:
name: "api-app"
want_effect: "deny"
# =========================================================================
# Dotted prefix before [*]
# =========================================================================
- note: field_wildcard_dotted_prefix
policy_rule: |
{
"if": {
"value": "[length(field('properties.ipRules[*].value'))]",
"equals": 2
},
"then": { "effect": "deny" }
}
resource:
properties:
ipRules:
- { "value": "10.0.0.0/8" }
- { "value": "192.168.0.0/16" }
want_effect: "deny"
# =========================================================================
# Missing array → empty collection
# =========================================================================
- note: field_wildcard_missing_array_length_zero
policy_rule: |
{
"if": {
"value": "[length(field('items[*]'))]",
"equals": 0
},
"then": { "effect": "deny" }
}
resource:
type: "some.type"
want_effect: "deny"
- note: field_wildcard_missing_array_empty_true
policy_rule: |
{
"if": {
"value": "[empty(field('properties.ipRules[*]'))]",
"equals": true
},
"then": { "effect": "deny" }
}
resource:
properties:
enabled: true
want_effect: "deny"
- note: field_wildcard_missing_nested_prefix
policy_rule: |
{
"if": {
"value": "[length(field('config.logging.entries[*].level'))]",
"equals": 0
},
"then": { "effect": "deny" }
}
resource:
type: "some.type"
want_effect: "deny"
# =========================================================================
# Empty array → empty collection (not missing, but zero elements)
# =========================================================================
- note: field_wildcard_empty_array
policy_rule: |
{
"if": {
"value": "[length(field('items[*]'))]",
"equals": 0
},
"then": { "effect": "deny" }
}
resource:
items: []
want_effect: "deny"
# =========================================================================
# Doubly-nested wildcards: field('a[*].b[*].c') — flat-map
# =========================================================================
- note: field_wildcard_doubly_nested
policy_rule: |
{
"if": {
"value": "[length(field('groups[*].members[*].name'))]",
"equals": 4
},
"then": { "effect": "deny" }
}
resource:
groups:
- members:
- { "name": "alice" }
- { "name": "bob" }
- members:
- { "name": "carol" }
- { "name": "dave" }
want_effect: "deny"
- note: field_wildcard_doubly_nested_no_suffix
policy_rule: |
{
"if": {
"value": "[length(field('groups[*].tags[*]'))]",
"equals": 5
},
"then": { "effect": "deny" }
}
resource:
groups:
- tags: ["a", "b", "c"]
- tags: ["d", "e"]
want_effect: "deny"
- note: field_wildcard_doubly_nested_partial_missing
policy_rule: |
{
"if": {
"value": "[length(field('groups[*].members[*].name'))]",
"equals": 2
},
"then": { "effect": "deny" }
}
resource:
groups:
- members:
- { "name": "alice" }
- { "name": "bob" }
- other_field: "no members here"
want_effect: "deny"
# =========================================================================
# Real-world pattern: field() with [*] used in condition comparisons
# =========================================================================
- note: field_wildcard_first_equals
policy_rule: |
{
"if": {
"value": "[first(field('ports[*]'))]",
"equals": 80
},
"then": { "effect": "deny" }
}
resource:
ports: [80, 443, 8080]
want_effect: "deny"

View File

@@ -0,0 +1,323 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Built-in Fields Test Suite
# Tests all built-in field types: type, id, kind, name, location, fullName,
# tags, identity.type, and tag indexing patterns.
cases:
# =========================================================================
# Core built-in fields
# =========================================================================
- note: field_type
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "deny"
- note: field_id
policy_rule: |
{
"if": {
"field": "id",
"contains": "/resourceGroups/myRg/"
},
"then": { "effect": "audit" }
}
resource:
id: "/subscriptions/sub1/resourceGroups/myRg/providers/Microsoft.Compute/virtualMachines/vm1"
want_effect: "audit"
- note: field_kind
policy_rule: |
{
"if": {
"field": "kind",
"equals": "StorageV2"
},
"then": { "effect": "audit" }
}
resource:
kind: "StorageV2"
want_effect: "audit"
- note: field_name
policy_rule: |
{
"if": {
"field": "name",
"contains": "prod"
},
"then": { "effect": "deny" }
}
resource:
name: "my-prod-vm"
want_effect: "deny"
- note: field_location
policy_rule: |
{
"if": {
"field": "location",
"equals": "eastus"
},
"then": { "effect": "deny" }
}
resource:
location: "eastus"
want_effect: "deny"
- note: field_fullName
policy_rule: |
{
"if": {
"field": "fullName",
"contains": "Microsoft.Compute"
},
"then": { "effect": "audit" }
}
resource:
fullName: "Microsoft.Compute/virtualMachines/vm1"
want_effect: "audit"
- note: field_identity_type
policy_rule: |
{
"if": {
"field": "identity.type",
"equals": "SystemAssigned"
},
"then": { "effect": "audit" }
}
resource:
identity:
type: "SystemAssigned"
want_effect: "audit"
# =========================================================================
# Tags
# =========================================================================
- note: field_tags_object
policy_rule: |
{
"if": {
"field": "tags",
"containsKey": "environment"
},
"then": { "effect": "audit" }
}
resource:
tags:
environment: "production"
want_effect: "audit"
- note: field_tags_dot_notation
policy_rule: |
{
"if": {
"field": "tags.environment",
"equals": "production"
},
"then": { "effect": "audit" }
}
resource:
tags:
environment: "production"
want_effect: "audit"
- note: field_tags_bracket_notation
policy_rule: |
{
"if": {
"field": "tags['environment']",
"equals": "production"
},
"then": { "effect": "deny" }
}
resource:
tags:
environment: "production"
want_effect: "deny"
- note: field_tags_dot_hyphen
policy_rule: |
{
"if": {
"field": "tags.cost-center",
"equals": "engineering"
},
"then": { "effect": "audit" }
}
resource:
tags:
cost-center: "engineering"
want_effect: "audit"
- note: field_tags_bracket_space
policy_rule: |
{
"if": {
"field": "tags['Created By']",
"exists": true
},
"then": { "effect": "audit" }
}
resource:
tags:
Created By: "admin"
want_effect: "audit"
- note: field_tags_missing
policy_rule: |
{
"if": {
"field": "tags.environment",
"exists": false
},
"then": { "effect": "deny" }
}
resource:
tags: {}
want_effect: "deny"
# =========================================================================
# Nested property fields (aliases)
# =========================================================================
# Note: These test parsing of alias-like dotted paths in field position.
# Actual alias resolution is out of scope; these confirm the parser
# correctly handles them.
- note: field_deep_property
policy_rule: |
{
"if": {
"field": "properties.securityProfile.uefiSettings.secureBootEnabled",
"equals": true
},
"then": { "effect": "audit" }
}
resource:
properties:
securityProfile:
uefiSettings:
secureBootEnabled: true
want_effect: "audit"
- note: field_multiple_field_conditions
policy_rule: |
{
"if": {
"allOf": [
{ "field": "type", "equals": "Microsoft.Network/networkSecurityGroups/securityRules" },
{ "field": "name", "contains": "allow" },
{ "field": "location", "in": ["eastus", "westus", "centralus"] },
{ "field": "tags.team", "equals": "security" }
]
},
"then": { "effect": "audit" }
}
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
name: "allow-https"
location: "eastus"
tags:
team: "security"
want_effect: "audit"
# =========================================================================
# Bracket notation in field paths
# =========================================================================
- note: field_bracket_notation_string_key
policy_rule: |
{
"if": {
"field": "properties.networkAcls['default-action']",
"equals": "Allow"
},
"then": { "effect": "deny" }
}
resource:
properties:
networkAcls:
default-action: "Allow"
want_effect: "deny"
- note: field_bracket_notation_double_quote
policy_rule: |
{
"if": {
"field": "properties.settings['log-level']",
"equals": "debug"
},
"then": { "effect": "deny" }
}
resource:
properties:
settings:
log-level: "debug"
want_effect: "deny"
# =========================================================================
# Array index access in field paths
# =========================================================================
- note: field_array_index_zero
policy_rule: |
{
"if": {
"field": "properties.ipConfigurations[0].name",
"equals": "primary"
},
"then": { "effect": "deny" }
}
resource:
properties:
ipConfigurations:
- name: "primary"
properties:
subnet: "default"
- name: "secondary"
properties:
subnet: "dmz"
want_effect: "deny"
- note: field_array_index_one
policy_rule: |
{
"if": {
"field": "properties.ipConfigurations[1].name",
"equals": "secondary"
},
"then": { "effect": "deny" }
}
resource:
properties:
ipConfigurations:
- name: "primary"
- name: "secondary"
want_effect: "deny"
- note: field_array_index_out_of_bounds
policy_rule: |
{
"if": {
"field": "properties.ipConfigurations[5].name",
"exists": true
},
"then": { "effect": "deny" }
}
resource:
properties:
ipConfigurations:
- name: "primary"
want_undefined: true

View File

@@ -0,0 +1,555 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Implicit allOf Test Suite
# When a field with [*] appears in a condition outside count, Azure Policy
# applies implicit allOf semantics: ALL elements must satisfy the operator.
# Empty arrays evaluate to true (vacuous truth); missing arrays evaluate to
# false because the field is not iterable and the condition is not met.
cases:
# =========================================================================
# Basic allOf — all elements match
# =========================================================================
- note: allof_equals_all_match
policy_rule: |
{
"if": {
"field": "items[*].status",
"equals": "active"
},
"then": { "effect": "deny" }
}
resource:
items:
- { "status": "active" }
- { "status": "active" }
- { "status": "active" }
want_effect: "deny"
- note: allof_equals_one_mismatch
policy_rule: |
{
"if": {
"field": "items[*].status",
"equals": "active"
},
"then": { "effect": "deny" }
}
resource:
items:
- { "status": "active" }
- { "status": "inactive" }
- { "status": "active" }
want_undefined: true
# =========================================================================
# Empty array → true (vacuous truth)
# =========================================================================
- note: allof_empty_array_is_true
policy_rule: |
{
"if": {
"field": "items[*].status",
"equals": "active"
},
"then": { "effect": "deny" }
}
resource:
items: []
want_effect: "deny"
# =========================================================================
# Missing array → false (not iterable → condition not met)
# Azure Policy: field[*] on null/missing/non-array → false
# =========================================================================
- note: allof_missing_array_is_false
policy_rule: |
{
"if": {
"field": "items[*].status",
"equals": "active"
},
"then": { "effect": "deny" }
}
resource:
type: "some.type"
want_undefined: true
# =========================================================================
# No suffix — elements compared directly
# =========================================================================
- note: allof_no_suffix_all_match
policy_rule: |
{
"if": {
"field": "ports[*]",
"equals": 443
},
"then": { "effect": "deny" }
}
resource:
ports: [443, 443, 443]
want_effect: "deny"
- note: allof_no_suffix_one_mismatch
policy_rule: |
{
"if": {
"field": "ports[*]",
"equals": 443
},
"then": { "effect": "deny" }
}
resource:
ports: [443, 80, 443]
want_undefined: true
# =========================================================================
# Dotted prefix before [*]
# =========================================================================
- note: allof_dotted_prefix
policy_rule: |
{
"if": {
"field": "properties.rules[*].enabled",
"equals": true
},
"then": { "effect": "deny" }
}
resource:
properties:
rules:
- { "enabled": true }
- { "enabled": true }
want_effect: "deny"
- note: allof_dotted_prefix_mismatch
policy_rule: |
{
"if": {
"field": "properties.rules[*].enabled",
"equals": true
},
"then": { "effect": "deny" }
}
resource:
properties:
rules:
- { "enabled": true }
- { "enabled": false }
want_undefined: true
# =========================================================================
# Various operators
# =========================================================================
- note: allof_not_equals
policy_rule: |
{
"if": {
"field": "items[*].value",
"notEquals": "bad"
},
"then": { "effect": "deny" }
}
resource:
items:
- { "value": "good" }
- { "value": "fine" }
want_effect: "deny"
- note: allof_not_equals_one_matches
policy_rule: |
{
"if": {
"field": "items[*].value",
"notEquals": "bad"
},
"then": { "effect": "deny" }
}
resource:
items:
- { "value": "good" }
- { "value": "bad" }
want_undefined: true
- note: allof_greater
policy_rule: |
{
"if": {
"field": "scores[*]",
"greater": 50
},
"then": { "effect": "deny" }
}
resource:
scores: [80, 90, 100]
want_effect: "deny"
- note: allof_greater_one_fails
policy_rule: |
{
"if": {
"field": "scores[*]",
"greater": 50
},
"then": { "effect": "deny" }
}
resource:
scores: [80, 30, 100]
want_undefined: true
- note: allof_in_operator
policy_rule: |
{
"if": {
"field": "regions[*]",
"in": ["eastus", "westus", "centralus"]
},
"then": { "effect": "deny" }
}
resource:
regions: ["eastus", "westus"]
want_effect: "deny"
- note: allof_in_operator_one_outside
policy_rule: |
{
"if": {
"field": "regions[*]",
"in": ["eastus", "westus", "centralus"]
},
"then": { "effect": "deny" }
}
resource:
regions: ["eastus", "northeurope"]
want_undefined: true
- note: allof_contains
policy_rule: |
{
"if": {
"field": "tags[*]",
"contains": "prod"
},
"then": { "effect": "deny" }
}
resource:
tags: ["prod-web", "prod-api"]
want_effect: "deny"
- note: allof_like
policy_rule: |
{
"if": {
"field": "names[*]",
"like": "vm-*"
},
"then": { "effect": "deny" }
}
resource:
names: ["vm-001", "vm-002"]
want_effect: "deny"
- note: allof_exists_true
policy_rule: |
{
"if": {
"field": "items[*].name",
"exists": true
},
"then": { "effect": "deny" }
}
resource:
items:
- { "name": "a" }
- { "name": "b" }
want_effect: "deny"
- note: allof_exists_false_missing_field
policy_rule: |
{
"if": {
"field": "items[*].name",
"exists": true
},
"then": { "effect": "deny" }
}
resource:
items:
- { "name": "a" }
- { "other": "b" }
want_undefined: true
# -- exists false with [*] ------------------------------------------------
- note: allof_exists_false_all_present
# All elements have the field → "exists false" is false for each → compliant
policy_rule: |
{
"if": {
"field": "items[*].name",
"exists": "false"
},
"then": { "effect": "deny" }
}
resource:
items:
- { "name": "a" }
- { "name": "b" }
want_undefined: true
- note: allof_exists_false_all_missing
# No element has the field → "exists false" is true for each → non-compliant
policy_rule: |
{
"if": {
"field": "items[*].name",
"exists": "false"
},
"then": { "effect": "deny" }
}
resource:
items:
- { "other": "x" }
- { "other": "y" }
want_effect: "deny"
- note: allof_exists_false_mixed
# Mixed — one has field, one doesn't → not all satisfy → compliant
policy_rule: |
{
"if": {
"field": "items[*].name",
"exists": "false"
},
"then": { "effect": "deny" }
}
resource:
items:
- { "name": "a" }
- { "other": "b" }
want_undefined: true
- note: allof_exists_true_null_values
# Null values → "exists true" is false (null = not defined) → compliant
policy_rule: |
{
"if": {
"field": "items[*].name",
"exists": "true"
},
"then": { "effect": "deny" }
}
resource:
items:
- { "name": null }
- { "name": null }
want_undefined: true
- note: allof_exists_false_null_values
# Null values → "exists false" is true (null = not defined) → non-compliant
policy_rule: |
{
"if": {
"field": "items[*].name",
"exists": "false"
},
"then": { "effect": "deny" }
}
resource:
items:
- { "name": null }
- { "name": null }
want_effect: "deny"
- note: allof_exists_false_empty_array
# Empty array → vacuous truth → non-compliant
policy_rule: |
{
"if": {
"field": "items[*].name",
"exists": "false"
},
"then": { "effect": "deny" }
}
resource:
items: []
want_effect: "deny"
# =========================================================================
# Real-world pattern: not + [*] + notEquals
# "at least one element equals X" via double negation
# =========================================================================
- note: allof_not_notequals_pattern_match
policy_rule: |
{
"if": {
"not": {
"field": "ports[*]",
"notEquals": "*"
}
},
"then": { "effect": "deny" }
}
resource:
ports: ["80", "*", "443"]
want_effect: "deny"
- note: allof_not_notequals_pattern_no_match
policy_rule: |
{
"if": {
"not": {
"field": "ports[*]",
"notEquals": "*"
}
},
"then": { "effect": "deny" }
}
resource:
ports: ["80", "443"]
want_undefined: true
# =========================================================================
# Doubly-nested [*] — allOf over nested arrays
# =========================================================================
- note: allof_doubly_nested_all_match
policy_rule: |
{
"if": {
"field": "groups[*].tags[*]",
"notEquals": "deprecated"
},
"then": { "effect": "deny" }
}
resource:
groups:
- tags: ["prod", "web"]
- tags: ["staging", "api"]
want_effect: "deny"
- note: allof_doubly_nested_one_fails
policy_rule: |
{
"if": {
"field": "groups[*].tags[*]",
"notEquals": "deprecated"
},
"then": { "effect": "deny" }
}
resource:
groups:
- tags: ["prod", "web"]
- tags: ["deprecated", "api"]
want_undefined: true
- note: allof_doubly_nested_with_suffix
policy_rule: |
{
"if": {
"field": "groups[*].members[*].role",
"equals": "admin"
},
"then": { "effect": "deny" }
}
resource:
groups:
- members:
- { "role": "admin" }
- { "role": "admin" }
- members:
- { "role": "admin" }
want_effect: "deny"
- note: allof_doubly_nested_with_suffix_fail
policy_rule: |
{
"if": {
"field": "groups[*].members[*].role",
"equals": "admin"
},
"then": { "effect": "deny" }
}
resource:
groups:
- members:
- { "role": "admin" }
- members:
- { "role": "viewer" }
want_undefined: true
# =========================================================================
# Doubly-nested — inner array missing/empty
# =========================================================================
- note: allof_doubly_nested_inner_empty
policy_rule: |
{
"if": {
"field": "groups[*].tags[*]",
"equals": "ok"
},
"then": { "effect": "deny" }
}
resource:
groups:
- tags: []
- tags: []
want_effect: "deny"
- note: allof_doubly_nested_inner_missing
# Inner [*] on missing field → false (not iterable), outer Every fails
policy_rule: |
{
"if": {
"field": "groups[*].tags[*]",
"equals": "ok"
},
"then": { "effect": "deny" }
}
resource:
groups:
- other: "no tags"
- other: "also no tags"
want_undefined: true
# =========================================================================
# Single element — trivially allOf
# =========================================================================
- note: allof_single_element_match
policy_rule: |
{
"if": {
"field": "items[*].v",
"equals": 42
},
"then": { "effect": "deny" }
}
resource:
items:
- { "v": 42 }
want_effect: "deny"
- note: allof_single_element_no_match
policy_rule: |
{
"if": {
"field": "items[*].v",
"equals": 42
},
"then": { "effect": "deny" }
}
resource:
items:
- { "v": 99 }
want_undefined: true

View File

@@ -0,0 +1,344 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Logical Combinators Test Suite
# Tests allOf, anyOf, not, and nested combinations.
cases:
# =========================================================================
# allOf
# =========================================================================
- note: allOf_two_conditions
policy_rule: |
{
"if": {
"allOf": [
{ "field": "type", "equals": "Microsoft.Compute/virtualMachines" },
{ "field": "location", "equals": "eastus" }
]
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
location: "eastus"
want_effect: "deny"
- note: allOf_partial_match
policy_rule: |
{
"if": {
"allOf": [
{ "field": "type", "equals": "Microsoft.Compute/virtualMachines" },
{ "field": "location", "equals": "westus" }
]
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
location: "eastus"
want_undefined: true
- note: allOf_three_conditions
policy_rule: |
{
"if": {
"allOf": [
{ "field": "type", "equals": "Microsoft.Compute/virtualMachines" },
{ "field": "location", "equals": "eastus" },
{ "field": "name", "contains": "prod" }
]
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
location: "eastus"
name: "my-prod-vm"
want_effect: "deny"
- note: allOf_single_condition
policy_rule: |
{
"if": {
"allOf": [
{ "field": "type", "equals": "Microsoft.Compute/virtualMachines" }
]
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "deny"
- note: allOf_empty_array
policy_rule: |
{
"if": {
"allOf": []
},
"then": { "effect": "deny" }
}
resource:
type: "anything"
want_effect: "deny"
# =========================================================================
# anyOf
# =========================================================================
- note: anyOf_first_matches
policy_rule: |
{
"if": {
"anyOf": [
{ "field": "location", "equals": "eastus" },
{ "field": "location", "equals": "westus" }
]
},
"then": { "effect": "deny" }
}
resource:
location: "eastus"
want_effect: "deny"
- note: anyOf_second_matches
policy_rule: |
{
"if": {
"anyOf": [
{ "field": "location", "equals": "eastus" },
{ "field": "location", "equals": "westus" }
]
},
"then": { "effect": "deny" }
}
resource:
location: "westus"
want_effect: "deny"
- note: anyOf_no_match
policy_rule: |
{
"if": {
"anyOf": [
{ "field": "location", "equals": "eastus" },
{ "field": "location", "equals": "westus" }
]
},
"then": { "effect": "deny" }
}
resource:
location: "northeurope"
want_undefined: true
- note: anyOf_three_options
policy_rule: |
{
"if": {
"anyOf": [
{ "field": "type", "equals": "Microsoft.Compute/virtualMachines" },
{ "field": "type", "equals": "Microsoft.Compute/virtualMachineScaleSets" },
{ "field": "type", "equals": "Microsoft.Compute/disks" }
]
},
"then": { "effect": "audit" }
}
resource:
type: "Microsoft.Compute/disks"
want_effect: "audit"
# =========================================================================
# not
# =========================================================================
- note: not_condition
policy_rule: |
{
"if": {
"not": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
}
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Storage/storageAccounts"
want_effect: "deny"
- note: not_condition_no_match
policy_rule: |
{
"if": {
"not": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
}
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_undefined: true
- note: not_allOf
policy_rule: |
{
"if": {
"not": {
"allOf": [
{ "field": "type", "equals": "Microsoft.Compute/virtualMachines" },
{ "field": "location", "equals": "eastus" }
]
}
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
location: "westus"
want_effect: "deny"
- note: not_anyOf
policy_rule: |
{
"if": {
"not": {
"anyOf": [
{ "field": "location", "equals": "eastus" },
{ "field": "location", "equals": "westus" }
]
}
},
"then": { "effect": "deny" }
}
resource:
location: "northeurope"
want_effect: "deny"
# =========================================================================
# Nested combinations
# =========================================================================
- note: allOf_with_nested_anyOf
policy_rule: |
{
"if": {
"allOf": [
{ "field": "type", "equals": "Microsoft.Compute/virtualMachines" },
{
"anyOf": [
{ "field": "location", "equals": "eastus" },
{ "field": "location", "equals": "westus" }
]
}
]
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
location: "westus"
want_effect: "deny"
- note: anyOf_with_nested_allOf
policy_rule: |
{
"if": {
"anyOf": [
{
"allOf": [
{ "field": "type", "equals": "Microsoft.Compute/virtualMachines" },
{ "field": "location", "equals": "eastus" }
]
},
{
"allOf": [
{ "field": "type", "equals": "Microsoft.Storage/storageAccounts" },
{ "field": "location", "equals": "westus" }
]
}
]
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Storage/storageAccounts"
location: "westus"
want_effect: "deny"
- note: allOf_with_not
policy_rule: |
{
"if": {
"allOf": [
{ "field": "type", "equals": "Microsoft.Compute/virtualMachines" },
{
"not": {
"field": "location",
"equals": "eastus"
}
}
]
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
location: "westus"
want_effect: "deny"
- note: deeply_nested_combinators
policy_rule: |
{
"if": {
"allOf": [
{ "field": "type", "equals": "Microsoft.Network/networkSecurityGroups/securityRules" },
{
"not": {
"anyOf": [
{
"allOf": [
{ "field": "properties.protocol", "equals": "TCP" },
{ "field": "properties.destinationPortRange", "in": ["443", "8443"] }
]
},
{
"allOf": [
{ "field": "properties.protocol", "equals": "UDP" },
{ "field": "properties.destinationPortRange", "equals": "53" }
]
}
]
}
}
]
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Network/networkSecurityGroups/securityRules"
properties:
protocol: "TCP"
destinationPortRange: "80"
want_effect: "deny"
- note: double_negation
policy_rule: |
{
"if": {
"not": {
"not": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
}
}
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "deny"

View File

@@ -0,0 +1,221 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Modifiable Check Test Suite
# When an alias catalog is loaded, the compiler validates that aliases used
# in Modify operations have `defaultMetadata.attributes = "Modifiable"`.
#
# Non-modifiable aliases should cause a compile-time error.
# Modifiable aliases, tag paths, and built-in fields should compile fine.
aliases: test_aliases.json
cases:
# =========================================================================
# Modifiable alias in Modify — should compile and evaluate
# =========================================================================
- note: modify_modifiable_alias_ok
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
},
"then": {
"effect": "modify",
"details": {
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
],
"operations": [
{
"operation": "addOrReplace",
"field": "Microsoft.Storage/storageAccounts/supportsHttpsTrafficOnly",
"value": true
}
]
}
}
}
resource:
type: "Microsoft.Storage/storageAccounts"
properties:
supportsHttpsTrafficOnly: false
want_effect: "modify"
want_details:
roleDefinitionIds:
- "/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
operations:
- operation: "addOrReplace"
field: "Microsoft.Storage/storageAccounts/supportsHttpsTrafficOnly"
value: true
# =========================================================================
# Non-modifiable alias in Modify — should fail compilation
# =========================================================================
- note: modify_non_modifiable_alias_error
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
},
"then": {
"effect": "modify",
"details": {
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
],
"operations": [
{
"operation": "addOrReplace",
"field": "Microsoft.Storage/storageAccounts/primaryEndpoints.blob",
"value": "https://example.blob.core.windows.net"
}
]
}
}
}
resource:
type: "Microsoft.Storage/storageAccounts"
want_compile_error: true
# =========================================================================
# Tag field in Modify — always allowed (no alias check needed)
# =========================================================================
- note: modify_tag_field_ok
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": {
"effect": "modify",
"details": {
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
],
"operations": [
{
"operation": "addOrReplace",
"field": "tags['environment']",
"value": "production"
}
]
}
}
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "modify"
# =========================================================================
# Properties path in Modify — no alias match, allowed
# =========================================================================
- note: modify_properties_path_ok
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": {
"effect": "modify",
"details": {
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
],
"operations": [
{
"operation": "addOrReplace",
"field": "properties.someCustomField",
"value": "custom-value"
}
]
}
}
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "modify"
# =========================================================================
# Multiple operations — one non-modifiable should fail entire compilation
# =========================================================================
- note: modify_mixed_modifiable_non_modifiable_error
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
},
"then": {
"effect": "modify",
"details": {
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
],
"operations": [
{
"operation": "addOrReplace",
"field": "Microsoft.Storage/storageAccounts/supportsHttpsTrafficOnly",
"value": true
},
{
"operation": "addOrReplace",
"field": "Microsoft.Storage/storageAccounts/primaryEndpoints.blob",
"value": "https://override.blob.core.windows.net"
}
]
}
}
}
resource:
type: "Microsoft.Storage/storageAccounts"
want_compile_error: true
# =========================================================================
# Modify with modifiable alias — details include resolved short name
# =========================================================================
- note: modify_modifiable_alias_details_check
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
},
"then": {
"effect": "modify",
"details": {
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
],
"operations": [
{
"operation": "addOrReplace",
"field": "Microsoft.Storage/storageAccounts/minimumTlsVersion",
"value": "TLS1_2"
}
]
}
}
}
resource:
type: "Microsoft.Storage/storageAccounts"
properties:
minimumTlsVersion: "TLS1_0"
want_effect: "modify"
want_details:
roleDefinitionIds:
- "/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
operations:
- operation: "addOrReplace"
field: "Microsoft.Storage/storageAccounts/minimumTlsVersion"
value: "TLS1_2"

View File

@@ -0,0 +1,453 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Operators Test Suite
# Tests all 20 Azure Policy condition operators with field-based conditions.
cases:
# =========================================================================
# equals / notEquals
# =========================================================================
- note: equals_string
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "deny"
- note: equals_string_no_match
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Storage/storageAccounts"
want_undefined: true
- note: equals_number
policy_rule: |
{
"if": {
"field": "properties.count",
"equals": 5
},
"then": { "effect": "audit" }
}
resource:
properties:
count: 5
want_effect: "audit"
- note: equals_boolean
policy_rule: |
{
"if": {
"field": "properties.enabled",
"equals": true
},
"then": { "effect": "audit" }
}
resource:
properties:
enabled: true
want_effect: "audit"
- note: equals_null
policy_rule: |
{
"if": {
"field": "properties.optionalField",
"equals": null
},
"then": { "effect": "audit" }
}
resource:
properties: {}
want_effect: "audit"
- note: notEquals_string
policy_rule: |
{
"if": {
"field": "type",
"notEquals": "Microsoft.Compute/virtualMachines"
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Storage/storageAccounts"
want_effect: "deny"
- note: notEquals_no_match
policy_rule: |
{
"if": {
"field": "type",
"notEquals": "Microsoft.Compute/virtualMachines"
},
"then": { "effect": "deny" }
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_undefined: true
# =========================================================================
# contains / notContains
# =========================================================================
- note: contains_string
policy_rule: |
{
"if": {
"field": "name",
"contains": "prod"
},
"then": { "effect": "audit" }
}
resource:
name: "my-prod-vm"
want_effect: "audit"
- note: contains_no_match
policy_rule: |
{
"if": {
"field": "name",
"contains": "staging"
},
"then": { "effect": "audit" }
}
resource:
name: "my-prod-vm"
want_undefined: true
- note: notContains_string
policy_rule: |
{
"if": {
"field": "name",
"notContains": "staging"
},
"then": { "effect": "audit" }
}
resource:
name: "my-prod-vm"
want_effect: "audit"
# =========================================================================
# containsKey / notContainsKey
# =========================================================================
- note: containsKey_field
policy_rule: |
{
"if": {
"field": "tags",
"containsKey": "environment"
},
"then": { "effect": "audit" }
}
resource:
tags:
environment: "production"
want_effect: "audit"
- note: notContainsKey_field
policy_rule: |
{
"if": {
"field": "tags",
"notContainsKey": "costCenter"
},
"then": { "effect": "deny" }
}
resource:
tags:
environment: "production"
want_effect: "deny"
# =========================================================================
# greater / greaterOrEquals / less / lessOrEquals
# =========================================================================
- note: greater_number
policy_rule: |
{
"if": {
"field": "properties.maxRetries",
"greater": 5
},
"then": { "effect": "deny" }
}
resource:
properties:
maxRetries: 10
want_effect: "deny"
- note: greater_no_match
policy_rule: |
{
"if": {
"field": "properties.maxRetries",
"greater": 5
},
"then": { "effect": "deny" }
}
resource:
properties:
maxRetries: 3
want_undefined: true
- note: greaterOrEquals_equal
policy_rule: |
{
"if": {
"field": "properties.minInstances",
"greaterOrEquals": 3
},
"then": { "effect": "audit" }
}
resource:
properties:
minInstances: 3
want_effect: "audit"
- note: less_number
policy_rule: |
{
"if": {
"field": "properties.retentionDays",
"less": 30
},
"then": { "effect": "deny" }
}
resource:
properties:
retentionDays: 7
want_effect: "deny"
- note: lessOrEquals_number
policy_rule: |
{
"if": {
"field": "properties.maxConnections",
"lessOrEquals": 100
},
"then": { "effect": "audit" }
}
resource:
properties:
maxConnections: 50
want_effect: "audit"
# =========================================================================
# in / notIn
# =========================================================================
- note: in_string_array
policy_rule: |
{
"if": {
"field": "location",
"in": ["eastus", "westus", "centralus"]
},
"then": { "effect": "deny" }
}
resource:
location: "eastus"
want_effect: "deny"
- note: in_no_match
policy_rule: |
{
"if": {
"field": "location",
"in": ["eastus", "westus"]
},
"then": { "effect": "deny" }
}
resource:
location: "northeurope"
want_undefined: true
- note: notIn_string_array
policy_rule: |
{
"if": {
"field": "location",
"notIn": ["eastus", "westus"]
},
"then": { "effect": "deny" }
}
resource:
location: "northeurope"
want_effect: "deny"
- note: in_number_array
policy_rule: |
{
"if": {
"field": "properties.port",
"in": [80, 443, 8080]
},
"then": { "effect": "deny" }
}
resource:
properties:
port: 443
want_effect: "deny"
# =========================================================================
# like / notLike
# =========================================================================
- note: like_wildcard
policy_rule: |
{
"if": {
"field": "name",
"like": "prod-*"
},
"then": { "effect": "audit" }
}
resource:
name: "prod-server-01"
want_effect: "audit"
- note: like_question_mark
policy_rule: |
{
"if": {
"field": "name",
"like": "vm-?"
},
"then": { "effect": "audit" }
}
resource:
name: "vm-1"
want_effect: "audit"
- note: notLike_wildcard
policy_rule: |
{
"if": {
"field": "name",
"notLike": "test-*"
},
"then": { "effect": "audit" }
}
resource:
name: "prod-server-01"
want_effect: "audit"
# =========================================================================
# match / matchInsensitively
# =========================================================================
- note: match_pattern
policy_rule: |
{
"if": {
"field": "name",
"match": "vm-##"
},
"then": { "effect": "audit" }
}
resource:
name: "vm-01"
want_effect: "audit"
- note: matchInsensitively_pattern
policy_rule: |
{
"if": {
"field": "name",
"matchInsensitively": "VM-##"
},
"then": { "effect": "audit" }
}
resource:
name: "vm-01"
want_effect: "audit"
- note: notMatch_pattern
policy_rule: |
{
"if": {
"field": "name",
"notMatch": "test-*"
},
"then": { "effect": "audit" }
}
resource:
name: "prod-server-01"
want_effect: "audit"
- note: notMatchInsensitively_pattern
policy_rule: |
{
"if": {
"field": "name",
"notMatchInsensitively": "TEST-##"
},
"then": { "effect": "audit" }
}
resource:
name: "prod-01"
want_effect: "audit"
# =========================================================================
# exists
# =========================================================================
- note: exists_true
policy_rule: |
{
"if": {
"field": "properties.optionalSetting",
"exists": true
},
"then": { "effect": "audit" }
}
resource:
properties:
optionalSetting: "value"
want_effect: "audit"
- note: exists_false
policy_rule: |
{
"if": {
"field": "properties.optionalSetting",
"exists": false
},
"then": { "effect": "audit" }
}
resource:
properties: {}
want_effect: "audit"
- note: exists_string_true
policy_rule: |
{
"if": {
"field": "properties.optionalSetting",
"exists": "true"
},
"then": { "effect": "audit" }
}
resource:
properties:
optionalSetting: "value"
want_effect: "audit"

View File

@@ -0,0 +1,269 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Parse Error Test Suite
# Tests that malformed policy JSON and invalid constructs are properly rejected.
# These test cases are expected to fail parsing.
cases:
# =========================================================================
# Missing required keys
# =========================================================================
- note: missing_if_key
policy_rule: |
{
"then": { "effect": "deny" }
}
want_parse_error: true
- note: missing_then_key
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
}
}
want_parse_error: true
- note: missing_effect_in_then
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": {}
}
want_parse_error: true
# =========================================================================
# Missing operator in condition
# =========================================================================
- note: field_without_operator
policy_rule: |
{
"if": {
"field": "type"
},
"then": { "effect": "deny" }
}
want_parse_error: true
- note: value_without_operator
policy_rule: |
{
"if": {
"value": "[parameters('x')]"
},
"then": { "effect": "deny" }
}
want_parse_error: true
# =========================================================================
# Invalid JSON structure
# =========================================================================
- note: allOf_not_array
policy_rule: |
{
"if": {
"allOf": "not-an-array"
},
"then": { "effect": "deny" }
}
want_parse_error: true
- note: anyOf_not_array
policy_rule: |
{
"if": {
"anyOf": 42
},
"then": { "effect": "deny" }
}
want_parse_error: true
- note: not_not_object
policy_rule: |
{
"if": {
"not": [1, 2, 3]
},
"then": { "effect": "deny" }
}
want_parse_error: true
# =========================================================================
# Unknown keys in condition objects
# =========================================================================
- note: unknown_key_in_condition
policy_rule: |
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines",
"unknownKey": "value"
},
"then": { "effect": "deny" }
}
want_parse_error: true
# =========================================================================
# Count structure issues
# =========================================================================
- note: count_missing_field_and_value
policy_rule: |
{
"if": {
"count": {},
"equals": 0
},
"then": { "effect": "deny" }
}
want_parse_error: true
- note: count_with_both_field_and_value
policy_rule: |
{
"if": {
"count": {
"field": "some.alias[*]",
"value": ["a", "b"]
},
"equals": 0
},
"then": { "effect": "deny" }
}
want_parse_error: true
# =========================================================================
# Invalid ARM template expressions
# =========================================================================
- note: malformed_expression_unclosed_paren
policy_rule: |
{
"if": {
"value": "[parameters('x']",
"equals": "something"
},
"then": { "effect": "deny" }
}
want_parse_error: true
# =========================================================================
# Both field and value LHS
# =========================================================================
- note: both_field_and_value_lhs
policy_rule: |
{
"if": {
"field": "type",
"value": "something",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": { "effect": "deny" }
}
want_parse_error: true
# =========================================================================
# Empty input
# =========================================================================
- note: empty_object
policy_rule: |
{}
want_parse_error: true
- note: not_an_object
policy_rule: |
"just a string"
want_parse_error: true
# =========================================================================
# Extra keys in logical operators
# =========================================================================
- note: extra_key_in_allOf
policy_rule: |
{
"if": {
"allOf": [
{ "field": "type", "equals": "X" }
],
"field": "name",
"equals": "Y"
},
"then": { "effect": "deny" }
}
want_parse_error: true
- note: extra_key_in_not
policy_rule: |
{
"if": {
"not": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"field": "name",
"equals": "something"
},
"then": { "effect": "deny" }
}
want_parse_error: true
# =========================================================================
# count.name errors
# =========================================================================
- note: count_name_with_field_not_value
policy_rule: |
{
"if": {
"count": {
"field": "items[*]",
"name": "item"
},
"equals": 0
},
"then": { "effect": "deny" }
}
want_parse_error: true
- note: count_name_not_string
policy_rule: |
{
"if": {
"count": {
"value": ["a", "b"],
"name": 42
},
"equals": 2
},
"then": { "effect": "deny" }
}
want_parse_error: true
# =========================================================================
# Edge cases: expressions that look malformed but are actually valid
# =========================================================================
- note: concat_zero_args_is_valid
policy_rule: |
{
"if": {
"value": "[concat()]",
"equals": ""
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"

View File

@@ -0,0 +1,399 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Full Policy Definition Test Suite
# Tests parsing of the complete Azure Policy definition envelope,
# including parameters, displayName, description, mode, and metadata.
cases:
# =========================================================================
# Unwrapped form (properties-level)
# =========================================================================
- note: defn_unwrapped_basic
policy_definition: |
{
"displayName": "Deny Public IPs",
"description": "Prevents creation of public IP addresses",
"mode": "All",
"parameters": {},
"policyRule": {
"if": {
"field": "type",
"equals": "Microsoft.Network/publicIPAddresses"
},
"then": {
"effect": "deny"
}
}
}
resource:
type: "Microsoft.Network/publicIPAddresses"
want_effect: "deny"
- note: defn_unwrapped_no_match
policy_definition: |
{
"displayName": "Deny Public IPs",
"mode": "All",
"policyRule": {
"if": {
"field": "type",
"equals": "Microsoft.Network/publicIPAddresses"
},
"then": {
"effect": "deny"
}
}
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_undefined: true
- note: defn_unwrapped_with_parameters
policy_definition: |
{
"displayName": "Require tag",
"description": "Requires a specified tag on resources",
"mode": "Indexed",
"parameters": {
"tagName": {
"type": "String",
"metadata": {
"displayName": "Tag Name",
"description": "Name of the tag to require"
}
},
"tagValue": {
"type": "String",
"defaultValue": "production",
"allowedValues": ["production", "staging", "development"]
}
},
"policyRule": {
"if": {
"field": "[concat('tags.', parameters('tagName'))]",
"notEquals": "[parameters('tagValue')]"
},
"then": {
"effect": "deny"
}
}
}
parameters:
tagName: "environment"
tagValue: "production"
resource:
tags:
environment: "production"
want_undefined: true
- note: defn_unwrapped_param_tag_mismatch
policy_definition: |
{
"displayName": "Require tag",
"parameters": {
"tagName": {
"type": "String"
},
"tagValue": {
"type": "String"
}
},
"policyRule": {
"if": {
"field": "[concat('tags.', parameters('tagName'))]",
"notEquals": "[parameters('tagValue')]"
},
"then": {
"effect": "deny"
}
}
}
parameters:
tagName: "environment"
tagValue: "production"
resource:
tags:
environment: "staging"
want_effect: "deny"
# =========================================================================
# Wrapped form (with "properties" envelope)
# =========================================================================
- note: defn_wrapped_basic
policy_definition: |
{
"id": "/providers/Microsoft.Authorization/policyDefinitions/test-001",
"name": "test-001",
"type": "Microsoft.Authorization/policyDefinitions",
"properties": {
"displayName": "Deny Storage without HTTPS",
"description": "Storage accounts should only allow HTTPS traffic",
"policyType": "BuiltIn",
"mode": "All",
"parameters": {},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
},
{
"field": "properties.supportsHttpsTrafficOnly",
"notEquals": true
}
]
},
"then": {
"effect": "deny"
}
}
}
}
resource:
type: "Microsoft.Storage/storageAccounts"
properties:
supportsHttpsTrafficOnly: false
want_effect: "deny"
- note: defn_wrapped_compliant
policy_definition: |
{
"id": "/providers/Microsoft.Authorization/policyDefinitions/test-001",
"name": "test-001",
"type": "Microsoft.Authorization/policyDefinitions",
"properties": {
"displayName": "Deny Storage without HTTPS",
"mode": "All",
"parameters": {},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
},
{
"field": "properties.supportsHttpsTrafficOnly",
"notEquals": true
}
]
},
"then": {
"effect": "deny"
}
}
}
}
resource:
type: "Microsoft.Storage/storageAccounts"
properties:
supportsHttpsTrafficOnly: true
want_undefined: true
# =========================================================================
# Parameterized effect
# =========================================================================
- note: defn_parameterized_effect
policy_definition: |
{
"displayName": "Allowed locations",
"parameters": {
"allowedLocations": {
"type": "Array",
"metadata": {
"displayName": "Allowed locations",
"description": "The list of allowed locations for resources"
}
},
"effect": {
"type": "String",
"defaultValue": "deny",
"allowedValues": ["audit", "deny", "disabled"]
}
},
"policyRule": {
"if": {
"not": {
"field": "location",
"in": "[parameters('allowedLocations')]"
}
},
"then": {
"effect": "[parameters('effect')]"
}
}
}
parameters:
allowedLocations:
- "eastus"
- "westus"
effect: "audit"
resource:
location: "northeurope"
want_effect: "audit"
# =========================================================================
# Extra / unknown fields preserved
# =========================================================================
- note: defn_extra_fields_ignored
policy_definition: |
{
"displayName": "Test Policy",
"policyType": "Custom",
"category": "General",
"version": "1.0.0",
"policyRule": {
"if": {
"field": "location",
"equals": "eastus"
},
"then": {
"effect": "audit"
}
}
}
resource:
location: "eastus"
want_effect: "audit"
# =========================================================================
# Metadata
# =========================================================================
- note: defn_with_metadata
policy_definition: |
{
"displayName": "Audit VMs",
"metadata": {
"version": "2.0.0",
"category": "Compute",
"preview": true
},
"parameters": {},
"policyRule": {
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": {
"effect": "audit"
}
}
}
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "audit"
# =========================================================================
# Missing policyRule should fail
# =========================================================================
- note: defn_missing_policy_rule
policy_definition: |
{
"displayName": "No Rule",
"description": "This definition is missing policyRule",
"parameters": {}
}
want_parse_error: true
# =========================================================================
# Complex: wrapped with all fields
# =========================================================================
- note: defn_wrapped_full
policy_definition: |
{
"id": "/subscriptions/xxx/providers/Microsoft.Authorization/policyDefinitions/require-tag",
"name": "require-tag",
"type": "Microsoft.Authorization/policyDefinitions",
"properties": {
"displayName": "Require a tag and its value on resources",
"description": "Enforces a required tag and its value.",
"policyType": "Custom",
"mode": "Indexed",
"metadata": {
"version": "1.0.0",
"category": "Tags"
},
"parameters": {
"tagName": {
"type": "String",
"metadata": {
"displayName": "Tag Name",
"description": "Name of the tag, such as costCenter"
}
},
"tagValue": {
"type": "String",
"metadata": {
"displayName": "Tag Value",
"description": "Value of the tag, such as IT"
}
}
},
"policyRule": {
"if": {
"not": {
"field": "[concat('tags[', parameters('tagName'), ']')]",
"equals": "[parameters('tagValue')]"
}
},
"then": {
"effect": "deny"
}
}
}
}
parameters:
tagName: "costCenter"
tagValue: "IT"
resource:
tags:
costCenter: "IT"
want_undefined: true
- note: defn_wrapped_full_non_compliant
policy_definition: |
{
"id": "/subscriptions/xxx/providers/Microsoft.Authorization/policyDefinitions/require-tag",
"name": "require-tag",
"type": "Microsoft.Authorization/policyDefinitions",
"properties": {
"displayName": "Require a tag and its value on resources",
"policyType": "Custom",
"mode": "Indexed",
"parameters": {
"tagName": {
"type": "String"
},
"tagValue": {
"type": "String"
}
},
"policyRule": {
"if": {
"not": {
"field": "[concat('tags[', parameters('tagName'), ']')]",
"equals": "[parameters('tagValue')]"
}
},
"then": {
"effect": "deny"
}
}
}
}
parameters:
tagName: "costCenter"
tagValue: "IT"
resource:
tags:
costCenter: "Finance"
want_effect: "deny"

View File

@@ -0,0 +1,548 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# ARM Template Functions Test Suite
# Tests: split, empty, first, last, createArray, startsWith, endsWith,
# int, string, bool.
cases:
# =========================================================================
# split(inputString, delimiter)
# =========================================================================
- note: fn_split_basic
policy_rule: |
{
"if": {
"value": "[first(split('a-b-c', '-'))]",
"equals": "a"
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
- note: fn_split_last_element
policy_rule: |
{
"if": {
"value": "[last(split('foo/bar/baz', '/'))]",
"equals": "baz"
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
- note: fn_split_length
policy_rule: |
{
"if": {
"value": "[length(split('a,b,c,d', ','))]",
"equals": 4
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
- note: fn_split_no_match_delimiter
policy_rule: |
{
"if": {
"value": "[length(split('hello', ','))]",
"equals": 1
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
# =========================================================================
# empty(item)
# =========================================================================
- note: fn_empty_string_true
policy_rule: |
{
"if": {
"value": "[empty('')]",
"equals": true
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
- note: fn_empty_string_false
policy_rule: |
{
"if": {
"value": "[empty('hello')]",
"equals": false
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
- note: fn_empty_with_parameter_array
policy_rule: |
{
"if": {
"value": "[empty(parameters('items'))]",
"equals": true
},
"then": { "effect": "deny" }
}
parameters:
items: []
resource:
type: "any"
want_effect: "deny"
- note: fn_empty_nonempty_array
policy_rule: |
{
"if": {
"value": "[empty(parameters('items'))]",
"equals": false
},
"then": { "effect": "deny" }
}
parameters:
items:
- "a"
resource:
type: "any"
want_effect: "deny"
# =========================================================================
# first(arg) / last(arg)
# =========================================================================
- note: fn_first_string
policy_rule: |
{
"if": {
"value": "[first('hello')]",
"equals": "h"
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
- note: fn_last_string
policy_rule: |
{
"if": {
"value": "[last('hello')]",
"equals": "o"
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
- note: fn_first_array
policy_rule: |
{
"if": {
"value": "[first(parameters('items'))]",
"equals": "alpha"
},
"then": { "effect": "deny" }
}
parameters:
items:
- "alpha"
- "beta"
- "gamma"
resource:
type: "any"
want_effect: "deny"
- note: fn_last_array
policy_rule: |
{
"if": {
"value": "[last(parameters('items'))]",
"equals": "gamma"
},
"then": { "effect": "deny" }
}
parameters:
items:
- "alpha"
- "beta"
- "gamma"
resource:
type: "any"
want_effect: "deny"
# =========================================================================
# createArray(items...)
# =========================================================================
- note: fn_createArray_basic
policy_rule: |
{
"if": {
"value": "[length(createArray('a', 'b', 'c'))]",
"equals": 3
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
- note: fn_createArray_first
policy_rule: |
{
"if": {
"value": "[first(createArray('x', 'y'))]",
"equals": "x"
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
# =========================================================================
# startsWith / endsWith
# =========================================================================
- note: fn_startsWith_true
policy_rule: |
{
"if": {
"value": "[startsWith('abcdef', 'abc')]",
"equals": true
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
- note: fn_startsWith_false
policy_rule: |
{
"if": {
"value": "[startsWith('abcdef', 'xyz')]",
"equals": false
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
- note: fn_startsWith_case_insensitive
policy_rule: |
{
"if": {
"value": "[startsWith('AbCdEf', 'abc')]",
"equals": true
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
- note: fn_endsWith_true
policy_rule: |
{
"if": {
"value": "[endsWith('abcdef', 'def')]",
"equals": true
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
- note: fn_endsWith_false
policy_rule: |
{
"if": {
"value": "[endsWith('abcdef', 'xyz')]",
"equals": false
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
- note: fn_endsWith_case_insensitive
policy_rule: |
{
"if": {
"value": "[endsWith('AbCdEf', 'DEF')]",
"equals": true
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
- note: fn_startsWith_field_value
policy_rule: |
{
"if": {
"value": "[startsWith(field('name'), 'test-')]",
"equals": true
},
"then": { "effect": "deny" }
}
resource:
name: "test-resource"
want_effect: "deny"
# =========================================================================
# int(value)
# =========================================================================
- note: fn_int_from_string
policy_rule: |
{
"if": {
"value": "[int('42')]",
"equals": 42
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
- note: fn_int_from_float_string
policy_rule: |
{
"if": {
"value": "[int('3.7')]",
"equals": 3
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
- note: fn_int_identity
policy_rule: |
{
"if": {
"value": "[int(parameters('num'))]",
"equals": 10
},
"then": { "effect": "deny" }
}
parameters:
num: 10
resource:
type: "any"
want_effect: "deny"
# =========================================================================
# string(value)
# =========================================================================
- note: fn_string_from_int
policy_rule: |
{
"if": {
"value": "[string(42)]",
"equals": "42"
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
- note: fn_string_from_bool
policy_rule: |
{
"if": {
"value": "[string(true)]",
"equals": "true"
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
- note: fn_string_identity
policy_rule: |
{
"if": {
"value": "[string('hello')]",
"equals": "hello"
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
# =========================================================================
# bool(value)
# =========================================================================
- note: fn_bool_from_true_string
policy_rule: |
{
"if": {
"value": "[bool('true')]",
"equals": true
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
- note: fn_bool_from_false_string
policy_rule: |
{
"if": {
"value": "[bool('false')]",
"equals": false
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
- note: fn_bool_from_1_string
policy_rule: |
{
"if": {
"value": "[bool('1')]",
"equals": true
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
- note: fn_bool_from_number
policy_rule: |
{
"if": {
"value": "[bool(1)]",
"equals": true
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
- note: fn_bool_zero_is_false
policy_rule: |
{
"if": {
"value": "[bool(0)]",
"equals": false
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
# =========================================================================
# Composed / nested ARM functions
# =========================================================================
- note: fn_composed_split_startsWith
policy_rule: |
{
"if": {
"value": "[startsWith(first(split(field('name'), '-')), 'prod')]",
"equals": true
},
"then": { "effect": "deny" }
}
resource:
name: "production-vm-001"
want_effect: "deny"
- note: fn_composed_int_add
policy_rule: |
{
"if": {
"value": "[add(int('10'), int('20'))]",
"equals": 30
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_effect: "deny"
- note: fn_composed_if_empty
policy_rule: |
{
"if": {
"value": "[if(empty(parameters('label')), 'default', parameters('label'))]",
"equals": "default"
},
"then": { "effect": "deny" }
}
parameters:
label: ""
resource:
type: "any"
want_effect: "deny"
- note: fn_composed_concat_with_string
policy_rule: |
{
"if": {
"value": "[concat('count=', string(length(parameters('items'))))]",
"equals": "count=3"
},
"then": { "effect": "deny" }
}
parameters:
items:
- "a"
- "b"
- "c"
resource:
type: "any"
want_effect: "deny"
- note: fn_composed_endsWith_toLower
policy_rule: |
{
"if": {
"value": "[endsWith(toLower(field('name')), '.json')]",
"equals": true
},
"then": { "effect": "deny" }
}
resource:
name: "Config.JSON"
want_effect: "deny"

View File

@@ -0,0 +1,364 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Date/Time ARM template functions + ipRangeContains tests
#
# Tests: utcNow, dateTimeAdd, dateTimeFromEpoch, dateTimeToEpoch, addDays,
# ipRangeContains
cases:
# ── utcNow ───────────────────────────────────────────────────────────
- note: utcNow_returns_context_timestamp
policy_rule: |
{
"if": {
"value": "[utcNow()]",
"equals": "2025-02-20T12:00:00Z"
},
"then": { "effect": "audit" }
}
context:
utcNow: "2025-02-20T12:00:00Z"
resourceGroup:
name: myRG
location: eastus
subscription:
subscriptionId: "00000000-0000-0000-0000-000000000000"
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "audit"
- note: utcNow_in_comparison
policy_rule: |
{
"if": {
"allOf": [
{ "field": "type", "equals": "Microsoft.Compute/virtualMachines" },
{ "value": "[utcNow()]", "greater": "2024-01-01T00:00:00Z" }
]
},
"then": { "effect": "audit" }
}
context:
utcNow: "2025-02-20T12:00:00Z"
resourceGroup:
name: myRG
location: eastus
subscription:
subscriptionId: "00000000-0000-0000-0000-000000000000"
resource:
type: "Microsoft.Compute/virtualMachines"
want_effect: "audit"
# ── dateTimeAdd ──────────────────────────────────────────────────────
- note: dateTimeAdd_P1D
policy_rule: |
{
"if": {
"value": "[dateTimeAdd('2024-01-15T12:00:00Z', 'P1D')]",
"equals": "2024-01-16T12:00:00Z"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: dateTimeAdd_PT2H
policy_rule: |
{
"if": {
"value": "[dateTimeAdd('2024-01-15T10:00:00Z', 'PT2H')]",
"equals": "2024-01-15T12:00:00Z"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: dateTimeAdd_negative_duration
policy_rule: |
{
"if": {
"value": "[dateTimeAdd('2024-01-15T12:00:00Z', '-P1D')]",
"equals": "2024-01-14T12:00:00Z"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: dateTimeAdd_complex_P1DT2H30M
policy_rule: |
{
"if": {
"value": "[dateTimeAdd('2024-01-15T10:00:00Z', 'P1DT2H30M')]",
"equals": "2024-01-16T12:30:00Z"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
# ── dateTimeFromEpoch ────────────────────────────────────────────────
- note: dateTimeFromEpoch_basic
policy_rule: |
{
"if": {
"value": "[dateTimeFromEpoch(1705312800)]",
"equals": "2024-01-15T10:00:00Z"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: dateTimeFromEpoch_zero
policy_rule: |
{
"if": {
"value": "[dateTimeFromEpoch(0)]",
"equals": "1970-01-01T00:00:00Z"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
# ── dateTimeToEpoch ──────────────────────────────────────────────────
- note: dateTimeToEpoch_basic
policy_rule: |
{
"if": {
"value": "[dateTimeToEpoch('2024-01-15T10:00:00Z')]",
"equals": 1705312800
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: dateTimeToEpoch_zero
policy_rule: |
{
"if": {
"value": "[dateTimeToEpoch('1970-01-01T00:00:00Z')]",
"equals": 0
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: dateTimeToEpoch_roundtrip
policy_rule: |
{
"if": {
"value": "[dateTimeToEpoch(dateTimeFromEpoch(1705312800))]",
"equals": 1705312800
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
# ── addDays ──────────────────────────────────────────────────────────
- note: addDays_positive
policy_rule: |
{
"if": {
"value": "[addDays('2024-01-15T12:00:00Z', 5)]",
"equals": "2024-01-20T12:00:00Z"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: addDays_negative
policy_rule: |
{
"if": {
"value": "[addDays('2024-01-15T12:00:00Z', -3)]",
"equals": "2024-01-12T12:00:00Z"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: addDays_cross_month
policy_rule: |
{
"if": {
"value": "[addDays('2024-01-30T00:00:00Z', 5)]",
"equals": "2024-02-04T00:00:00Z"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: addDays_with_utcNow
policy_rule: |
{
"if": {
"value": "[addDays(utcNow(), -1)]",
"equals": "2025-02-19T12:00:00Z"
},
"then": { "effect": "audit" }
}
context:
utcNow: "2025-02-20T12:00:00Z"
resourceGroup:
name: myRG
location: eastus
subscription:
subscriptionId: "00000000-0000-0000-0000-000000000000"
resource:
type: "any"
want_effect: "audit"
# ── ipRangeContains ──────────────────────────────────────────────────
- note: ipRangeContains_ip_in_range
policy_rule: |
{
"if": {
"value": "[ipRangeContains('10.0.0.0/24', '10.0.0.5')]",
"equals": true
},
"then": { "effect": "audit" }
}
resource:
type: "Microsoft.KeyVault/vaults"
want_effect: "audit"
- note: ipRangeContains_ip_not_in_range
policy_rule: |
{
"if": {
"value": "[ipRangeContains('10.0.0.0/24', '10.0.1.5')]",
"equals": true
},
"then": { "effect": "audit" }
}
resource:
type: "Microsoft.KeyVault/vaults"
want_undefined: true
- note: ipRangeContains_subnet_contained
policy_rule: |
{
"if": {
"value": "[ipRangeContains('10.0.0.0/16', '10.0.1.0/24')]",
"equals": true
},
"then": { "effect": "audit" }
}
resource:
type: "Microsoft.KeyVault/vaults"
want_effect: "audit"
- note: ipRangeContains_subnet_not_contained
policy_rule: |
{
"if": {
"value": "[ipRangeContains('10.0.0.0/24', '10.0.0.0/16')]",
"equals": true
},
"then": { "effect": "audit" }
}
resource:
type: "Microsoft.KeyVault/vaults"
want_undefined: true
- note: ipRangeContains_exact_match_32
policy_rule: |
{
"if": {
"value": "[ipRangeContains('10.0.0.5/32', '10.0.0.5')]",
"equals": true
},
"then": { "effect": "audit" }
}
resource:
type: "Microsoft.KeyVault/vaults"
want_effect: "audit"
- note: ipRangeContains_ipv6_in_range
policy_rule: |
{
"if": {
"value": "[ipRangeContains('2001:db8::/32', '2001:db8::1')]",
"equals": true
},
"then": { "effect": "audit" }
}
resource:
type: "Microsoft.KeyVault/vaults"
want_effect: "audit"
- note: ipRangeContains_ipv6_not_in_range
policy_rule: |
{
"if": {
"value": "[ipRangeContains('2001:db8::/32', '2001:db9::1')]",
"equals": true
},
"then": { "effect": "audit" }
}
resource:
type: "Microsoft.KeyVault/vaults"
want_undefined: true
# ── Composition tests ───────────────────────────────────────────────
- note: addDays_with_mul_negative_days
policy_rule: |
{
"if": {
"value": "[addDays(utcNow(), mul(int('30'), -1))]",
"less": "2025-02-20T12:00:00Z"
},
"then": { "effect": "audit" }
}
context:
utcNow: "2025-02-20T12:00:00Z"
resourceGroup:
name: myRG
location: eastus
subscription:
subscriptionId: "00000000-0000-0000-0000-000000000000"
resource:
type: "Microsoft.DocumentDB/databaseAccounts"
want_effect: "audit"
- note: dateTimeToEpoch_with_dateTimeAdd
policy_rule: |
{
"if": {
"value": "[dateTimeToEpoch(dateTimeAdd('2024-01-15T00:00:00Z', 'P7D'))]",
"greater": "[dateTimeToEpoch('2024-01-20T00:00:00Z')]"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"

View File

@@ -0,0 +1,561 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# ARM Template Functions — Additional String, Collection, and Numeric Functions
# Tests indexOf, lastIndexOf, trim, format, base64, base64ToString, base64ToJson,
# uri, uriComponent, uriComponentToString, dataUri, dataUriToString,
# intersection, union, take, skip, range, array, coalesce, createObject,
# sub, mul, div, mod, min, max, float.
cases:
# =========================================================================
# String functions
# =========================================================================
- note: fn_indexOf_found
policy_rule: |
{
"if": {
"value": "[indexOf('hello world', 'world')]",
"equals": 6
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_indexOf_not_found
policy_rule: |
{
"if": {
"value": "[indexOf('hello world', 'xyz')]",
"equals": -1
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_lastIndexOf_found
policy_rule: |
{
"if": {
"value": "[lastIndexOf('hello world hello', 'hello')]",
"equals": 12
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_lastIndexOf_not_found
policy_rule: |
{
"if": {
"value": "[lastIndexOf('hello', 'xyz')]",
"equals": -1
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_trim
policy_rule: |
{
"if": {
"value": "[trim(' hello ')]",
"equals": "hello"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_format_simple
policy_rule: |
{
"if": {
"value": "[format('Hello {0}, you are {1}', 'World', 'great')]",
"equals": "Hello World, you are great"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_format_numbers
policy_rule: |
{
"if": {
"value": "[format('{0} + {1} = {2}', 1, 2, 3)]",
"equals": "1 + 2 = 3"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_base64_encode
policy_rule: |
{
"if": {
"value": "[base64('hello')]",
"equals": "aGVsbG8="
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_base64ToString
policy_rule: |
{
"if": {
"value": "[base64ToString('aGVsbG8=')]",
"equals": "hello"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_base64ToJson
policy_rule: |
{
"if": {
"value": "[base64ToJson('eyJrZXkiOiJ2YWx1ZSJ9').key]",
"equals": "value"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_uriComponent_encode
policy_rule: |
{
"if": {
"value": "[uriComponent('hello world')]",
"equals": "hello%20world"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_uriComponentToString
policy_rule: |
{
"if": {
"value": "[uriComponentToString('hello%20world')]",
"equals": "hello world"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_uri_combine
policy_rule: |
{
"if": {
"value": "[uri('https://example.com/path/', 'api/v1')]",
"equals": "https://example.com/path/api/v1"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_dataUri
policy_rule: |
{
"if": {
"value": "[dataUri('Hello')]",
"contains": "base64,"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_dataUriToString
policy_rule: |
{
"if": {
"value": "[dataUriToString(dataUri('Hello'))]",
"equals": "Hello"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
# =========================================================================
# Collection functions
# =========================================================================
- note: fn_intersection_arrays
policy_rule: |
{
"if": {
"value": "[length(intersection(createArray('a','b','c'), createArray('b','c','d')))]",
"equals": 2
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_union_arrays
policy_rule: |
{
"if": {
"value": "[length(union(createArray('a','b'), createArray('b','c')))]",
"equals": 3
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_take_array
policy_rule: |
{
"if": {
"value": "[length(take(createArray('a','b','c','d'), 2))]",
"equals": 2
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_take_string
policy_rule: |
{
"if": {
"value": "[take('Hello World', 5)]",
"equals": "Hello"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_skip_array
policy_rule: |
{
"if": {
"value": "[length(skip(createArray('a','b','c','d'), 2))]",
"equals": 2
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_skip_string
policy_rule: |
{
"if": {
"value": "[skip('Hello World', 6)]",
"equals": "World"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_range
policy_rule: |
{
"if": {
"value": "[length(range(0, 5))]",
"equals": 5
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_array_wrap
policy_rule: |
{
"if": {
"value": "[length(array('hello'))]",
"equals": 1
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_coalesce_first_non_null
policy_rule: |
{
"if": {
"value": "[coalesce('first', 'second')]",
"equals": "first"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_createObject
policy_rule: |
{
"if": {
"value": "[string(createObject('key', 'value'))]",
"contains": "key"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
# =========================================================================
# Numeric functions
# =========================================================================
- note: fn_sub
policy_rule: |
{
"if": {
"value": "[sub(10, 3)]",
"equals": 7
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_mul
policy_rule: |
{
"if": {
"value": "[mul(3, 4)]",
"equals": 12
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_div
policy_rule: |
{
"if": {
"value": "[div(10, 3)]",
"equals": 3
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_mod
policy_rule: |
{
"if": {
"value": "[mod(10, 3)]",
"equals": 1
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_min_args
policy_rule: |
{
"if": {
"value": "[min(5, 3, 8, 1)]",
"equals": 1
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_max_args
policy_rule: |
{
"if": {
"value": "[max(5, 3, 8, 1)]",
"equals": 8
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_min_array
policy_rule: |
{
"if": {
"value": "[min(createArray(5, 3, 8, 1))]",
"equals": 1
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_max_array
policy_rule: |
{
"if": {
"value": "[max(createArray(5, 3, 8, 1))]",
"equals": 8
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_float_from_int
policy_rule: |
{
"if": {
"value": "[float(42)]",
"equals": 42
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_float_from_string
policy_rule: |
{
"if": {
"value": "[float('3.14')]",
"equals": 3.14
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
# =========================================================================
# Composition tests — functions calling functions
# =========================================================================
- note: fn_composition_trim_tolower
policy_rule: |
{
"if": {
"value": "[toLower(trim(' Hello '))]",
"equals": "hello"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_composition_indexOf_with_param
policy_rule: |
{
"if": {
"value": "[indexOf(parameters('input'), parameters('search'))]",
"greaterOrEquals": 0
},
"then": { "effect": "deny" }
}
parameters:
input: "Microsoft.Compute/virtualMachines"
search: "Compute"
resource:
type: "any"
want_effect: "deny"
- note: fn_composition_base64_roundtrip
policy_rule: |
{
"if": {
"value": "[base64ToString(base64('round trip'))]",
"equals": "round trip"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_composition_uri_roundtrip
policy_rule: |
{
"if": {
"value": "[uriComponentToString(uriComponent('hello world&foo=bar'))]",
"equals": "hello world&foo=bar"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_composition_padleft_format
policy_rule: |
{
"if": {
"value": "[format('Days: {0}', padLeft('5', 3, '0'))]",
"equals": "Days: 005"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: fn_composition_arithmetic
policy_rule: |
{
"if": {
"value": "[add(mul(3, 4), sub(10, 5))]",
"equals": 17
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"

View File

@@ -0,0 +1,358 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Type Coercion Test Suite
# Tests string↔number coercion, null/undefined handling, and other
# implicit type behaviors covered by this test suite.
cases:
# =========================================================================
# String ↔ Number coercion
# =========================================================================
- note: coercion_string_number_equals
policy_rule: |
{
"if": {
"field": "properties.destinationPortRange",
"equals": 80
},
"then": { "effect": "deny" }
}
resource:
properties:
destinationPortRange: "80"
want_effect: "deny"
- note: coercion_number_string_equals
policy_rule: |
{
"if": {
"field": "properties.port",
"equals": "443"
},
"then": { "effect": "deny" }
}
resource:
properties:
port: 443
want_effect: "deny"
- note: coercion_string_number_greater
policy_rule: |
{
"if": {
"field": "properties.destinationPortRange",
"greater": 1024
},
"then": { "effect": "deny" }
}
resource:
properties:
destinationPortRange: "8080"
want_effect: "deny"
- note: coercion_string_number_less
policy_rule: |
{
"if": {
"field": "properties.port",
"less": 100
},
"then": { "effect": "deny" }
}
resource:
properties:
port: "80"
want_effect: "deny"
- note: coercion_in_with_mixed_types
policy_rule: |
{
"if": {
"field": "properties.destinationPortRange",
"in": [80, 443, 8080]
},
"then": { "effect": "deny" }
}
resource:
properties:
destinationPortRange: "443"
want_effect: "deny"
- note: coercion_non_numeric_string
policy_rule: |
{
"if": {
"field": "properties.port",
"equals": 80
},
"then": { "effect": "deny" }
}
resource:
properties:
port: "not-a-number"
want_undefined: true
# =========================================================================
# Null and undefined
# =========================================================================
- note: null_field_exists_false
policy_rule: |
{
"if": {
"field": "properties.optionalField",
"exists": false
},
"then": { "effect": "audit" }
}
resource:
properties: {}
want_effect: "audit"
- note: null_field_equals_null
policy_rule: |
{
"if": {
"field": "properties.nullableField",
"equals": null
},
"then": { "effect": "audit" }
}
resource:
properties:
nullableField: null
want_effect: "audit"
- note: empty_string_not_undefined
policy_rule: |
{
"if": {
"field": "properties.emptyField",
"exists": true
},
"then": { "effect": "audit" }
}
resource:
properties:
emptyField: ""
want_effect: "audit"
# =========================================================================
# Boolean semantics
# =========================================================================
- note: bool_string_coercion_matches
policy_rule: |
{
"if": {
"field": "properties.enabled",
"equals": true
},
"then": { "effect": "audit" }
}
resource:
properties:
enabled: "true"
want_effect: "audit"
- note: bool_equals_direct
policy_rule: |
{
"if": {
"field": "properties.httpsOnly",
"equals": false
},
"then": { "effect": "deny" }
}
resource:
properties:
httpsOnly: false
want_effect: "deny"
# =========================================================================
# Array values in conditions
# =========================================================================
- note: array_rhs_in_operator
policy_rule: |
{
"if": {
"field": "location",
"in": ["eastus", "westus", "centralus"]
},
"then": { "effect": "deny" }
}
resource:
location: "eastus"
want_effect: "deny"
- note: array_rhs_from_parameter
policy_rule: |
{
"if": {
"field": "location",
"in": "[parameters('allowedLocations')]"
},
"then": { "effect": "deny" }
}
parameters:
allowedLocations:
- "eastus"
- "westus"
resource:
location: "northeurope"
want_undefined: true
# =========================================================================
# Negative numbers in conditions
# =========================================================================
- note: negative_number_rhs
policy_rule: |
{
"if": {
"field": "properties.offset",
"equals": -10
},
"then": { "effect": "audit" }
}
resource:
properties:
offset: -10
want_effect: "audit"
- note: fractional_number_rhs
policy_rule: |
{
"if": {
"field": "properties.threshold",
"greater": 0.5
},
"then": { "effect": "audit" }
}
resource:
properties:
threshold: 0.75
want_effect: "audit"
# =========================================================================
# String ↔ Bool coercion
# =========================================================================
- note: coercion_string_true_equals_bool_true
policy_rule: |
{
"if": {
"field": "properties.enabled",
"equals": true
},
"then": { "effect": "deny" }
}
resource:
properties:
enabled: "true"
want_effect: "deny"
- note: coercion_string_false_equals_bool_false
policy_rule: |
{
"if": {
"field": "properties.enabled",
"equals": false
},
"then": { "effect": "deny" }
}
resource:
properties:
enabled: "false"
want_effect: "deny"
- note: coercion_bool_true_equals_string_true
policy_rule: |
{
"if": {
"field": "properties.enabled",
"equals": "True"
},
"then": { "effect": "deny" }
}
resource:
properties:
enabled: true
want_effect: "deny"
- note: coercion_bool_false_notEquals_string_true
policy_rule: |
{
"if": {
"field": "properties.enabled",
"notEquals": "true"
},
"then": { "effect": "deny" }
}
resource:
properties:
enabled: false
want_effect: "deny"
- note: coercion_string_TRUE_case_insensitive
policy_rule: |
{
"if": {
"field": "properties.flag",
"equals": true
},
"then": { "effect": "deny" }
}
resource:
properties:
flag: "TRUE"
want_effect: "deny"
- note: coercion_string_random_not_bool
policy_rule: |
{
"if": {
"field": "properties.flag",
"equals": true
},
"then": { "effect": "deny" }
}
resource:
properties:
flag: "yes"
want_undefined: true
# =========================================================================
# Unicode case-insensitivity
# =========================================================================
- note: unicode_case_equals
policy_rule: |
{
"if": {
"field": "properties.city",
"equals": "MÜNCHEN"
},
"then": { "effect": "deny" }
}
resource:
properties:
city: "münchen"
want_effect: "deny"
- note: unicode_case_contains
policy_rule: |
{
"if": {
"field": "properties.name",
"contains": "CAFÉ"
},
"then": { "effect": "deny" }
}
resource:
properties:
name: "my-café-app"
want_effect: "deny"

View File

@@ -0,0 +1,264 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Value Conditions Test Suite
# Tests the "value" LHS in conditions (as opposed to "field" or "count").
cases:
# =========================================================================
# Value with literal values
# =========================================================================
- note: value_string_literal
policy_rule: |
{
"if": {
"value": "hello",
"equals": "hello"
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: value_number_literal
policy_rule: |
{
"if": {
"value": 42,
"equals": 42
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: value_boolean_literal
policy_rule: |
{
"if": {
"value": true,
"equals": true
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: value_null_literal
policy_rule: |
{
"if": {
"value": null,
"equals": null
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
# =========================================================================
# Value with expressions
# =========================================================================
- note: value_parameters_expression
policy_rule: |
{
"if": {
"value": "[parameters('environment')]",
"equals": "production"
},
"then": { "effect": "deny" }
}
parameters:
environment: "production"
resource:
type: "any"
want_effect: "deny"
- note: value_concat_expression
policy_rule: |
{
"if": {
"value": "[concat(parameters('prefix'), '-resource')]",
"contains": "prod"
},
"then": { "effect": "audit" }
}
parameters:
prefix: "prod"
resource:
type: "any"
want_effect: "audit"
- note: value_field_expression
policy_rule: |
{
"if": {
"value": "[field('name')]",
"contains": "prod"
},
"then": { "effect": "audit" }
}
resource:
name: "my-prod-vm"
want_effect: "audit"
- note: value_length_expression
policy_rule: |
{
"if": {
"value": "[length(field('name'))]",
"greater": 5
},
"then": { "effect": "audit" }
}
resource:
name: "my-long-resource-name"
want_effect: "audit"
# =========================================================================
# Value with array RHS
# =========================================================================
- note: value_in_array
policy_rule: |
{
"if": {
"value": "[parameters('location')]",
"in": ["eastus", "westus", "centralus"]
},
"then": { "effect": "deny" }
}
parameters:
location: "eastus"
resource:
type: "any"
want_effect: "deny"
- note: value_not_in_array
policy_rule: |
{
"if": {
"value": "[parameters('location')]",
"notIn": ["eastus", "westus"]
},
"then": { "effect": "deny" }
}
parameters:
location: "northeurope"
resource:
type: "any"
want_effect: "deny"
# =========================================================================
# Value in allOf / anyOf
# =========================================================================
- note: value_in_allOf
policy_rule: |
{
"if": {
"allOf": [
{ "value": "[parameters('env')]", "equals": "production" },
{ "value": "[parameters('region')]", "in": ["eastus", "westus"] }
]
},
"then": { "effect": "deny" }
}
parameters:
env: "production"
region: "eastus"
resource:
type: "any"
want_effect: "deny"
- note: value_in_anyOf
policy_rule: |
{
"if": {
"anyOf": [
{ "value": "[parameters('tier')]", "equals": "free" },
{ "value": "[parameters('tier')]", "equals": "basic" }
]
},
"then": { "effect": "deny" }
}
parameters:
tier: "free"
resource:
type: "any"
want_effect: "deny"
# =========================================================================
# Value mixed with field conditions
# =========================================================================
- note: value_mixed_with_field
policy_rule: |
{
"if": {
"allOf": [
{ "field": "type", "equals": "Microsoft.Compute/virtualMachines" },
{ "value": "[parameters('enforcePolicy')]", "equals": true },
{ "field": "location", "notIn": "[parameters('allowedLocations')]" }
]
},
"then": { "effect": "deny" }
}
parameters:
enforcePolicy: true
allowedLocations:
- "eastus"
- "westus"
resource:
type: "Microsoft.Compute/virtualMachines"
location: "northeurope"
want_effect: "deny"
# =========================================================================
# Value with negative numbers
# =========================================================================
- note: value_negative_number
policy_rule: |
{
"if": {
"value": -1,
"less": 0
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: value_zero
policy_rule: |
{
"if": {
"value": 0,
"equals": 0
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"
- note: value_float
policy_rule: |
{
"if": {
"value": 3.14,
"greater": 3
},
"then": { "effect": "audit" }
}
resource:
type: "any"
want_effect: "audit"

File diff suppressed because it is too large Load Diff