Exclude .terraform.lock.hcl from Version Control
Date: 2026-05-10 [Format=YYYY-MM-DD]
Status
- Draft
- Proposed
- Accepted
- Deprecated
- Superseded by 0002
Decision
Exclude the Terraform dependency lock file (.terraform.lock.hcl) from version
control across every Terraform component and blueprint in this repository, and
rely on explicit provider version constraints plus a fresh terraform init in
CI to guarantee reproducible builds.
Context
The OSSF Scorecard Silver criterion build_repeatable
requires that the project's build can be repeated by anyone, from a clean
checkout, without unstated environmental assumptions. Issue
microsoft/edge-ai#166 (build_repeatable — Terraform half) flagged
that the repository excludes .terraform.lock.hcl via .gitignore without a
recorded rationale and without a documented alternative for guaranteeing
reproducibility, which is the artifact that OSSF Silver expects to see.
This repository spans many independent Terraform components and blueprints
(src/000-cloud/..., src/100-edge/..., blueprints/...) and is consumed from
multiple operating systems and CI runners (Linux x86_64, macOS arm64/x86_64,
Windows x86_64, Linux arm64 dev containers). A single committed lock file
records provider package hashes only for the platforms that were initialized
when the file was generated. When a contributor on a different platform runs
terraform init, Terraform either rejects the run with Failed to query available provider packages / checksums previously recorded in the dependency lock file errors, or silently appends new hashes that then drift between
branches — both of which undermine repeatability rather than improve it.
Reproducibility for this repository is instead enforced through:
- Explicit provider version constraints in every component's
versions.tf(orproviders.tf) with pinnedrequired_providers { source, version }blocks, so the resolved provider set is deterministic from the manifest alone. - CI pipelines (
azure-pipelines.yml, GitHub Actions) and the local validation scripts underscripts/always runterraform initfrom a clean working directory, so the provider plugins are re-fetched and re-verified against the registry on every build. - The
npm run tf-validateandnpm run tflint-fix-allworkflows referenced in.github/copilot-instructions.mdexercise this clean-init path locally, matching CI behavior.
Recording this decision closes the documentation gap that build_repeatable
calls out without changing the existing .gitignore behavior or any working
contributor flow.
Decision drivers
- OSSF Scorecard Silver
build_repeatablerequires a documented, repeatable build path; the existing.gitignoreline for.terraform.lock.hclhad no accompanying rationale. - Lock files contain platform-specific provider hashes; committing one
generated on a single OS/arch breaks
terraform initfor contributors and CI runners on other platforms. - The repository contains many independent Terraform working directories; managing a separate lock file per component multiplies the cross-platform hash maintenance burden.
- Provider versions are already pinned in each component's
versions.tf, giving deterministic resolution without the lock file. - CI consistently performs a fresh
terraform initper run, so cached provider state from a committed lock file would not change CI behavior.
Considered options
-
Exclude
.terraform.lock.hcland rely onversions.tfpins (selected)- Good, avoids cross-platform hash conflicts during
terraform init. - Good, keeps the source of truth for provider versions in human-readable
versions.tffiles that already live next to each component. - Good, matches what CI already does (clean init every run).
- Bad, does not record the exact provider package hashes that were used at a given commit; reproducibility depends on the registry continuing to serve the pinned versions.
- Good, avoids cross-platform hash conflicts during
-
Commit a single
.terraform.lock.hclper component- Good, captures exact provider hashes per component.
- Bad, generated on one platform, breaks
terraform initon others unless every contributor runsterraform providers lock -platform=...for the full matrix on every provider bump. - Bad, multiplies maintenance across dozens of components and blueprints.
- Bad, increases churn in PRs unrelated to provider changes.
-
Commit a multi-platform
.terraform.lock.hclper component- Good, addresses the cross-platform hash problem from option 2.
- Bad, requires every contributor (and CI) to run
terraform providers lock -platform=linux_amd64 -platform=linux_arm64 -platform=darwin_amd64 -platform=darwin_arm64 -platform=windows_amd64after any provider change in any component. - Bad, the maintenance cost scales with the number of components and the frequency of provider updates, with no observed benefit over option 1 given that CI re-initializes every run.
-
Pin providers via a private mirror or
dev_overrides- Good, gives full control over which provider artifacts CI consumes.
- Bad, requires standing up and maintaining mirror infrastructure that the project does not currently operate.
- Bad, out of scope for the
build_repeatablegap this ADR addresses.
Decision Conclusion
.terraform.lock.hcl remains excluded from version control via .gitignore.
Reproducibility is provided by pinned required_providers entries in each
component's versions.tf and by CI pipelines that always run a clean
terraform init. This ADR is the recorded rationale required by OSSF Silver
build_repeatable.
Consequences
- The repository satisfies the documentation expectation behind
build_repeatablefor the Terraform portions of the codebase. - Contributors do not need to regenerate or merge
.terraform.lock.hclfiles when working across operating systems or architectures. - Bumping a provider version is a single edit to the relevant
versions.tffollowed byterraform initand validation; there is no lock-file step. - If a pinned provider version is later yanked from the Terraform Registry, builds for that component will break until the pin is updated. This is an accepted trade-off; the registry's published immutability policy makes this rare in practice.
- Any future move to a stricter supply-chain posture (for example, OSSF Gold or a private provider mirror) would supersede this ADR with an option that records exact artifact hashes.
References
- Issue: microsoft/edge-ai#166
- OSSF Scorecard checks:
Build-Repeatable - Terraform docs: Dependency Lock File
.gitignoreentry:.terraform.lock.hcl