Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 177 additions & 0 deletions .github/workflows/arm-template-validation.yml
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replace azure/setup-azure-cli@v1 with the latest supported version. As of now, the latest version is azure/setup-azure-cli@v3. Update the workflow as follows:

  • name: Setup Azure CLI
    uses: azure/setup-azure-cli@v3

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's the corrected part:

jobs:
validate_templates:
name: Validate ARM Templates
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3

  - name: Setup Az PowerShell module
    shell: pwsh
    run: |
      Install-Module -Name Az -Force -AllowClobber -Scope CurrentUser
      Install-Module -Name PSRule.Rules.Azure -Force -Scope CurrentUser

  - name: Setup Azure CLI
    uses: azure/setup-azure-cli@v3  # Updated version

  - name: Setup Bicep
    uses: anthony-c-martin/[email protected]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated the Azure CLI setup action from v1 to v3 as requested. The change can be found in commit 3356e4b.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Azure CLI setup action has already been updated from v1 to v3 as requested. This change was implemented in commit 3356e4b.

Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
name: 'ARM Template Validation'

permissions:
contents: read

# Phase 1 of ARM template validation rollout - workflow is disabled for CI/CD
# To enable in Phase 2, uncomment the 'on' section below
# on:
# pull_request:
# paths:
# - 'src/templates/**'
# - 'src/bicep-registry/**'
# - '.github/workflows/arm-template-validation.yml'

# Workflow can still be run manually during Phase 1
on:
workflow_dispatch:

jobs:
validate_templates:
name: Validate ARM Templates
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Setup Az PowerShell module
shell: pwsh
run: |
Install-Module -Name Az -Force -AllowClobber -Scope CurrentUser
Install-Module -Name PSRule.Rules.Azure -Force -Scope CurrentUser

- name: Setup Azure CLI
uses: azure/setup-azure-cli@v3

- name: Setup Bicep
uses: anthony-c-martin/[email protected]

- name: Build templates
shell: pwsh
run: |
cd ${{ github.workspace }}
./src/scripts/Build-Toolkit

- name: Download ARM-TTK
shell: pwsh
run: |
cd ${{ github.workspace }}
# ARM-TTK version pinning - using stable release 0.26 (20250401)
# Update this version when newer stable releases are available
$armTtkVersion = "20250401"
$armTtkPath = "./release/.tools/arm-ttk"

New-Item -Path $armTtkPath -ItemType Directory -Force
Write-Host "Downloading ARM-TTK version $armTtkVersion..."
$armTtkZip = "$armTtkPath/arm-ttk-$armTtkVersion.zip"
Invoke-WebRequest -Uri "https://github.com/Azure/arm-ttk/archive/refs/tags/$armTtkVersion.zip" -OutFile $armTtkZip

# Extract to a versioned subfolder
$extractPath = "$armTtkPath/arm-ttk-$armTtkVersion"
Expand-Archive -Path $armTtkZip -DestinationPath $extractPath -Force

# Clean up the zip file
Remove-Item -Path $armTtkZip -Force

Import-Module "$armTtkPath/arm-ttk-$armTtkVersion/arm-ttk-$armTtkVersion/arm-ttk/arm-ttk.psd1" -Force

- name: Validate templates with PSRule
shell: pwsh
run: |
cd ${{ github.workspace }}

# Get all ARM JSON templates
$templates = Get-ChildItem -Path "release" -Filter "*.json" -Recurse

foreach ($template in $templates) {
Write-Host "Validating template: $($template.FullName)"

# Run PSRule validation
$results = $template.FullName | Invoke-PSRule -Module PSRule.Rules.Azure -WarningAction SilentlyContinue

# Check for failures
$failures = $results | Where-Object { $_.Outcome -eq 'Fail' }
if ($failures) {
Write-Host "::error::PSRule validation failed for $($template.Name):"
$failures | Format-Table -Property RuleName, TargetName, Message -AutoSize | Out-String | Write-Host
exit 1
}
}

Write-Host "All templates validated successfully with PSRule!"

- name: Validate templates with ARM-TTK
shell: pwsh
run: |
cd ${{ github.workspace }}

# Get all ARM JSON templates
$templates = Get-ChildItem -Path "release" -Filter "*.json" -Recurse

$hasErrors = $false

foreach ($template in $templates) {
Write-Host "Validating template with ARM-TTK: $($template.FullName)"

# Run ARM-TTK validation
$testResults = Test-AzTemplate -TemplatePath $template.FullName

# Check for failures
$failures = $testResults | Where-Object { -not $_.Passed }
if ($failures) {
$hasErrors = $true
Write-Host "::error::ARM-TTK validation failed for $($template.Name):"
$failures | Format-Table -Property Name, Group, Errors -AutoSize | Out-String | Write-Host
}
}

if ($hasErrors) {
exit 1
}

Write-Host "All templates validated successfully with ARM-TTK!"

- name: Validate templates with az CLI
shell: pwsh
run: |
cd ${{ github.workspace }}

# Get all ARM JSON templates
$templates = Get-ChildItem -Path "release" -Filter "*.json" -Recurse

$hasErrors = $false

foreach ($template in $templates) {
Write-Host "Validating template with az CLI: $($template.FullName)"

# Skip files that are not ARM templates (like UI definitions)
if ($template.Name -like "*.ui.json") {
Write-Host "Skipping UI definition file: $($template.Name)"
continue
}

# Determine deployment scope based on template content
$templateContent = Get-Content -Path $template.FullName -Raw | ConvertFrom-Json
$deploymentScope = if ($templateContent.resources -and $templateContent.resources[0].type -eq "Microsoft.Resources/deployments") {
# This is likely a subscription level template
"subscription"
} else {
# Default to resource group level
"resourcegroup"
}

# Run appropriate az validate command based on scope
try {
if ($deploymentScope -eq "subscription") {
Write-Host "Running subscription-level validation"
az deployment sub validate --location eastus --template-file $template.FullName --no-prompt
} else {
Write-Host "Running resource-group level validation"
az deployment group validate --resource-group "validation-rg" --template-file $template.FullName --no-prompt
}

if ($LASTEXITCODE -ne 0) {
$hasErrors = $true
Write-Host "::error::Azure CLI validation failed for $($template.Name)"
}
} catch {
$hasErrors = $true
Write-Host "::error::Exception during Azure CLI validation for $($template.Name): $_"
}
}

if ($hasErrors) {
exit 1
}

Write-Host "All templates validated successfully with az CLI!"
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -368,3 +368,4 @@ venv/
ENV/
env/

CLAUDE.md
8 changes: 8 additions & 0 deletions docs-mslearn/toolkit/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ This article summarizes the features and enhancements in each release of the Fin

The following section lists features and enhancements that are currently in development.

### Development tools v13

- **Added**
- Added ARM template validation infrastructure with GitHub Actions workflow and PowerShell script ([#1606](https://github.com/microsoft/finops-toolkit/issues/1606)).
- New `Test-ArmTemplate.ps1` script for local ARM template validation with PSRule, ARM-TTK, and Azure CLI.
- New GitHub Actions workflow for automated ARM template validation in CI/CD (currently manual trigger only, phased rollout planned).
- Supports strict and lenient validation modes for different development scenarios.

### Bicep Registry module pending updates

- Cost Management export modules for subscriptions and resource groups.
Expand Down
148 changes: 148 additions & 0 deletions docs-wiki/Build-and-test.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ On this page:
- [βš™οΈ Building tools](#️-building-tools)
- [🀏 Lint tests](#-lint-tests)
- [🀞 PS -WhatIf / az validate](#-ps--whatif--az-validate)
- [πŸ” Automated ARM template validation](#-automated-arm-template-validation)
- [πŸ‘ Manually deployed + verified](#-manually-deployed--verified)
- [πŸ’ͺ Unit tests](#-unit-tests)
- [πŸ™Œ Integration tests](#-integration-tests)
Expand Down Expand Up @@ -189,6 +190,153 @@ src/scripts/Deploy-Toolkit "<tool-name>" -Build -WhatIf

<br>

## πŸ” Automated ARM template validation

> **Note**: ARM template validation is currently in Phase 1 of rollout and is available for local use only. Automated CI/CD validation is temporarily disabled while we fix existing template validation errors. See issue #1696 for Phase 2 rollout plans.

ARM templates in the repository can be validated using multiple tools to ensure templates meet best practices and will deploy successfully. During Phase 1, validation must be run locally before submitting PRs.

### Phased rollout plan

The ARM template validation is being rolled out in phases to ensure smooth integration:

**Phase 1 (Current)**:
- Validation tools are available for local use only
- CI/CD workflow is disabled to prevent PR failures
- Contributors should run validation locally before submitting PRs
- ARM-TTK is downloaded to `release/.tools/arm-ttk` instead of `.temp`

**Phase 2 (Planned)**:
- Fix all existing template validation errors
- Re-enable CI/CD workflow for automatic PR validation
- All PRs will be required to pass validation checks

### GitHub Actions workflow

The validation workflow will be triggered automatically when a PR includes changes to ARM templates or Bicep files (**currently disabled in Phase 1**). The following validations are performed:

1. **Bicep Linting**: The Bicep linter checks for syntax errors and best practices.
2. **PSRule.Rules.Azure**: [PSRule.Rules.Azure](https://github.com/Azure/PSRule.Rules.Azure) runs comprehensive validation against Azure best practices and security standards.
3. **ARM Template Test Toolkit (ARM-TTK)**: [ARM-TTK](https://learn.microsoft.com/azure/azure-resource-manager/templates/test-toolkit) provides additional checks for common deployment issues.
4. **Azure CLI validation**: Templates are validated using `az deployment validate` to check for syntax errors without actual deployment.

### Running validation locally

To run ARM template validation locally before submitting a PR, use the `Test-ArmTemplate` script:

```powershell
cd "<repo-root>"
src/scripts/Test-ArmTemplate
```

This script will:
1. Validate all ARM templates in the release directory
2. Run checks with PSRule.Rules.Azure
3. Run validation with ARM-TTK
4. Validate templates with Azure CLI

You can also validate a specific template:

```powershell
cd "<repo-root>"
src/scripts/Test-ArmTemplate -TemplatePath "release/finops-hub/azuredeploy.json"
```

Alternatively, you can run individual validation steps manually:

1. **Build the templates**:

```powershell
cd "<repo-root>"
src/scripts/Build-Toolkit "<template-name>"
```

2. **Run PSRule validation** (requires [PSRule.Rules.Azure](https://github.com/Azure/PSRule.Rules.Azure) module):

```powershell
cd "<repo-root>"
Install-Module -Name PSRule.Rules.Azure -Force -Scope CurrentUser
Get-ChildItem -Path "release" -Filter "*.json" -Recurse | Invoke-PSRule -Module PSRule.Rules.Azure
```

3. **Run ARM-TTK** (requires [ARM-TTK](https://github.com/Azure/arm-ttk)):

```powershell
cd "<repo-root>"
# Install ARM-TTK if not already installed
$armTtkPath = "<path-to-arm-ttk>"
Import-Module "$armTtkPath/arm-ttk.psd1"

# Run validation
Get-ChildItem -Path "release" -Filter "*.json" -Recurse | ForEach-Object {
Test-AzTemplate -TemplatePath $_.FullName
}
```

4. **Validate with Azure CLI**:

```powershell
cd "<repo-root>"
$template = "<path-to-json-template>"
az deployment group validate --resource-group "validation-rg" --template-file $template
```

### What's Being Validated

The ARM template validation process helps prevent common deployment failures and ensures templates follow Azure best practices. Here's what each validation tool checks:

#### PSRule.Rules.Azure

PSRule.Rules.Azure validates templates against Azure best practices, including:

- **Security standards**: Ensures resources follow security best practices (e.g., HTTPS enforcement, encryption at rest)
- **Resource configuration**: Validates proper resource naming, tagging, and configuration
- **Parameter usage**: Checks that parameters are properly defined and used
- **API versions**: Ensures recent and stable API versions are used
- **Network security**: Validates network security rules and configurations
- **Diagnostics**: Checks that diagnostic settings are properly configured

#### ARM Template Test Toolkit (ARM-TTK)

ARM-TTK performs additional validation checks including:

- **Template structure**: Validates JSON syntax and schema compliance
- **Parameter files**: Ensures parameter files match template parameters
- **Security**: Checks for hardcoded passwords, secure parameter usage
- **Resource dependencies**: Validates proper use of dependsOn
- **Output usage**: Ensures outputs are properly defined
- **Location handling**: Validates proper use of location parameters
- **Resource naming**: Checks for proper resource naming conventions

#### Azure CLI Validation

Azure CLI validation (`az deployment validate`) performs:

- **Syntax validation**: Checks JSON syntax and ARM template schema
- **Resource provider registration**: Validates required providers are available
- **Quota checks**: Ensures deployment won't exceed subscription quotas
- **Permission validation**: Checks if the deployment has required permissions
- **Parameter validation**: Ensures all required parameters are provided
- **Deployment scope**: Validates resources match the deployment scope

### Validation Modes

The validation script supports two modes:

- **Strict mode** (default): All validation rules are enforced. Use this for production-ready templates.
- **Lenient mode**: Skips certain validation rules that might fail for experimental features or prototypes. Use `-ValidationLevel Lenient` when running `Test-ArmTemplate`.

Rules skipped in lenient mode include:
- Hardcoded values in templates (for quick prototypes)
- Missing parameter definitions (for experimental features)
- Debug deployment settings
- Larger parameter files
- Flexible location handling

This multi-layered validation approach helps catch issues early in the development process, reducing failed deployments and improving template quality.

<br>

## πŸ‘ Manually deployed + verified

Manual verification is always expected; however, we do prefer automated tests. Unit test are preferred with integration tests next. Refer to the details above for how to build and deploy each type of tool.
Expand Down
Loading