Testing your Bicep modules with PSRule is a great way to identify that your code is meeting Azure best practice.
But how do you actually test your Bicep modules with PSRule properly?
How can you structure your Git repository?
How can I configure PSRule to test the modules? Can I document what the modules do, and their params?
I’ll go into depth on this below ?
All of the content shared here is uploaded to my GitHub repository which can be found here: bicep-module-tests/ at main · riosengineer/bicep-module-tests (github.com).
The problem
PSRule cannot run reliably against your actual Bicep templates. Errors like "The parameter named 'someParam' was not set or a defaultValue was defined."
may be familiar if you’ve stumbled across this post.
Why? PSRule needs actual parameter values in order to expand and run the ruleset to determine what could be deployed. The PSRule creator Bernie White explains this well in this GitHub issue: Expansion & defaultValues · microsoft/PSRule · Discussion #1256 (github.com)
With this in mind, it’s best to try and not run PSRule directly against your Bicep templates to get a more reliable CI pipeline experience.
Repository structure
.
└── bicep/
├── modules/
│ ├── storageAccount/
│ │ ├── storageAccount.bicep
│ │ ├── metadata.json
│ │ └── README.md
│ └── .tests/
│ └── storageAccount.tests.bicep
└── prod/
├── main.bicep
└── prd.bicepparam
By structuring the repository like the above example we’re going to be able to target PSRule to run against the ‘.tests’ files to get a consistent scan output on our Azure best practices.
This will mean we can get PSRule to scan the module and tell us if there’s any best practice gaps we may want to consider adding to the module.
You can see we have a sub-modules folder for in-line Bicep modules. We also have a separate folder for our actual deployments which reference our modules as seen in the example above. This means we can shift a lot of the scanning onto the tests file and off the templates that may be problematic, this is because the modules will be called by the main templates for deployments.
Tests file
The test file will comprise of only the required parameters with actual values populated. As mentioned earlier, this will ensure PSRule can fully scan the code and analyse it for us.
The test file needs to be within it’s own sub-folder of the module like the above structure hierarchy.
Here’s an example test Bicep module file:
// Test with only required parameters
module test_required_params '../storageAccount.bicep' = {
name: 'test_required_params'
params: {
location: 'uksouth'
tags: {
Demo: 'Rios Engineer Blog'
}
storageName: 'riosengineerst001'
storageSkuName: 'Standard_GRS'
storagePleBlobName: 'someBlob'
storagePleFileName: 'someFileshare'
subnetId: 'test'
virtualNetworkId: 'test'
}
}
BICEPBicep Module(s)
The Bicep modules are located within an inline ‘modules’ folder, separating out each module like so:
└── bicep/
└── modules/
├── storageAccount/
├── storage.bicep
└── metadata.json
Metadata
A great way to display the parameters of the module, along with all relevant metadata & descriptions is to have a readme present in the module folder. This helps other people understand the module, and it’s parameters. This metadata json file sits within the modules/storageAccount folder (as seen above in the structure).
Here’s an example of what the metadata.json
file looks like:
{
"itemDisplayName": "Storage Account Module.",
"description": "Storage Account Bicep Module",
"summary": "Storage Account Bicep standard for deployments"
}
JSONWith this JSON file we can run an absolutely AWESOME readme script created by Microsoft MVP Tao Yang which auto-generates a markdown file with all the information. Tao’s blog on how this works is here: Generating README for Bicep Files – Managing Cloud and Datacenter by Tao Yang (tyang.org)
I would highly recommend you head over there and check it out.
Here’s a sample output from my example module:
Azure DevOps Pipeline
Next is the ADO pipeline, you’ll need to install the PSRule extension into your Organisation if you haven’t got it already for this to work. Additionally, you’ll likely need a build validation policy so this will trigger on PR automatically. I’ve written a guide about that before here.
In my example Repository in GitHub you can find the structure on all of this so far, and also the pipeline file like so:
bicep-module-tests/bicep-ci.yaml at main · riosengineer/bicep-module-tests (github.com)
---
trigger: none
name: $(SourceBranchName)_$(date:yyyyMMdd)$(rev:.r)
pool:
vmImage: "ubuntu-latest"
jobs:
- job: 'PSRuleAnalysis'
displayName: "Run PSRule analysis"
steps:
- task: bewhite.ps-rule.assert.ps-rule-assert@2
inputs:
source: "$(System.DefaultWorkingDirectory)/ps-rule.yaml"
modules: PSRule.Rules.Azure, PSRule.Rules.CAF, PSRule.Rules.Kubernetes
outputFormat: Sarif
outputPath: "reports/ps-rule-results.sarif"
YAMLThis file needs to be part of your build validation so you can run PSRule when changes are made to existing modules, or new ones added to the repository.
PSRule module scan failure
Amending my tests file to have storageSkuName: 'Standard_LRS'
we can see the pipeline gives us a best practice recommendation from PSRule:
PSRule module scan success
However, when changing the value to storageSkuName: 'Standard_GRS'
we can see the pipeline is happy with the Bicep module:
Have you considered creating a getting started with Bicep series?
I like your blog/repo, but I am pretty new to bicep.
Hey Mark,
I am thinking of doing a ‘Did you know’ Bicep series, which should hopefully cover some of that aspect. There is a ton of really useful information on the Docs on Bicep on getting started. However, my focus will be around the lesser documented methods, tips and tricks, etc. Follow me on LinkedIn to stay tuned 🙂
Thank you for your kind words,
Dan
Hi Mark,
Just an update for you, I’ve started a new GitHub repository for getting started with Bicep and will continually add content over the coming months/years. Feel free to check it out, star/follow or fork if you want to test and demo some of the examples. https://github.com/riosengineer/Bicepify