diff --git a/.github/workflows/terraform-lock.yml b/.github/workflows/terraform-lock.yml new file mode 100644 index 0000000..451462f --- /dev/null +++ b/.github/workflows/terraform-lock.yml @@ -0,0 +1,43 @@ +name: Verify Terraform Lock Files + +# Fails if any root's .terraform.lock.hcl is incomplete or stale for the +# expected platforms (darwin_arm64 + linux_amd64). Re-runs `providers lock` +# for both platforms and fails on any diff, so a lock missing EITHER +# platform's hashes is caught regardless of the runner OS (a plain +# `init -lockfile=readonly` on a linux runner would miss a darwin-only lock). +# `providers lock` only talks to the provider registry, so no backend creds. + +on: + pull_request: + paths: + - '**/.terraform.lock.hcl' + - '**/version.tf' + - '.github/workflows/terraform-lock.yml' + +jobs: + lock-check: + permissions: + contents: read + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + root: + - state-backend + - cluster/local + - cluster/scaleway + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3.1.2 + with: + # Keep in sync with mise.toml [tools] terraform version. + terraform_version: "1.14" + + - name: Re-lock providers for both platforms and assert no drift + run: | + terraform -chdir=${{ matrix.root }} providers lock \ + -platform=darwin_arm64 -platform=linux_amd64 + git diff --exit-code -- ${{ matrix.root }}/.terraform.lock.hcl diff --git a/CLAUDE.md b/CLAUDE.md index 2b25b7b..38bda78 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -16,10 +16,31 @@ mise install # Install all tools (kubectl, minikube, terraform, helm, a mise run dev # Full local env: start minikube + terraform init + apply mise run reset # Destroy minikube cluster +# Provider lock files +mise run lock # Re-generate all 3 roots' .terraform.lock.hcl for darwin_arm64 + linux_amd64 + # Linting actionlint .github/workflows/*.yml # Lint GitHub Actions workflows (also runs as pre-push hook) ``` +### Re-running `providers lock` + +The `.terraform.lock.hcl` in each root must cover **both** `darwin_arm64` (local dev) and `linux_amd64` (CI). Re-run `mise run lock` whenever you: + +- bump a provider version constraint in any `version.tf` +- add a new provider to a root +- see a CI failure on the `Verify Terraform Lock Files` workflow + +`mise run lock` is equivalent to: + +```bash +terraform -chdir=state-backend providers lock -platform=darwin_arm64 -platform=linux_amd64 +terraform -chdir=cluster/local providers lock -platform=darwin_arm64 -platform=linux_amd64 +terraform -chdir=cluster/scaleway providers lock -platform=darwin_arm64 -platform=linux_amd64 +``` + +Commit the updated lock files alongside the version change. + ## Architecture Two cluster environments, each its own Terraform root module: diff --git a/cluster/local/.terraform.lock.hcl b/cluster/local/.terraform.lock.hcl index 737d0d6..fbcb11d 100644 --- a/cluster/local/.terraform.lock.hcl +++ b/cluster/local/.terraform.lock.hcl @@ -5,6 +5,7 @@ provider "registry.terraform.io/hashicorp/helm" { version = "2.17.0" constraints = "~> 2.0" hashes = [ + "h1:K5FEjxvDnxb1JF1kG1xr8J3pNGxoaR3Z0IBG9Csm/Is=", "h1:kQMkcPVvHOguOqnxoEU2sm1ND9vCHiT8TvZ2x6v/Rsw=", "zh:06fb4e9932f0afc1904d2279e6e99353c2ddac0d765305ce90519af410706bd4", "zh:104eccfc781fc868da3c7fec4385ad14ed183eb985c96331a1a937ac79c2d1a7", @@ -25,6 +26,7 @@ provider "registry.terraform.io/hashicorp/kubernetes" { version = "2.38.0" constraints = "~> 2.0" hashes = [ + "h1:5CkveFo5ynsLdzKk+Kv+r7+U9rMrNjfZPT3a0N/fhgE=", "h1:soK8Lt0SZ6dB+HsypFRDzuX/npqlMU6M0fvyaR1yW0k=", "zh:0af928d776eb269b192dc0ea0f8a3f0f5ec117224cd644bdacdc682300f84ba0", "zh:1be998e67206f7cfc4ffe77c01a09ac91ce725de0abaec9030b22c0a832af44f", @@ -46,6 +48,7 @@ provider "registry.terraform.io/infisical/infisical" { constraints = "~> 0.16" hashes = [ "h1:etvAh0EI+HV8I+4NCF/6eGicc2W6+SZH26tsqyk2JHc=", + "h1:kb47QLEMFwOWEjajtA5fEEaNqINyyRy/IUaWa8sgjtk=", "zh:04cc2c2c6479eb04ef5cb5adc6f327f034ce490bdd72ed921883ae00eac5b36d", "zh:25a82805c4d6b79860e1cca00c0f1d732d30b76dcede5208d824557487c63e64", "zh:3382727a82a9a2f47a7fe3817c6228e478d1da269c85f39d6ffe6839a24406b4", diff --git a/cluster/local/main.tf b/cluster/local/main.tf index 5bef475..9f153e0 100644 --- a/cluster/local/main.tf +++ b/cluster/local/main.tf @@ -14,7 +14,7 @@ resource "helm_release" "argocd" { version = "9.4.17" set_sensitive { - name = "configs.secret.argocdServerAdminPassword" + name = "configs.secret.argocdServerAdminPassword" # ArgoCD require a `bcrypt()` hashed password here. But `bcrypt` generate a new hash at each execution # So instead, we store the hash directly, so terraform is not confused anymore by fake changes value = data.infisical_secrets.this.secrets["ArgoCD_admin_encrypted"].value @@ -38,8 +38,8 @@ EOF ] } resource "helm_release" "argocd_apps" { - name = "argocd-apps" - namespace = "argocd" + name = "argocd-apps" + namespace = "argocd" repository = "https://argoproj.github.io/argo-helm" chart = "argocd-apps" diff --git a/cluster/local/variables.tf b/cluster/local/variables.tf index 1c8871f..87f0bc3 100644 --- a/cluster/local/variables.tf +++ b/cluster/local/variables.tf @@ -1,9 +1,9 @@ variable "infisical_client_id" { - type = string + type = string } variable "infisical_client_secret" { - type = string + type = string } variable "gitops_revision" { diff --git a/cluster/local/version.tf b/cluster/local/version.tf index f71039a..5c4ab7a 100644 --- a/cluster/local/version.tf +++ b/cluster/local/version.tf @@ -10,7 +10,7 @@ terraform { } infisical = { version = "~> 0.16" - source = "infisical/infisical" + source = "infisical/infisical" } } } diff --git a/cluster/scaleway/.terraform.lock.hcl b/cluster/scaleway/.terraform.lock.hcl index 4278a27..e8679c5 100644 --- a/cluster/scaleway/.terraform.lock.hcl +++ b/cluster/scaleway/.terraform.lock.hcl @@ -5,6 +5,7 @@ provider "registry.terraform.io/hashicorp/helm" { version = "2.17.0" constraints = "~> 2.0" hashes = [ + "h1:K5FEjxvDnxb1JF1kG1xr8J3pNGxoaR3Z0IBG9Csm/Is=", "h1:kQMkcPVvHOguOqnxoEU2sm1ND9vCHiT8TvZ2x6v/Rsw=", "zh:06fb4e9932f0afc1904d2279e6e99353c2ddac0d765305ce90519af410706bd4", "zh:104eccfc781fc868da3c7fec4385ad14ed183eb985c96331a1a937ac79c2d1a7", @@ -25,6 +26,7 @@ provider "registry.terraform.io/hashicorp/kubernetes" { version = "2.38.0" constraints = "~> 2.0" hashes = [ + "h1:5CkveFo5ynsLdzKk+Kv+r7+U9rMrNjfZPT3a0N/fhgE=", "h1:soK8Lt0SZ6dB+HsypFRDzuX/npqlMU6M0fvyaR1yW0k=", "zh:0af928d776eb269b192dc0ea0f8a3f0f5ec117224cd644bdacdc682300f84ba0", "zh:1be998e67206f7cfc4ffe77c01a09ac91ce725de0abaec9030b22c0a832af44f", @@ -45,6 +47,7 @@ provider "registry.terraform.io/hashicorp/local" { version = "2.9.0" constraints = "~> 2.0" hashes = [ + "h1:9rBZCMNpxKwMlRbWH2QpwD3kqUCAejdOZQ/aiiDObXQ=", "h1:m24fjcInWvTVZ1XSo2MaNuKPe+X/gfG8SIi09rA7a7M=", "zh:0baa4566cf77f1ff52f4293d1c8536202dd23edc197c3196413a28343c3ac3a0", "zh:16b5559c3c07088ddad11a9bb9e9c0799999363c2958e9a5be2bcbbf2cd9ca64", @@ -67,6 +70,7 @@ provider "registry.terraform.io/hashicorp/null" { constraints = "~> 3.0" hashes = [ "h1:a14TKo7Xvg4W8+H1VA6p+oLZTLxVQnYUD8LOaOs14A8=", + "h1:l+dm3lhmu4ys7GbvIldfn544olSPH0DOiYruuFSfQkY=", "zh:021748b5ea3b5f6956f2e75c42c5cdc113b391fb98ac71364a4965d23b37000f", "zh:3b27956f8541d46704fda234e0d535c2ae2a4b33411848b1ee262a1ec03568b0", "zh:3de4ed47d6d0f4d8edba4a5092c7c9799950eda63989d8d0d2586e6afcb0aa20", @@ -88,6 +92,7 @@ provider "registry.terraform.io/infisical/infisical" { constraints = "~> 0.16" hashes = [ "h1:IkYJCDS/T+DOphpxxD7DRR0DLVerV4qAQHti85SVIVQ=", + "h1:gXZ47EfO3stEXB5TN/JKMlg9eMNETX+WhpmLlnC/Rn4=", "zh:013b47edce338eb6ed75112ebb2753a61e016abdeb0553865ed410c3f31c6efb", "zh:14ced8e88b66c035e808ac5276dc7cdd9d761d91b54ad69de6262204c2c674a5", "zh:1f6463f27bbfd083d91ccbbba8699e378b7c3fdb5c93f0e88c923f39889f940a", @@ -111,6 +116,7 @@ provider "registry.terraform.io/scaleway/scaleway" { constraints = "~> 2.0" hashes = [ "h1:k9SfjZLDyy+1uk3GEaEsQZt3r6+zNW+dGcrNicIuUtA=", + "h1:wjdKvqynHsar/6uGQeOvozuBJdf/q4Lt7H4cieDuBWg=", "zh:000eb75f83e651b76d46b201dde6c6129070b2cfa0c2a7ba63644d8386cfb737", "zh:003fb8aabb69ec995b2f5f8f60aa78eac9dd4eddb4c3c91de99765070291a6a3", "zh:1e2d23bcf64ba0604e4b9c2a2ea5a0c9e07ce6f65b7e2b124412cdcc36417003", diff --git a/mise.toml b/mise.toml index c514830..899eafd 100644 --- a/mise.toml +++ b/mise.toml @@ -94,3 +94,13 @@ run = "terraform apply" description = "Tear down the Scaleway cluster (terraform destroy)" dir = "cluster/scaleway" run = "terraform destroy" + +# ── Provider locks ─────────────────────────────────────────────────────────── + +[tasks.lock] +description = "Re-generate all .terraform.lock.hcl files for darwin_arm64 + linux_amd64" +run = """ +terraform -chdir=state-backend providers lock -platform=darwin_arm64 -platform=linux_amd64 +terraform -chdir=cluster/local providers lock -platform=darwin_arm64 -platform=linux_amd64 +terraform -chdir=cluster/scaleway providers lock -platform=darwin_arm64 -platform=linux_amd64 +""" diff --git a/state-backend/.terraform.lock.hcl b/state-backend/.terraform.lock.hcl index e19ca7c..f4eb038 100644 --- a/state-backend/.terraform.lock.hcl +++ b/state-backend/.terraform.lock.hcl @@ -6,6 +6,7 @@ provider "registry.terraform.io/scaleway/scaleway" { constraints = "~> 2.0" hashes = [ "h1:3RImo3Jf88dXcIqmBRuO/A85jAxrAQsvYa4zhVqW1tI=", + "h1:ktRogBsJlCf3JTOTYPm9hKaPUzaps0aLwxsNfP155ns=", "zh:13b6790dca2c91c7478d6e9cd03d84713e0b0ec001c9923d3c93bd12a1f4152f", "zh:219582ef77ec6f27d2928684b95603b5a921001631f9eec68c14819fdbc1efea", "zh:26bc09c7aadc49fe83a9d6af9c1d0951f93de129f90d04e5e65e1d82c8ac1914",