# 3.6.6

**Release Date:** May 21, 2026

---

## 🐛 Bug Fixes

### Terraform Modules

#### Fix Cookie Secret Naming Convention and Add Lifecycle Policy in `saif-api-service` 🔧

**Module:** `saif-api-service` (api module — `apimanagement.tf`)

**Commit:** [`766d3410`](https://github.com/saif-corp/forge/commit/766d3410)

Corrects the APIM Named Value name for the cookie secret resource from the all-lowercase `cookiesecret` suffix to the properly-cased `CookieSecret`, aligning it with APIM display name conventions. Additionally adds a `create_before_destroy = true` lifecycle policy to the `azurerm_api_management_named_value.cookie_secret` resource, preventing a brief availability gap when the named value is replaced (e.g. during a rename or key vault secret rotation).

**Changes:**

- Fixed Named Value name: `${project_id}-${env_short}-cookiesecret` → `${project_id}-${env_short}-CookieSecret`
- Added `lifecycle { create_before_destroy = true }` to prevent downtime on replacement

**Benefits:**

- 🔄 Ensures the APIM Named Value `name` attribute matches the casing used by APIM display names and downstream policy references
- 🚀 Eliminates a potential brief disruption when the named value resource is replaced, thanks to create-before-destroy ordering
- 🎯 Workspaces that had not yet provisioned the cookie secret resource will get the correctly-cased name from the start

---

#### Fix Spurious Role Assignment Replacement Due to Resource Group Casing Drift in `saif-resources` 🔧

**Module:** `saif-resources` (identity module — `main.tf`)

Adds a `lifecycle { ignore_changes = [scope] }` block to the `azurerm_role_assignment.client_secret_reader` resource. The AzureRM provider normalises resource group names to PascalCase in `resource_versionless_id` (e.g. `Shared-Services`), but Azure's RBAC API returns the casing used when the assignment was first created (e.g. `shared-services`). This mismatch caused Terraform to plan a forced replacement on every apply, and the subsequent `PUT` would 409 Conflict because the assignment already existed at the original scope.

**Changes:**

- Added `lifecycle { ignore_changes = [scope] }` to `azurerm_role_assignment.client_secret_reader`

**Benefits:**

- 🚫 Eliminates 409 Conflict errors on workspaces where the role assignment was created with lowercase resource group casing
- 🔄 Prevents unnecessary role assignment replacement cycles caused purely by casing drift
- ✅ Safe for all workspaces — ignoring `scope` does not affect the actual permissions granted

---

#### Replace `lower()` Workaround with `ignore_changes` for Application Secret Role Assignments in `saif-api-service` 🔧

**Module:** `saif-api-service` (`main.tf` — `azurerm_role_assignment.Application_Secret_Permissions`)

Removes the `lower()` call on `each.value.resource_versionless_id` and replaces it with `lifecycle { ignore_changes = [scope] }`, consistent with the fix applied to `saif-resources`. The `lower()` workaround locked newly created assignments to lowercase scopes, while the provider normalises to PascalCase — causing the same casing drift and 409 Conflict pattern on subsequent applies.

**Changes:**

- Removed `lower()` from `scope = lower(each.value.resource_versionless_id)`
- Added `lifecycle { ignore_changes = [scope] }` to suppress casing-only diffs

**Benefits:**

- 🚫 Eliminates 409 Conflict errors caused by `lower()` forcing a scope mismatch on re-apply
- 🔄 Consistent pattern across all Forge role assignment resources
- ✅ `resource_versionless_id` is stable (no version GUID), so ignoring `scope` carries no risk of masking real drift

---

## 🔄 Breaking Changes

None in this release ✅

---

## 📋 Additional Notes

- Total commits: 3
- Files changed: 3
- Contributors: Emmitt Johnson

---

### Support

- 📧 Teams Support Channel: [Support](https://teams.microsoft.com/l/channel/19%3Acb611810fb0b42b080cfff5590bdd51c%40thread.tacv2/Support?groupId=514d2dac-2d62-48ce-bf99-0fa0ce39469c&tenantId=a86cb8ed-369b-4df5-ace5-43811f6e08cf)
