Terraform Module Swapping¶
This tool provides a safe, reversible way to swap Terraform module source attributes between remote registry addresses and local relative paths for development.
Overview¶
The swap-terraform-modules.ps1 script automatically detects Terraform module sources pointing to app.terraform.io/SAIFCorp/... and swaps them with local relative paths, enabling local development while maintaining the ability to easily revert changes.
Files¶
swap-terraform-modules.ps1- Main swapping toolcheck-no-local-sources.ps1- CI validation scriptREADME-swap-terraform-modules.md- This documentation
Usage¶
Basic Commands¶
# See what would be changed (dry run)
pwsh ./scripts/swap-terraform-modules.ps1 -DryRun
# Apply changes to use local paths
pwsh ./scripts/swap-terraform-modules.ps1 -Apply
# Revert back to registry sources
pwsh ./scripts/swap-terraform-modules.ps1 -Undo
# List current operations
pwsh ./scripts/swap-terraform-modules.ps1 -ListOperations
Advanced Options¶
# Specify custom path
pwsh ./scripts/swap-terraform-modules.ps1 -Path src/terraform -DryRun
# Check for local sources (CI usage)
pwsh ./scripts/check-no-local-sources.ps1
How It Works¶
Auto-Detection¶
The script automatically scans .tf files for registry sources matching the pattern:
And converts them to local paths, routing each reference to the correct local repository:
| Provider | Registry path | Local repo | Local path |
|---|---|---|---|
azure |
networking/azure//modules/private_endpoint |
iac-azure-modules (sibling to forge) |
../iac-azure-modules/modules/azure-networking/modules/private_endpoint |
saif |
utilities/saif//modules/namer |
forge (current repo) |
src/terraform/saif-utilities/modules/namer |
Prerequisite for cross-repo swaps: Azure and Okta modules are now in separate GitHub repositories (
iac-azure-modules,iac-okta-modules). To swap references to those modules, clone them into the same parent directory asforge:
Example Conversion¶
Before (Registry Source):
module "search_diagnostic_settings" {
source = "app.terraform.io/SAIFCorp/observability/azure//modules/diagnostic_settings"
version = ">= 1.0.0, < 2.0.0"
# ... other configuration
}
After (Local Path — FullyQualified mode):
module "search_diagnostic_settings" {
source = "C:/tfsgit/github.com/saif-corp/iac-azure-modules/modules/azure-observability/modules/diagnostic_settings"
version = ">= 1.0.0, < 2.0.0"
# ... other configuration
}
Mapping Logic¶
The script uses this mapping logic (resolved relative to repos located as siblings of forge):
observability/azure//modules/diagnostic_settings→iac-azure-modules/modules/azure-observability/modules/diagnostic_settingsnetworking/azure//modules/private_endpoint→iac-azure-modules/modules/azure-networking/modules/private_endpointutilities/saif//modules/namer→src/terraform/saif-utilities/modules/namer(stays in forge)
Safety Features¶
Operation Tracking¶
- Records all operations in
scripts/.terraform/swap.json - Enables reliable undo functionality
- Tracks file paths, original/replacement values, and context
Validation¶
- Only modifies exact quoted
source = "..."patterns - Verifies file existence before operations
- Warns about mismatches during undo
Development Workflow¶
1. Start Local Development¶
# Check what would be changed
pwsh ./scripts/swap-terraform-modules.ps1 -DryRun
# Apply local path swapping
pwsh ./scripts/swap-terraform-modules.ps1 -Apply
# Verify changes work
terraform init
terraform plan
2. During Development¶
- Edit Terraform modules locally
- Test changes with local paths
- All module sources point to local directories
3. Before Committing¶
# Revert to registry sources
pwsh ./scripts/swap-terraform-modules.ps1 -Undo
# Verify no local paths remain
pwsh ./scripts/check-no-local-sources.ps1
# Test with registry sources
terraform init
terraform plan
# Commit changes
git add -A
git commit -m "Your changes"
CI/CD Integration¶
Add the CI check script to your build pipeline:
# Azure DevOps example
- task: PowerShell@2
displayName: 'Check No Local Sources'
inputs:
targetType: 'filePath'
filePath: 'scripts/check-no-local-sources.ps1'
arguments: '-Quiet'
workingDirectory: '$(Build.SourcesDirectory)'
The CI script will fail the build if any local source paths are detected.
Troubleshooting¶
Common Issues¶
"Could not parse registry source"
- The source format doesn't match expected pattern
- Manually verify the source URL format
"Current source not found during undo"
- File was manually modified after apply
- Check the current source value manually
- May need to manually revert specific files
"Path not found"
- Specified search path doesn't exist
- Use absolute paths or verify working directory
Recovery¶
If operations fail or files are corrupted:
- Use
git checkoutto revert file changes - Delete
scripts/.terraform/swap.jsonto reset state if needed
Best Practices¶
- Always run dry-run first to see what would be changed
- Run terraform init/plan after applying swaps
- Never commit local paths to main branches
- Use undo before committing to restore registry sources
- Test changes thoroughly in both local and registry modes
File Structure¶
scripts/
├── .terraform/
│ └── swap.json # Operation tracking (generated)
├── swap-terraform-modules.ps1 # Main script
├── check-no-local-sources.ps1 # CI validation
└── README-swap-terraform-modules.md
Exit Codes¶
0- Success1- Error or validation failure
Security Note¶
Local source modifications should only be used for development. Never commit local paths to production branches, as they will break CI/CD pipelines that don't have access to local file paths.