Skip to content

build(terraform): record linux and darwin provider hashes in every lock file, init env roots with -lockfile=readonly - #1439

Merged
IAmJSD merged 4 commits into
LeanerCloud:mainfrom
IAmJSD:fix/issue-1435
Oct 26, 2026
Merged

IAmJSD merged 4 commits into
LeanerCloud:mainfrom
IAmJSD:fix/issue-1435

Conversation

@IAmJSD

@IAmJSD IAmJSD commented Oct 26, 2026

Copy link
Copy Markdown
Collaborator

Closes #1435

Root cause

24 of the 42 committed .terraform.lock.hcl files recorded one platform's h1: hash per provider (darwin, from whoever ran terraform init), and most of the rest recorded three. On Linux, terraform init -lockfile=readonly then terraform validate fails with "the cached package ... does not match any of the checksums recorded in the dependency lock file", and a plain init quietly adds the Linux hashes to the working copy. CI never noticed because its Terraform Init step for the environment roots ran a plain terraform init -backend=false.

Fix

  • Regenerated all 42 lock files with terraform providers lock -platform=linux_amd64 -platform=linux_arm64 -platform=darwin_arm64 -platform=darwin_amd64 (Terraform 1.10.5). Roots that call local modules needed terraform get first. These diffs are mechanical: they add h1: lines and refresh the constraints = ... line terraform writes for the current config. No provider version changed (all 81 provider/version pairs compared before and after), and no existing h1:/zh: line was removed. I did all 42, not only the 24 single-platform ones, because the three-hash files were also missing a platform.
  • .github/workflows/ci.yml (terraform-validate job): Terraform Init now runs terraform init -backend=false -lockfile=readonly -input=false. Test CI/CD trust (immutable ids) also gets -lockfile=readonly. Its comment said that lock file is gitignored, but all three are committed (terraform/.gitignore re-includes them).
  • New terraform/lock_platforms_test.go (TestLockFilesRecordEveryPlatform): fails when a lock file under terraform/ or iac/federation/ records fewer than 4 h1: hashes for a provider. A lock file doesn't say which platform a hash is for, so this only checks the count. CI's readonly init on linux_amd64 is the check for the platform itself.

Commits are split by area (federation / environments / modules / CI + test). Each is under 400 lines.

The deploy workflows still use plain terraform init -backend-config=.... I left them alone because they're outside the issue's acceptance criteria, and they now find the linux_arm64/amd64 hashes already present.

Verification

All local, on linux/amd64 with Terraform 1.10.5. No plan or apply, and no real backends (-backend=false throughout).

  • Fail-before, strict init: on origin/main (6b586cc), terraform/modules/build: terraform init -backend=false -lockfile=readonly then terraform validate gives Error: registry.terraform.io/hashicorp/external: the cached package ... does not match any of the checksums recorded in the dependency lock file. On this branch: Success! The configuration is valid.
  • Fail-before, Go guard: go test ./terraform/ -run TestLockFilesRecordEveryPlatform against main's lock files fails, listing every under-hashed provider (e.g. terraform/modules/build/.terraform.lock.hcl: registry.terraform.io/hashicorp/external (1 h1: hashes), want 4). It passes on this branch.
  • Every root, strict: for each of the 42 lock-file roots, I ran terraform init -backend=false -lockfile=readonly -input=false and terraform validate, with a throwaway TF_DATA_DIR. All 42 passed, and the worktree stayed clean, so no lock file was rewritten. For the 16 roots with a tests/ dir, terraform test also passed: environments aws 9, azure 3, azure/ci-cd-permissions 2, gcp 3, gcp/ci-cd-permissions 13; iac azure-target 24; modules compute/aws/fargate 1, compute/aws/lambda 15, compute/azure/aks 9, database/azure 2, database/gcp 2, deployment-checks 4, monitoring/aws 5, monitoring/azure 1, monitoring/gcp 2, networking/aws 3 (counts are tests passed).
  • actionlint .github/workflows/ci.yml: clean.
  • go build ./... && go vet ./... && go vet -tags integration ./... && (cd tests/e2e && go vet -tags e2e ./...): OK. golangci-lint run ./terraform/... with and without --build-tags integration: 0 issues. go test -race -short -count=1 ./terraform/... and go test -race -tags integration -count=1 ./terraform/...: ok.
  • Secrets scan on the changed files: clean. scripts/test-git-secrets-allowlist.sh: 183 PASS.

Not verified locally: linux_arm64 and darwin. Their hashes come from terraform providers lock against the public registry, and I had no arm64 or macOS runner to init on. CI's run of the edited workflow steps is also still to come.

Conflicts to expect

Open PRs #1086, #1090, #1309 and #1312 also edit lock files (database/aws, networking/aws, compute/azure/{aks,container-apps}, compute/gcp/cloud-run). Whichever lands second should regenerate that lock file with the four-platform command above rather than hand-merge it. Once this lands, TestLockFilesRecordEveryPlatform and the readonly init will flag any lock file that loses a platform.

🤖 Generated with Claude Code

IAmJSD and others added 4 commits October 26, 2026 05:22
…files

The federation roots' lock files recorded one platform's h1: hash per
provider, so `terraform init -lockfile=readonly` and `terraform validate`
failed on Linux and a plain init rewrote the lock file (LeanerCloud#1435).
Regenerated with `terraform providers lock` for linux_amd64, linux_arm64,
darwin_arm64 and darwin_amd64. Provider versions are unchanged; the
constraints lines are what terraform writes for the current config.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… files

Same regeneration as the federation roots (LeanerCloud#1435), for the three
environment roots and their ci-cd-permissions roots. CI initialises the
environment roots on linux_amd64 and the deploy jobs run on linux_arm64,
so both need hashes before init can be made strict. Provider versions are
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Same regeneration (LeanerCloud#1435) for every module lock file. Modules without
Linux hashes could not get readonly-init tests in CI without a lock fix
first, as LeanerCloud#1086 found for modules/database/aws. Provider versions are
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A plain `terraform init` quietly adds the runner's hashes to a lock file
that lacks them, which is how single-platform lock files went unnoticed
(LeanerCloud#1435). The Terraform Init and CI/CD trust steps now use
-lockfile=readonly, so a lock file without linux_amd64 hashes fails the
job. The ci-cd-permissions comment said its lock file is gitignored; it
is committed.

TestLockFilesRecordEveryPlatform also fails when a committed lock file
records fewer than four h1: hashes per provider, which catches a
single-platform lock in the unit tests before CI's init runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@IAmJSD IAmJSD added impact/internal Team-internal only type/chore Maintenance / non-user-visible priority/p3 Polish / idea / may never ship severity/low Minor harm urgency/this-quarter Within the quarter effort/s Hours triaged Item has been triaged labels Oct 26, 2026
@coderabbitai

coderabbitai Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

  • Run on-demand review

This review includes 44 billable files and costs up to $11.00.

Or wait 59 minutes for your next included review.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
Commits

Reviewing files that changed from the base of the PR and between c8bb869 and ce84481.

Files selected for processing: 44
  • .github/workflows/ci.yml
  • iac/federation/aws-cross-account/terraform/.terraform.lock.hcl
  • iac/federation/aws-target/terraform/.terraform.lock.hcl
  • iac/federation/azure-target/terraform/.terraform.lock.hcl
  • iac/federation/gcp-sa-impersonation/terraform/.terraform.lock.hcl
  • iac/federation/gcp-target/terraform/.terraform.lock.hcl
  • terraform/environments/aws/.terraform.lock.hcl
  • terraform/environments/aws/ci-cd-permissions/.terraform.lock.hcl
  • terraform/environments/azure/.terraform.lock.hcl
  • terraform/environments/azure/ci-cd-permissions/.terraform.lock.hcl
  • terraform/environments/gcp/.terraform.lock.hcl
  • terraform/environments/gcp/ci-cd-permissions/.terraform.lock.hcl
  • terraform/lock_platforms_test.go
  • terraform/modules/build/.terraform.lock.hcl
  • terraform/modules/compute/aws/cleanup-lambda/.terraform.lock.hcl
  • terraform/modules/compute/aws/fargate/.terraform.lock.hcl
  • terraform/modules/compute/aws/lambda/.terraform.lock.hcl
  • terraform/modules/compute/azure/aks/.terraform.lock.hcl
  • terraform/modules/compute/azure/cleanup-function/.terraform.lock.hcl
  • terraform/modules/compute/azure/container-apps/.terraform.lock.hcl
  • terraform/modules/compute/gcp/cleanup-function/.terraform.lock.hcl
  • terraform/modules/compute/gcp/cloud-run/.terraform.lock.hcl
  • terraform/modules/compute/gcp/gke/.terraform.lock.hcl
  • terraform/modules/database/aws/.terraform.lock.hcl
  • terraform/modules/database/azure/.terraform.lock.hcl
  • terraform/modules/database/gcp/.terraform.lock.hcl
  • terraform/modules/deployment-checks/.terraform.lock.hcl
  • terraform/modules/email/azure/.terraform.lock.hcl
  • terraform/modules/frontend/aws/.terraform.lock.hcl
  • terraform/modules/frontend/azure/.terraform.lock.hcl
  • terraform/modules/frontend/gcp/.terraform.lock.hcl
  • terraform/modules/iam/azure/cudly-reservation-role/.terraform.lock.hcl
  • terraform/modules/monitoring/aws/.terraform.lock.hcl
  • terraform/modules/monitoring/azure/.terraform.lock.hcl
  • terraform/modules/monitoring/gcp/.terraform.lock.hcl
  • terraform/modules/networking/aws/.terraform.lock.hcl
  • terraform/modules/networking/azure/.terraform.lock.hcl
  • terraform/modules/networking/gcp/.terraform.lock.hcl
  • terraform/modules/registry/aws/.terraform.lock.hcl
  • terraform/modules/registry/azure/.terraform.lock.hcl
  • terraform/modules/registry/gcp/.terraform.lock.hcl
  • terraform/modules/secrets/aws/.terraform.lock.hcl
  • terraform/modules/secrets/azure/.terraform.lock.hcl
  • terraform/modules/secrets/gcp/.terraform.lock.hcl
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@IAmJSD

IAmJSD commented Oct 26, 2026

Copy link
Copy Markdown
Collaborator Author

Opened at head ce844810603509a0b765682234c855f0eb27a09e (4 commits: federation, environment and module lock files regenerated for linux_amd64/linux_arm64/darwin_arm64/darwin_amd64 with versions unchanged, then the CI readonly-init change plus TestLockFilesRecordEveryPlatform). Local verification is in the PR body. CI is running.

@IAmJSD

IAmJSD commented Oct 26, 2026

Copy link
Copy Markdown
Collaborator Author

Independent review (IAmJSD's agent, fresh context, given only the diff, the issue and the PR text): VERDICT: APPROVE ce844810603509a0b765682234c855f0eb27a09e

Blocking:

  • none

Non-blocking:

Attacked:

  • Ran a script over all 42 tracked lock files, main against the head. All 81 provider/version pairs are unchanged and no existing h1:/zh: line was removed. Every provider now has exactly 4 h1:. The hash sets agree across files for each of the 19 distinct provider/version pairs. The only other changes are constraints = refreshes and alignment.
  • Checked the hashes independently. In a scratch root pinned to the locked external 2.3.5, http 3.5.0, null 3.2.4, random 3.8.1, time 0.13.1 and tls 4.2.1, with the PR's provider blocks copied in, terraform providers lock -platform=linux_amd64 -platform=linux_arm64 -platform=darwin_arm64 -platform=darwin_amd64 reported "no need for changes", and the h1: sets were identical. terraform init -backend=false -lockfile=readonly -input=false + validate (TF 1.10.5, linux_amd64, throwaway TF_DATA_DIR) passed for environments/aws, azure, gcp and azure/ci-cd-permissions, and the worktree stayed clean. The ci-cd-permissions lock files are tracked, so the removed "gitignored" comment was indeed false.
  • Fail-before: restored main's 42 lock files, and TestLockFilesRecordEveryPlatform failed with 71 under-hashed providers. Restored afterwards.
  • go vet with and without -tags integration, go test -race -short -count=1 ./terraform/..., go test -race -tags integration -count=1 ./terraform/... and golangci-lint with and without integration tags: all clean. ci.yml: the job runs on ubuntu-latest (amd64) with TF 1.10.5, and the two changed run blocks add flags only, with no new expressions or inputs.

Body-stale:

  • none

Reviewer: rC2. Bar while the maintainers are away (set by IAmJSD as acting owner): one approving independent review on the head, two for money, auth and security paths.

@IAmJSD

IAmJSD commented Oct 26, 2026

Copy link
Copy Markdown
Collaborator Author

Independent review (IAmJSD's agent, fresh context, given only the diff, the issue and the PR text): VERDICT: APPROVE ce844810603509a0b765682234c855f0eb27a09e

Blocking:

  • none

Non-blocking:

Attacked:

  • Supply chain (the reason this is marked sensitive): I regenerated all 19 distinct provider/version pairs in the 42 lock files from scratch with terraform providers lock for the same four platforms, in empty roots pinned = <version>. Every h1: and zh: set in every lock file on this head matches my independent regeneration exactly. No h1:/zh: line was removed (git diff ... | grep '^- "(h1|zh):' returns 0). Provider versions are unchanged: the only version diffs are whitespace alignment. The rest is constraints lines refreshed to the current config.
  • Strict init on linux_amd64: for all 42 tracked lock-file roots I ran terraform init -backend=false -lockfile=readonly -input=false and terraform validate, with a throwaway TF_DATA_DIR and Terraform 1.10.5. 42/42 OK, and the worktree stayed clean afterwards. I didn't run terraform test.
  • Fail-before: I checked out main's 42 lock files under the new test. TestLockFilesRecordEveryPlatform failed with 71 under-hashed providers. Restored, it passes. The CI edits only add -lockfile=readonly -input=false. All three ci-cd-permissions lock files are tracked (git ls-files), so dropping the "gitignored" comment is correct. actionlint ci.yml: clean.
  • go vet ./terraform/ (plain and -tags integration); go test -race -short -count=1 ./terraform/... and go test -race -tags integration -count=1 ./terraform/...: ok. golangci-lint ./terraform/: 0 issues.

Body-stale:

  • none

Reviewer: rC3. Bar while the maintainers are away (set by IAmJSD as acting owner): one approving independent review on the head, two for money, auth and security paths.

@IAmJSD

IAmJSD commented Oct 26, 2026

Copy link
Copy Markdown
Collaborator Author

Local verification at ce844810603509a0b765682234c855f0eb27a09e merged onto main (d87b96ff), together with #1437, #1438, #1439, #1440, #1441 in that order (combined tree 37f4d0bb, Linux, Go 1.26.10): go build ./..., go vet with and without -tags integration, the full go test -race -short -count=1 ./..., and go test -race -tags integration -count=1 on every changed package, against Docker Postgres. All pass. CI Success and pre-commit are green on this head, with 2 approving independent review(s) on it. Nothing was run against any cloud.

@IAmJSD
IAmJSD marked this pull request as ready for review October 26, 2026 07:04
@IAmJSD
IAmJSD merged commit 0be0374 into LeanerCloud:main Oct 26, 2026
41 checks passed
@IAmJSD

IAmJSD commented Oct 26, 2026

Copy link
Copy Markdown
Collaborator Author

Merged by IAmJSD's agent at IAmJSD's request (IAmJSD is acting owner while the maintainers are away), under the bar IAmJSD set: 2 approving independent review(s) on ce844810 (two required: money, auth or security path), green CI, and the combined-tree verification above. Squash-merged at exactly ce844810603509a0b765682234c855f0eb27a09e.

IAmJSD added a commit to IAmJSD/cloud-commitments-platform that referenced this pull request Oct 26, 2026
Bring the branch up to date with main. The only conflicts were the two
Azure compute lock files (aks, container-apps). Main's versions already
carry linux_amd64, linux_arm64, darwin_arm64 and darwin_amd64 hashes
(LeanerCloud#1439) for the same provider versions this branch pins, so main's files
were taken and re-checked with `terraform providers lock` for all four
platforms, which reported no changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/s Hours impact/internal Team-internal only priority/p3 Polish / idea / may never ship severity/low Minor harm triaged Item has been triaged type/chore Maintenance / non-user-visible urgency/this-quarter Within the quarter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

build(terraform): record linux_amd64/linux_arm64 provider hashes in every lock file and init the env roots with -lockfile=readonly

1 participant