Skip to content

Commit

Permalink
feat: PSRule them all (#1392)
Browse files Browse the repository at this point in the history
## Description

- Add a platform workflow to run PSRule analisys on the whole library,
manually and on weekly schedule
   > Example for Reliability check
>
![image](https://github.com/Azure/bicep-registry-modules/assets/56914614/31300522-7eba-4a4f-8760-2e85ef3dfa0e)

- Allow selecting specific WAF pillar in input (defaults to
Azure.Default = all pillars)
>
![image](https://github.com/Azure/bicep-registry-modules/assets/56914614/6462cff7-3be8-492d-bd98-04c5a9f5bf27)
>
![image](https://github.com/Azure/bicep-registry-modules/assets/56914614/8fd5f41a-ed5a-4fa9-863f-bb9dd4fbfd03)

- Fix bug with filtering unique values when listing rules in the job
summary

## Pipeline Reference

<!-- Insert your Pipeline Status Badge below -->

| Pipeline |
| -------- |
|
[![avm.platform.check.psrule](https://github.com/eriqua/bicep-registry-modules/actions/workflows/avm.platform.check.psrule.yml/badge.svg)](https://github.com/eriqua/bicep-registry-modules/actions/workflows/avm.platform.check.psrule.yml)
(test new workflow)|
|
[![avm.res.app-configuration.configuration-store](https://github.com/eriqua/bicep-registry-modules/actions/workflows/avm.res.app-configuration.configuration-store.yml/badge.svg?branch=feat%2Fpsrule-them-all)](https://github.com/eriqua/bicep-registry-modules/actions/workflows/avm.res.app-configuration.configuration-store.yml)
(test usual module validation workflow) |

## Type of Change

<!-- Use the check-boxes [x] on the options that are relevant. -->

- [x] Update to CI Environment or utlities (Non-module effecting
changes)
- [ ] Azure Verified Module updates:
- [ ] Bugfix containing backwards compatible bug fixes, and I have NOT
bumped the MAJOR or MINOR version in `version.json`:
- [ ] Someone has opened a bug report issue, and I have included "Closes
#{bug_report_issue_number}" in the PR description.
- [ ] The bug was found by the module author, and no one has opened an
issue to report it yet.
- [ ] Feature update backwards compatible feature updates, and I have
bumped the MINOR version in `version.json`.
- [ ] Breaking changes and I have bumped the MAJOR version in
`version.json`.
  - [ ] Update to documentation

## Checklist

- [x] I'm sure there are no other open Pull Requests for the same
update/change
- [ ] I have run `Set-AVMModule` locally to generate the supporting
module files.
- [ ] My corresponding pipelines / checks run clean and green without
any errors or warnings

<!-- Please keep up to day with the contribution guide at
https://aka.ms/avm/contribute/bicep -->
  • Loading branch information
eriqua authored Mar 25, 2024
1 parent 8d70f80 commit 45b846e
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 25 deletions.
24 changes: 7 additions & 17 deletions .github/actions/templates/avm-validateModulePSRule/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,6 @@
## This composite action contains the logic to validate a module using a set of PSRule tests
##
#########################################################
##
##-------------------------------------------##
## ACTION PARAMETERS ##
##-------------------------------------------##
##
## |=================================================================================================================================================================|
## | Parameter | Required | Default | Description | Example |
## |--------------------------|----------|---------|--------------------------------------|--------------------------------------------------------------------------|
## | templateFilePath | true | '' | The path to the module PSRule tests. | 'modules/api-management/service/.test/common/main.test.bicep' |
## | subscriptionId | false | '' | The subscriptionId to deploy to | '1a97b80a-4dda-4f50-ab53-349e29344654' |
## | managementGroupId | false | '' | The managementGroupId to deploy to | '1a97b80a-4dda-4f50-ab53-349e29344654' |
## |=================================================================================================================================================================|
##
##---------------------------------------------##

name: "Execute PSRule module tests"
description: "Execute PSRule module tests (if any)"
Expand All @@ -37,6 +23,10 @@ inputs:
psrulePath:
description: "The path to PSRule configurations"
required: false
skipPassedRulesReport:
description: "Show only failed rules in job summary"
required: false
default: $false
psruleBaseline:
description: "The PSRule baseline to be used"
required: true
Expand Down Expand Up @@ -155,9 +145,9 @@ runs:
# Populate parameter input
$ParameterInput = @{
inputFilePath = '${{ inputs.templateFilePath}}-PSRule-output.csv'
outputFilePath = '${{ inputs.templateFilePath}}-PSRule-output.md'
skipPassedRulesReport = $false
inputFilePath = '${{ inputs.templateFilePath}}-PSRule-output.csv'
outputFilePath = '${{ inputs.templateFilePath}}-PSRule-output.md'
skipPassedRulesReport = ${{ inputs.skipPassedRulesReport}}
}
Write-Verbose ('Set PS Rule Output with following parameters:`n{0}' -f (ConvertTo-Json $ParameterInput -Depth 10)) -Verbose
Expand Down
199 changes: 199 additions & 0 deletions .github/workflows/avm.platform.check.psrule.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
name: "avm.platform.check.psrule"

on:
workflow_dispatch:
inputs:
psruleBaseline:
type: choice
description: "PSRule baseline"
required: true
default: "Azure.Default"
options:
- Azure.Default
- Azure.Pillar.CostOptimization
- Azure.Pillar.OperationalExcellence
- Azure.Pillar.PerformanceEfficiency
- Azure.Pillar.Reliability
- Azure.Pillar.Security
skipPassedRulesReport:
type: boolean
description: "Show only failed rules in job summary"
required: true
default: true
schedule:
- cron: "0 12 * * 0" # Weekly Sunday Analysis

env:
workflowPath: ".github/workflows/avm.platform.check.psrule.yml"
targetPath: "avm/res/"
PSRuleOutputFilePath: "avm/res/PSRule-output.csv"
PSRuleInputFilePath: "avm/res/PSRule-output.md"
psRuleFilterRegex: "(defaults|waf-aligned)" # The regex used to filter PSRule compliant files
psrulePath: "avm/utilities/pipelines/staticValidation/psrule"
ARM_SUBSCRIPTION_ID: "${{ secrets.ARM_SUBSCRIPTION_ID }}"
ARM_MGMTGROUP_ID: "${{ secrets.ARM_MGMTGROUP_ID }}"
TOKEN_NAMEPREFIX: "${{ secrets.TOKEN_NAMEPREFIX }}"

jobs:
###########################
# Initialize pipeline #
###########################
job_init_psrule_pipeline:
runs-on: ubuntu-latest
name: "Initialize pipeline"
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set input parameters to output variables
id: get-workflow-param
uses: ./.github/actions/templates/avm-getWorkflowInput
with:
workflowPath: "${{ env.workflowPath}}"
outputs:
workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }}

##############
# PSRule #
##############
job_psrule:
runs-on: ubuntu-latest
name: "PSRule validation"
needs:
- job_init_psrule_pipeline
steps:
# [Init] task(s)
# ---------------------------
- name: Checkout
uses: actions/checkout@v4

- name: Set environment
uses: ./.github/actions/templates/avm-setEnvironment

# [Token replacement] task(s)
# ---------------------------
- name: Replace tokens in relevant files
uses: azure/powershell@v1
with:
azPSVersion: "latest"
inlineScript: |
# Grouping task logs
Write-Output '::group::Replace tokens in relevant files'
# Load used functions
. (Join-Path $env:GITHUB_WORKSPACE 'avm' 'utilities' 'pipelines' 'sharedScripts' 'tokenReplacement' 'Convert-TokensInFileList.ps1')
. (Join-Path $env:GITHUB_WORKSPACE 'avm' 'utilities' 'pipelines' 'sharedScripts' 'Get-LocallyReferencedFileList.ps1')
$targetPath = Join-Path $env:GITHUB_WORKSPACE '${{ env.targetPath }}'
$psRuleFilterRegex = '${{ env.psRuleFilterRegex }}'
Write-Verbose ('targetPath [{0}]' -f $targetPath) -Verbose
# Get target files in target path
$targetFileList = @()
# Retrieve all relevant test files in targetPath
$allTestFiles = (Get-ChildItem -Path $targetPath -Recurse -Filter 'main.test.bicep').FullName | Sort-Object
$relevantTestFiles = $allTestFiles | Where-Object { $_ -match $psRuleFilterRegex }
# Add all relevant test files and related module template files as they may contain tokens
foreach ($relevantTestFile in $relevantTestFiles) {
$targetFileList += $relevantTestFile
$targetFileList += (Get-LocallyReferencedFileList -FilePath $relevantTestFile)
}
$targetFileList = $targetFileList | Sort-Object -Unique
# Construct Token Function Input
$ConvertTokensInputs = @{
FilePathList = $targetFileList
Tokens = @{}
}
# Add enforced tokens
$ConvertTokensInputs.Tokens += @{
subscriptionId = '${{ env.ARM_SUBSCRIPTION_ID }}'
managementGroupId = '${{ env.ARM_MGMTGROUP_ID }}'
}
# Add local (source control) tokens
$tokenMap = @{}
foreach ($token in (Get-ChildItem env: | Where-Object -Property Name -Like "localToken_*")) {
$tokenMap += @{ $token.Name.Replace('localToken_','','OrdinalIgnoreCase') = $token.value }
}
Write-Verbose ('Using local tokens [{0}]' -f ($tokenMap.Keys -join ', ')) -Verbose
$ConvertTokensInputs.Tokens += $tokenMap
# Swap 'namePrefix' token if empty and provided as a GitHub secret
if([String]::IsNullOrEmpty($ConvertTokensInputs.Tokens['namePrefix'])){
Write-Verbose 'Using [namePrefix] token from GitHub' -Verbose
$ConvertTokensInputs.Tokens['namePrefix'] = '${{ env.TOKEN_NAMEPREFIX }}'
}
Write-Verbose "Convert Tokens Input:`n $($ConvertTokensInputs | ConvertTo-Json -Depth 10)" -Verbose
# Invoke Token Replacement Functionality [For Module]
$null = Convert-TokensInFileList @ConvertTokensInputs
Write-Output '::endgroup::'
# [PSRule validation] task(s)
#-----------------------------
- name: Run PSRule analysis
uses: microsoft/[email protected]
with:
modules: "PSRule.Rules.Azure"
prerelease: true
baseline: "${{(fromJson(needs.job_init_psrule_pipeline.outputs.workflowInput)).psruleBaseline }}"
inputPath: "${{(fromJson(needs.job_init_psrule_pipeline.outputs.workflowInput)).targetPath }}"
outputFormat: Csv
outputPath: "${{ env.PSRuleOutputFilePath }}"
option: "${{ github.workspace }}/${{ env.psrulePath}}/ps-rule.yaml" # Path to PSRule configuration options file
source: "${{ env.psrulePath}}/.ps-rule/" # Path to folder containing suppression rules to use for analysis.
summary: false # Disabling as taken care in customized task

# [Print to Summary] task(s)
#-----------------------------
- name: Parse CSV content
if: always()
uses: azure/powershell@v1
with:
azPSVersion: "latest"
inlineScript: |
# Grouping task logs
Write-Output '::group::Parse CSV content'
# Load used functions
. (Join-Path $env:GITHUB_WORKSPACE 'avm' 'utilities' 'pipelines' 'staticValidation' 'psrule' 'Set-PSRuleGitHubOutput.ps1')
# Populate parameter input
$ParameterInput = @{
inputFilePath = '${{ env.PSRuleOutputFilePath }}'
outputFilePath = '${{ env.PSRuleInputFilePath }}'
skipPassedRulesReport = [System.Convert]::ToBoolean('${{(fromJson(needs.job_init_psrule_pipeline.outputs.workflowInput)).skipPassedRulesReport }}')
}
Write-Verbose ('Set PS Rule Output with following parameters:`n{0}' -f (ConvertTo-Json $ParameterInput -Depth 10)) -Verbose
# Invoke Set PSRule Output Functionality
$null = Set-PSRuleGitHubOutput @ParameterInput
Write-Output '::endgroup::'
- name: Output to GitHub job summaries
if: always()
shell: pwsh
run: |
# Grouping task logs
Write-Output '::group::Output to GitHub job summaries'
$mdPSRuleOutputFilePath = Join-Path $env:GITHUB_WORKSPACE '${{ env.PSRuleInputFilePath }}'
if (-not (Test-Path $mdPSRuleOutputFilePath)) {
Write-Warning ('Input file [{0}] not found. Please check if the previous task threw an error and try again.' -f $mdPSRuleOutputFilePath)
return ''
} else {
Get-Content $mdPSRuleOutputFilePath >> $env:GITHUB_STEP_SUMMARY
Write-Verbose ('Successfully printed out file [{0}] to Job Summaries' -f $mdPSRuleOutputFilePath) -Verbose
}
Write-Output '::endgroup::'
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,9 @@ function Set-PSRuleGitHubOutput {
Write-Warning ('Input File [{0}] not found' -f $inputFilePath)
return ''
} else {

$results = Import-Csv -Path $inputFilePath

$passedRules += $results | Where-Object { $_.Outcome -EQ 'Pass' } | Sort-Object -Property 'RuleName' -Unique
$failedRules += $results | Where-Object { $_.Outcome -EQ 'Fail' } | Sort-Object -Property 'RuleName' -Unique
$passedRules += $results | Where-Object { $_.Outcome -EQ 'Pass' } | Sort-Object -Property 'TargetName','RuleName' -Unique
$failedRules += $results | Where-Object { $_.Outcome -EQ 'Fail' } | Sort-Object -Property 'TargetName','RuleName' -Unique

######################
# Set output content #
Expand Down Expand Up @@ -92,7 +90,7 @@ function Set-PSRuleGitHubOutput {
foreach ($content in $failedRules ) {
# Shorten the target name for deployment resoure type
if ($content.TargetType -eq 'Microsoft.Resources/deployments') {
$content.TargetName = $content.TargetName.replace('/home/runner/work/ResourceModules/ResourceModules/modules/', '')
$content.TargetName = $content.TargetName.replace('/home/runner/work/bicep-registry-modules/bicep-registry-modules/avm/', '')
}

# Build hyperlinks to PSRule documentation for the rules
Expand Down Expand Up @@ -131,7 +129,7 @@ function Set-PSRuleGitHubOutput {
foreach ($content in $passedRules ) {
# Shorten the target name for deployment resoure type
if ($content.TargetType -eq 'Microsoft.Resources/deployments') {
$content.TargetName = $content.TargetName.replace('/home/runner/work/ResourceModules/ResourceModules/modules/', '')
$content.TargetName = $content.TargetName.replace('/home/runner/work/bicep-registry-modules/bicep-registry-modules/avm/', '')
}

# Build hyperlinks to PSRule documentation for the rules
Expand Down
5 changes: 3 additions & 2 deletions avm/utilities/pipelines/staticValidation/psrule/ps-rule.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ input:
pathIgnore:
# Exclude all files.
- "*"
# Only process test files.
- "!avm/**/*.test.bicep"
# Only process defaults and waf-aligned test files.
- "!avm/**/defaults/*.test.bicep"
- "!avm/**/waf-aligned/*.test.bicep"

configuration:
# Enable automatic expansion of Azure parameter files.
Expand Down

0 comments on commit 45b846e

Please sign in to comment.