Skip to main content

Repository layout

Producer: eigenoid/platform-actions

Contains the reusable workflows and centralized environment configuration.

platform-actions/
├── .github/
│ ├── workflows/
│ │ ├── terraform-orchestrator.yml ← Main workflow (parses spec, computes waves)
│ │ ├── terraform-layer.yml ← Per-layer workflow (auth, init, plan/apply)
│ │ ├── terraform-compliance.yml ← Compliance validation (future)
│ │ ├── release.yml ← Release-please + CI
│ │ ├── ci.yml ← Linting (actionlint, shellcheck)
│ │ └── pr-title.yml ← Conventional Commits validation
│ └── dependabot.yml
├── config/
│ ├── environments.yaml ← Centralized environment config (GCP projects, WIF, SA)
│ └── README.md ← Config documentation
├── scripts/
│ ├── compute-waves.sh ← Dependency wave calculation
│ └── resolve-config.sh ← Per-environment config resolution
├── release-please-config.json
├── .release-please-manifest.json
├── CHANGELOG.md
└── README.md

Key files

FilePurpose
terraform-orchestrator.ymlEntry point for consumers. Parses terraflow.yaml, resolves config, dispatches layers by waves.
terraform-layer.ymlRuns Terraform for a single layer. Handles auth (WIF), backend, init, plan/apply. Supports GCP, AWS, and Azure.
config/environments.yamlSource of truth for project IDs, WIF providers, SA emails, and buckets. One block per environment.
scripts/compute-waves.shReads depends_on from layers and produces wave0..wave4 assignments.
scripts/resolve-config.shReads environments.yaml with yq and emits variables for the layer workflow.

Versioning

  • Each merge to main triggers release-please, which creates a vX.Y.Z release.
  • The v1 tag automatically moves to the latest release in the v1 major line.
  • Consumers call @v1 and receive updates without changing anything.

Consumer: eigenoid/iac-foundation

The foundational infrastructure stack. Defines WIF, service accounts, and governance SAs for each GCP project.

iac-foundation/
├── .github/
│ └── workflows/
│ └── terraform.yml ← Consumer workflow (triggers, slash commands, dispatch to producer)
├── terraflow.yaml ← Stack spec (environments, layers, dependencies)
├── platform-wif/ ← Layer: Workload Identity Federation pool + provider + terraform-ci SA
│ ├── workload_identity.tf
│ ├── sa.tf
│ ├── apis.tf
│ ├── locals.tf
│ ├── variables.tf
│ ├── variables_iac.tf
│ ├── outputs.tf
│ ├── providers.tf
│ ├── backend.tf
│ ├── versions.tf
│ └── tfvars/
│ ├── dev.tfvars
│ ├── qa.tfvars
│ └── prd.tfvars
├── service-wif/ ← Layer: Per-repo WIF bindings + deploy-ci SA
│ ├── main.tf
│ ├── sa.tf
│ ├── variables.tf
│ ├── variables_iac.tf
│ ├── outputs.tf
│ ├── providers.tf
│ ├── backend.tf
│ ├── versions.tf
│ └── tfvars/
│ ├── dev.tfvars
│ ├── qa.tfvars
│ └── prd.tfvars
├── governance-sa/ ← Layer: platform-bootstrap SAs for governance workflows
│ └── ...
└── README.md

Layer conventions

Every layer directory follows this structure:

FileContents
backend.tfBackend config (GCS bucket, prefix by layer name)
providers.tfProvider block (Google, AWS, etc.)
versions.tfrequired_providers + required_version
variables.tfInfrastructure variables (project_id, region, etc.)
variables_iac.tfCI metadata variables (auto-injected, never edited manually)
locals.tfDerived locals (labels, lists, etc.)
outputs.tfOutputs for consumption by other layers or documentation
*.tfResources grouped by domain (apis, networking, compute, etc.)
tfvars/Per-environment .tfvars files (for manual bootstrap)

IaC metadata variables

The layer workflow automatically injects these variables via TF_VAR_iac_*:

VariableSourceUse
iac_stack_nameterraflow.yaml stack.nameResource naming, labels
iac_environmentResolved environment (dev/qa/prd)Labels, conditional logic
iac_layerLayer nameLabels
iac_commit_shagithub.shaAudit trail, labels
tip

Additional variables like iac_run_id and iac_tf_version are injected but not declared in Terraform -- they are silently ignored. Only declare the ones you actually use in your resources.


Adding a new consumer

  1. Create a repo with the iac category via the governance workflow -- state buckets are created automatically (ADR-0012).
  2. The repo is created from the iac-template, which includes a pre-configured terraflow.yaml, backend configs, and CI workflow.
  3. Create directories for each layer following the standard structure.
  4. Open a PR -- the orchestrator will detect the layers automatically.

Adding a new layer to an existing consumer

  1. Create the directory following the standard structure.
  2. Add an entry in terraflow.yaml under layers:.
  3. If it has dependencies, add depends_on: [other-layer].
  4. Open a PR -- the orchestrator will detect the new layer automatically.