Validate Spoke Files in a Pull Request¶
Spoke files are flexible and have many fields. That makes a wrong configuration easy to write and expensive to find at deployment time. A validation pipeline checks every spoke file when a pull request is created or updated, and blocks the merge when a file is wrong. This page describes what such a pipeline checks, how to set it up in Azure DevOps and which parts of the JSON schema you customise per organisation.
Relation to the config tests
The platform pipelines run config tests before every deployment (Pipelines),
and you can run them locally (Run the tests locally). The validation
pipeline on this page is the same idea, earlier: it runs on the pull request, so the author and the reviewer see the
problem before the merge. It is part of the spoke canvas of earlier versions. Check whether your code version ships it
(Scripts folder of the code repository) before you set it up.
What it checks¶
The script reads all spoke files below the spoke folder and tests each one:
| Test | Result |
|---|---|
| The file is valid JSON | Fails with the position of the error |
| The file complies with the spoke schema | Fails with the file and the part of the configuration that is wrong |
The isprivatelinksubnet setting is correct for every virtual network |
Fails when it is not |
| The file name matches the intended environment | Fails when, for example, a production environment is in a non-production file name |
Everything else in a spoke file is not checked and needs the manual review (Spoke pull request review). The pipeline output tells you which files failed and, on selecting a failed item, the issues in it.
Components¶
| What | Repository | Remark |
|---|---|---|
| Validation script (a PowerShell script) | Code repository | Part of the platform. Do not change it in your copy. |
| Pipeline file | Configuration repository | A starter file exists. Adapt it. |
spokeschema.json |
Configuration repository | A starter file exists. Adapt it, see Customise the schema. |
.vscode/settings.json |
Configuration repository | Binds the schema to the spoke files in Visual Studio Code (Edit the JSON files with schema support). |
Set up the pipeline¶
- Create a pipeline from the existing YAML file in the configuration repository. Name it, for example,
VerifySpokeFiles. - Run it once by hand and authorise the pipeline to use the variable group, the agent pool and the service connection. Scheduled and triggered runs cannot ask for that approval.
- Update the pipeline file (next section).
- Add the pipeline as build validation to the branch policy of
main(below).
Pipeline file¶
The file has no trigger of its own (trigger: none). It checks out the configuration repository and the code repository at a
version tag, and runs the script with these arguments. A short, anonymised excerpt:
trigger: none
variables:
- group: <variable-group-of-the-spoke-deployment>
resources:
repositories:
- repository: spokedeployment-tf
type: git
name: "<project>/<code-repository>"
ref: refs/tags/<version> # update with every new code version
steps:
- checkout: self
path: s/spokedeployment-params
- checkout: spokedeployment-tf
path: s/spokedeployment-tf
- task: AzurePowerShell@5
displayName: "Verify SpokeFiles"
inputs:
azureSubscription: $(ServiceConnectionName)
ScriptType: "FilePath"
ScriptPath: $(System.DefaultWorkingDirectory)/spokedeployment-tf/Scripts/<validation-script>.ps1
ScriptArguments: -SpokeFilePath <spoke-folder> -SpokeSchemaPath <schema-file> -ProdEnvironmentsList "acc,prd,prod" -NonProdEnvironmentsList "dev,tst,test" -ExludedFilenames ""
pwsh: true
Update at least these:
| Item | What to do |
|---|---|
| Variable group | Only when its name differs from the variable group of your spoke deployment. |
ref of the code repository |
Set to the tag of the code version you run, and change it with every upgrade (What to do when a new version is released). |
SpokeFilePath |
The folder with the spoke files. Normally leave the default of the starter file. |
SpokeSchemaPath |
The path of your spokeschema.json. Normally leave the default. |
ProdEnvironmentsList |
Comma-separated environments that count as production. Default in the starter file: acc,prd,prod. |
NonProdEnvironmentsList |
Comma-separated environments that count as non-production. Default: dev,tst,test. |
ExludedFilenames |
Comma-separated file names that are not verified. Normally empty. The parameter name is spelled like this in the script. |
Require it on main¶
In Azure DevOps: Repos, Branches, the main branch, Branch policies, Build validation, add the pipeline. Then every
pull request, and every new commit in it, starts the check, and a failed check blocks the approval. Set it as required.
Customise the schema¶
The starter spokeschema.json follows the general structure of the spoke JSON. Most
organisations share the same structure and differ in a few allowed values. Update these three:
| Property | What it holds | Customise |
|---|---|---|
environment |
An enum with the allowed environment names |
The environments you use, for example dev, tst, acc, prd. Keep it in line with ProdEnvironmentsList and NonProdEnvironmentsList. |
managementGroupId |
An enum with the management groups in which a spoke subscription may be placed |
The names of your landing zone management groups. They must exist in the hub configuration (Spoke JSON reference). |
tags |
An object with the allowed tags, and a required list |
Your tag set. Put a tag in required when a missing tag must fail the check. See Naming and tags. |
An excerpt, with placeholders:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Schema for spoke canvas deployment",
"type": "object",
"properties": {
"workloadShortName": { "type": "string", "maxLength": 6 },
"environment": { "type": "string", "enum": ["dev", "tst", "acc", "prd"] },
"managementGroupId": {
"type": "string",
"enum": ["<prefix>-landingzone-corp-prd", "<prefix>-landingzone-online-prd"]
},
"tags": {
"type": "object",
"properties": { "owner": { "type": "string" }, "pii": { "type": "string", "enum": ["yes", "no"] } },
"required": ["owner", "department", "workload", "pii", "costcentre", "environment"]
}
}
}
The full schema also describes adInfo (member lists, PIMGroupConfig with the values nopim, self-approve and
approval, and the allowed SPNGraphPermissions), targetRegions, azdo and resourceconfiguration. Take the schema of
your code version as the base and keep it current after each upgrade, because the schema must accept every field the
Terraform reads (Known issues).
In the editor¶
Bind the schema to the spoke files in .vscode/settings.json, so authors see mistakes while they type: an issue is underlined
and Ctrl+Space suggests values.
{
"json.schemas": [
{ "fileMatch": ["/**/canvas_*.json"], "url": "./spokeschema.json" }
]
}
More on this in Edit the JSON files with schema support.