Skip to content
Draft
Show file tree
Hide file tree
Changes from 3 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
155 changes: 155 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/setup-bicep@v0.5

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,155 @@
name: 'ARM Template Validation'

on:
pull_request:
paths:
- 'src/templates/**'
- 'src/bicep-registry/**'
- '.github/workflows/arm-template-validation.yml'

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@v1

- name: Setup Bicep
uses: anthony-c-martin/setup-bicep@v0.5

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

- name: Download ARM-TTK
shell: pwsh
run: |
cd ${{ github.workspace }}
$armTtkPath = "./arm-ttk"
New-Item -Path $armTtkPath -ItemType Directory -Force
Invoke-WebRequest -Uri "https://github.com/Azure/arm-ttk/archive/refs/heads/master.zip" -OutFile "./arm-ttk.zip"
Expand-Archive -Path "./arm-ttk.zip" -DestinationPath $armTtkPath -Force
Import-Module "$armTtkPath/arm-ttk-master/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!"
57 changes: 57 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,62 @@ src/scripts/Deploy-Toolkit "<tool-name>" -Build -WhatIf

<br>

## πŸ” Automated ARM template validation

ARM templates in the repository are automatically validated using GitHub Actions as part of the PR process. This validation includes multiple checks to ensure templates meet best practices and will deploy successfully.

### GitHub Actions workflow

The validation workflow is triggered automatically when a PR includes changes to ARM templates or Bicep files. 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:

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
```

<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