# 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 tool
- `check-no-local-sources.ps1` - CI validation script
- `README-swap-terraform-modules.md` - This documentation

## Usage

### Basic Commands

```powershell
# 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

```powershell
# 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:

```
app.terraform.io/SAIFCorp/{category}/{type}//modules/{module_name}
```

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 as `forge`:
>
> ```text
> saif-corp/
>   forge/               ← you are here
>   iac-azure-modules/   ← clone from github.com/saif-corp/iac-azure-modules
>   iac-okta-modules/    ← clone from github.com/saif-corp/iac-okta-modules
> ```

### Example Conversion

**Before (Registry Source):**

```hcl
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):**

```hcl
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_settings`
- `networking/azure//modules/private_endpoint` → `iac-azure-modules/modules/azure-networking/modules/private_endpoint`
- `utilities/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

```powershell
# 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

```powershell
# 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:

```yaml
# 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:

1. Use `git checkout` to revert file changes
2. Delete `scripts/.terraform/swap.json` to reset state if needed

## Best Practices

1. **Always run dry-run first** to see what would be changed
2. **Run terraform init/plan** after applying swaps
3. **Never commit local paths** to main branches
4. **Use undo before committing** to restore registry sources
5. **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` - Success
- `1` - 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.
