Files
regorus/tests/azure_policy/cases/parse_errors.yaml
Anand Krishnamoorthi 4c92fb4d92 feat(azure_policy): test runner, compiler fixes, and example program (#700)
Adds the YAML test runner that exercises the companion test data PRs, plus
several compiler fixes surfaced during testing:

- Removed parameter register caching that produced wrong results inside
  short-circuiting allOf/anyOf blocks; added literal-index caching for
  parameter defaults to avoid repeated O(n) literal-table scans
- Simplified cross-resource effect details to only emit roleDefinitionIds
  and type (deployment templates are not evaluated for compliance)
- Replaced guid/uniqueString builtins with clear "unsupported" errors
- Normalized datetime output to ISO 8601 with Z suffix
- Added azure_policy parser MAX_COL constant (8192) for long template
  expressions, keeping the global DEFAULT_MAX_COL at 1024
- Added rvm to azure_policy feature dependencies since the compiler
  targets RVM bytecode

Also restructures the example binary into examples/regorus/ with new
azure-policy-eval and azure-policy-aliases subcommands, adds C# alias
normalization tests, and documents Azure Policy support in the README.

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-30 13:02:37 -05:00

301 lines
7.4 KiB
YAML

# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Parse Error and Edge Case Test Suite
# Tests mostly malformed policy JSON and invalid constructs to ensure they are
# properly rejected, but also includes valid edge cases that verify parser
# behavior at boundary conditions.
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"
# =========================================================================
# Compile errors: unsupported deployment-template functions
# =========================================================================
- note: guid_compile_error
policy_rule: |
{
"if": {
"value": "[guid('baseString')]",
"equals": "anything"
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_compile_error: true
- note: uniquestring_compile_error
policy_rule: |
{
"if": {
"value": "[uniqueString('baseString')]",
"equals": "anything"
},
"then": { "effect": "deny" }
}
resource:
type: "any"
want_compile_error: true