# 3.8.6

**Release Date:** September 1, 2026

---

## 🐛 Bug Fixes

### Terraform Modules

#### Fix Spurious `409 RoleAssignmentExists` Errors in `saif-resources` External Identity 🔧

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

**PRs:** [#1075](https://github.com/saif-corp/forge/pull/1075), [#1077](https://github.com/saif-corp/forge/pull/1077) (backport of fixes already on `main`)

Fixes a Terraform apply failure:

```text
Error: unexpected status 409 (409 Conflict) with error: RoleAssignmentExists: The role assignment already exists. The ID of the existing role assignment is <guid>.

  with module.saif-appservices.module.external_identity.azurerm_role_assignment.okta_secret_reader["External"],
  on .terraform/modules/saif-appservices.external_identity/modules/external-identity/main.tf line 74, in resource "azurerm_role_assignment" "okta_secret_reader":
  74: resource "azurerm_role_assignment" "okta_secret_reader" {
```

`azurerm_role_assignment.okta_secret_reader` and `azurerm_role_assignment.oidc_secret_reader` had no `lifecycle` block. 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`). That casing-only diff forced a replacement on every subsequent apply, and the replacement's create collided with the still-existing original assignment, producing the 409. This is the same casing-drift pattern fixed for other role assignments in 3.6.6/3.6.7 and PR #1075, which had not yet reached `okta_secret_reader`/`oidc_secret_reader` on this release branch.

**Changes:**

- Added `lifecycle { ignore_changes = [scope] }` to `azurerm_role_assignment.okta_secret_reader` and `azurerm_role_assignment.oidc_secret_reader`, suppressing the casing-only diff
- Added `replace_triggered_by = [<the Key Vault secret resource>]` alongside it, so a genuine secret replacement (rename or move to a different vault) still forces the role assignment to re-create at the new scope, instead of silently pointing at a stale one

**Benefits:**

- 🚫 Eliminates `409 RoleAssignmentExists` errors on workspaces using the Okta/OIDC external-identity secrets
- 🔄 Prevents unnecessary role assignment replacement cycles caused purely by casing drift
- ✅ Consistent with the guard already applied to `client_secret_reader`, `cookie_secret_user`, and `cookie_secret_readers`

---

## 🔄 Breaking Changes

None in this release ✅

---

## 📋 Additional Notes

- Total commits: 2 (backported from `main`)
- 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)

---
