Skip to main content

Versioning policy

Every third-party input to the platform is pinned to an exact version in one known place, and every pin is changed on its own, planned in dev before staging and prod, with a risk level and an approver that depend on the kind of change. This policy is what the update lifecycle document delivered with the Baseline prescribes; the current pins are on the release notes page.

Where each kind of pin lives

KindPinOne place
OpenTofuExact in CI (TF_VERSION), range in root.hcl (>= 1.12.6, < 2.0.0)root.hcl and the workflows of each repository
TerragruntExact in CI (TG_VERSION), minimum in root.hcl (>= 1.1.5)Same
AWS provider~> 6.65root.hcl generates versions.tf into every unit; a module ships its own versions.tf only for provider aliases or extra providers, repeating the pin exactly
Other providers (helm, kubernetes)Version constraintThe module versions.tf files that declare them
Registry modulesExact (?version=6.7.3)The unit definition (landing-zone VPC and Transit Gateway) or the module main.tf
GitHub ActionsCommit SHA, version in the trailing commentEvery workflow file
SOPS, tflint and its rulesetExactThe secrets workflows; plan.yml and .tflint.hcl
Container imagesImmutable tags, main-<sha> and vX.Y.ZECR; see immutable artifacts

scripts/check-module-versions.py fails in pre-commit and CI when a module declares required_providers it should not, or repeats the root pins incorrectly. Registry module upgrades are their own change with a plan review; a provider upgrade changes root.hcl and every module versions.tf the guard lists in the same change.

Risk and approval per change

ChangeRiskTestingApproval
Patch version (x.y.Z)LowDev onlyTeam Lead
Minor version (x.Y.z)MediumDev and stagingDevOps Lead
Major version (X.y.z)HighDev, staging and a canaryPlatform Lead and DevOps Lead
Provider majorHighFull chainPlatform Lead
New module introductionMediumDev and stagingPlatform Lead
Self-hosted runner module updateMediumA disposable workflowDevOps Lead

Per component, the update lifecycle rates OpenTofu and Terragrunt updates and AWS provider updates as medium risk, registry module updates as high risk for a major version and low for a patch, and GitHub Actions SHA updates as low risk. Major module versions (for example EKS 20.x to 21.x) often include breaking changes: the upgrade guide is read and dev is tested first.

The update path

  1. Install the new version locally where the change is a tool.
  2. Change the pin in its one place (and, for OpenTofu and Terragrunt, TF_VERSION / TG_VERSION in every workflow of the repository; for the AWS provider, the module versions.tf files the guard lists).
  3. Plan in dev from the stage or account folder and look for resource replacements. A single unit is planned with terragrunt run --all plan --filter '**/<unit>'.
  4. Open the pull request; CI plans with the new version and posts the plan.
  5. After merge, the apply workflow runs: in the Baseline as one job under the prod GitHub Environment, in the blueprint infrastructure repositories as a dev, staging and prod matrix, each job under the Environment of its stage.

Rollback is reverting the pin: the version constraint in root.hcl, the module version, or the action SHA.

Monitoring after an update

CheckHowWhen
No unexpected driftThe drift detection workflowNext scheduled run
Resources healthyCloudWatch metrics and alarmsOne hour after apply
CI still worksThe next pull request pipelineAfter merge

Repository versions and upstream updates

Each repository carries a version in its README (currently 1.0.0). Customer repositories are forks; the update lifecycle explains how to compare a fork with the upstream repository and how to merge upstream changes on a branch so that the fork's own plan workflow verifies them first. Changes that touch already-applied deployments come with a runbook; they are indexed under upgrade guides.