# 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"
