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
| File | Purpose |
|---|---|
terraform-orchestrator.yml | Entry point for consumers. Parses terraflow.yaml, resolves config, dispatches layers by waves. |
terraform-layer.yml | Runs Terraform for a single layer. Handles auth (WIF), backend, init, plan/apply. Supports GCP, AWS, and Azure. |
config/environments.yaml | Source of truth for project IDs, WIF providers, SA emails, and buckets. One block per environment. |
scripts/compute-waves.sh | Reads depends_on from layers and produces wave0..wave4 assignments. |
scripts/resolve-config.sh | Reads environments.yaml with yq and emits variables for the layer workflow. |
Versioning
- Each merge to
maintriggersrelease-please, which creates avX.Y.Zrelease. - The
v1tag automatically moves to the latest release in the v1 major line. - Consumers call
@v1and 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:
| File | Contents |
|---|---|
backend.tf | Backend config (GCS bucket, prefix by layer name) |
providers.tf | Provider block (Google, AWS, etc.) |
versions.tf | required_providers + required_version |
variables.tf | Infrastructure variables (project_id, region, etc.) |
variables_iac.tf | CI metadata variables (auto-injected, never edited manually) |
locals.tf | Derived locals (labels, lists, etc.) |
outputs.tf | Outputs for consumption by other layers or documentation |
*.tf | Resources 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_*:
| Variable | Source | Use |
|---|---|---|
iac_stack_name | terraflow.yaml stack.name | Resource naming, labels |
iac_environment | Resolved environment (dev/qa/prd) | Labels, conditional logic |
iac_layer | Layer name | Labels |
iac_commit_sha | github.sha | Audit 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
- Create a repo with the
iaccategory via the governance workflow -- state buckets are created automatically (ADR-0012). - The repo is created from the
iac-template, which includes a pre-configuredterraflow.yaml, backend configs, and CI workflow. - Create directories for each layer following the standard structure.
- Open a PR -- the orchestrator will detect the layers automatically.
Adding a new layer to an existing consumer
- Create the directory following the standard structure.
- Add an entry in
terraflow.yamlunderlayers:. - If it has dependencies, add
depends_on: [other-layer]. - Open a PR -- the orchestrator will detect the new layer automatically.