pre-commit
pre-commit is a framework that runs checks on the files of a commit before Git records it. Every Azure repository ships a .pre-commit-config.yaml, so the formatting, scanning and layout checks CI will run fail on the engineer's machine first.
What it does
pre-commit install adds a Git hook; on each commit the framework runs the hooks listed in .pre-commit-config.yaml against the staged files that match each hook's pattern. Hooks come from remote repositories pinned by tag or from local scripts in the repository. pre-commit run --all-files runs every hook on the whole tree. The Baseline pins pre-commit 4.3.0.
How BuiltForProd uses it
| Repositories | Hooks |
|---|---|
| Azure Enterprise Baseline, web app and ETL infrastructure | pre-commit-hooks v6.0.0 (whitespace, end of file, YAML, merge conflicts, private keys); pre-commit-opentofu v2.4.2 (tofu_fmt, tofu_validate, tofu_docs); pre-commit-terraform v1.109.1 (terragrunt_fmt, terraform_tflint, terraform_trivy); Checkov 3.3.19; the local guard scripts |
| Web app and ETL code | pre-commit-hooks v6.0.0 with JSON checks; ruff v0.16.10 (ruff, ruff-format), the same version CI pins; Checkov 3.3.22 |
| Secrets | check-yaml (not on the encrypted stage files), detect-private-key, end-of-file-fixer, and the local sops-encrypted hook |
The generated .terragrunt-cache/ and .terragrunt-stack/ folders are excluded from every hook. The sops-encrypted hook refuses any stage file without a sops: block, so a plaintext value cannot be committed by accident; see SOPS.
Guard scripts. Local hooks run Python scripts from scripts/, the same ones the lint-and-scan job of plan.yml runs:
| Script | Blocks | Repositories |
|---|---|---|
check-no-hardcoded-cidrs.py | A private address range written in HCL or OpenTofu instead of coming from the address plan | Baseline |
check-vnet-maps.py | An invalid, overlapping or mis-nested range in either VNet map, or an Azure-reserved subnet name | Baseline |
check-mock-outputs.py | A dependency without complete mock outputs, which could not be planned before it exists | All three infrastructure |
check-stack-layout.py | A region folder without a stack file, an unreferenced unit definition, a hand-written unit under environments/ | All three |
check-module-versions.py | A module versions.tf that does not repeat the pins of root.hcl | All three |
check-required-inputs.py | A generated unit that does not supply every required variable of its module | All three |
The scanners these hooks call are described in Checkov, Trivy and tflint. A hook that a developer skips locally still runs in CI, so pre-commit saves a round trip rather than replacing the gate.
Terms you will see
| Term | Meaning |
|---|---|
| Hook | One check pre-commit runs on matching staged files. |
| Local hook | A hook that runs a script from the repository itself. |
| Guard script | A scripts/check-*.py that enforces a platform convention. |
rev | The pinned tag of a remote hook repository. |
| Address plan | vnet_map.yaml, the only place address ranges are written. |
Where to read more
- Azure Enterprise Baseline overview and the Azure Secrets Blueprint overview.
- Checkov, Trivy and tflint for the scanners.
- Policy as code for checks as code.