diff --git a/.azuredevops/pipelines/README.md b/.azuredevops/pipelines/README.md
index 9a8ebd5..4ad9229 100644
--- a/.azuredevops/pipelines/README.md
+++ b/.azuredevops/pipelines/README.md
@@ -1,2 +1,3 @@
# Introduction
-This folder contains the build and deploy pipelines in YAML format.
\ No newline at end of file
+
+This folder contains the build and deploy pipelines in YAML format.
diff --git a/.azuredevops/pipelines/validation/azure-pipelines-pr-validation.yml b/.azuredevops/pipelines/validation/azure-pipelines-pr-validation.yml
index a157df8..e384f90 100644
--- a/.azuredevops/pipelines/validation/azure-pipelines-pr-validation.yml
+++ b/.azuredevops/pipelines/validation/azure-pipelines-pr-validation.yml
@@ -24,7 +24,8 @@ stages:
-e VALIDATE_BIOME_FORMAT=false \
-e IGNORE_GITIGNORED_FILES=true \
-e GITHUB_ACTIONS_ZIZMOR_CONFIG_FILE=.zizmor.yml \
+ -e MARKDOWN_CONFIG_FILE=.markdownlint.json \
-v $(System.DefaultWorkingDirectory):/tmp/lint \
- ghcr.io/super-linter/super-linter:v8.5.0
+ ghcr.io/super-linter/super-linter:v8.6.0
displayName: 'GitHub Super-Linter Code Scan'
diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
index 17c77c3..95a4a7d 100644
--- a/.github/copilot-instructions.md
+++ b/.github/copilot-instructions.md
@@ -1 +1 @@
-- @azure Rule - Use Azure Best Practices: When generating code for Azure, running terminal commands for Azure, or performing operations related to Azure, invoke your `get_azure_best_practices` tool if available.
\ No newline at end of file
+- @azure Rule - Use Azure Best Practices: When generating code for Azure, running terminal commands for Azure, or performing operations related to Azure, invoke your `get_azure_best_practices` tool if available.
diff --git a/.github/workflows/pr-code-scan.yml b/.github/workflows/pr-code-scan.yml
index 2030b7c..bc0b9a3 100644
--- a/.github/workflows/pr-code-scan.yml
+++ b/.github/workflows/pr-code-scan.yml
@@ -46,3 +46,4 @@ jobs:
VALIDATE_ARM: false
IGNORE_GITIGNORED_FILES: true
GITHUB_ACTIONS_ZIZMOR_CONFIG_FILE: .zizmor.yml
+ MARKDOWN_CONFIG_FILE: ../../.markdownlint.json
diff --git a/.markdownlint.json b/.markdownlint.json
index a0511af..06c17e0 100644
--- a/.markdownlint.json
+++ b/.markdownlint.json
@@ -39,9 +39,7 @@
},
"no-multiple-space-blockquote": true,
"no-blanks-blockquote": true,
- "ol-prefix": {
- "style": "one_or_ordered"
- },
+ "ol-prefix": false,
"list-marker-space": true,
"blanks-around-fences": true,
"blanks-around-lists": true,
@@ -49,7 +47,7 @@
"hr-style": {
"style": "---"
},
- "no-emphasis-as-header": true,
+ "no-emphasis-as-heading": false,
"no-space-in-emphasis": true,
"no-space-in-code": true,
"no-space-in-links": true,
diff --git a/README.md b/README.md
index e795af2..06a5e55 100644
--- a/README.md
+++ b/README.md
@@ -25,6 +25,7 @@ This repository contains the complete set of IaC solutions for deploying Azure P
- Deploying Azure Policy Definitions, Initiatives, Assignments, and Exemptions
- PR Validation Code Scan using GitHub Super-Linter
- PR Validation for Azure Policy Assignment configurations between production and development environments
+ - Policy Integration Tests to test assigned policies on real resources in Azure and validate the expected results
The solution automates the entire lifecycle of Azure Policy resources — from code commit through testing and validation to production deployment — ensuring quality and correctness at every stage.
@@ -39,7 +40,22 @@ The Azure Policy IaC solution in this repository includes the following key feat
- Comprehensive set of tests and validation at different stages of the CI/CD pipelines to ensure the quality and correctness of the Azure Policy resources being deployed.
- Follows industry best practices for Azure Policy management, safe deployment, code scan, and PR validation to ensure that the Azure Policy resources are deployed in a secure and compliant manner.
- Unit tests for every policy resource being deployed.
-- Policy Integration Test (coming soon) to validate the functionality and effectiveness of the deployed Azure Policy resources in enforcing the desired governance and compliance requirements.
+- Policy Integration Test to validate the functionality and effectiveness of the deployed Azure Policy resources in enforcing the desired governance and compliance requirements.
+
+### Tests for Azure Policy
+
+The key to successfully implementing Azure Policy is to have confidence that your policies are correctly defined and will work as expected in your environment. The `AzPolicyFactory` solution is strongly focused in testing every step along the deployment process.
+
+The following Tests are included in the `AzPolicyFactory` solution:
+
+- **Policy Definitions and Initiatives Syntax Tests:** Static tests for syntax and best practices validation of policy definitions.
+- **Bicep Template PSRule Tests:** Validate Bicep templates for policy definitions using [PSRule for Azure](https://azure.github.io/PSRule.Rules.Azure/).
+- **Bicep Template Test Deployments:** Validate policy definition Bicep templates against Azure deployment engine to ensure they can be successfully deployed.
+- **Policy Assignments and Exemptions Syntax Tests:** Static tests for syntax validation of the configuration files for policy assignments and exemptions.
+- **Policy Assignments Environment Consistency Tests:** Validate that the policy assignments defined for production and development environments are consistent with each other to ensure the policies being tested in the development environment are the same as those being deployed to production.
+- **Policy Integration Tests:** Deploy real resources in Azure that are expected to either comply or violate the assigned policies, then validate the policy states and policy violation results to ensure the policies are working as expected in the Azure environment.
+
+For more details on the tests included in this solution, please refer to the [Tests for Azure Policy](./policy-testing.md) documentation.
## Recommended Architectural Approach for Azure Policy IaC
diff --git a/docs/FAQ.md b/docs/FAQ.md
index 9352426..ee33999 100644
--- a/docs/FAQ.md
+++ b/docs/FAQ.md
@@ -22,6 +22,16 @@
- [Do I need to update the Bicep templates when I add new policy resources to the repository?](#do-i-need-to-update-the-bicep-templates-when-i-add-new-policy-resources-to-the-repository)
- [Azure Configurations](#azure-configurations)
- [What is the purpose of dedicated development management group hierarchy in the recommended architecture for Azure Policy IaC implementation?](#what-is-the-purpose-of-dedicated-development-management-group-hierarchy-in-the-recommended-architecture-for-azure-policy-iac-implementation)
+ - [Testing](#testing)
+ - [What is the purpose of Policy Assignment Environment Consistency tests and why are they important?](#what-is-the-purpose-of-policy-assignment-environment-consistency-tests-and-why-are-they-important)
+ - [My Policy Integration Tests failed, how do I troubleshoot the failures?](#my-policy-integration-tests-failed-how-do-i-troubleshoot-the-failures)
+ - [What Terraform for Azure providers can I use for the Policy Integration Tests?](#what-terraform-for-azure-providers-can-i-use-for-the-policy-integration-tests)
+ - [Why do I need to encrypt the Terraform state file in the Policy Integration Test pipeline / workflow?](#why-do-i-need-to-encrypt-the-terraform-state-file-in-the-policy-integration-test-pipeline--workflow)
+ - [In Policy Integration Test pipeline / workflow, do I need to configure a remote backend for Terraform state management?](#in-policy-integration-test-pipeline--workflow-do-i-need-to-configure-a-remote-backend-for-terraform-state-management)
+ - [A Policy Integration Test case that uses Terraform failed with an error indicating resource already exists](#a-policy-integration-test-case-that-uses-terraform-failed-with-an-error-indicating-resource-already-exists)
+ - [How does the Policy Integration Test pipeline determine which subscriptions to trigger policy compliance scan for and how long does it have to wait after the resource deployments](#how-does-the-policy-integration-test-pipeline-determine-which-subscriptions-to-trigger-policy-compliance-scan-for-and-how-long-does-it-have-to-wait-after-the-resource-deployments)
+ - [How do I define the wait time for each policy effect type in the Policy Integration Test pipeline / workflow?](#how-do-i-define-the-wait-time-for-each-policy-effect-type-in-the-policy-integration-test-pipeline--workflow)
+ - [In the Policy Integration Test pipeline / workflow, what happens if the required policy assignments are missing or not evaluated](#in-the-policy-integration-test-pipeline--workflow-what-happens-if-the-required-policy-assignments-are-missing-or-not-evaluated)
## Pipeline Configurations
@@ -34,13 +44,13 @@ You can exclude specific Pester tests by excluding the test tags associated with
For the 3 sets of tests included from the `AzPolicyTest` module, use the following commands to get the list of available tags for each test:
-1. Firstly, install the `AzPolicyTest` module from the PowerShell Gallery if you haven't already:
+Firstly, install the `AzPolicyTest` module from the PowerShell Gallery if you haven't already:
```powershell
Install-Module -Name AzPolicyTest -Scope CurrentUser
```
-2. To get the list of tags for each test, you can run the following command:
+Then, to get the list of tags for each test, you can run the following command:
```powershell
#Policy Definition tests
@@ -83,7 +93,7 @@ The pipeline / workflow parameters for excluded tags for each test type are as f
At the moment, the following Pester tests used in this project do not support excluding tags:
- Bicep Support File tests
-- PSRule tests (configured using the PSRule configuration file [ps-rule.yaml](../ps-rule.yaml))
+- PSRule tests (configured using the PSRule configuration file [ps-rule.yml](../.ps-rule/ps-rule.yml))
- Policy Assignment Environment Consistency tests
@@ -277,3 +287,164 @@ The policy development management group hierarchy should mirror the production m
However, we do not need to recreate all the production subscriptions in the policy development management group hierarchy. This will be explained in detail in the Policy Integration Test documentation which is coming soon.
+
+## Testing
+
+### What is the purpose of Policy Assignment Environment Consistency tests and why are they important?
+
+
+Click to expand
+
+When deploying Policy definitions and initiatives, the same artifacts are deployed to both development and production management group hierarchies. Unlike policy definitions and initiatives, the policy assignments have different configurations for each environment.
+
+There is no way to test the exact same policy assignment configuration in the development environment before deploying to production because the resources referenced in the policy assignment for the development environment are different from those in production and some assignments may have different settings between environments.
+
+The Policy Assignment Environment Consistency tests PR validation pipeline was the result of an actual failed policy deployment in production environments in a customer's environment due to the inconsistency between the policy assignment configurations for development and production environments.
+
+The tests are designed to validate the consistency of the policy assignment configurations between development and production environments to prevent such issues from happening again in the future.
+
+Refer to the [Policy Assignment Environment Consistency Tests documentation](./assignment-environment-consistency-tests.md) for more details.
+
+
+
+### My Policy Integration Tests failed, how do I troubleshoot the failures?
+
+
+Click to expand
+
+Troubleshooting the policy integration test pipeline failure can be hard because by default the pipeline will remove the deployed resources at the end of the test run, which makes it hard to investigate the failed resources in Azure.
+
+To make it easier to troubleshoot the failures, we have added few parameters in the Pipeline / workflow to allow you to keep the deployed resources in Azure after the test run for investigation and have verbose output in the pipeline logs to provide more context on the test execution and failure.
+
+You can manually execute the Policy Integration Test pipeline / workflow with the following parameters:
+
+Azure DevOps Pipeline Parameters:
+
+
+
+
+
+GitHub Action Workflow Inputs:
+
+
+
+- **Remove Test Resources:** Untick this parameter to keep the deployed resources in Azure after the test run for investigation. By default, this parameter is set to `true` which means the deployed resources will be removed at the end of the test run.
+- **Tests To Run (separate with commas ','):** Specify the test cases you want to run. By default, all test cases will be executed. You can specify the test cases by their test names defined in the local configuration file for each test case (e.g. `storage-account`, `key-vault`).
+- **Enable system diagnostics (ADO) / Enable debug logging (GitHub Actions):** Enable this option to have more verbose output in the pipeline logs for troubleshooting. By default, this option is set to `false` which means the pipeline logs will not be verbose.
+
+>:memo: Remember to clean up the deployed resources manually in Azure after you have finished the investigation if you choose to keep the resources for troubleshooting.
+
+
+
+### What Terraform for Azure providers can I use for the Policy Integration Tests?
+
+
+Click to expand
+
+Currently there are 2 Terraform providers for Azure:
+
+- [AzureRM Provider](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs) - The most widely used Terraform provider for Azure, which supports a wide range of Azure resources and is maintained by HashiCorp in collaboration with Microsoft.
+- [AzAPI Provider](https://registry.terraform.io/providers/Azure/azapi/latest/docs) - A newer Terraform provider for Azure, which provides support for Azure resources that are not yet supported in the AzureRM provider by directly calling the Azure REST APIs.
+
+Natively in Azure Resource Manager deployment API, the [`what-if` API](https://learn.microsoft.com/rest/api/resources/deployments/what-if?view=rest-resources-2025-04-01&tabs=HTTP) can be used to validate a deployment against assigned policies with `deny` effect. However, since `terraform plan` command does not use the ARM deployment APIs, it does not have the capability for Azure Policy evaluation.
+
+We are leveraging the [Policy Restriction API](https://learn.microsoft.com/rest/api/policyinsights/policy-restrictions?view=rest-policyinsights-2024-10-01) to evaluate the resource configuration for Terraform. This API supports both `deny` and `audit` effect policies.
+
+To use the Policy Restriction API, we have to pass the resource configuration payload EXACTLY as what the resource provider defines it (like Bicep templates). The resource configuration payload in AzureRM is obscured and does not align with the definitions from each Azure Resource Provider. It is not possible to reconstruct the resource configuration payload in AzureRM to match the format required by the Policy Restriction API.
+
+On the other hand, the AzAPI provider uses the **EXACT** same payload as the resource provider, hence we can use the `terraform plan` output from AzAPI provider to call the Policy Restriction API for policy evaluation.
+
+In summary, if you evaluating `Append`, `Modify`, `Audit` or `AuditIfNotExists` effects by evaluating the deployed resource configuration or the policy compliance state of these resources in Azure, you can use either AzureRM or AzAPI provider for the Policy Integration Tests. However, if you want to evaluate `Deny` or `Audit` effect policies by validating the resource configuration without deploying the resources, you **MUST** use the AzAPI provider for the Policy Integration Tests.
+
+**TL,DR**:
+
+- In the `main-test-terraform` project, you can use either AzureRM or AzAPI providers
+- In the `main-bad-terraform` and `main-good-terraform` projects, you **MUST** only use the AzAPI provider
+
+
+
+### Why do I need to encrypt the Terraform state file in the Policy Integration Test pipeline / workflow?
+
+
+Click to expand
+
+If you are using the cloud version of Azure DevOps or GitHub Actions, the logs and artifacts generated in the pipeline / workflow runs are stored in a centralized storage which is encrypted at rest.
+
+However, since the storage used by the platform are typically owned and operated by the platform provider (Microsoft and GitHub in this case), to add an extra layer of security for the Terraform state files, we have implemented an additional encryption mechanism in the pipeline / workflow using AES encryption.
+
+By adding the extra layer of encryption, we can ensure that even if someone gains unauthorized access to the storage where the pipeline / workflow logs and artifacts are stored, they will not be able to access the sensitive information in the Terraform state files without the AES encryption key and initialization vector (IV) which are stored securely in the pipeline / workflow variables as secrets.
+
+Although this is not a mandatory requirement, it is recommended because Terraform state file may contain sensitive information if the Terraform code is not aligned with best practices.
+
+
+
+### In Policy Integration Test pipeline / workflow, do I need to configure a remote backend for Terraform state management?
+
+
+Click to expand
+
+No. The terraform deployments are short-lived and will be destroyed at the end of each test run. The lifecycle of the terraform state files are limited to the duration of the test run.
+
+To make the terraform state file available across multiple stages / jobs in the pipeline / workflow, we have configured the pipeline to upload the state file as a pipeline artifact after the terraform deployment stage / job, and download the state file artifact in the subsequent stages / jobs that need to access the state file.
+
+
+
+### A Policy Integration Test case that uses Terraform failed with an error indicating resource already exists
+
+
+Click to expand
+
+A resource deployment step may fail with the error similar to the following:
+
+
+
+This error typically occurs when the test resources were deployed by Terraform in a previous run and were not destroyed at the end of the test run due to a failure in the destroy step or because the "Remove Test Resources" parameter was set to false for troubleshooting purposes.
+
+To resolve this issue, you must manually delete all the resources defined in the Terraform project and re-run the failed pipeline / workflow.
+
+
+
+### How does the Policy Integration Test pipeline determine which subscriptions to trigger policy compliance scan for and how long does it have to wait after the resource deployments
+
+
+Click to expand
+
+The `Get Test Configuration` job in the Policy Integration Test pipeline / workflow runs a PowerShell script to scan each in scope test cases and identify the following:
+
+- Which test configurations from the `AzResourceTest` module are used by each test case
+- Which subscriptions are targeted for each test case based on the test configuration
+
+It also retrieves the required wait time for each policy effect type from the [Policy Integration Test global configuration file](./policy-integration-tests-global-config.md).
+
+From here, it determines which subscriptions will need to trigger the policy compliance scan (based on the use of the `New-ARTPolicyStateTestConfig` command), and what is the maximum wait time for the pipeline based on the configuration from the global configuration file.
+
+The Pipeline then uses the output of this job to trigger (or skip triggering) the policy compliance scan for each required subscription in the subsequent job after the resource deployment, and to determine how long it should wait before checking the policy compliance state for the test resources.
+
+
+### How do I define the wait time for each policy effect type in the Policy Integration Test pipeline / workflow?
+
+
+Click to expand
+
+The following properties in the [Policy Integration Test global configuration file](./policy-integration-tests-global-config.md) are used to define the wait time for each policy effect type:
+
+- Policy Compliance state validation (for all effect types)
+ - `waitTimeForPolicyComplianceStateAfterDeployment`: Set to 15. This is the time required for the policy compliance scan to finish. Based on our experience, 15 minutes is typically sufficient in this case.
+- Append and Modify effect policies
+ - `waitTimeForAppendModifyPoliciesAfterDeployment`: Set to 1. As long as the policy assignment has completed the initial evaluation, there is no need to wait. We have configured the pipeline to wait for 1 minute for this use case just to be safe.
+- Resource Existence validation for policies with `DeployIfNotExists` effect
+ - `waitTimeForDeployIfNotExistsPoliciesAfterDeployment`: Set to 5. This is the time required for `DeployIfNotExists` policy deployments to trigger and complete, including Azure Resource Graph indexing if querying resource existence via ARG. Increase this value if you experience failures due to long-running deployments or missing `evaluationDelay` in the policy definition.
+
+
+
+### In the Policy Integration Test pipeline / workflow, what happens if the required policy assignments are missing or not evaluated
+
+
+Click to expand
+
+In the [local configuration file](./policy-integration-tests-local-config.md) of each test case, the `policyAssignmentIds` property defines the required policy assignments for the test case.
+
+If any of the required policy assignments are missing, the test case will fail.
+
+If any of the required policy assignments are not evaluated yet (after initial deployment or after a change is made to the policy assignment), the Policy Integration Test pipeline / workflow will wait for up to 20 minutes for the policy assignments to complete the initial evaluation cycle.
+
diff --git a/docs/README.md b/docs/README.md
index bd8ef06..5cb36ab 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -15,8 +15,11 @@ The following DevOps / CICD platforms are supported:
| Policy Initiatives | [Documentation](ado-pipelines/policy-initiatives.md) | [Documentation](github-action/policy-initiatives.md) | Deploys Azure Policy initiatives (policy sets) to the target Azure environment |
| Policy Assignments | [Documentation](ado-pipelines/policy-assignments.md) | [Documentation](github-action/policy-assignments.md) | Deploys Azure Policy assignments based on environment-specific configuration files |
| Policy Exemptions | [Documentation](ado-pipelines/policy-exemptions.md) | [Documentation](github-action/policy-exemptions.md) | Deploys Azure Policy exemptions based on environment-specific configuration files |
-| PR Validation Code Scan | [Documentation](ado-pipelines/pr-validation.md) | [Documentation](github-action/pr-code-scan.md) | Runs GitHub Super-Linter to validate code quality and syntax in pull requests |
-| PR Validation for Policy Assignment Consistency | [Documentation](ado-pipelines/pr-policy-assignment-env-consistency.md) | [Documentation](github-action/pr-policy-assignment-env-consistency.md) | Validates that policy assignment configurations in development and production environments are consistent and do not contain unintended differences |
+
+## Test and Validation Pipelines and Workflows
+
+- PR Validation Code Scan: Runs GitHub Super-Linter to validate code quality and syntax in pull requests
+- PR Validation for Policy Assignment Consistency:Validates that policy assignment configurations in development and production environments are consistent and do not contain unintended differences |
## Instructions
@@ -24,7 +27,11 @@ The following DevOps / CICD platforms are supported:
- [Setup Guide for GitHub Actions Workflows](github-action/setup-guide.md)
- [Add Policy Resources to the Repository](add-policy-resources.md)
- [Policy Assignment Environment Consistency Tests](assignment-environment-consistency-tests.md)
-- [How to generate documentations for Bicep templates and modules](generate-bicep-docs.md)
+- [How to generate documentation for Bicep templates and modules](generate-bicep-docs.md)
+- [Policy Integration Tests](policy-integration-tests.md)
+ - [Get Started Guide for Policy Integration Tests](policy-integration-tests-get-started.md)
+ - [Global Configuration for Policy Integration Tests](policy-integration-tests-global-config.md)
+ - [Local Configuration for Policy Integration Tests](policy-integration-tests-local-config.md)
## FAQs
@@ -65,6 +72,7 @@ The repository is organized into the following folders:
| [`bicep/`](../tests/bicep/) | Pester tests for validating Bicep templates, modules, and bicepconfig settings |
| [`policyAssignment/`](../tests/policyAssignment/) | Tests for policy assignment configuration syntax validation and cross-environment consistency checks |
| [`policyExemption/`](../tests/policyExemption/) | Tests for policy exemption configuration syntax validation |
+| [`policy-integration-tests/`](../tests/policy-integration-tests/) | Policy integration tests |
## Pipeline and Workflow Overview
@@ -78,6 +86,8 @@ The repository includes the following CI/CD pipelines and GitHub Actions workflo
| Policy Exemptions | [Link](../.azuredevops/pipelines/policies/azure-pipelines-policy-exemptions.yml) | [Link](../.github/workflows/alz-policy-exemptions.yml) | Deploys Azure Policy exemptions based on environment-specific configuration files |
| PR Validation Code Scan | [Link](../.azuredevops/pipelines/validation/azure-pipelines-pr-validation.yml) | [Link](../.github/workflows/pr-code-scan.yml) | Runs GitHub Super-Linter to validate code quality and syntax in pull requests |
| PR Validation for Policy Assignment Consistency | [Link](../.azuredevops/pipelines/validation/azure-pipelines-pr-policy-assignment-env-consistency-tests.yml) | [Link](../.github/workflows/pr-policy-assignment-env-consistency.yml) | Validates that policy assignment configurations in development and production environments are consistent and do not contain unintended differences |
+| Policy Integration Tests | [Link](../.azuredevops/pipelines/validation/azure-pipelines-pr-policy-int-tests.yml) | [Link](../.github/workflows/policy-integration-tests.yml) | Tests assigned policies in Dev management group using real resources in Azure and validate the expected results |
+
## Configurations
@@ -86,6 +96,7 @@ The repository includes the following configuration files:
| Name | Description |
| :--- | :---------- |
| [settings.yml](../settings.yml) | Centralized configuration file for pipeline variables and configurations |
+| [policy_integration_test_config.jsonc](../tests/policy-integration-tests/.shared/policy_integration_test_config.jsonc) | Configuration file for policy integration tests |
| [ps-rule.yml](../.ps-rule/ps-rule.yml) | PSRule configuration file |
| [bicepconfig.json](../bicepconfig.json) | Bicep configuration file |
| [markdownlint.json](../.github/linters/markdownlint.json) | Markdownlint configuration file |
@@ -104,3 +115,58 @@ This repository includes a comprehensive set of Azure Policy resources that can
| Policy Initiatives | [policyInitiatives/](../policyInitiatives/) | Azure Policy initiative (policy set) definition files |
| Policy Assignments | [policyAssignments/](../policyAssignments/) | Azure Policy assignment configuration files (JSON), organized by environment |
| Policy Exemptions | [policyExemptions/](../policyExemptions/) | Azure Policy exemption configuration files (JSON), organized by environment |
+
+## Order of Deployment
+
+The policy resources are recommended to be developed, deployed and tested in the development management group prior to production deployment. The diagram below illustrates the recommended approach for developing and deploying Azure Policy resources in the development management group:
+
+```mermaid
+flowchart TD
+ start[Start] -->
+ createGitBranch[Create a Git feature branch] -->
+ policyCode[Create or Update code for Policy Definitions, Initiatives, Assignments and Exemptions] -->
+ policyAssignmentEnvConsistCode[Create or Update Policy Assignment environment consistency configuration file] -->
+ policyIntTestCode[Create or Update Policy Integration Tests]-->
+ deployPolicyDefDev[Run Policy Definition Pipeline / Workflow from Feature Branch] -->
+ deployPolicyInitiativeDev[Run Policy Initiative Pipeline / Workflow from Feature Branch]-->
+ deployPolicyAssignmentDev[Run Policy Assignment Pipeline / Workflow from Feature Branch]-->
+ deployPolicyExemptionDev[Run Policy Exemption Pipeline / Workflow from Feature Branch]-->
+ manualRunIntTest[Manually run Policy Integration Tests if required]
+ style start fill:#28F906,stroke:#333,stroke-width:4px
+```
+
+Once the policy resources are developed and fully tested in the development management group, then follow the recommended approach as shown below to promote the code to the default branch for production deployment:
+
+```mermaid
+flowchart TD
+ pr[Raise PR]-->prCodeScan[PR Validation - Code Scan]
+ pr[Raise PR]-->policyIntTest[PR Validation - Policy Integration Tests]
+ pr[Raise PR]-->assignmentEnvConsistency[PR Validation - Policy Assignment Environment Consistency Tests]
+ prCodeScan-->prreview[PR Review]
+ policyIntTest-->prreview[PR Review]
+ assignmentEnvConsistency-->prreview[PR Review]
+ prreview-->prmerge[PR Merge]-->Complete
+ style pr fill:#28F906,stroke:#333,stroke-width:4px
+```
+
+Once the code is merged to the default branch, the pipelines and workflows for production deployment are daisy-chained. To start the deployment, manually trigger the `Policy Definitions` pipeline / workflow, which will then trigger the `Policy Initiatives`, `Policy Assignments`, and `Policy Exemptions` pipelines / workflows in sequence (as shown below).
+
+```mermaid
+flowchart TD
+ trigger[Manually trigger Policy Definitions pipeline / workflow] -->
+ deployPolicyDef[Deploy Policy Definitions] -->
+ defSuccess{Success?} -->|Yes|deployPolicyInitiative[Automatically Deploy Policy Initiatives]
+ defSuccess-->|No|EndWithError[End with Error]
+ deployPolicyInitiative -->
+ intSuccess{Success?}-->|Yes|deployPolicyAssignment[Automatically Deploy Policy Assignments]
+ intSuccess-->|No|EndWithError
+ deployPolicyAssignment -->
+ assignSuccess{Success?}-->|Yes|deployPolicyExemption[Automatically Deploy Policy Exemptions]
+ assignSuccess-->|No|EndWithError
+ deployPolicyExemption-->
+ exemptSuccess{Success?}-->|Yes|EndSuccessfully[Completed Successfully]
+ exemptSuccess-->|No|EndWithError
+ style trigger fill:#28F906,stroke:#333,stroke-width:4px
+ style EndSuccessfully fill:#28F906,stroke:#333,stroke-width:4px
+ style EndWithError fill:#FF0000,stroke:#333,stroke-width:4px
+```
diff --git a/docs/add-policy-resources.md b/docs/add-policy-resources.md
index ebf98e6..99e7eff 100644
--- a/docs/add-policy-resources.md
+++ b/docs/add-policy-resources.md
@@ -110,7 +110,7 @@ If the assignment is targeting a subscription, replace the `managementGroupId` p
If the assignment is targeting a resource group, remove the `managementGroupId` property and add `subscriptionId` and `resourceGroupName` properties and provide the target resource group name.
-> :memo: NOTE: the Policy Assignment ADO pipeline and GitHub actions workflow will automatically populate the `nonComplianeceMessages` property based on assigned policies during the build stage / job. You do not need to provide any value for this property when creating the policy assignment configuration file.
+> :memo: NOTE: the Policy Assignment ADO pipeline and GitHub actions workflow will automatically populate the `nonComplianceMessages` property based on assigned policies during the build stage / job. You do not need to provide any value for this property when creating the policy assignment configuration file.
## Step 4: Add Policy Exemptions to the repository
@@ -124,6 +124,7 @@ The configuration files must be aligned with the JSON schema file [policyExempti
Example:
```json
+{
"$schema": "../policyExemption.schema.json",
"policyExemption": {
"name": "pex-lz-corp-sub-eh-001",
@@ -157,6 +158,7 @@ Example:
]
},
"subscriptionId": "0f1b7d98-c832-4d46-8a29-a0c63d54a2fa"
+}
```
In the above example, the policy exemption is scoped to the subscription `0f1b7d98-c832-4d46-8a29-a0c63d54a2fa`.
@@ -172,7 +174,7 @@ This script has included the following tests based on the metadata property valu
- Requester and Approver should be different people (`requestedBy` and `approvedBy` properties should have different value)
- Exemption approved date should be a validate date in the past (`approvedOn` property value should be a valid date and should be less than the current date)
-These tests are excluded by the Policy Exmemption ADO pipeline and GitHub actions workflow by default. You can enable them by removing the `ExcludeTag` filter in the Pester test task in the Test stages / jobs in the ADO pipeline and GitHub actions workflow.
+These tests are excluded by the Policy Exemption ADO pipeline and GitHub actions workflow by default. You can enable them by removing the `ExcludeTag` filter in the Pester test task in the Test stages / jobs in the ADO pipeline and GitHub actions workflow.
> :memo: NOTE: The Policy Exemption ADO pipeline and GitHub actions workflow evaluates the expiry date of each exemption based on the value from `expiresOn` property during the build stage / job. If the exemption is expired, the pipeline / workflow will automatically exclude the expired exemption from the deployment. However, this does not automatically remove the expired exemption from Azure.
diff --git a/docs/ado-pipelines/setup-guide.md b/docs/ado-pipelines/setup-guide.md
index 52e6db9..6b51ad2 100644
--- a/docs/ado-pipelines/setup-guide.md
+++ b/docs/ado-pipelines/setup-guide.md
@@ -2,7 +2,7 @@
This document provides a step-by-step guide to set up the Azure DevOps (ADO) pipelines for deploying Azure Policy resources using the AzPolicyFactory solution.
-Before you begin, make sure you have the necessary pre-requisites in place as outlined in the [Pre-requisites](pre-requisites.md) document.
+Before you begin, make sure you have the necessary pre-requisites in place as outlined in the [Pre-requisites](../pre-requisites.md) document.
## Step 1: Create Service Connections in your Azure DevOps Project
@@ -32,7 +32,7 @@ Update the following variable values in the [settings.yml](../../settings.yml) f
## Step 3: Add Policy Resources to the repository
-Follow the instructions in the [Add Policy Resources](add-policy-resources.md) document to add the following resources to the repository:
+Follow the instructions in the [Add Policy Resources](../add-policy-resources.md) document to add the following resources to the repository:
- Custom Azure Policy definitions in the `./policyDefinitions` folder
- Custom Azure Policy initiatives in the `./policyInitiatives` folder
@@ -45,10 +45,10 @@ Create the following pipelines in your Azure DevOps project using the YAML files
| Pipeline Name | Description | YAML File |
| :------------ | :---------- | :-------- |
-| Policy-Definitions | deploys custom Azure Policy definitions | [`azure-pipelines-policy-definitions.yml`](.azuredevops/pipelines/policies/azure-pipelines-policy-definitions.yml) |
-| Policy-Initiatives | deploys custom Azure Policy initiatives | [`azure-pipelines-policy-initiatives.yml`](.azuredevops/pipelines/policies/azure-pipelines-policy-initiatives.yml) |
-| Policy-Assignments | deploys Azure Policy assignments | [`azure-pipelines-policy-assignments.yml`](.azuredevops/pipelines/policies/azure-pipelines-policy-assignments.yml) |
-| Policy-Exemptions | deploys Azure Policy exemptions | [`azure-pipelines-policy-exemptions.yml`](.azuredevops/pipelines/policies/azure-pipelines-policy-exemptions.yml) |
+| Policy-Definitions | deploys custom Azure Policy definitions | [`azure-pipelines-policy-definitions.yml`](../../.azuredevops/pipelines/policies/azure-pipelines-policy-definitions.yml) |
+| Policy-Initiatives | deploys custom Azure Policy initiatives | [`azure-pipelines-policy-initiatives.yml`](../../.azuredevops/pipelines/policies/azure-pipelines-policy-initiatives.yml) |
+| Policy-Assignments | deploys Azure Policy assignments | [`azure-pipelines-policy-assignments.yml`](../../.azuredevops/pipelines/policies/azure-pipelines-policy-assignments.yml) |
+| Policy-Exemptions | deploys Azure Policy exemptions | [`azure-pipelines-policy-exemptions.yml`](../../.azuredevops/pipelines/policies/azure-pipelines-policy-exemptions.yml) |
>:exclamation: IMPORTANT: You **MUST** create the ADO pipelines with the **EXACT** name as shown in the table above. The pipeline YAML files reference each other and rely on the pipeline names to trigger the correct downstream pipelines. If you choose to use different pipeline names, you will need to update the downstream pipeline YAML files to reference the new pipeline names.
@@ -71,7 +71,7 @@ This pipeline validates and compares the values in each production policy assign
| Pipeline Name | Description | YAML File |
| :------------ | :---------- | :-------- |
-| Validate-Policy-Assignment-Environment-Consistency | validates and compares policy assignment configuration files between environments | [`azure-pipelines-pr-policy-assignment-env-consistency-tests.yml`](.azuredevops/pipelines/validation/azure-pipelines-pr-policy-assignment-env-consistency-tests.yml) |
+| Validate-Policy-Assignment-Environment-Consistency | validates and compares policy assignment configuration files between environments | [`azure-pipelines-pr-policy-assignment-env-consistency-tests.yml`](../../.azuredevops/pipelines/validation/azure-pipelines-pr-policy-assignment-env-consistency-tests.yml) |
This is to ensure any value deviations between the two environments are intentional and reviewed before being merged into the main branch.
@@ -81,7 +81,7 @@ The pipeline will fail if any differences are detected between the production an
This pipeline should be triggered automatically when a pull request is created that includes changes to any of the policy assignment configuration files or the related pipeline YAML files.
-- `Build pipeline`: [`azure-pipelines-pr-policy-assignment-env-consistency-tests.yml`](.azuredevops/pipelines/validation/azure-pipelines-pr-policy-assignment-env-consistency-tests.yml)
+- `Build pipeline`: [`azure-pipelines-pr-policy-assignment-env-consistency-tests.yml`](../../.azuredevops/pipelines/validation/azure-pipelines-pr-policy-assignment-env-consistency-tests.yml)
- Path filter: `/policyAssignments/*; /.azuredevops/pipelines/validation/azure-pipelines-pr-policy-assignment-config-tests.yml; /.azuredevops/templates/template-stage-policy-assignment-config-tests.yml; /tests/policy/assignment/environment-consistency/*`
- trigger: `Automatic`
- Policy requirement: `Required`
@@ -94,11 +94,11 @@ This pipeline performs a code scan using GitHub Super-Linter to validate all the
| Pipeline Name | Description | YAML File |
| :------------ | :---------- | :-------- |
-| PR-Code-Scan | performs a code scan using GitHub Super-Linter to validate all the files in the repository | [`azure-pipelines-pr-validation.yml`](.azuredevops/pipelines/validation/azure-pipelines-pr-validation.yml) |
+| PR-Code-Scan | performs a code scan using GitHub Super-Linter to validate all the files in the repository | [`azure-pipelines-pr-validation.yml`](../../.azuredevops/pipelines/validation/azure-pipelines-pr-validation.yml) |
Once the pipeline is created, configure the branch protection policy for the `main` branch to include this pipeline as a required check before merging.
-- `Build pipeline`: [`azure-pipelines-pr-validation.yml`](.azuredevops/pipelines/validation/azure-pipelines-pr-validation.yml)
+- `Build pipeline`: [`azure-pipelines-pr-validation.yml`](../../.azuredevops/pipelines/validation/azure-pipelines-pr-validation.yml)
- Path filter: leave it blank
- trigger: `Automatic`
- Policy requirement: `Required`
diff --git a/docs/github-action/policy-assignments.md b/docs/github-action/policy-assignments.md
index db0054e..adcd771 100644
--- a/docs/github-action/policy-assignments.md
+++ b/docs/github-action/policy-assignments.md
@@ -4,7 +4,7 @@
The [Policy Assignments GitHub Actions Workflow](../../.github/workflows/policy-assignments.yml) deploys all required policy assignments to the target Azure environments.
-
+
The workflow consists of the following jobs:
diff --git a/docs/github-action/policy-exemptions.md b/docs/github-action/policy-exemptions.md
index 6cffca6..3a88e2d 100644
--- a/docs/github-action/policy-exemptions.md
+++ b/docs/github-action/policy-exemptions.md
@@ -4,7 +4,7 @@
The [Policy Exemptions GitHub Actions Workflow](../../.github/workflows/policy-exemptions.yml) deploys all required policy exemptions to the target Azure environments.
-
+
The workflow consists of the following jobs:
diff --git a/docs/github-action/policy-initiatives.md b/docs/github-action/policy-initiatives.md
index d834128..e4b96ea 100644
--- a/docs/github-action/policy-initiatives.md
+++ b/docs/github-action/policy-initiatives.md
@@ -18,9 +18,9 @@ The workflow consists of the following jobs:
- Deploy Prod
1. After the `Initiation` job, the `Policy Tests` job performs a number of predefined Pester tests for each policy initiative file that are to be deployed.
-2. The `Build Dev` and `Build Prod` jobs are kicked off concurrently upon the successful completion of the `Policy Tests` job. These jobs are responsible for building the policy definition Bicep template for the development and production environments respectively.
+2. The `Build Dev` and `Build Prod` jobs are kicked off concurrently upon the successful completion of the `Policy Tests` job. These jobs are responsible for building the policy initiative Bicep template for the development and production environments respectively.
3. The `Test Dev` and `Test Prod` jobs are responsible for performing additional tests in their respective environments. They are kicked off after the `Build Dev` and `Build Prod` jobs respectively.
-4. The `Deploy Dev` job is kicked off upon successful completion of the `Test Dev` job. It is responsible for deploying the policy definitions to the development environment.
+4. The `Deploy Dev` job is kicked off upon successful completion of the `Test Dev` job. It is responsible for deploying the policy initiatives to the development environment.
5. The `Deploy Prod` job will only be kicked off when all the following conditions are met:
- The `Deploy Dev` job has completed successfully.
- The `Test Prod` job has completed successfully.
diff --git a/docs/github-action/setup-guide.md b/docs/github-action/setup-guide.md
index 44a5e51..ebc6f47 100644
--- a/docs/github-action/setup-guide.md
+++ b/docs/github-action/setup-guide.md
@@ -2,7 +2,7 @@
This document provides a step-by-step guide to set up the GitHub Actions workflows for deploying Azure Policy resources using the AzPolicyFactory solution.
-Before you begin, make sure you have the necessary pre-requisites in place as outlined in the [Pre-requisites](pre-requisites.md) document.
+Before you begin, make sure you have the necessary pre-requisites in place as outlined in the [Pre-requisites](../pre-requisites.md) document.
## Step 1: Create GitHub Secrets for Azure authentication
@@ -51,7 +51,7 @@ Update the following variable values in the [settings.yml](../../settings.yml) f
## Step 3: Add Policy Resources to the repository
-Follow the instructions in the [Add Policy Resources](add-policy-resources.md) document to add the following resources to the repository:
+Follow the instructions in the [Add Policy Resources](../add-policy-resources.md) document to add the following resources to the repository:
- Custom Azure Policy definitions in the `./policyDefinitions` folder
- Custom Azure Policy initiatives in the `./policyInitiatives` folder
diff --git a/docs/images/pol-int-test-ado-parameters-01.png b/docs/images/pol-int-test-ado-parameters-01.png
new file mode 100644
index 0000000..93ffa51
Binary files /dev/null and b/docs/images/pol-int-test-ado-parameters-01.png differ
diff --git a/docs/images/pol-int-test-ado-parameters-02.png b/docs/images/pol-int-test-ado-parameters-02.png
new file mode 100644
index 0000000..5940bf6
Binary files /dev/null and b/docs/images/pol-int-test-ado-parameters-02.png differ
diff --git a/docs/images/pol-int-test-ado-pipeline-run.png b/docs/images/pol-int-test-ado-pipeline-run.png
new file mode 100644
index 0000000..bd6f8a0
Binary files /dev/null and b/docs/images/pol-int-test-ado-pipeline-run.png differ
diff --git a/docs/images/pol-int-test-ado-stdout.png b/docs/images/pol-int-test-ado-stdout.png
new file mode 100644
index 0000000..d15ac7e
Binary files /dev/null and b/docs/images/pol-int-test-ado-stdout.png differ
diff --git a/docs/images/pol-int-test-gh-inputs.png b/docs/images/pol-int-test-gh-inputs.png
new file mode 100644
index 0000000..95c868b
Binary files /dev/null and b/docs/images/pol-int-test-gh-inputs.png differ
diff --git a/docs/images/pol-int-test-gh-pipeline-run.png b/docs/images/pol-int-test-gh-pipeline-run.png
new file mode 100644
index 0000000..68cfec0
Binary files /dev/null and b/docs/images/pol-int-test-gh-pipeline-run.png differ
diff --git a/docs/images/pol-int-test-gh-stdout.png b/docs/images/pol-int-test-gh-stdout.png
new file mode 100644
index 0000000..da88c3b
Binary files /dev/null and b/docs/images/pol-int-test-gh-stdout.png differ
diff --git a/docs/images/pol-int-test-tf-error-existing-resource.png b/docs/images/pol-int-test-tf-error-existing-resource.png
new file mode 100644
index 0000000..ba073e7
Binary files /dev/null and b/docs/images/pol-int-test-tf-error-existing-resource.png differ
diff --git a/tests/policy-integration-tests/README.md b/docs/policy-integration-tests-get-started.md
similarity index 81%
rename from tests/policy-integration-tests/README.md
rename to docs/policy-integration-tests-get-started.md
index 5ef9a8b..346779a 100644
--- a/tests/policy-integration-tests/README.md
+++ b/docs/policy-integration-tests-get-started.md
@@ -1,34 +1,20 @@
-# Azure Policy Integration Tests
+# Policy Integration Tests - Get Started Guide
## Overview
-This directory contains integration tests for Azure Policy assignments. Each subfolder (except `.shared` and `test-template`) represents a test case targeting specific policy definitions or initiatives.
+The [`tests/policy-integration-tests`](../tests/policy-integration-tests) directory contains integration tests for Azure Policy assignments. Each subfolder (except `.shared` and `.test-template`) represents a test case targeting specific policy definitions or initiatives.
-The `test-template` folder provides a starting point for creating new tests. Copy it, customise the configuration and templates, then define your test assertions.
+The `.test-template` folder provides a starting point for creating new tests. Copy it, customise the configuration and templates, then define your test assertions.
## Developing a New Test
### 1. Copy the test template
-Copy the `test-template` folder and rename it to reflect the policy or scenario being tested (e.g. `storage-account`, `key-vault`).
+Copy the `.test-template` folder and rename it to reflect the policy or scenario being tested (e.g. `storage-account`, `key-vault`).
### 2. Update the local configuration (`config.json`)
-Edit `config.json` in the new folder. The file supports the following properties:
-
-| Property | Required | Description |
-| :------- | :------: | :---------- |
-| `policyAssignmentIds` | Yes | Array of policy assignment resource IDs to evaluate during testing. These policy assignments are the pre-requisites for the test. Test will not start until they have been initially evaluated after creation. |
-| `testName` | Yes | A short name for the test case. Used in test titles and output filenames. |
-| `assignmentName` | No | The name of the primary policy assignment being tested. |
-| `testSubscription` | Yes | The name of the subscription (as defined in the global config `subscriptions` map) to deploy test resources into. |
-| `testResourceGroup` | No | The resource group name for testing. If specified, a `$script:testResourceGroupId` variable is calculated. |
-| `testManagementGroup` | No | The management group name that are used to form the policy assignment scope in the `tests.ps1` script. |
-| `location` | No | Azure region for resource deployments. |
-| `tagsForResourceGroup` | No | Boolean. Whether to apply tags to the test resource group. Defaults to `false`. |
-| `removeTestResourceGroup` | Yes | Boolean. Whether to remove the test resource group after the test run. Defaults to `true`. |
-
-You can also add custom properties (e.g. `diagSettingsAssignmentName`) and access them in `tests.ps1` as `$script:LocalConfig_`.
+Edit `config.json` in the new folder. Refer to [Policy Integration Tests - Local Configuration](./policy-integration-tests-local-config.md) for details on the required and optional configuration properties.
### 3. Define Bicep and/or Terraform templates
diff --git a/docs/policy-integration-tests-global-config.md b/docs/policy-integration-tests-global-config.md
new file mode 100644
index 0000000..14047e7
--- /dev/null
+++ b/docs/policy-integration-tests-global-config.md
@@ -0,0 +1,136 @@
+# Policy Integration Tests Global Configuration File
+
+This document describes the properties in the [`policy_integration_test_config.jsonc`](../tests/policy-integration-tests/.shared/policy_integration_test_config.jsonc) configuration file used by the policy integration test framework.
+
+## General Settings
+
+Before running the tests, make sure to review and update the following general settings in the configuration file to ensure that they are appropriate for your testing environment and requirements.
+
+| Property | Type | Description |
+| :------- | :--- | :---------- |
+| `tags` | object | Tags to be applied to all resources created by the tests. |
+| `namePrefix` | string | Prefix to be applied to the names of all resources created by the tests. This helps to easily identify and filter test resources in the Azure portal. |
+| `deploymentPrefix` | string | Prefix to be applied to the names of all deployments created by the tests. This helps to easily identify and filter test deployments in the Azure portal. |
+
+## Test Configurations
+
+Unless there are specific requirements for certain tests, the default values for these settings should work for most scenarios. However, you may need to adjust some of these settings based on the specific policies being tested, or should you wish to change the default filenames, or wait times for tests for different policy effects.
+
+### Bicep
+
+| Property | Type | Description |
+| :------- | :--- | :---------- |
+| `testBicepTemplateName` | string | Name of the Bicep template used for testing. This template should be located in the directory of each test case. If it is not found, the test will not deploy any Bicep templates during testing. |
+| `whatIfViolateBicepTemplateName` | string | Name of the Bicep template used for What-If deployments that are expected to violate the policy. This template should be located in the directory of each test case. |
+| `whatIfComplyBicepTemplateName` | string | Name of the Bicep template used for What-If deployments that are expected to comply with the policy. This template should be located in the directory of each test case. |
+
+### Terraform
+
+| Property | Type | Description |
+| :------- | :--- | :---------- |
+| `testTerraformDirectoryName` | string | Name of the directory containing the Terraform configuration used for testing. This directory should be located in the directory of each test case. If not found, the test will not deploy any Terraform configurations during testing. |
+| `terraformViolateDirectoryName` | string | Name of the Terraform directory used for validate against Policy Violation API that expected to violate deny or audit policies. |
+| `terraformComplyDirectoryName` | string | Name of the Terraform directory used for validate against Policy Violation API that expected to comply with the policy. |
+| `testTerraformBackendConfigFileName` | string | Name of the Terraform file that contains the backend configuration. This file should be located in the `testTerraformDirectoryName` directory. |
+| `testTerraformStateFileName` | string | Terraform state filename. |
+| `testTerraformEncryptedStateFileName` | string | Encrypted Terraform state filename. |
+
+### Test Execution Settings
+
+| Property | Type | Description |
+| :------- | :--- | :---------- |
+| `testLocalConfigFileName` | string | Name of the local configuration file used for testing. This file will be created in the same directory as the test scripts during testing and will contain the configuration for the tests. |
+| `testScriptName` | string | Name of the test script used for testing. This script should be located in the directory of each test case. |
+| `testOutputFilePrefix` | string | Prefix to be applied to the names of the output files generated by the tests. This helps to easily identify and filter test output files in the Azure portal and in the test results. |
+| `testOutputFormat` | string | Pester test output format. |
+| `testBicepDeploymentOutputArtifactPrefix` | string | Prefix for the Azure pipeline build artifact that contains the Bicep deployment result output files generated during the test runs. |
+| `testTerraformDeploymentOutputArtifactPrefix` | string | Prefix for the Azure pipeline build artifact that contains the Terraform deployment result output files generated during the test runs. |
+| `testDeploymentOutputFileName` | string | Name of the file that contains the Bicep or Terraform deployment result output generated during the test runs. |
+
+### Wait Times and Retries
+
+| Property | Type | Description |
+| :------- | :--- | :---------- |
+| `initialEvalMaximumWaitTime` | integer | Maximum wait time in minutes for the initial evaluation of the policy assignment to complete. This is needed to ensure that the tests do not proceed until the policy assignment is fully evaluated and any non-compliant resources are identified. |
+| `waitTimeForPolicyComplianceStateAfterDeployment` | integer | Minutes to wait after the resource deployment for testing audit policies before proceeding with the tests. This is needed to ensure that the compliance state of resources is updated before the tests check for compliance. |
+| `waitTimeForAppendModifyPoliciesAfterDeployment` | integer | Minutes to wait after the resource deployment for testing append and modify policies before proceeding with the tests. This is needed to ensure that the policies are fully deployed and in effect before the tests check for compliance. |
+| `waitTimeForDeployIfNotExistsPoliciesAfterDeployment` | integer | Minutes to wait after the resource deployment for testing deployIfNotExists policies before proceeding with the tests. This is needed to ensure that the policies are fully deployed and have had enough time to create any necessary resources before the tests check for compliance. |
+| `whatIfMaxRetry` | integer | Maximum number of retries for the What-If deployment operation in case of transient failures. This is needed to improve the reliability of the tests by allowing for retries in case of temporary issues with the deployment. |
+
+## Azure Settings
+
+You must review and update the following Azure-related settings in the configuration file to match your Azure environment.
+
+### Existing Azure Resources
+
+| Property | Type | Description |
+| :------- | :--- | :---------- |
+| `privateDNSSubscription` | string | Subscription where the private DNS zones are located. This is needed for testing policies that deploys DNS records for Private Endpoints. |
+| `privateDNSResourceGroup` | string | Resource group where the private DNS zones are located. This is needed for testing policies that deploys DNS records for Private Endpoints. |
+| `diagnosticSettingsIdSuffix` | string | Suffix for the resource ID of the diagnostic settings created by the policy. This is used for testing of the diagnostic settings DINE policies. |
+| `privateEndpointPrivateDNSZoneGroupIdSuffix` | string | Suffix for the resource ID of the private DNS zone group created by the policy for private endpoints. This is used for testing of the private endpoint DINE policies. |
+
+### Azure API Versions
+
+If your tests involve Azure ARM API calls to get Azure resources (i.e. the resource type is not supported by Azure Resource Graph), you may specify the API versions for different resource types in the configuration file, so you don't have to hardcode the API versions in your individual test scripts.
+
+This also allows you to standardize the API versions used across different test cases, and easily update the API versions in the future if needed by just updating the configuration file.
+
+| Property | Type | Description |
+| :------- | :--- | :---------- |
+| `diagnosticSettingsAPIVersion` | string | API version for diagnostic settings. |
+| `resourceGroupApiVersion` | string | API version for resource groups. |
+| `privateDNSZoneGroupAPIVersion` | string | API version for private DNS zone groups. |
+| `privateEndpointAPIVersion` | string | API version for private endpoints. |
+| `vnetFlowLogApiVersion` | string | API version for VNet flow logs. |
+| `appServicesAPIVersion` | string | API version for App Services. |
+
+### Subscriptions
+
+The `subscriptions` object contains details about each subscription used in the tests. This is needed to provide the necessary information for the tests to create and manage resources in the correct subscriptions and resource groups.
+
+Each subscription entry may contain the following mandatory properties:
+
+| Property | Type | Description |
+| :------- | :--- | :---------- |
+| `id` | string | The subscription ID. |
+
+You can also define additional properties for each subscription that are relevant to your testing scenarios. For example, if your tests involve creating resources in specific virtual networks and subnets, you may want to include properties for the resource group, virtual network, and subnets associated with each subscription. You can reference these properties in your test scripts when required. For example:
+
+| Property | Type | Description |
+| :------- | :--- | :---------- |
+| `networkResourceGroup` | string | The resource group containing network resources. |
+| `vNet` | string | The virtual network name. |
+| `peSubnet` | string | The subnet for private endpoints. |
+| `resourceSubnet` | string | The subnet for resources (e.g., VMs). |
+
+## Test Triggers
+
+The `testTriggers` configuration helps the pipeline to automatically determine what test cases need to be executed based on the files that have been changed in a pull request.
+
+### Repository Paths
+
+The pipeline will look at the files that have been changed in a pull request and check if any of the changed files are under these paths. If there are changes under these paths, the pipeline will trigger the corresponding tests that are related to the changed files. For example, if a policy definition file is changed under the `policyDefinitions` path, the pipeline will trigger the tests that are related to that policy definition.
+
+| Property | Type | Description |
+| :------- | :--- | :---------- |
+| `policyDefinitionsPath` | string | Path to the policy definitions in the repository. |
+| `policyInitiativesPath` | string | Path to the policy initiatives in the repository. |
+| `policyAssignmentsPath` | string | Path to the policy assignments in the repository. |
+| `policyIntegrationTestsPath` | string | Path to the policy integration tests in the repository. Each sub folder represents a test case. |
+
+### Policy Assignment Configuration JSON Paths
+
+| Property | Type | Description |
+| :------- | :--- | :---------- |
+| `policyAssignmentConfigurationJsonPathForAssignmentName` | string | For the configuration file for each policy assignment JSON file, the property that represents the name of the policy assignment. This is used by the test framework to identify the policy assignment during the test runs. |
+| `policyAssignmentConfigurationJsonPathForPolicyDefinitionId` | string | For the configuration file for each policy assignment JSON file, the property that represents the ID of the policy definition or initiative that is assigned. This is used by the test framework to look up the corresponding policy definition or initiative during the test runs. |
+
+### Global Test Paths
+
+The `globalTestPaths` array contains the list of files that if any of them are changed in a pull request, the pipeline will trigger all the policy integration test cases. This is useful for changes that may impact multiple test cases or the overall test framework, such as changes to the test scripts, helper functions, or the configuration file itself.
+
+### Ignored Files
+
+The `ignoredFiles` array contains file patterns that will be ignored and will not trigger any tests when changed.
+
diff --git a/docs/policy-integration-tests-local-config.md b/docs/policy-integration-tests-local-config.md
new file mode 100644
index 0000000..dc694f5
--- /dev/null
+++ b/docs/policy-integration-tests-local-config.md
@@ -0,0 +1,43 @@
+# Policy Integration Tests - Local Configuration
+
+## Overview
+
+The local configuration file is used to store variables that are specific to each test case. This file is created during the test execution based on the `testLocalConfigFileName` variable defined in the global configuration file.
+
+The Local Configuration file stores test-specific settings required for the tests to run. In addition to the mandatory configurations, users can also add additional variables to the local configuration file as needed for their specific test cases.
+
+The purpose of using a local configuration file is to allow users to define test-specific variables that are accessible in all the Azure Bicep / Terraform templates as well as the test scripts for that test case. This provides flexibility and allows users to customize the test execution based on their specific requirements.
+
+The global configuration file is loaded at the beginning of the test execution, and the variables defined in it are available for use in all test scripts.
+
+>:exclamation: **IMPORTANT**: All the variables are made available in the test scripts as script-based variables with the prefix `$Script:LocalConfig_`. For example, a variable named `testName` in the local configuration file can be accessed in the test scripts as `$script:LocalConfig_testName`.
+
+## Mandatory Variables
+
+The following mandatory variables are defined in the local configuration file:
+
+| Name | Expected Data Type | Description | Example |
+| :--- | :----------------- | :---------- | :------ |
+| `policyAssignmentIds` | Yes | Array of pre-requisites policy assignment resource IDs for the test. Test will not start until they have been initially evaluated after creation. | `["/providers/Microsoft.Management/managementGroups/CONTOSO-DEV/providers/Microsoft.Authorization/policyAssignments/pa-d-pedns", "/providers/Microsoft.Management/managementGroups/CONTOSO-DEV/providers/Microsoft.Authorization/policyAssignments/pa-d-diag-settings"]` |
+| `testName` | String | Name of the test case. This is used for to form the Pester test container | `storageAccount` |
+| `testSubscription` | String | Name of the subscription used for testing. This should be one of the subscriptions defined in the global configuration file. | `sub-d-lz-corp-01` |
+| `location` | String | Azure region where the test resources will be deployed. | `australiaeast` |
+
+>:exclamation: **IMPORTANT**: Please ensure all above listed mandatory variables are accurately defined for each test case.
+
+## Optional Variables
+
+The following optional variables are defined in the local configuration file to support the sample test cases provided in this repository. These variables may not be necessary for all test cases, and users can choose to include or exclude them as needed for their specific test cases.
+
+| Name | Expected Data Type | Description | Example |
+| :--- | :----------------- | :---------- | :------ |
+| `testManagementGroup` | String | Name of the management group where the policy assignment for testing is located. This is needed to construct the resource ID of the policy assignment for testing. | `CONTOSO-DEV` |
+| `assignmentName` | String | Name of the policy assignment for testing. This is needed to construct the resource ID of the policy assignment for testing. | `pa-d-storage` |
+| `testResourceGroup` | String | Name of the resource group to be created for testing. This resource group will be used to deploy resources during the tests. This may not be necessary for all test cases. | `rg-policy-integration-test` |
+| `tagsForResourceGroup` | Boolean | Indicates whether tags should be applied to the resource group created for testing. If set to true, the tags defined in the global configuration file will be applied to the resource group. | `true` |
+
+> :memo: **NOTE**: You may add or remove optional properties in each local configuration file as needed for your specific test cases.
+
+## Self-defined Variables
+
+In addition to the mandatory and optional variables listed above, you can also define your own variables in the local configuration file as needed for your specific test cases. These self-defined variables can be used to store any additional information or settings that are relevant to your test case.
diff --git a/docs/policy-integration-tests.md b/docs/policy-integration-tests.md
new file mode 100644
index 0000000..33077b7
--- /dev/null
+++ b/docs/policy-integration-tests.md
@@ -0,0 +1,318 @@
+# Policy Integration Tests
+
+## Introduction
+
+Policy Integration tests are implemented to test assigned policies that have the following effects:
+
+- Deny
+- Audit & AuditIfNotExists
+- Modify & Append
+- DeployIfNotExists
+
+>**NOTE**: Only Azure resources that are deployed to `subscription` or `resourceGroup` levels can be governed by Azure Policy. `Tenant` and `ManagementGroup` level resources cannot be governed by Azure Policy. Therefore, the Policy integration tests cannot cover these types of resources.
+
+## Potential Pipeline Workflow
+
+The policy integration tests can be embedded into CI/CD pipelines. The pipelines can be configured to run automatically when a new pull request is created on the repository that contains the Azure Policy Infrastructure as Code solutions. Below is a potential workflow of the pipeline:
+
+```mermaid
+flowchart TD
+ start[Start] -->
+ TriggerType{Trigger Type}
+ TriggerType --> |PR Trigger|DetectTestCasesFromGitDiff[Detect Test Cases from Git Diff]
+ DetectTestCasesFromGitDiff[Detect Test Cases from Git Diff] -->
+ GetTestConfig[Get Test Configurations]
+ TriggerType --> |Manual Trigger|GetTestConfig-->
+ GetTests[Get In-Scope Tests] -->
+ DeployTestResources[Deploy Test Resources for All Tests] -->
+ policyComplianceScan[Run Compliance Scan Asynchronously if Required] -->
+ WaitPolicyEval[Wait Policy Evaluation] --> ExecuteTests
+ ExecuteTests[Execute Tests] --> PublishTestResults[Publish Test Results]
+ PublishTestResults-->DeleteResources{Delete Deployed Resources?}
+ DeleteResources --> |Yes| ResourceDeletion[Resource Deletion]
+ ResourceDeletion --> End
+ DeleteResources --> |No| End
+ style start fill:#28F906,stroke:#333,stroke-width:4px
+ style End fill:#28F906,stroke:#333,stroke-width:4px
+```
+
+## `AzResourceTest` Module
+
+The [`AzResourceTest` PowerShell module](https://www.powershellgallery.com/packages/AzResourceTest) is a PowerShell module that can be used to perform Azure resource configuration tests using Pester and various native capabilities offered from Azure such as `Azure Resource Graph (ARG)`, `Azure Policy Insights` and `Azure Resource Manager (ARM) What-If APIs`.
+
+It covers the following testing scenarios:
+
+- Azure Resource configurations via Azure Resource Graph (ARG)
+- Azure Resource existence via Azure Resource Graph (ARG) or relevant Azure Resource Provider (RP)
+- Resource policy compliance via Azure Resource Graph (ARG)
+- `Deny` Policy violation via ARM What-If API
+- Terraform plan validation (AzAPI provider only) via Azure Policy Restriction API.
+
+### AzResourceTest Commands
+
+The following commands are provided in the `AzResourceTest` module:
+
+| Command Name | Description | Use Cases |
+| :----------- | :---------- | :-------- |
+| `Test-ARTResourceConfiguration` | Invoke Azure resource tests by passing defined test cases. | Use this command to execute the tests that are defined by the test configuration objects. |
+| `New-ARTPropertyValueTestConfig` | Create a new instance of the PropertyValueTestConfig object. This object is used to define a test that checks the value of a property of an existing resource. | `Append` and `Modify` policy effects that require checking the value of a specific property. |
+| `New-ARTPropertyCountTestConfig` | Create a new instance of the PropertyCountTestConfig object. This object is used to define a test that checks the count of a property value of an existing resource. | `Append` and `Modify` policy effects that require checking the count of items within an array or the existence of a property. |
+| `New-ARTPolicyStateTestConfig` | Create a new instance of the PolicyStateTestConfig object. This object is used to define a test that checks the compliance state of a policy for an existing resource. | `Audit` and `AuditIfNotExists` effects tested by querying Policy Compliance State of an existing resource via Azure Resource Graph. |
+| `New-ARTWhatIfDeploymentTestConfig` | Create a new instance of the WhatIfDeploymentTestConfig object. This object is used to define a test that checks the What-If template validation for a given Bicep or ARM template. | `Deny` effects tested via ARM What-If API by passing a Bicep or ARM template with policy-violating configurations to the ARM What-If API. |
+| `New-ARTResourceExistenceTestConfig` | Create a new instance of the ResourceExistenceTestConfig object. This object is used to define a test that checks the existence of a resource. | `DeployIfNotExists` effects are tested by querying the existence of the resource via Azure Resource Graph or Azure Resource Provider API. |
+| `New-ARTManualWhatIfTestConfig` | Create a new instance of the ManualWhatIfTestConfig object. This object is used to define a test that checks the What-If validation result that is obtained from an external Azure Resource Manager REST API response. | `Deny` effects tested via ARM What-If API by passing the What-If API response that is obtained externally. This is useful when testing resource updates that are not allowed using Bicep or ARM templates (i.e. Subscription tags update). |
+| `New-ARTTerraformPolicyRestrictionTestConfig` | Create a new instance of the TerraformPolicyRestrictionTestConfig object. This object is used to define a test that checks the resource configuration from Terraform plan result against the Azure Policy Restriction REST API for a given resource. | `Audit` and `Deny` effects using the Terraform plan result (AzAPI provider only) tested via Azure Policy Restriction API. |
+| `New-ARTArmPolicyRestrictionTestConfig` | Create a new instance of the ArmPolicyRestrictionTestConfig object. This object is used to define a test that checks the ARM resource configuration against the Azure Policy Restriction REST API for a given resource. | `Audit` and `Deny` effects using the ARM resource configuration tested via Azure Policy Restriction API. |
+| `Get-ARTResourceConfiguration` | Get the configuration of an existing Azure resource via Azure Resource Graph search. | This is a helper function that can be used to examine the configuration of an existing resource when developing test cases. |
+
+## Testing Different Policy Effects
+
+The `AzResourceTest` module provides a function called `Test-ARTResourceConfiguration` that can be used to execute one or more test cases defined for different policy effects. Each test case is defined as a configuration object that specifies the details of the test, such as the resource to be tested, the expected policy violation, and the method of testing.
+
+To prepare for the test cases, firstly create an array for the various test cases:
+
+```PowerShell
+#Add test configurations to $tests array
+$tests = @()
+```
+
+### `Deny` Effect Using Azure Bicep Templates
+
+`Deny` effects are tested via ARM What-If API.
+
+A Bicep template with the target deployment scope of either `subscription` or `resourceGroup` must be created and it should contain configurations that violate the testing policies.
+
+>**NOTE**: When testing the `Deny` policy violation for resources within a resource group, **DO NOT** create a Bicep template with the `subscription` deployment scope that also deploys the resource group. ARM What-If API will not identify the policy violation for a resource inside a resource group if the resource group does not exist. Instead, create a `resource group` scoped test template. The pipeline will automatically create the resource group in a pre-configured region with if it does not exist.
+
+To configure the test:
+
+```PowerShell
+$violatingPolicies = @(
+ @{
+ policyAssignmentId = $policyAssignmentId
+ policyDefinitionReferenceId = 'abc_111'
+ }
+ @{
+ policyAssignmentId = $policyAssignmentId
+ policyDefinitionReferenceId = 'abc_222'
+ }
+ @{
+ policyAssignmentId = $policyAssignmentId
+ policyDefinitionReferenceId = 'abc_333'
+ }
+)
+$params = @{
+ testName = 'Policy violating deployment should fail'
+ templateFilePath = $whatIfFailedTemplatePath
+ deploymentTargetResourceId = $whatIfDeploymentTargetResourceId
+ requiredWhatIfStatus = 'Failed'
+ policyViolation = $violatingPolicies
+ #Add Parameter file path if a parameter file is required
+ parameterFilePath = $parameterFilePath
+ #Specify the Bicep module subscription Id if private TS or BR Bicep modules are used
+ bicepModuleSubscriptionId = $bicepModuleSubscriptionId
+}
+$tests += New-ARTWhatIfDeploymentTestConfig @params
+```
+
+### `Audit` and `AuditIfNotExists` Effects from existing resources
+
+`Audit` and `AuditIfNotExists` effects are tested by querying Policy Compliance State via Azure Resource Graph.
+
+To configure the test:
+
+```PowerShell
+$params = @{
+ testName = 'Audit CMK Encryption policy should be NonCompliant'
+ resourceId = $resourceId
+ policyAssignmentId = $policyAssignmentId
+ requiredComplianceState = 'NonCompliant'
+ policyDefinitionReferenceId = 'abc_444'
+}
+$tests += New-ARTPolicyStateTestConfig @params
+```
+
+### `Append` and `Modify` Effects
+
+`Append` and `Modify` effects can be tested by checking the actual configuration of the resource. We can use Azure Resource Graph to check the value of a specific property of the resource, or compare the count of items within an array.
+
+To configure the test:
+
+```PowerShell
+#Test a single value
+$params = @{
+ testName = 'Minimum TLS version should be TLS1.2'
+ resourceId = $resourceId
+ valueType = 'string'
+ property = 'properties.minimumTlsVersion'
+ condition = 'equals'
+ value = 'TLS1_2'
+}
+$tests += New-ARTPropertyValueTestConfig @params
+
+#Test property count
+$params = @{
+ testName = 'Should have environment tag'
+ resourceId = $resourceId
+ property = 'tags.environment'
+ condition = 'equals'
+ count = 1
+}
+$tests += New-ARTPropertyCountTestConfig @params
+
+#Test array count
+$params = @{
+ testName = 'Should Use Private Endpoints'
+ resourceId = $resourceId
+ property = @('properties.privateEndpointConnections', 'properties.manualPrivateEndpointConnections')
+ condition = 'greaterequal'
+ count = 1
+ operator = 'concat' # indicate the combined count of all specified properties
+}
+$tests += New-ARTPropertyCountTestConfig @params
+```
+
+### `DeployIfNotExists` Effect
+
+`DeployIfNotExists` effects are tested by querying the existence of the resource via Azure Resource Graph or Azure Resource Provider API.
+
+>**NOTE**: Since not all resource types are supported by Azure Resource Graph, some resources may require querying the Azure Resource Provider API. Hence the `AzResourceTest` module also supports querying the Azure Resource Provider API as the backup method.
+
+To configure the test:
+
+```PowerShell
+# Test resource existence via Azure Resource Provider API by providing the API version
+$diagnosticSettingsAPIVersion = '2021-05-01-preview'
+$params = @{
+ testName = 'Diagnostic Settings Must Be Configured'
+ resourceId = $diagnosticSettingsId
+ condition = 'exists'
+ apiVersion = $diagnosticSettingsAPIVersion
+}
+
+$tests += New-ARTResourceExistenceTestConfig @params
+
+# Test resource existence via Azure Resource Graph
+$params = @{
+ testName = 'Private DNS Record for Blob PE must exist'
+ resourceId = $blobPrivateDNSARecordId
+ condition = 'exists'
+}
+$tests += New-ARTResourceExistenceTestConfig @params
+
+```
+
+### `Audit` and `Deny` Effects for Terraform Plan Validation via Azure Policy Restriction API
+
+`Audit` and `Deny` effects for Terraform plan validation (AzAPI provider only) are tested via Azure Policy Restriction API. The test will submit the Terraform plan to the Restriction API and check the response for any policy violations.
+
+To configure the test:
+
+```PowerShell
+#Must run az cli command to get the access token because Terraform only supports az cli authentication.
+$token = $(az account get-access-token --resource 'https://management.azure.com/' | convertfrom-json).accessToken
+#Specify the Terraform project directory
+$terraformDirectory = 'C:\Terraform\MyProject'
+#Define the expected policy violations
+#The Terraform project would deploy a resource with address 'azapi_resource.storage_account' that violates two policies: one with 'Deny' effect and another with 'Audit' effect.
+$violatingPolicies = @(
+ @{
+ policyAssignmentId = '/providers/Microsoft.Management/managementGroups/myMG/providers/Microsoft.Authorization/policyAssignments/myPolicyAssignment'
+ policyDefinitionReferenceId = 'STG-001'
+ resourceReference = 'azapi_resource.storage_account'
+ policyEffect = 'Deny'
+ }
+ @{
+ policyAssignmentId = '/providers/Microsoft.Management/managementGroups/myMG/providers/Microsoft.Authorization/policyAssignments/myPolicyAssignment'
+ policyDefinitionReferenceId = 'STG-002'
+ resourceReference = 'azapi_resource.storage_account'
+ policyEffect = 'Audit'
+ }
+)
+$tests += New-ARTTerraformPolicyRestrictionTestConfig 'Storage Account should violate deny policies' $token $terraformDirectory $violatingPolicies
+
+#Above command creates a new instance of the TerraformPolicyRestrictionTestConfig object by passing required parameters in the correct order "testName", "token", "terraformDirectory" and "policyViolation".
+```
+
+### Test Execution
+
+The tests are executed using the `Test-ARTResourceConfiguration` function. The function takes the test configuration object as input and executes the test.
+
+```PowerShell
+$params = @{
+ tests = $tests
+ testTitle = "Storage Account Configuration Test"
+ contextTitle = "Storage Configuration"
+ testSuiteName = 'StorageAccountTest'
+ OutputFile = $outputFilePath
+ OutputFormat = 'NUnitXml'
+
+}
+Test-ARTResourceConfiguration @params
+```
+
+## Test Output
+
+Due to the differences between Azure DevOps pipelines and GitHub Actions, the test output is handled differently in the two platforms.
+
+You can access the test outputs in the following locations:
+
+### Standard output in the pipeline / workflow runs
+
+**Azure DevOps**
+
+
+
+**GitHub Actions**
+
+
+
+### Pipeline run
+
+**Azure DevOps**
+
+
+
+**GitHub Actions**
+
+
+
+## Example Test Cases
+
+The following example test cases can be found here:
+
+| Test Case Name | Tested Azure Resources | Policy Effects | Comment |
+| :------------- | :--------------------- | :------------- | :------ |
+| [acr](../tests/policy-integration-tests/acr) | Azure Container Registry | `Modify`, `DeployIfNotExists` | Reference for testing ACR related policies using a set of Bicep templates. |
+| [event-hub](../tests/policy-integration-tests/event-hub) | Azure Event Hub | `Deny`, `Audit`, `AuditIfNotExists`, `DeployIfNotExists` | Reference for testing Event Hub related policies using a set of Bicep templates. |
+| [key-vault](../tests/policy-integration-tests/key-vault) | Azure Key Vault | `Deny`, `Audit`, `Modify`, `DeployIfNotExists` | Reference for testing Key Vault related policies using a set of Bicep templates. |
+| [monitor](../tests/policy-integration-tests/monitor) | Azure Monitor resources such as Log Analytics Workspace and Action Group, etc. | `Deny`, `Audit`, `DeployIfNotExists` | Reference for testing Azure Monitor related policies using a set of Bicep templates, as well as using Azure Policy Restriction API. |
+| [network-security-group](../tests/policy-integration-tests/network-security-group) | Azure Network Security Group | `Deny`, `DeployIfNotExists` | Reference for testing NSG related policies using a set of Bicep templates. |
+| [PostgreSQL](../tests/policy-integration-tests/postgresql) | Azure Database for PostgreSQL | `Deny` | Reference for testing PostgreSQL related policies using a set of Bicep templates. |
+| [private-endpoint](../tests/policy-integration-tests/private-endpoint) | Azure Private Endpoint | `Deny` | Reference for testing Private Endpoint related policies using Bicep template. |
+| [storage-account](../tests/policy-integration-tests/storage-account) | Azure Storage Account | `Deny`, `Audit`, `Modify`, `DeployIfNotExists` | Reference for testing Storage Account related policies using Terraform (using the Terraform `AzAPI` provider and Azure Policy Restriction API). |
+| [tags](../tests/policy-integration-tests/tags) | Subscription and Resource Group tags | `Deny`, `Modify` | Reference for testing subscription and resource group tagging policies using Bicep templates and manual What-If API response from resource update request (updating tags of an existing subscription). |
+| [virtual-network](../tests/policy-integration-tests/virtual-network) | Azure Virtual Network | `Deny`, `DeployIfNotExists` | Reference for testing Virtual Network related policies using a set of Bicep templates. |
+| [web](../tests/policy-integration-tests/web) | Azure App Service | `Deny`, `Audit`, `DeployIfNotExists` | Reference for testing App Service related policies using a set of Bicep templates including cross-subscription deployments. |
+
+## Get Started
+
+To get started with the policy integration tests:
+
+1. Refer to the [Policy Integration Tests - Get Started Guide](./policy-integration-tests-get-started.md) which provides a step-by-step guide on how to create your own test case using the provided test template.
+2. Refer to the [Policy Integration Tests - Global Configuration](./policy-integration-tests-global-config.md) document to understand the global configuration settings that are required for the tests and to ensure your test case is properly configured.
+3. Refer to the [Policy Integration Tests - Local Configuration](./policy-integration-tests-local-config.md) document to understand the configuration variables that are required for defining your test case.
+
+## Limitations
+
+The `AzResourceTest` module does not support testing policies with [resource provider modes](https://learn.microsoft.com/en-us/azure/governance/policy/concepts/definition-structure-basics#resource-provider-modes).
+
+## References
+
+The `AzResourceTest` module uses the following Azure APIs:
+
+- [Azure Resource Manager Deployment What-If](https://learn.microsoft.com/rest/api/resources/deployments/what-if?view=rest-resources-2025-04-01&tabs=HTTP)
+- [Azure Resource Graph](https://learn.microsoft.com/rest/api/azureresourcegraph/resourcegraph/resources/resources?view=rest-azureresourcegraph-resourcegraph-2024-04-01&tabs=HTTP)
+- [Azure Resource Manager Resource GET](https://learn.microsoft.com/rest/api/resources/resources/get?view=rest-resources-2021-04-01)
+- [Azure Policy Insights Policy State](https://learn.microsoft.com/rest/api/policyinsights/policy-states?view=rest-policyinsights-2024-10-01)
+- [Azure Policy Restriction](https://learn.microsoft.com/rest/api/policyinsights/policy-restrictions?view=rest-policyinsights-2024-10-01)
diff --git a/docs/policy-testing.md b/docs/policy-testing.md
new file mode 100644
index 0000000..0c96411
--- /dev/null
+++ b/docs/policy-testing.md
@@ -0,0 +1,43 @@
+# Tests for Azure Policy
+
+## Introduction
+
+To follow the shift-left testing approach advocated by this solution, we have implemented comprehensive tests for Azure Policy resources at different stages of the CI/CD pipelines. These tests are designed to ensure the quality and correctness of the Azure Policy resources being deployed, and to provide confidence that the policies will work as expected in the target Azure environment.
+
+## Tests
+
+The following tests are included in the `AzPolicyFactory` solution:
+
+### Policy Definitions and Initiatives Syntax Tests
+
+These tests are embedded in the `Policy Definition Test` stages in the Policy Definitions and Policy Initiatives Azure DevOps pipelines and GitHub Action workflows. They perform static validation of the syntax of the policy definitions and initiatives using the open-source PowerShell Module [`AzPolicyTest`](https://www.powershellgallery.com/packages/AzPolicyTest).
+
+These tests ensure the policy definitions and initiatives are correctly defined and follow the required schema and best practices before they are built into Bicep templates and deployed to Azure.
+
+### Policy Assignments and Exemptions Syntax Tests
+
+These tests are embedded in the Policy Assignments and Policy Exemptions Azure DevOps pipelines and GitHub Action workflows. They perform static validation of the syntax of the configuration files for policy assignments and exemptions using custom built Pester tests.
+
+### Bicep Template PSRule Tests
+
+After the bicep templates are built for each policy resource type, [PSRule for Azure](https://azure.github.io/PSRule.Rules.Azure/) is used to validate the Bicep templates ensuring they follow the best practices for Azure resources defined in PSRule.
+
+### Bicep Template Test Deployments
+
+After the Bicep templates are validated by PSRule, they are validated against the Azure deployment engine to ensure they can be successfully deployed.
+
+### Policy Assignments Environment Consistency Tests
+
+The Policy Assignments Environment Consistency Tests ADO pipeline and GitHub Action workflow validate that the policy assignments defined for production and development environments are consistent with each other to ensure the policies being tested in the development environment are the same as those being deployed to production. Any deviations between the assignments for the two environments must be explicitly defined in the configuration file.
+
+For example, if the effect for a policy definition is set to `Deny` in development, you cannot set it to `DeployIfNotExists` in production because these 2 effects are not interchangeable.
+
+Another Example, if you are referencing an Azure resource in the development environment, you must define the corresponding resource for production and reference it in the configuration file. if the reference of the resource in the production environment does not match what's defined in the configuration file, the test will fail.
+
+### Policy Integration Tests
+
+The Policy Integration Tests are designed to collectively validate each individual assigned policy in a real Azure environment where all the required policies are assigned and fully effective.
+
+The tests work by leveraging multiple Azure REST APIs to validate the resource configurations against desired state defined by the assigned policies. It supports the two most popular Infrastructure as Code languages used in Azure: Azure Bicep and Terraform.
+
+For more information on the Policy Integration Tests, please refer to the [Policy Integration Tests](./policy-integration-tests.md).
diff --git a/docs/pre-requisites.md b/docs/pre-requisites.md
index 751e8da..992f470 100644
--- a/docs/pre-requisites.md
+++ b/docs/pre-requisites.md
@@ -6,13 +6,13 @@ Before you can use the ADO pipelines and GitHub Actions workflows provided in Az
You need to have an Azure DevOps project or a GitHub repository where you want to set up the pipelines or workflows.
-Once the ADO project or GitHub repository is created, can add the files from this repository to your ADO or GitHub repository. You can either copy the files directly or use Git to clone this repository and push the files to your own repository.
+Once the ADO project or GitHub repository is created, you can add the files from this repository to your ADO or GitHub repository. You can either copy the files directly or use Git to clone this repository and push the files to your own repository.
To push the files to your own repository, you can follow these steps:
```bash
git remote add origin
-git checkout -b feature/initial-ssetup
+git checkout -b feature/initial-setup
git add .
git commit -m "Initial commit of pipeline/workflow files"
git push --set-upstream origin feature/initial-ssetup
@@ -33,4 +33,4 @@ New-AzRoleAssignment -ObjectId -Scope '/providers/Mic
```
-> :memo: Note: If you are using a same Microsoft Entra ID tenant for both development and production environments, make sure you have separate service principals for each environment. It is a security risk for using the same identity for production and non-production environments.
+> :memo: Note: If you are using the same Microsoft Entra ID tenant for both development and production environments, make sure you have separate service principals for each environment. It is a security risk for using the same identity for production and non-production environments.
diff --git a/scripts/pipelines/policy-integration-tests/pipeline-get-policy-assignment-compliance-state.ps1 b/scripts/pipelines/policy-integration-tests/pipeline-get-policy-assignment-compliance-state.ps1
index ace0c58..ee040b1 100644
--- a/scripts/pipelines/policy-integration-tests/pipeline-get-policy-assignment-compliance-state.ps1
+++ b/scripts/pipelines/policy-integration-tests/pipeline-get-policy-assignment-compliance-state.ps1
@@ -160,7 +160,7 @@ if ($wait -eq 'true') {
if ($($timeDifference.TotalMinutes -lt $waitMinutesForNewAssignments)) {
Write-Verbose " - Initial creation date: $($initialCreationDate)" -Verbose
Write-Verbose " - Current date (UTC): $utcNow" -Verbose
- Write-Verbose " - Waiting for 5 minutes from the initial creation date..." -Verbose
+ Write-Verbose " - Waiting for 1 minute from the initial creation date..." -Verbose
$shouldWait = $true
} else {
Write-Verbose " - Initial creation date: $($initialCreationDate)" -Verbose
diff --git a/scripts/support/psDocs/README.md b/scripts/support/psDocs/README.md
index 12e0887..7a8dc88 100644
--- a/scripts/support/psDocs/README.md
+++ b/scripts/support/psDocs/README.md
@@ -1,6 +1,6 @@
# PSDocs Related scripts
-* [**generateTemplateReadme.ps1**](./generateTemplateReadme.ps1) - Script to generate README.md for the bicep template
+- [**generateTemplateReadme.ps1**](./generateTemplateReadme.ps1) - Script to generate README.md for the bicep template
process.
## generateTemplateReadme.ps1
diff --git a/tests/policy-integration-tests/.shared/policy_integration_test_config.jsonc b/tests/policy-integration-tests/.shared/policy_integration_test_config.jsonc
index 24d1ea1..aff7750 100644
--- a/tests/policy-integration-tests/.shared/policy_integration_test_config.jsonc
+++ b/tests/policy-integration-tests/.shared/policy_integration_test_config.jsonc
@@ -127,6 +127,9 @@
//changes to the following files will be ignored and will not trigger any tests.
"ignoredFiles": [
"*.md",
+ "*.png",
+ "*.jpg",
+ "*.jpeg",
".gitignore",
"markdownlint.json",
"ps-rule.yaml",
diff --git a/tests/policy-integration-tests/.test-template/README.md b/tests/policy-integration-tests/.test-template/README.md
index 521a11e..6df173f 100644
--- a/tests/policy-integration-tests/.test-template/README.md
+++ b/tests/policy-integration-tests/.test-template/README.md
@@ -1,57 +1,18 @@
-# Test Template for Azure Policy Integration Tests
+# Policy Integration Test - Policy Integration Test Cases for xxx
## Introduction
-This folder contains a template for creating Azure Policy integration tests. You can copy the entire folder and use it as a starting point for your own tests.
+This folder contains a sample test case for xxx related policies.
-## Instructions
+The test case is designed to test the following policy assignments:
-### 1. Copy the `test-template` folder and rename it to something relevant to your test case
+| Policy Assignment Name | Policy Assignment Scope | Description |
+| :--------------------- | :--------------------- | :---------- |
-Make a copy of this folder and give it a name that reflects the specific policy or scenario you are testing. For example, if you are testing a policy related to storage accounts, you could name the folder `storage-account`.
-### 2. Update the local configuration file (`config.json`) with the specific settings for your test case
-Use the document [Policy Integration Tests - Local Configuration](../TEST-LOCAL-CONFIG.md) as a reference to understand the mandatory and optional variables that you need to define in the [`config.json`](config.json) file for your test case.
+The following policies are in scope for testing:
-### 3. Define the Bicep and/or Terraform templates for your test case
+| Policy Assignment | Policy Reference ID | Policy Name | Policy Effect |
+| :---------------- | :---------------- | :------------ | :------------ |
-- If you plan to use Bicep or Terraform templates to deploy test resources for `Audit`, `AuditIfNotExists`, `Append`, `Modify`, or `DeployIfNotExists` policies, make sure to create the necessary templates and place them in the test case folder.
-
- - For Bicep template: Finalize [`main.test.bicep`](main.test.bicep) for the resources to be deployed during testing.
- - For Terraform: Finalize the Terraform files in the [`main-test-terraform`](main-test-terraform) directory for the resources to be deployed during testing.
-
-- If you plan to use Bicep templates for testing `Deny` policies, define the [`main.bad.bicep`](main.bad.bicep) template for the resources that violate the policy, and optionally the [`main.good.bicep`](main.good.bicep) template for the resources that comply with the policy. Together, these define both positive and negative scenarios.
-- If you plan to use Terraform for testing `Deny` or `Audit` policies against the Policy restriction API, define the Terraform files in the [`main-bad-terraform`](main-bad-terraform) directory for the resources that violate the policy, and optionally the Terraform files in the [`main-good-terraform`](main-good-terraform) directory for the resources that comply with the policy. Together, these define both positive and negative scenarios.
-
-### 4. Update the test script (`tests.ps1`) with the specific test logic for your test case
-
-Update the [`tests.ps1`](tests.ps1) file with the specific test logic for your test case. Use the example tests as references.
-
-The `tests.ps1` script has prepopulated sections that are common for all test cases. You will need to populate the `#region defining tests` section with the specific tests for your test case. You can also add additional sections as needed for your test logic.
-
-Use the documents [Policy Integration Tests - Local Configuration](../TEST-LOCAL-CONFIG.md) and [Policy Integration Tests - Global Configuration](../TEST-GLOBAL-CONFIG.md) as references to understand how to access the configuration variables in your test script and to ensure that your test logic aligns with the configurations defined in both the local and global configuration files.
-
-### 4. Delete the `.testignore` file if it exists
-
-Make sure to delete the `.testignore` file in the test case folder if it exists. This file is used to exclude the test case from being executed in the test pipelines. Deleting this file ensures that your test case will be included in the test runs.
-
-## Executing the Tests
-
-### Prerequisites
-
-Prior to executing the tests, ensure that you have the following prerequisites in place:
-
-- The policy assignments that you intend to test are already created and properly configured in your Azure environment and already finished the initial policy evaluation. This is crucial to ensure that the tests can accurately validate the compliance state of the deployed resources against the policies.
-- Have the Azure PowerShell module installed on the computer where you will be running the tests.
-- If you are using Bicep templates in your tests, ensure that the standalone version of the Bicep CLI is installed and properly configured on your machine.
-- If you are using Terraform templates in your tests, ensure that Terraform is installed and properly configured on your machine.
-- If you are using Terraform templates, ensure Azure CLI is installed and properly configured on your machine, as it is required for authentication when running Terraform commands that interact with Azure.
-- The identity running the tests has sufficient permissions to deploy resources in the target subscription and resource group.
-- The identity running the tests has at least `Reader` role on the tenant root management group level. This is required to ensure the `AzResourceTest` module can retrieve information from various APIs.
-- Signed in to Azure using `Connect-AzAccount`.
-- If you are using Terraform templates, also sign in to Azure CLI using `az login`.
-
-### Running the Tests
-
-The test will be automatically executed as part of the Azure Policy integration test pipelines in Azure DevOps.
diff --git a/tests/policy-integration-tests/.test-template/tests.ps1 b/tests/policy-integration-tests/.test-template/tests.ps1
index c1cbaae..7a5ca12 100644
--- a/tests/policy-integration-tests/.test-template/tests.ps1
+++ b/tests/policy-integration-tests/.test-template/tests.ps1
@@ -16,7 +16,7 @@ Write-Output "Initiating test with global config file: $globalConfigFilePath and
$initiateTestScriptPath = (resolve-path -RelativeBasePath $PSScriptRoot -path '../.shared/initiate-test.ps1').Path
. $initiateTestScriptPath -globalConfigFilePath $globalConfigFilePath -TestDirectory $TestDirectory
-# Refer to the ../README.md for details on the expected variables to be set by the initiate-test script and the structure of those variables.
+# Refer to the ../../docs/policy-integration-test-get-started.md for details on the expected variables to be set by the initiate-test script and the structure of those variables.
#endregion
#region defining tests
diff --git a/tests/policy-integration-tests/acr/tests.ps1 b/tests/policy-integration-tests/acr/tests.ps1
index 613bf18..0292f5c 100755
--- a/tests/policy-integration-tests/acr/tests.ps1
+++ b/tests/policy-integration-tests/acr/tests.ps1
@@ -16,25 +16,10 @@ Write-Output "Initiating test with global config file: $globalConfigFilePath and
$initiateTestScriptPath = (resolve-path -RelativeBasePath $PSScriptRoot -path '../.shared/initiate-test.ps1').Path
. $initiateTestScriptPath -globalConfigFilePath $globalConfigFilePath -TestDirectory $TestDirectory
-# Refer to the ../README.md for details on the expected variables to be set by the initiate-test script and the structure of those variables.
+# Refer to the ../../docs/policy-integration-test-get-started.md for details on the expected variables to be set by the initiate-test script and the structure of those variables.
#endregion
#region test specific configuration and tests
-<#
-Test cases:
-- PEDNS-012: Configure a private DNS Zone ID for Azure Container Registry (DeployIfNotExists)
-- DS-003: Deploy Diagnostic Settings for Container Registry to Log Analytics workspace. (DeployIfNotExists)
-- TAG-005: Inherit the tag from the Subscription to Resource Group if missing (appid)
-- TAG-006: Inherit the tag from the Subscription to Resource Group if missing (dataclass)
-- TAG-007: Inherit the tag from the Subscription to Resource Group if missing (owner)
-- TAG-008: Inherit the tag from the Subscription to Resource Group if missing (supportteam)
-- TAG-018: Inherit the tag from the Subscription to Resource Group if missing (environment)
-- TAG-009: Inherit the tag from the Resource Group to Resources if missing (appid)
-- TAG-010: Inherit the tag from the Resource Group to Resources if missing (dataclass)
-- TAG-011: Inherit the tag from the Resource Group to Resources if missing (owner)
-- TAG-012: Inherit the tag from the Resource Group to Resources if missing (supportteam)
-- TAG-019: Inherit the tag from the Resource Group to Resources if missing (environment)
-#>
#Parse deployment outputs
$resourceId = $script:bicepDeploymentOutputs.resourceId.value
diff --git a/tests/policy-integration-tests/event-hub/README.md b/tests/policy-integration-tests/event-hub/README.md
new file mode 100644
index 0000000..d756030
--- /dev/null
+++ b/tests/policy-integration-tests/event-hub/README.md
@@ -0,0 +1,26 @@
+# Policy Integration Test - Sample Test Cases for Azure Event Hub
+
+## Introduction
+
+This folder contains a sample test case for Azure Event Hub related policies.
+
+The test case is designed to test the following policy assignments:
+
+| Policy Assignment Name | Policy Assignment Scope | Description |
+| :--------------------- | :--------------------- | :---------- |
+| `pa-d-eh` | `/providers/Microsoft.Management/managementGroups/CONTOSO-DEV` | Policy Assignment for the Azure Event Hub initiative |
+| `pa-d-pedns` | `/providers/Microsoft.Management/managementGroups/CONTOSO-DEV` | Policy Assignment for Azure Private Endpoint DNS Records Policy Initiative (deploy DNS records for Private Endpoints) |
+| `pa-d-diag-settings` | `/providers/Microsoft.Management/managementGroups/CONTOSO-DEV` | Policy Assignment for Azure Diagnostic Settings Policy Initiative (deploy diagnostic settings for all applicable Azure resources) |
+
+
+The following policies are in scope for testing:
+
+| Policy Assignment | Policy Reference ID | Policy Name | Policy Effect |
+| :---------------- | :---------------- | :------------ | :------------ |
+| `pa-d-eh` | `EH-001` | Restrict Event Hub Local Authentication | `Deny` |
+| `pa-d-eh` | `EH-002` | Restrict Event Hub Minimum TLS version | `Deny` |
+| `pa-d-eh` | `EH-003` | Event Hub Event Hub Restrict Public Network Access | `Deny` |
+| `pa-d-eh` | `EH-004` | Event Hub Namespace should use CMK encryption | `Audit` |
+| `pa-d-eh` | `EH-005` | Event Hub Namespace should use Private Endpoint | `AuditIfNotExists` |
+| `pa-d-pedns` | `PEDNS-007` | Private DNS Record for Event Hub PE must exist | `DeployIfNotExists` |
+| `pa-d-diag-settings` | `DS-022` | Diagnostic Settings for Event Hub Must Be Configured | `DeployIfNotExists` |
diff --git a/tests/policy-integration-tests/event-hub/tests.ps1 b/tests/policy-integration-tests/event-hub/tests.ps1
index c5360f5..4d4b035 100755
--- a/tests/policy-integration-tests/event-hub/tests.ps1
+++ b/tests/policy-integration-tests/event-hub/tests.ps1
@@ -16,20 +16,10 @@ Write-Output "Initiating test with global config file: $globalConfigFilePath and
$initiateTestScriptPath = (resolve-path -RelativeBasePath $PSScriptRoot -path '../.shared/initiate-test.ps1').Path
. $initiateTestScriptPath -globalConfigFilePath $globalConfigFilePath -TestDirectory $TestDirectory
-# Refer to the ../README.md for details on the expected variables to be set by the initiate-test script and the structure of those variables.
+# Refer to the ../../docs/policy-integration-test-get-started.md for details on the expected variables to be set by the initiate-test script and the structure of those variables.
#endregion
#region test specific configuration and tests
-<#
-Test cases in scope:
-- EH-001: Restrict Event Hub Local Authentication (Deny)
-- EH-002: Event Hub must have the minimum TLS version configured as per standard - (Deny)
-- EH-003: Event Hub Restrict Public Network Access - (Deny)
-- EH-004: Event Hub should use CMK Encryption - (Audit)
-- EH-005: Event Hub namespaces should use private link - (AuditIfNotExists)
-- PEDENS-007: Configure a private dns zone id for Event Hub - (DeployIfNotExists)
-- DS-032: custom policy - eh-config-diag-logs - Configure Diagnostic Setting for Event Hub - (DeployIfNotExists)
-#>
#Parse deployment outputs
$resourceId = $script:bicepDeploymentOutputs.resourceId.value
diff --git a/tests/policy-integration-tests/key-vault/README.md b/tests/policy-integration-tests/key-vault/README.md
index e65b61b..1f3d76e 100644
--- a/tests/policy-integration-tests/key-vault/README.md
+++ b/tests/policy-integration-tests/key-vault/README.md
@@ -7,21 +7,21 @@ This folder contains a sample test case for Azure Key Vault related policies.
The test case is designed to test the following policy assignments:
| Policy Assignment Name | Policy Assignment Scope | Description |
-| :-------------------- | :--------------------- | :---------- |
-| `pa-d-kv` | `/providers/Microsoft.Management/managementGroups/CONTOSO-DEV` | Policy Assignment for the Azure Key Vault initiative |
-| `pa-d-tags` | `/providers/Microsoft.Management/managementGroups/CONTOSO-DEV` | Policy Assignment for resource tags initiative |
+| :--------------------- | :--------------------- | :---------- |
+| `pa-d-key-vault` | `/providers/Microsoft.Management/managementGroups/CONTOSO-DEV` | Policy Assignment for the Azure Key Vault initiative |
| `pa-d-pedns` | `/providers/Microsoft.Management/managementGroups/CONTOSO-DEV` | Policy Assignment for Azure Private Endpoint DNS Records Policy Initiative (deploy DNS records for Private Endpoints) |
| `pa-d-diag-settings` | `/providers/Microsoft.Management/managementGroups/CONTOSO-DEV` | Policy Assignment for Azure Diagnostic Settings Policy Initiative (deploy diagnostic settings for all applicable Azure resources) |
+| `pa-d-tags` | `/providers/Microsoft.Management/managementGroups/CONTOSO-DEV` | Policy Assignment for resource tags initiative |
The following policies are in scope for testing:
| Policy Assignment | Policy Reference ID | Policy Name | Policy Effect |
| :---------------- | :---------------- | :------------ | :------------ |
-| `pa-d-tags` | `TAG-006` | Resource Group inherit the 'dataclass' tag from subscription | `Modify` |
-| `pa-d-tags` | `TAG-007` | Resource Group inherit the 'owner' tag from subscription | `Modify` |
-| `pa-d-kv` | `KV-002` | Key Vault should have purge protection enabled | `Modify` |
-| `pa-d-kv` | `KV-003` | Key Vault permission model should be configured to use Azure RBAC | `Deny` |
-| `pa-d-kv` | `KV-004` | Azure Key Vault should disable public network access | `Audit` |
+| `pa-d-tags` | `TAG-006` | Inherit the tag from the Subscription to Resource Group if missing (dataclass) | `Modify` |
+| `pa-d-tags` | `TAG-007` | Inherit the tag from the Subscription to Resource Group if missing (owner) | `Modify` |
+| `pa-d-key-vault` | `KV-002` | Key Vault should have purge protection enabled | `Modify` |
+| `pa-d-key-vault` | `KV-003` | Key Vault permission model should be configured to use Azure RBAC | `Deny` |
+| `pa-d-key-vault` | `KV-004` | Azure Key Vault should disable public network access | `Audit` |
| `pa-d-pedns` | `PEDNS-005` | Private DNS Record for Key Vault PE must exist | `DeployIfNotExists` |
| `pa-d-diag-settings` | `DS-029` | Diagnostic Settings for Key Vault Must Be Configured | `DeployIfNotExists` |
diff --git a/tests/policy-integration-tests/key-vault/config.json b/tests/policy-integration-tests/key-vault/config.json
index 3c72b9f..94b16ee 100644
--- a/tests/policy-integration-tests/key-vault/config.json
+++ b/tests/policy-integration-tests/key-vault/config.json
@@ -2,7 +2,8 @@
"policyAssignmentIds": [
"/providers/Microsoft.Management/managementGroups/CONTOSO-DEV/providers/Microsoft.Authorization/policyAssignments/pa-d-key-vault",
"/providers/Microsoft.Management/managementGroups/CONTOSO-DEV/providers/Microsoft.Authorization/policyAssignments/pa-d-pedns",
- "/providers/Microsoft.Management/managementGroups/CONTOSO-DEV/providers/Microsoft.Authorization/policyAssignments/pa-d-diag-settings"
+ "/providers/Microsoft.Management/managementGroups/CONTOSO-DEV/providers/Microsoft.Authorization/policyAssignments/pa-d-diag-settings",
+ "/providers/Microsoft.Management/managementGroups/CONTOSO-DEV/providers/Microsoft.Authorization/policyAssignments/pa-d-tags"
],
"testName": "KeyVault",
"assignmentName": "pa-d-key-vault",
diff --git a/tests/policy-integration-tests/key-vault/tests.ps1 b/tests/policy-integration-tests/key-vault/tests.ps1
index 16bbd07..99ba294 100644
--- a/tests/policy-integration-tests/key-vault/tests.ps1
+++ b/tests/policy-integration-tests/key-vault/tests.ps1
@@ -16,20 +16,10 @@ Write-Output "Initiating test with global config file: $globalConfigFilePath and
$initiateTestScriptPath = (resolve-path -RelativeBasePath $PSScriptRoot -path '../.shared/initiate-test.ps1').Path
. $initiateTestScriptPath -globalConfigFilePath $globalConfigFilePath -TestDirectory $TestDirectory
-# Refer to the ../README.md for details on the expected variables to be set by the initiate-test script and the structure of those variables.
+# Refer to the ../../docs/policy-integration-test-get-started.md for details on the expected variables to be set by the initiate-test script and the structure of those variables.
#endregion
#region test specific configuration and tests
-<#
-The following policy definitions are tested:
- - Resource Group inherit the 'dataclass' tag from subscription
- - Resource Group inherit the 'owner' tag from subscription
- - Azure Key Vault should disable public network access (Audit)
- - Key Vault should have purge protection enabled (Modify)
- - Private DNS Record for Key Vault PE must exist (DeployIfNotExists)
- - Diagnostic Settings for Key Vault Must Be Configured (DeployIfNotExists)
- - KeyVault permission model should be configured to use Azure RBAC (Deny)
-#>
#Parse Deployment outputs
$resourceId = $script:bicepDeploymentOutputs.resourceId.Value
diff --git a/tests/policy-integration-tests/monitor/config.json b/tests/policy-integration-tests/monitor/config.json
index eefb6fb..a285284 100644
--- a/tests/policy-integration-tests/monitor/config.json
+++ b/tests/policy-integration-tests/monitor/config.json
@@ -1,7 +1,6 @@
{
"policyAssignmentIds": [
- "/providers/Microsoft.Management/managementGroups/CONTOSO-DEV/providers/Microsoft.Authorization/policyAssignments/pa-d-monitor",
- "/providers/Microsoft.Management/managementGroups/CONTOSO-DEV/providers/Microsoft.Authorization/policyAssignments/pa-d-tags"
+ "/providers/Microsoft.Management/managementGroups/CONTOSO-DEV/providers/Microsoft.Authorization/policyAssignments/pa-d-monitor"
],
"testName": "AzureMonitor",
"assignmentName": "pa-d-monitor",
diff --git a/tests/policy-integration-tests/monitor/tests.ps1 b/tests/policy-integration-tests/monitor/tests.ps1
index 6d52de2..6f61b8f 100644
--- a/tests/policy-integration-tests/monitor/tests.ps1
+++ b/tests/policy-integration-tests/monitor/tests.ps1
@@ -16,22 +16,10 @@ Write-Output "Initiating test with global config file: $globalConfigFilePath and
$initiateTestScriptPath = (resolve-path -RelativeBasePath $PSScriptRoot -path '../.shared/initiate-test.ps1').Path
. $initiateTestScriptPath -globalConfigFilePath $globalConfigFilePath -TestDirectory $TestDirectory
-# Refer to the ../README.md for details on the expected variables to be set by the initiate-test script and the structure of those variables.
+# Refer to the ../../docs/policy-integration-test-get-started.md for details on the expected variables to be set by the initiate-test script and the structure of those variables.
#endregion
#region test specific configuration and tests
-<#
-The following policy definitions are tested via both What-If deployment and Poilcy Restriction API.
-In real world scenario, select one of the two methods as this is for demonstration purpose to show the flexibility of the test framework in supporting different test methods.
- - MON-001: Restrict Azure Monitor Action Group Send Email Notification to External Email Addresses (Deny)
- - MON-002: Restrict Azure Monitor Action Group Send SMS Notification to Unauthorized country codes (Deny)
- - MON-003: Restrict Azure Monitor Action Group Trigger Actions to Cross-Subscription Azure Automation or not on the Allowed List (Deny)
- - MON-004: Restrict Azure Monitor Action Group Trigger Actions to Cross-Subscription Event Hubs or not on the Allowed List (Deny)
- - MON-005: Restrict Azure Monitor Action Group Trigger Actions to Cross-Subscription Function Apps or not on the Allowed List (Deny)
- - MON-006: Restrict Azure Monitor Action Group Trigger Actions to Cross-Subscription Logic Apps or not on the Allowed List (Deny)
- - MON-007: Restrict Azure Monitor Action Group Trigger Actions to Webhooks that are not on the Allowed List (Deny)
- - MON-008: Restrict Azure Monitor Action Group Trigger Actions to Webhooks that are not using HTTPS (Deny)
-#>
$actionGroupName = 'ag01'
$monitorAssignmentId = $script:LocalConfig_policyAssignmentIds | Where-Object { $_ -imatch "$script:LocalConfig_assignmentName`$" }
diff --git a/tests/policy-integration-tests/network-security-group/README.md b/tests/policy-integration-tests/network-security-group/README.md
new file mode 100644
index 0000000..225e08f
--- /dev/null
+++ b/tests/policy-integration-tests/network-security-group/README.md
@@ -0,0 +1,21 @@
+# Policy Integration Test - Sample Test Cases for Network Security Group
+
+## Introduction
+
+This folder contains a sample test case for Azure Network Security Group related policies.
+
+The test case is designed to test the following policy assignments:
+
+| Policy Assignment Name | Policy Assignment Scope | Description |
+| :--------------------- | :--------------------- | :---------- |
+| `pa-d-nsg` | `/providers/Microsoft.Management/managementGroups/CONTOSO-DEV` | Policy Assignment for the Network Security Group initiative |
+| `pa-d-diag-settings` | `/providers/Microsoft.Management/managementGroups/CONTOSO-DEV` | Policy Assignment for Azure Diagnostic Settings Policy Initiative (deploy diagnostic settings for all applicable Azure resources) |
+
+
+The following policies are in scope for testing:
+
+| Policy Assignment | Policy Reference ID | Policy Name | Policy Effect |
+| :---------------- | :---------------- | :------------ | :------------ |
+| `pa-d-nsg` | `NSG-003` | Allowed list of Service Tags in Network Security Group Inbound Security Rules | `Deny` |
+| `pa-d-nsg` | `NSG-004` | Allowed list of Service Tags in Network Security Group Outbound Security Rules | `Deny` |
+| `pa-d-diag-settings` | `DS-038` | Diagnostic Settings for Network Security Group Must Be Configured | `DeployIfNotExists` |
diff --git a/tests/policy-integration-tests/network-security-group/tests.ps1 b/tests/policy-integration-tests/network-security-group/tests.ps1
index 5c9e984..5fa85c6 100644
--- a/tests/policy-integration-tests/network-security-group/tests.ps1
+++ b/tests/policy-integration-tests/network-security-group/tests.ps1
@@ -16,7 +16,7 @@ Write-Output "Initiating test with global config file: $globalConfigFilePath and
$initiateTestScriptPath = (resolve-path -RelativeBasePath $PSScriptRoot -path '../.shared/initiate-test.ps1').Path
. $initiateTestScriptPath -globalConfigFilePath $globalConfigFilePath -TestDirectory $TestDirectory
-# Refer to the ../README.md for details on the expected variables to be set by the initiate-test script and the structure of those variables.
+# Refer to the ../../docs/policy-integration-test-get-started.md for details on the expected variables to be set by the initiate-test script and the structure of those variables.
#endregion
#region test specific configuration and tests
diff --git a/tests/policy-integration-tests/postgresql/README.md b/tests/policy-integration-tests/postgresql/README.md
new file mode 100644
index 0000000..23d2caa
--- /dev/null
+++ b/tests/policy-integration-tests/postgresql/README.md
@@ -0,0 +1,18 @@
+# Policy Integration Test - Sample Test Cases for Azure Database for PostgreSQL
+
+## Introduction
+
+This folder contains a sample test case for Azure Database for PostgreSQL related policies.
+
+The test case is designed to test the following policy assignments:
+
+| Policy Assignment Name | Policy Assignment Scope | Description |
+| :--------------------- | :--------------------- | :---------- |
+| `pa-d-postgresql` | `/providers/Microsoft.Management/managementGroups/CONTOSO-DEV` | Policy Assignment for the Azure Database for PostgreSQL initiative |
+
+The following policies are in scope for testing:
+
+| Policy Assignment | Policy Reference ID | Policy Name | Policy Effect |
+| :---------------- | :---------------- | :------------ | :------------ |
+| `pa-d-postgresql` | `PGS-001` | Azure PostgreSQL flexible server should have Microsoft Entra Only Authentication enabled | `Deny` |
+| `pa-d-postgresql` | `PGS-002` | Public network access should be disabled for PostgreSQL flexible servers | `Deny` |
diff --git a/tests/policy-integration-tests/postgresql/tests.ps1 b/tests/policy-integration-tests/postgresql/tests.ps1
index 3832437..4f80e6d 100644
--- a/tests/policy-integration-tests/postgresql/tests.ps1
+++ b/tests/policy-integration-tests/postgresql/tests.ps1
@@ -16,15 +16,10 @@ Write-Output "Initiating test with global config file: $globalConfigFilePath and
$initiateTestScriptPath = (resolve-path -RelativeBasePath $PSScriptRoot -path '../.shared/initiate-test.ps1').Path
. $initiateTestScriptPath -globalConfigFilePath $globalConfigFilePath -TestDirectory $TestDirectory
-# Refer to the ../README.md for details on the expected variables to be set by the initiate-test script and the structure of those variables.
+# Refer to the ../../docs/policy-integration-test-get-started.md for details on the expected variables to be set by the initiate-test script and the structure of those variables.
#endregion
#region defining tests
-<#
-The following policy definitions are tested:.
- - PGS-001: Azure PostgreSQL flexible server should have Microsoft Entra Only Authentication enabled (Deny)
- - PGS-002: Public network access should be disabled for PostgreSQL flexible servers (Deny)
-#>
$policyAssignmentId = $script:LocalConfig_policyAssignmentIds | Where-Object { $_ -imatch "$script:LocalConfig_assignmentName`$" }
diff --git a/tests/policy-integration-tests/private-endpoint/README.md b/tests/policy-integration-tests/private-endpoint/README.md
new file mode 100644
index 0000000..dc19313
--- /dev/null
+++ b/tests/policy-integration-tests/private-endpoint/README.md
@@ -0,0 +1,17 @@
+# Policy Integration Test - Sample Test Cases for Azure Private Endpoint
+
+## Introduction
+
+This folder contains a sample test case for Azure Private Endpoint related policies.
+
+The test case is designed to test the following policy assignments:
+
+| Policy Assignment Name | Policy Assignment Scope | Description |
+| :--------------------- | :--------------------- | :---------- |
+| `pa-d-pe-lz` | `/providers/Microsoft.Management/managementGroups/CONTOSO-DEV-LandingZones` | Policy Assignment for the Azure Private Endpoint initiative |
+
+The following policies are in scope for testing:
+
+| Policy Assignment | Policy Reference ID | Policy Name | Policy Effect |
+| :---------------- | :---------------- | :------------ | :------------ |
+| `pa-d-pe-lz` | `PE-002` | AMPLS Private Endpoints Policy violating deployment should fail | `Deny` |
diff --git a/tests/policy-integration-tests/private-endpoint/tests.ps1 b/tests/policy-integration-tests/private-endpoint/tests.ps1
index e114ef2..9d4abe3 100644
--- a/tests/policy-integration-tests/private-endpoint/tests.ps1
+++ b/tests/policy-integration-tests/private-endpoint/tests.ps1
@@ -16,14 +16,10 @@ Write-Output "Initiating test with global config file: $globalConfigFilePath and
$initiateTestScriptPath = (resolve-path -RelativeBasePath $PSScriptRoot -path '../.shared/initiate-test.ps1').Path
. $initiateTestScriptPath -globalConfigFilePath $globalConfigFilePath -TestDirectory $TestDirectory
-# Refer to the ../README.md for details on the expected variables to be set by the initiate-test script and the structure of those variables.
+# Refer to the ../../docs/policy-integration-test-get-started.md for details on the expected variables to be set by the initiate-test script and the structure of those variables.
#endregion
#region test specific configuration and tests
-<#
-Test cases:
-- P-PE-02: AMPLS Private Endpoint is not allowed (Deny)
-#>
#variables
@@ -37,7 +33,7 @@ $amplsViolatingPolicies = @(
#define tests
$tests = @()
-$tests += New-ARTWhatIfDeploymentTestConfig 'E-002: AMPLS Private Endpoints Policy violating deployment should fail' $script:token $script:whatIfViolateBicepTemplatePath $script:testResourceGroupId 'Failed' $amplsViolatingPolicies -maxRetry $script:GlobalConfig_whatIfMaxRetry
+$tests += New-ARTWhatIfDeploymentTestConfig 'PE-002: AMPLS Private Endpoints Policy violating deployment should fail' $script:token $script:whatIfViolateBicepTemplatePath $script:testResourceGroupId 'Failed' $amplsViolatingPolicies -maxRetry $script:GlobalConfig_whatIfMaxRetry
#endregion
#region Invoke tests - do not modify
diff --git a/tests/policy-integration-tests/storage-account/README.md b/tests/policy-integration-tests/storage-account/README.md
new file mode 100644
index 0000000..91a1978
--- /dev/null
+++ b/tests/policy-integration-tests/storage-account/README.md
@@ -0,0 +1,30 @@
+# Policy Integration Test - Sample Test Cases for Storage Account
+
+## Introduction
+
+This folder contains a sample test case for Azure Storage Account related policies.
+
+The test case is designed to test the following policy assignments:
+
+| Policy Assignment Name | Policy Assignment Scope | Description |
+| :--------------------- | :--------------------- | :---------- |
+| `pa-d-storage` | `/providers/Microsoft.Management/managementGroups/CONTOSO-DEV` | Policy Assignment for the Azure Storage Account initiative |
+| `pa-d-pedns` | `/providers/Microsoft.Management/managementGroups/CONTOSO-DEV` | Policy Assignment for Azure Private Endpoint DNS Records Policy Initiative (deploy DNS records for Private Endpoints) |
+| `pa-d-diag-settings` | `/providers/Microsoft.Management/managementGroups/CONTOSO-DEV` | Policy Assignment for Azure Diagnostic Settings Policy Initiative (deploy diagnostic settings for all applicable Azure resources) |
+| `pa-d-tags` | `/providers/Microsoft.Management/managementGroups/CONTOSO-DEV` | Policy Assignment for resource tags initiative |
+
+
+The following policies are in scope for testing:
+
+| Policy Assignment | Policy Reference ID | Policy Name | Policy Effect |
+| :---------------- | :---------------- | :------------ | :------------ |
+| `pa-d-tags` | `TAG-010` | Inherit the tag from the Resource Group to Resource if missing (dataclass) | `Modify` |
+| `pa-d-tags` | `TAG-011` | Inherit the tag from the Resource Group to Resource if missing (owner) | `Modify` |
+| `pa-d-storage` | `STG-006` | Storage accounts should prevent cross tenant object replication | `Deny` |
+| `pa-d-storage` | `STG-007` | Storage accounts should prevent shared key access | `Audit` |
+| `pa-d-storage` | `STG-008` | Secure transfer to storage accounts should be enabled | `Deny` |
+| `pa-d-storage` | `STG-009` | Restrict Storage Account with public network access | `Deny` |
+| `pa-d-storage` | `STG-010` | Storage accounts should have the specified minimum TLS version | `Deny` |
+| `pa-d-storage` | `STG-012` | Storage accounts should prevent permitted copy scopes from any storage accounts | `Deny` |
+| `pa-d-pedns` | `PEDNS-002` | Private DNS Record for Storage Blob PE must exist | `DeployIfNotExists` |
+| `pa-d-diag-settings` | `DS-052` | Diagnostic Settings for Storage Account Must Be Configured | `DeployIfNotExists` |
diff --git a/tests/policy-integration-tests/storage-account/config.json b/tests/policy-integration-tests/storage-account/config.json
index eec8c82..fdbb904 100644
--- a/tests/policy-integration-tests/storage-account/config.json
+++ b/tests/policy-integration-tests/storage-account/config.json
@@ -2,7 +2,8 @@
"policyAssignmentIds": [
"/providers/Microsoft.Management/managementGroups/CONTOSO-DEV/providers/Microsoft.Authorization/policyAssignments/pa-d-storage",
"/providers/Microsoft.Management/managementGroups/CONTOSO-DEV/providers/Microsoft.Authorization/policyAssignments/pa-d-pedns",
- "/providers/Microsoft.Management/managementGroups/CONTOSO-DEV/providers/Microsoft.Authorization/policyAssignments/pa-d-diag-settings"
+ "/providers/Microsoft.Management/managementGroups/CONTOSO-DEV/providers/Microsoft.Authorization/policyAssignments/pa-d-diag-settings",
+ "/providers/Microsoft.Management/managementGroups/CONTOSO-DEV/providers/Microsoft.Authorization/policyAssignments/pa-d-tags"
],
"testName": "StorageAccount",
"storageAccountAssignmentName": "pa-d-storage",
diff --git a/tests/policy-integration-tests/storage-account/tests.ps1 b/tests/policy-integration-tests/storage-account/tests.ps1
index 6ee34b9..8290a21 100644
--- a/tests/policy-integration-tests/storage-account/tests.ps1
+++ b/tests/policy-integration-tests/storage-account/tests.ps1
@@ -16,7 +16,7 @@ Write-Output "Initiating test with global config file: $globalConfigFilePath and
$initiateTestScriptPath = (resolve-path -RelativeBasePath $PSScriptRoot -path '../.shared/initiate-test.ps1').Path
. $initiateTestScriptPath -globalConfigFilePath $globalConfigFilePath -TestDirectory $TestDirectory
-# Refer to the ../README.md for details on the expected variables to be set by the initiate-test script and the structure of those variables.
+# Refer to the ../../docs/policy-integration-test-get-started.md for details on the expected variables to be set by the initiate-test script and the structure of those variables.
#endregion
#region test specific configuration and tests
diff --git a/tests/policy-integration-tests/tags/tests.ps1 b/tests/policy-integration-tests/tags/tests.ps1
index b9e124d..a277006 100644
--- a/tests/policy-integration-tests/tags/tests.ps1
+++ b/tests/policy-integration-tests/tags/tests.ps1
@@ -16,28 +16,10 @@ Write-Output "Initiating test with global config file: $globalConfigFilePath and
$initiateTestScriptPath = (resolve-path -RelativeBasePath $PSScriptRoot -path '../.shared/initiate-test.ps1').Path
. $initiateTestScriptPath -globalConfigFilePath $globalConfigFilePath -TestDirectory $TestDirectory
-# Refer to the ../README.md for details on the expected variables to be set by the initiate-test script and the structure of those variables.
+# Refer to the ../../docs/policy-integration-test-get-started.md for details on the expected variables to be set by the initiate-test script and the structure of those variables.
#endregion
#region test specific configuration and tests
-<#
-Test cases:
-- TAG-001: Subscription Should have appid tag (deny)
-- TAG-002: Subscription Should have dataclass tag with allowed value (deny)
-- TAG-003: Subscription Should have owner tag (deny)
-- TAG-004: Subscription Should have supportteam tag (deny)
-- TAG-005: Inherit the tag from the Subscription to Resource Group if missing (appid)
-- TAG-006: Inherit the tag from the Subscription to Resource Group if missing (dataclass)
-- TAG-007: Inherit the tag from the Subscription to Resource Group if missing (owner)
-- TAG-008: Inherit the tag from the Subscription to Resource Group if missing (supportteam)
-- TAG-013: Resource Group Should have required tag value for dataclass tag (deny)
-- TAG-014: Resource Should have required tag value for dataclass tag (deny)
-- TAG-015: Subscription Should have required tag value for environment tag (deny)
-- TAG-016: Resource Group Should have required tag value for environment tag (deny)
-- TAG-017: Resource Should have required tag value for environment tag (deny)
-- TAG-018: Inherit the tag from the Subscription to Resource Group if missing (environment)
-#>
-
#variables
#Parse deployment outputs
diff --git a/tests/policy-integration-tests/virtual-network/README.md b/tests/policy-integration-tests/virtual-network/README.md
new file mode 100644
index 0000000..c44205e
--- /dev/null
+++ b/tests/policy-integration-tests/virtual-network/README.md
@@ -0,0 +1,23 @@
+# Policy Integration Test - Sample Test Cases for Virtual Network
+
+## Introduction
+
+This folder contains a sample test case for Virtual Network related policies.
+
+The test case is designed to test the following policy assignments:
+
+| Policy Assignment Name | Policy Assignment Scope | Description |
+| :--------------------- | :--------------------- | :---------- |
+| `pa-d-vnet` | `/providers/Microsoft.Management/managementGroups/CONTOSO-DEV` | Policy Assignment for the Azure Virtual Network initiative |
+| `pa-d-diag-settings` | `/providers/Microsoft.Management/managementGroups/CONTOSO-DEV` | Policy Assignment for Azure Diagnostic Settings Policy Initiative (deploy diagnostic settings for all applicable Azure resources) |
+
+
+The following policies are in scope for testing:
+
+| Policy Assignment | Policy Reference ID | Policy Name | Policy Effect |
+| :---------------- | :---------------- | :------------ | :------------ |
+| `pa-d-vnet` | `VNET-001` | Gateway Subnet should not have Network Security Group associated | `Deny` |
+| `pa-d-vnet` | `VNET-002` | Subnets should be associated with a Network Security Group | `Deny` |
+| `pa-d-vnet` | `VNET-003` | VNet Flow Log must be enabled in Australia East | `DeployIfNotExists` |
+| `pa-d-vnet` | `VNET-004` | VNet Flow Log must be enabled in Australia Southeast| `DeployIfNotExists` |
+| `pa-d-diag-settings` | `DS-058` | Diagnostic Settings for Virtual Network Must Be Configured | `DeployIfNotExists` |
diff --git a/tests/policy-integration-tests/virtual-network/tests.ps1 b/tests/policy-integration-tests/virtual-network/tests.ps1
index d3dbf54..bd75eb2 100644
--- a/tests/policy-integration-tests/virtual-network/tests.ps1
+++ b/tests/policy-integration-tests/virtual-network/tests.ps1
@@ -16,18 +16,11 @@ Write-Output "Initiating test with global config file: $globalConfigFilePath and
$initiateTestScriptPath = (resolve-path -RelativeBasePath $PSScriptRoot -path '../.shared/initiate-test.ps1').Path
. $initiateTestScriptPath -globalConfigFilePath $globalConfigFilePath -TestDirectory $TestDirectory
-# Refer to the ../README.md for details on the expected variables to be set by the initiate-test script and the structure of those variables.
+# Refer to the ../../docs/policy-integration-test-get-started.md for details on the expected variables to be set by the initiate-test script and the structure of those variables.
#endregion
#region defining tests
-<#
-Test cases:
-- VNET-001: Gateway Subnet should not have Network Security Group associated (Deny)
-- VNET-002: Subnets should be associated with a Network Security Group (Deny)
-- VNET-003: Configure virtual networks to enable vnet flow log and traffic analytics (Australia East) (DeployIfNotExists)
-- VNET-004: Configure virtual networks to enable vnet flow log and traffic analytics (Australia Southeast) (DeployIfNotExists)
-- DS-058: Configure Diagnostic logging for Virtual Network (DeployIfNotExists)
-#>
+
#variables
#Australia East VNet
$resourceId = $script:bicepDeploymentOutputs.resourceId.value
diff --git a/tests/policy-integration-tests/web/README.md b/tests/policy-integration-tests/web/README.md
new file mode 100644
index 0000000..52f7ae2
--- /dev/null
+++ b/tests/policy-integration-tests/web/README.md
@@ -0,0 +1,33 @@
+# Policy Integration Test - Sample Test Cases for Azure App Services and Function Apps
+
+## Introduction
+
+This folder contains a sample test case for Azure App Services and Function Apps related policies.
+
+The test case is designed to test the following policy assignments:
+
+| Policy Assignment Name | Policy Assignment Scope | Description |
+| :--------------------- | :--------------------- | :---------- |
+| `pa-d-web` | `/providers/Microsoft.Management/managementGroups/CONTOSO-DEV` | Policy Assignment for the Azure App Services and Function Apps initiative |
+| `pa-d-pedns` | `/providers/Microsoft.Management/managementGroups/CONTOSO-DEV` | Policy Assignment for Azure Private Endpoint DNS Records Policy Initiative (deploy DNS records for Private Endpoints) |
+| `pa-d-diag-settings` | `/providers/Microsoft.Management/managementGroups/CONTOSO-DEV` | Policy Assignment for Azure Diagnostic Settings Policy Initiative (deploy diagnostic settings for all applicable Azure resources) |
+
+The following policies are in scope for testing:
+
+| Policy Assignment | Policy Reference ID | Policy Name | Policy Effect |
+| :---------------- | :---------------- | :------------ | :------------ |
+| `pa-d-diag-settings` | `DS-026` | Configure Diagnostic Settings for Function App | `DeployIfNotExists` |
+| `pa-d-diag-settings` | `DS-062` | Configure Diagnostic Settings for App Services | `DeployIfNotExists` |
+| `pa-d-pedns` | `PEDNS-006` | Configure Private DNS Record for Web App Private Endpoint | `DeployIfNotExists` |
+| `pa-d-pedns` | `PEDNS-015` | Configure Private DNS Record for Web App Slots Private Endpoint | `DeployIfNotExists` |
+| `pa-d-web` | `WEB-001` | App Service and function app slots should only be accessible over HTTPS | `Deny` |
+| `pa-d-web` | `WEB-002` | App Service and Function apps should only be accessible over HTTPS | `Deny` |
+| `pa-d-web` | `WEB-003` | Function apps should only use approved identity providers for authentication | `Deny` |
+| `pa-d-web` | `WEB-004` | Prevent cross-subscription Private Link for App Services and Function Apps | `Audit` |
+| `pa-d-web` | `WEB-005` | Function apps should route application traffic over the virtual network | `Deny` |
+| `pa-d-web` | `WEB-006` | App Service and Function apps should route configuration traffic over the virtual network | `Deny` |
+| `pa-d-web` | `WEB-007` | Function apps should route configuration traffic over the virtual network | `Deny` |
+| `pa-d-web` | `WEB-008` | Function app slots should route configuration traffic over the virtual network | `Deny` |
+| `pa-d-web` | `WEB-009` | App Service apps should use a SKU that supports private link | `Deny` |
+| `pa-d-web` | `WEB-010` | Public network access should be disabled for App Services and Function Apps | `Deny` |
+| `pa-d-web` | `WEB-011` | Public network access should be disabled for App Service and Function App slots | `Deny` |
diff --git a/tests/policy-integration-tests/web/tests.ps1 b/tests/policy-integration-tests/web/tests.ps1
index 9d6e8af..2444757 100644
--- a/tests/policy-integration-tests/web/tests.ps1
+++ b/tests/policy-integration-tests/web/tests.ps1
@@ -16,28 +16,10 @@ Write-Output "Initiating test with global config file: $globalConfigFilePath and
$initiateTestScriptPath = (resolve-path -RelativeBasePath $PSScriptRoot -path '../.shared/initiate-test.ps1').Path
. $initiateTestScriptPath -globalConfigFilePath $globalConfigFilePath -TestDirectory $TestDirectory
-# Refer to the ../README.md for details on the expected variables to be set by the initiate-test script and the structure of those variables.
+# Refer to the ../../docs/policy-integration-test-get-started.md for details on the expected variables to be set by the initiate-test script and the structure of those variables.
#endregion
#region defining tests
-<#
-Test cases:
-- DS-026: Configure Diagnostic Settings for Function App (DeployIfNotExists)
-- DS-062: Configure Diagnostic Settings for App Services (DeployIfNotExists)
-- PEDNS-006: Configure Private DNS Record for Web App Private Endpoint (DeployIfNotExists)
-- PEDNS-015: Configure Private DNS Record for Web App Slots Private Endpoint (DeployIfNotExists)
-- WEB-001: App Service and function app slots should only be accessible over HTTPS (Deny)
-- WEB-002: App Service and Function apps should only be accessible over HTTPS (Deny)
-- WEB-003: Function apps should only use approved identity providers for authentication (Deny)
-- WEB-004: Prevent cross-subscription Private Link for App Services and Function Apps (Audit)
-- WEB-005: Function apps should route application traffic over the virtual network (Deny)
-- WEB-006: App Service and Function apps should route configuration traffic over the virtual network (Deny)
-- WEB-007: Function apps should route configuration traffic over the virtual network (Deny)
-- WEB-008: Function app slots should route configuration traffic over the virtual network (Deny)
-- WEB-009: App Service apps should use a SKU that supports private link (Deny)
-- WEB-010: Public network access should be disabled for App Services and Function Apps (Deny)
-- WEB-011: Public network access should be disabled for App Service and Function App slots (Deny)
-#>
#Parse deployment outputs
$functionAppResourceId = $script:bicepDeploymentOutputs.resourceId.value