Linter for Azure Policy Definitions that surfaces known issues, gotchas, and best practices.
Azure Policy allows users to define, assign and manage policies that apply to their Azure resources. Policies can define various effects to determine what action the policy should take when a non-compliant resource is being created/updated. Policies are also evaluated periodically against all existing resources to produce compliance data.
Writing a good policy requires a deep knowledge of the capabilities of the policy language, policy effects, as well as the API of the resources each policy is targeting. This knowledge is scattered across multiple sources, and in cases such as resource API behavior, might not be documented at all. The linter project is meant to codify this knowledge and surface it as actionable error/warning/informational findings on a specific policy definition.
Install the Microsoft.Azure.Policy.PolicyLinter.Cli CLI as a global .NET tool:
dotnet tool install --global Microsoft.Azure.Policy.PolicyLinter.Cli
Then invoke it as policylinter (see Usage). To consume the linter as a library, reference the Microsoft.Azure.Policy.PolicyLinter.Core package. Alternatively, build from source.
The linter supports processing single or multiple policy definition files:
policylinter c:\path\to\policyDefinition.json
- Processes up to 1,000 files in a single run
policylinter c:\path\to\policy1.json c:\path\to\policy2.json c:\path\to\policy3.json
policylinter c:\path\to\policy1.json c:\path\to\policy2.json --output results.json
or
policylinter c:\path\to\policy1.json -o results.json
The linter organizes rules into rule sets for different linting scenarios. By default, the linter uses the "default" rule set which includes general-purpose rules.
List available rule sets:
policylinter --list-rule-sets
Apply a specific rule set:
policylinter policy.json --rule-set <RuleSetName>
Apply multiple rule sets:
policylinter policy.json --rule-set <RuleSetName> --rule-set default
Each rule has a corresponding documentation file in the docs/Rules/ directory.
policylinter --help
The linter accepts either a full policy definition resource payload or a JSON containing just the policy definition property bag. When processing multiple files, the linter processes them in parallel for improved performance and provides file-specific results.
The exit code indicates whether the linter successfully performed the requested operation, not whether the policy definition is valid. Policy issues, including parsing errors and lint findings of any severity, are reported through diagnostics and do not affect the exit code. A non-zero exit code indicates that the linter could not complete the operation, such as when an input file could not be read or the output could not be written.
- No support for the more obscure leaf expressions like
source. - No support for data-plane policies.
- No support for effect details.
- docs/linter-rule-design.md - what a good linter rule should be: scope, severity, naming, and description conventions.
- docs/linter-architecture.md - how the linter works in code and what it takes to add a rule.
- docs/Rules/ - per-rule documentation, one file per rule.
Requires the .NET SDK version pinned in global.json.
Build the solution:
dotnet build src/dirs.proj --configuration Release
Run the CLI directly from source:
dotnet run --project src/PolicyLinter.Cli -- <path-to-policy-json>
There is no standalone
.exesince the Cli is modeled as a dotnet tool; run the CLI viadotnet run(or the installedpolicylintercommand).
Run the tests:
dotnet test src/Tests/PolicyLinter.Tests.csproj
To open the repository in an editor, use the helper scripts at the repo root:
vs.cmd- restores packages, generatesdirs.slnvia slngen, and opens Visual Studio. Pass--no-launchto generate the solution without opening Visual Studio.vsc.cmd- restores packages, generatesdirs.slnvia slngen, and opens the repository in Visual Studio Code. The C# Dev Kit extension uses the solution file to load the full project structure.
To pack the CLI and install it as a global .NET tool (so you can invoke policylinter directly). Run these from the repository root:
Both NuGet packages take their version from <Version> in Directory.Build.props.
-
Uninstall any existing global install first - the local install will fail otherwise:
dotnet tool uninstall -g Microsoft.Azure.Policy.PolicyLinter.CliIf
dotnet tool installlater fails with thepolicylintercommand already in use, a tool installed under a different package id owns the command; rundotnet tool list -gto find it and uninstall that id too. -
Pack the CLI:
dotnet pack src/PolicyLinter.Cli/PolicyLinter.Cli.csproj --configuration Release -o <output-path> -
Install from the local output:
dotnet tool install -g Microsoft.Azure.Policy.PolicyLinter.Cli --add-source <output-path> --no-cache -
Run:
policylinter <path-to-policy-json>
- docs/linter-rule-design.md - what a good rule looks like (scope, severity, naming, description).
- docs/linter-architecture.md - how rules are wired up in the code.
- .github/skills/triage-linter-rule/ - interactive skill to turn an idea into a spec.
- .github/skills/implement-linter-rule/ - interactive skill to implement a rule from a spec.
- Every rule should have a doc file in docs/Rules/ and at least one unit test.
We are not accepting pull requests at this time. However, we welcome all feedback, bug reports, issues, and suggestions. Please feel free to open an issue to share your thoughts or report any problems you encounter. For more information about contributing, please see our Contributing guidelines.
This project is licensed under the MIT License - see LICENSE file for details.
For issues, questions, or suggestions, please open an issue on GitHub.
For security issues, please see our Security policy.
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft's Trademark & Brand Guidelines. Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies.
