When contributing to this repository, please first discuss the change you wish to make via issue preferably a GitHub Issue, email, or any other method with the owners of this repository before making a change.
- Prerequisites
- Repository Architecture
- Development Workflow
- GitHub Workflows
- Branching Strategy
- Commit Conventions
- Pull Request Process
- Module Versioning
- Testing
- Versioning and Changelog
Required:
- Terraform >= 1.9.0
- PowerShell 7+ (not Windows PowerShell 5.1)
- Akamai PowerShell v2+ - For testing with
deploy.ps1 pre-commit- Pre-commit hook frameworkterraform-docs- Auto-generates module documentationtflint- Terraform lintingtrivy- Security scanning
You must install pre-commit hooks to ensure code quality before committing:
pre-commit installThis installs hooks for both pre-commit and commit-msg stages:
- Pre-commit stage: Formats code, generates docs, runs linting
- Commit-msg stage: Validates conventional commit message format
To manually run all checks:
pre-commit run --all-files Why required? The hooks enforce:
- Code formatting (
terraform fmt) - Up-to-date documentation (
terraform-docs) - Linting best practices (
tflint) - Security scanning (
trivy) - Conventional commit message format - Validates at commit time before you push
- The PR validation workflow will fail if any of the above checks are caught
Pre-commit hooks catch these issues locally before the PR validation workflow runs.
This repository uses a modular PowerShell architecture to manage Terraform deployments. The deploy.ps1 script orchestrates template-specific handlers through a clean separation of concerns:
Core Components:
-
lib/core/- Shared functionality used across all templatesTerraformRunner.psm1- Terraform execution wrapper (init, plan, apply, destroy)Validation.psm1- Product ID validation and tfvars parsingLogger.psm1- Logging and output formatting
-
lib/templates/- Template-specific handlers (one per template type)AAP.psm1- App & API Protector configuration handlerAAPASM.psm1- AAP + Advanced Security Management handlerPropertyManager.psm1- Property Manager configuration handlerCPS.psm1- Certificate Provisioning System handler
-
deploy.ps1- Main orchestration script- Maps template types to handlers via hashtables
- Loads appropriate template module dynamically
- Delegates all template-specific logic to modules
Design Principles:
- Separation of Concerns - Template-specific quirks isolated in template modules
- DRY (Don't Repeat Yourself) - Common Terraform operations in core modules
- Extensibility - Add new templates by creating a new template module
- Testability - Each module can be tested independently
terraform-templates/
├── deploy.ps1 # Main orchestration script
├── lib/ # PowerShell module library
│ ├── core/ # Shared functionality
│ │ ├── TerraformRunner.psm1 # Terraform execution wrapper
│ │ ├── Validation.psm1 # Product/tfvars validation
│ │ └── Logger.psm1 # Logging utilities
│ └── templates/ # Template-specific handlers
│ ├── AAP.psm1 # AAP template handler
│ ├── AAPASM.psm1 # AAP+ASM template handler
│ ├── PropertyManager.psm1 # Property Manager handler
│ └── CPS.psm1 # CPS handler
├── tests/
│ ├── deploy.Tests.ps1 # Deploy script tests
│ └── lib-modules.Tests.ps1 # Module unit tests
├── new-aap-configuration/ # AAP template files
├── new-aapasm-configuration/ # AAP+ASM template files
├── new-property/ # Property Manager template files
└── new-*-cert/ # CPS certificate templates
Always branch from integration, not main. See Branch Naming Convention for required format.
git checkout integration
git pull origin integration
git checkout -b feat/add-custom-rate-policies- Follow Terraform best practices
- Update the tests suites accordingly (new templates, deployment script)
- Include new templates in the Github Workflows if needed:
- terraform validate
- tflint
- terraform-docs
- Update documentation:
main.tfcomments.tfvars.distexamples- Include new templates in the
.pre-commit-config.yaml
- Test locally using
deploy.ps1 - Pre-commit hooks will auto-run on
git commit(formats code, updatesREADME.md)- Or run manually:
pre-commit run --all-files
- Or run manually:
To add a new template type (e.g., EdgeWorkers, ImageManager):
-
Create template module in
lib/templates/:# lib/templates/EdgeWorkers.psm1 using module ../core/TerraformRunner.psm1 using module ../core/Validation.psm1 using module ../core/Logger.psm1 class EdgeWorkersTemplate { [string]$TemplateName [string]$Environment [string]$TemplateFolder EdgeWorkersTemplate([string]$env, [string]$folder) { $this.TemplateName = "EdgeWorkers" $this.Environment = $env $this.TemplateFolder = $folder } [void]ValidatePrerequisites([hashtable]$params) { # Validation logic } [hashtable]BuildTerraformVars([hashtable]$params) { # Build runtime variables return @{} } [void]Deploy([hashtable]$params) { # Deploy logic using core modules } [void]Destroy([hashtable]$params) { # Destroy logic } } Export-ModuleMember -Variable EdgeWorkersTemplate
-
Update deploy.ps1:
- Add to
ValidateSetinTemplateTypeparameter - Add to
$templateModuleMaphashtable - Add to
$templateFolderMaphashtable - Add switch case in template routing section
- Add to
-
Create tests in
tests/lib-modules.Tests.ps1:Describe "Template Module - EdgeWorkers" { It "Should load EdgeWorkers template module" { { Import-Module "$RepoRoot/lib/templates/EdgeWorkers.psm1" -Force } | Should -Not -Throw } }
-
Update documentation:
- Update this file (CONTRIBUTING.md) if needed
- Add template-specific guidance to README.md
- Create migration examples
See Commit Conventions for required format.
git add .
git commit -m "feat(aap): add support for custom rate policies"git push origin feat/add-custom-rate-policiesOpen PR against integration branch (not main). This triggers the PR Validation workflow. See Pull Request Process below.
After PR is merged to integration:
- Terraform Docs workflow auto-runs - Updates template
README.mdfiles automatically - Test the integrated changes thoroughly
- Verify multiple templates work together
- Confirm module version compatibility
- Template
README.mdfiles should now reflect latest changes (auto-committed by workflow)
When ready for release, create PR from integration to main. Once merged, this triggers the Release Automation workflow which:
- Analyzes commits and determines version bump
- Updates
VERSIONfile andCHANGELOG.md - Creates Git tag and GitHub release
Use this workflow when a critical bug in production needs to be fixed immediately, without waiting for changes currently in integration to be ready.
hotfix/* branch → main (release automation) → integration (backmerge, no CI)
Steps:
-
Cut the hotfix branch from
main(notintegration):git checkout main git pull origin main git checkout -b hotfix/fix-critical-issue
-
Apply the fix and commit using a
fix:conventional commit:git commit -am "fix: resolve critical issue in rate policy" git push origin hotfix/fix-critical-issue -
Open a PR from
hotfix/*→main:- The
main-branch-protectionworkflow validates the source ishotfix/*✓ - PR validation and tf-docs do not run (they only trigger on PRs/pushes to
integration) - Once approved, merge the PR
- This triggers the Release Automation workflow (patch version bump) ✓
- The
-
Backmerge
mainintointegrationto keep branches in sync:git checkout integration git pull origin integration git merge origin/main # resolve any conflicts if needed git push origin integrationBoth
git merge main(local ref) andgit merge origin/main(remote-tracking ref) are supported. The tf-docs workflow is configured to skip on both resulting commit message formats. -
Verify
integrationis up to date — no CI workflows will re-run for this backmerge:pr-validationis skipped (no PR opened againstintegration)tf-docsis skipped (commit message matches themain→integrationbackmerge pattern)
This repository uses three automated workflows that execute in sequence:
Trigger: Pull requests to integration branch
Purpose: Validate code quality and security before merging
Note: This workflow is automatically skipped when the source branch is main (i.e., during a hotfix backmerge PR). The code already passed production standards via the hotfix PR to main.
Runs:
- Terraform Format Check - Ensures consistent formatting
- Terraform Validate - Tests all templates (AAP, AAP+ASM, Property, etc)
- TFLint - Static analysis for best practices
- Trivy Security Scan - Identifies vulnerabilities (uploads to GitHub Security tab)
- Deployment Tests - Tests for the
deploy.ps1script
Required Secrets:
DEPLOY_KEY- SSH private key for accessing private module repository
Note: This workflow does NOT modify code. All checks are read-only validation.
Trigger: Pushes to integration branch (i.e., when PRs are merged)
Purpose: Auto-generate and commit updated README.md files for all templates
Runs (example):
- Generate terraform-docs for AAP Configuration - Updates
new-aap-configuration/README.md - Generate terraform-docs for AAP/ASM Configuration - Updates
new-aapasm-configuration/README.md - Generate terraform-docs for Property - Updates
new-property/README.md - Auto-commit - Pushes updated
README.mdfiles back tointegrationbranch
Note: This workflow runs AFTER merge to integration, ensuring documentation stays in sync with code changes. It is automatically skipped when the push is a backmerge from main, covering both standard merge message formats (Merge branch 'main' from git merge main and Merge remote-tracking branch 'origin/main' from git merge origin/main), preventing unnecessary doc regeneration during hotfix backmerges.
Trigger: Merges to main or master branch
Purpose: Create versioned releases with changelog and tags
Runs:
- Analyzes conventional commits since last tag
- Determines version bump (major/minor/patch)
- Updates
VERSIONfile - Generates/updates
CHANGELOG.md - Commits changes with
[skip ci]to prevent loops - Creates Git tag (e.g.
v1.2.3) - Publishes GitHub release with extracted release notes
Version Bump Logic:
- Commits with
BREAKING CHANGE:footer → Major (1.0.0 → 2.0.0) feat:orfeature:→ Minor (1.0.0 → 1.1.0)fix:orbugfix:→ Patch (1.0.0 → 1.0.1)
For Terraform to access the terraform-templates-modules repository SSH access is required. See for example the module reference in the new-aap-configuration/main.tf:
source = "git::ssh://git@github.com/akamai/terraform-templates-modules.git//aap/security?ref=v1.2.3"
Setup SSH for GitHub module access:
-
Generate SSH key pair (no passphrase):
ssh-keygen -t rsa -b 4096 -C "github-actions" -f deploy_key -
Add public key (
deploy_key.pub) to module repository:- Go to module repo → Settings → Deploy keys
- Add key with read-only access
-
Add private key (
deploy_key) to this repository:- Settings → Secrets and variables → Actions
- New repository secret:
DEPLOY_KEY
This repository uses a three-stage branching model with automated CI/CD:
feature branch → integration (PR validation + auto-docs) → main (release automation)
↑
hotfix/* branch ─────────────────┘
(then backmerged to integration with no CI)
| Branch | Purpose | Triggers |
|---|---|---|
| Feature branches | Active development work | Nothing |
integration |
Pre-release testing and validation | PR validation workflow (on PR) + Terraform Docs workflow (on merge) |
hotfix/* |
Critical production fixes bypassing integration |
Main branch protection (PR to main) + Release automation (on merge to main) |
main/master |
Production-ready code | Release automation workflow |
Required for integration branch:
- Require pull request reviews before merging
- Require status checks to pass (PR validation workflow)
- Require branches to be up to date before merging
Required for main branch:
- All of the above, plus:
- Restrict push access (only allow merges from
integration) - Require linear history (squash or rebase merges)
Use descriptive branch names that match commit types for consistency:
Format: <type>/<short-description> or <type>/<issue>-<short-description>
Examples:
# New features
feat/custom-rate-policies
feat/DOHRMY-126-botman-integration
# Bug fixes
fix/rate-policy-import
fix/DOHRMY-456-state-file-conflict
# Hotfixes (critical production fixes - branched from main)
hotfix/fix-rate-policy-conflict
hotfix/DOHRMY-789-critical-security-patch
# Documentation
docs/update-readme-examples
# Refactoring
refactor/module-structure
# Chores
chore/new-release-versionGuidelines:
- Use lowercase with hyphens (kebab-case)
- Be descriptive but concise (3-5 words max)
- Include issue/ticket number when applicable
- Match the commit type you'll use later
- Avoid special characters except hyphens and forward slashes
This repository follows Conventional Commits for automated changelog generation.
<type>(<scope>): <subject>
| Type | Purpose | Version Bump | Example |
|---|---|---|---|
feat: |
New features | Minor (1.0.0→1.1.0) | feat(aap): add custom rate policies |
fix: |
Bug fixes | Patch (1.0.0→1.0.1) | fix(asm): correct match target config |
docs: |
Documentation | None | docs: update README examples |
refactor: |
Code restructuring | None | refactor: simplify module calls |
chore: |
Maintenance | None (skipped) | chore: update dependencies |
test: |
Add or Update Tests | None | test: deployment script |
To trigger a major version bump, include BREAKING CHANGE: in the commit body:
# Breaking change with body footer (triggers major bump)
git commit -m "feat: upgrade Akamai provider
BREAKING CHANGE: Provider v9.0 requires Terraform >= 1.9.0"
# Alternative multi-line format
git commit -m "feat: require PowerShell 7+" -m "BREAKING CHANGE: PowerShell 5.1 no longer supported"Note: The feat!: syntax is NOT supported by the changelog action. Always use the BREAKING CHANGE: footer.
Use scopes to indicate which template is affected:
(aap)- App & API Protector template(aapasm)- AAP+ASM template(pm)- Property Manager template(deploy)- deploy.ps1 script(ci)- CI/CD workflows(docs): Documentation
# Feature (minor bump)
git commit -m "feat(aap): add support for custom rate policies"
# Bug fix (patch bump)
git commit -m "fix(asm): correct match target configuration"
# Breaking change (major bump) - requires BREAKING CHANGE footer
git commit -m "feat: upgrade to Terraform 1.9" -m "BREAKING CHANGE: Terraform 1.8 no longer supported"
# Documentation (no version bump)
git commit -m "docs: update README with new examples"
# Chore (no version bump, excluded from changelog)
git commit -m "chore: update dependencies"-
Fork the project (for external contributors) or create branch (for team members)
-
Create feature branch from
integration:git checkout -b feat/your-feature-name integration
-
Make your changes:
- Update code/templates
- Update documentation (
main.tf,.tfvars.dist) - Test with:
pwsh deploy.ps1 <template> -Env dev -Save -Dry - Pre-commit hooks will run on commit (or manually:
pre-commit run --all-files)
-
Commit with conventional format:
git commit -m "feat(aap): add new feature" -
Push to remote:
git push origin feat/your-feature-name
-
Create PR against
integration:# Option 1: Open repo in browser - GitHub will show "Compare & pull request" banner open https://github.com/jaescalo/terraform-templates/pulls # Option 2: Use GitHub CLI (requires 'gh' installed) gh pr create --base integration --title "feat(aap): add new feature" --body "Description of changes"
-
Wait for PR validation to pass - All checks must be green
-
Address review feedback if requested
-
Merge to integration - Test thoroughly
-
Create PR from
integrationtomainwhen ready for release
Before submitting, ensure:
- Pre-commit hooks installed and run successfully
- Conventional commit format used (at least one semantic commit)
- Documentation updated (
main.tf, inline comments,.tfvars.dist) - Tested with
deploy.ps1for affected templates - Test suite/scenarios updated or created for the affected templates
- Module version references are pinned (never use
ref=main) - PR validation workflow passes (all checks green)
Note: Template README.md files are auto-generated by the Terraform Docs workflow after merge to integration, so you don't need to update them manually.
Note: If PR validation fails on formatting/docs, run pre-commit run --all-files locally and push the fixes.
Always pin modules to specific versions using Git tags:
module "security" {
source = "git::ssh://git@github.com/akamai/terraform-templates-modules.git//aap/security?ref=v1.1.1"
# ...
}Never use: ref=main or ref=master in production templates.
When module repository changes (it follows the same release process):
-
Update template references in this repository:
# Update all module source refs in affected templates # Example: new-aap-configuration/main.tf source = "git::ssh://...//aap/security?ref=v1.2.0"
-
Test changes:
pwsh deploy.ps1 aap -Env dev -Save -Dry
-
Commit with semantic message:
git commit -m "feat: upgrade security module to v1.2.0"
Run Pester tests for the modular architecture:
# Install Pester if not already installed
Install-Module -Name Pester -Force -SkipPublisherCheck
# Run all tests
pwsh -Command "Invoke-Pester -Path ./tests/"
# Run specific test file
pwsh -Command "Invoke-Pester -Path ./tests/lib-modules.Tests.ps1"
# Run with detailed output
pwsh -Command "Invoke-Pester -Path ./tests/lib-modules.Tests.ps1 -Output Detailed"Test Coverage:
- Core module loading (
TerraformRunner.psm1,Validation.psm1,Logger.psm1) - Template module loading (AAP, AAPASM, PropertyManager, CPS)
- Function exports and imports
- Integration with
deploy.ps1
Before submitting PR, test your changes:
pwsh deploy.ps1 <template> -Env dev -Save
# or
# Dry-run (plan only, no changes)
pwsh deploy.ps1 <template> -Env dev -Save -Dry
# Examples:
pwsh deploy.ps1 aap -Env dev -Save -Dry
pwsh deploy.ps1 aapasm -Env qa -Save -Dry
pwsh deploy.ps1 pm -Env dev -Save -DryEnable detailed logging for troubleshooting:
pwsh deploy.ps1 aap -Env dev -Save -Debug
# Logs saved to: ./new-aap-configuration/environments/dev/dev-akamai_tf.logWhile deploy.ps1 is the primary interface, you can run Terraform directly for debugging:
cd new-aap-configuration
terraform init -backend-config="./environments/dev/config.backend"
terraform plan -var-file="./environments/dev/dev.tfvars"Note: Direct Terraform usage bypasses state isolation and retry logic.
With the release workflow, versioning is fully automated:
- ✅ Commits analyzed for semantic prefixes
- ✅
VERSIONfile auto-updated onmainbranch - ✅
CHANGELOG.mdauto-generated with categorized entries - ✅ Git tags created automatically
- ✅ GitHub releases published
No manual changelog or version updates needed!
Note: VERSION and CHANGELOG.md files in the integration branch may be outdated. The main branch is the single source of truth for releases. Always check the latest tag or main branch to see the current version.
If automation fails, manually update:
- VERSION file - Single line with semantic version
- CHANGELOG.md - Add entry following existing format
- Git tag - Create and push tag matching VERSION
- Open an issue: GitHub Issues
Thank you for contributing to the Terraform Templates!