Infrastructure Changes
Every infrastructure change follows the same loop: edit Terraform files, plan locally, push a PR, and let Cloud Build verify. This page walks through each step.
Agent Skill
This skill automates the full workflow below
/infra [Describe your change]Prerequisites
Complete the setup guide before your first infrastructure change.
What the setup guide covers
- Google Cloud SDK authenticated (
gcloud auth loginandgcloud auth application-default login) - Membership in the
sg-hb-infra-developmentGoogle Group - Project dependencies installed
(
./zig/zig build install)
Identify the project
This monorepo contains five infrastructure projects:
| Project | Description |
|---|---|
hb-infra |
Default THB infrastructure |
pd-infra |
Partner-centric infrastructure [Blue] [CoPo] |
ha-infra |
HomeAlign infrastructure |
bees-infra |
Bees API infrastructure [Yellow] |
common-infra |
Shared infrastructure components |
Each project follows the same directory layout:
infra/<project>/business_unit_1/
├── development/
├── non-production/ # UAT / Staging
└── production/
Edit the .tf files in the relevant environment
directory.
Run Plan
Before pushing, run plan to preview what Terraform will
do. The build system handles authentication, initialization, and
formatting automatically.
./zig/zig build plan -- <project> <environment>The environment argument accepts short aliases:
| Environment | Aliases |
|---|---|
development |
d, dev |
non-production |
n, np, staging |
production |
p, prod |
shared |
s |
Omit the environment to plan all environments at once (slower but comprehensive):
./zig/zig build plan -- ha-infraTo plan a single submodule within an environment, pass it as a third argument:
./zig/zig build plan -- ha-infra non-production cloudflareThis is useful when your changes are scoped to one folder.
Reading the output
Terraform marks each resource with a symbol:
# Will be CREATED
+ resource "azurerm_virtual_machine" "web_server" { ... }
# Will be MODIFIED in-place
~ resource "azurerm_dns_record" "api" {
~ ttl = 300 -> 600
}
# Will be DESTROYED then RECREATED --- investigate before approving
-/+ resource "azurerm_storage_account" "logs" { ... }Replace (
-/+) means destroy-then-recreate. This can cause downtime, data loss, or changed IP addresses. Always investigate replacements before approving a plan.
The summary line at the bottom tells you the totals:
Plan: 1 to add, 1 to change, 0 to destroy.
Review every change. Unexpected destroys or
replacements mean your branch is out of date with plan —
rebase first (see below).
Format and Rebase
Format your code before pushing:
./zig/zig build fmtThen rebase on the latest plan branch:
git fetch origin
git rebase origin/planWhy rebase? If someone merged changes after you branched, your plan will show phantom destroys — Terraform sees their resources in state but not in your stale config, so it tries to delete them. Rebasing pulls in their config and eliminates the false positives.
After rebasing, re-run plan to confirm only your
intended changes remain.
Create a Pull Request
All PRs target the
planbranch, notmain.
When the plan shows only your intended changes:
- Commit your Terraform changes
- Push your branch
- Open a PR to
planand request review from the DevOps team
Cloud Build Verification
GCP Cloud Build runs plan commands for all environments automatically when the PR is created. Review the CI output to confirm it matches your local plan.
If CI shows changes you don’t see locally:
- Rebase on
origin/planand re-plan — your branch is behind - If changes persist after rebasing, someone may have made manual
infrastructure changes (drift). Check the DevHive developer dashboard — its
continuous fuzzer checks for
infra_drift, which indicates manual changes. Flag any drift to the DevOps team.
Troubleshooting
Plan shows resources I didn’t touch Rebase on
origin/plan and re-plan. Stale branches produce phantom
destroys.
Plan shows -/+ (replace) on a resource I only
modified Some attribute changes force recreation (e.g.,
renaming a storage account). Check the Terraform docs for the resource
to confirm which attributes are “ForceNew.”
./zig/zig build plan fails before showing
output Run ./zig/zig build install to ensure
dependencies are up to date, then retry.
Builds, authentication, or cached state errors Clear the project cache and retry:
./zig/zig build cleanNext Steps
After your PR is approved and merged, see Deploying Releases.
Edit this page