mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
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:
committed by
GitHub
parent
afdb894d85
commit
7f42115b63
1131
tests/azure_policy/cases/aliases.yaml
Normal file
1131
tests/azure_policy/cases/aliases.yaml
Normal file
File diff suppressed because it is too large
Load Diff
1214
tests/azure_policy/cases/azure_policies.yaml
Normal file
1214
tests/azure_policy/cases/azure_policies.yaml
Normal file
File diff suppressed because it is too large
Load Diff
1155
tests/azure_policy/cases/casing.yaml
Normal file
1155
tests/azure_policy/cases/casing.yaml
Normal file
File diff suppressed because it is too large
Load Diff
482
tests/azure_policy/cases/complex_policies.yaml
Normal file
482
tests/azure_policy/cases/complex_policies.yaml
Normal 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"
|
||||
617
tests/azure_policy/cases/count.yaml
Normal file
617
tests/azure_policy/cases/count.yaml
Normal 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"
|
||||
684
tests/azure_policy/cases/deep_nesting.yaml
Normal file
684
tests/azure_policy/cases/deep_nesting.yaml
Normal 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"
|
||||
539
tests/azure_policy/cases/effect_details.yaml
Normal file
539
tests/azure_policy/cases/effect_details.yaml
Normal 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
|
||||
428
tests/azure_policy/cases/effects.yaml
Normal file
428
tests/azure_policy/cases/effects.yaml
Normal 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"
|
||||
463
tests/azure_policy/cases/exists.yaml
Normal file
463
tests/azure_policy/cases/exists.yaml
Normal 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
|
||||
541
tests/azure_policy/cases/expressions.yaml
Normal file
541
tests/azure_policy/cases/expressions.yaml
Normal 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"
|
||||
253
tests/azure_policy/cases/field_wildcard_collect.yaml
Normal file
253
tests/azure_policy/cases/field_wildcard_collect.yaml
Normal 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"
|
||||
323
tests/azure_policy/cases/fields.yaml
Normal file
323
tests/azure_policy/cases/fields.yaml
Normal 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
|
||||
555
tests/azure_policy/cases/implicit_allof.yaml
Normal file
555
tests/azure_policy/cases/implicit_allof.yaml
Normal 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
|
||||
344
tests/azure_policy/cases/logical_combinators.yaml
Normal file
344
tests/azure_policy/cases/logical_combinators.yaml
Normal 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"
|
||||
221
tests/azure_policy/cases/modifiable_check.yaml
Normal file
221
tests/azure_policy/cases/modifiable_check.yaml
Normal 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"
|
||||
453
tests/azure_policy/cases/operators.yaml
Normal file
453
tests/azure_policy/cases/operators.yaml
Normal 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"
|
||||
269
tests/azure_policy/cases/parse_errors.yaml
Normal file
269
tests/azure_policy/cases/parse_errors.yaml
Normal 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"
|
||||
399
tests/azure_policy/cases/policy_definition.yaml
Normal file
399
tests/azure_policy/cases/policy_definition.yaml
Normal 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"
|
||||
548
tests/azure_policy/cases/template_functions.yaml
Normal file
548
tests/azure_policy/cases/template_functions.yaml
Normal 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"
|
||||
364
tests/azure_policy/cases/template_functions_datetime_ip.yaml
Normal file
364
tests/azure_policy/cases/template_functions_datetime_ip.yaml
Normal 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"
|
||||
561
tests/azure_policy/cases/template_functions_extra.yaml
Normal file
561
tests/azure_policy/cases/template_functions_extra.yaml
Normal 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"
|
||||
358
tests/azure_policy/cases/type_coercion.yaml
Normal file
358
tests/azure_policy/cases/type_coercion.yaml
Normal 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"
|
||||
264
tests/azure_policy/cases/value_conditions.yaml
Normal file
264
tests/azure_policy/cases/value_conditions.yaml
Normal 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"
|
||||
2129
tests/azure_policy/cases/versioned_normalization.yaml
Normal file
2129
tests/azure_policy/cases/versioned_normalization.yaml
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user