From 23d768ccd53edabb0339ba3fa2c6fceec2725251 Mon Sep 17 00:00:00 2001 From: Shubhangi-Microsoft Date: Tue, 9 Jun 2026 14:38:01 +0530 Subject: [PATCH 1/4] fix(post-deploy): harden Content Understanding refresh against stale azd env value Bug #46192: the postprovision hook trusted azd env get-value CONTENT_UNDERSTANDING_ACCOUNT_NAME blindly and passed it to az cognitiveservices account update. A stale value (e.g. from a prior deployment against a different template) made Azure CLI emit a noisy ResourceNotFound block before the script swallowed the exit code, surfacing visible errors even though azd up ultimately succeeded. infra/scripts/post_deployment.sh: - Silent existence probe (2>/dev/null) before using the env value. - Fallback discovery via az cognitiveservices account list --query "[?kind=='AIServices'].name | [0]". - azd env set self-heals the env on successful discovery so subsequent runs are clean. - Refresh failure is now a non-fatal warning instead of a hard error. infra/scripts/post_deployment.ps1: - Added the previously-missing CU refresh block with the same three-stage logic adapted to PowerShell. Windows users were silently skipping the refresh step entirely before. Verified by reproducing the stale-value condition in a live azd env and confirming azd hooks run postprovision completes cleanly with no ResourceNotFound, the env value is auto-corrected, and the Cognitive Services account receives the refresh=true tag. Refs ADO #46192, #46576, #46577 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- infra/scripts/post_deployment.ps1 | 49 +++++++++++++++++++++++++++++++ infra/scripts/post_deployment.sh | 31 +++++++++++++++++-- 2 files changed, 77 insertions(+), 3 deletions(-) diff --git a/infra/scripts/post_deployment.ps1 b/infra/scripts/post_deployment.ps1 index aa116003..0aed3ff5 100644 --- a/infra/scripts/post_deployment.ps1 +++ b/infra/scripts/post_deployment.ps1 @@ -239,3 +239,52 @@ if (-not $ApiReady) { Write-Host " Schemas registered: $($Registered.Count)" Write-Host ("=" * 60) } + +# --- Refresh Content Understanding Cognitive Services account --- +Write-Host "" +Write-Host ("=" * 60) +Write-Host "Refreshing Content Understanding Cognitive Services account..." +Write-Host ("=" * 60) + +$CU_ACCOUNT_NAME = "" +try { + $CU_ACCOUNT_NAME = (azd env get-value CONTENT_UNDERSTANDING_ACCOUNT_NAME 2>$null) + if (-not $CU_ACCOUNT_NAME) { $CU_ACCOUNT_NAME = "" } +} catch { + $CU_ACCOUNT_NAME = "" +} + +# Verify the account from the env value still exists; if not, fall back to discovering +# the AIServices account in the resource group. This protects against stale .env values +# left over from prior deployments (different template/fork) and against the env value +# pointing to a resource that no longer exists. +if ($CU_ACCOUNT_NAME) { + az cognitiveservices account show -g $RESOURCE_GROUP -n $CU_ACCOUNT_NAME --output none 2>$null + if ($LASTEXITCODE -ne 0) { + Write-Host " [Warn] Cognitive Services account '$CU_ACCOUNT_NAME' from azd env was not found in resource group '$RESOURCE_GROUP'." + Write-Host " The azd env value may be stale. Attempting to discover the AIServices account in the resource group..." + $CU_ACCOUNT_NAME = "" + } +} + +if (-not $CU_ACCOUNT_NAME) { + $DiscoveredCuAccount = (az cognitiveservices account list -g $RESOURCE_GROUP --query "[?kind=='AIServices'].name | [0]" -o tsv 2>$null) + if ($DiscoveredCuAccount) { + Write-Host " Discovered AIServices account in resource group: $DiscoveredCuAccount" + $CU_ACCOUNT_NAME = $DiscoveredCuAccount + # Refresh the azd env so subsequent runs use the correct value. + try { azd env set CONTENT_UNDERSTANDING_ACCOUNT_NAME $CU_ACCOUNT_NAME 2>$null | Out-Null } catch { } + } +} + +if (-not $CU_ACCOUNT_NAME) { + Write-Host " [Warn] No Content Understanding (AIServices) account found in resource group '$RESOURCE_GROUP'. Skipping refresh." +} else { + Write-Host " Refreshing account: $CU_ACCOUNT_NAME in resource group: $RESOURCE_GROUP" + az cognitiveservices account update -g $RESOURCE_GROUP -n $CU_ACCOUNT_NAME --tags refresh=true --output none 2>$null + if ($LASTEXITCODE -eq 0) { + Write-Host " [OK] Successfully refreshed Cognitive Services account '$CU_ACCOUNT_NAME'." + } else { + Write-Host " [Warn] Could not refresh Cognitive Services account '$CU_ACCOUNT_NAME'. Continuing - this step is non-fatal." + } +} diff --git a/infra/scripts/post_deployment.sh b/infra/scripts/post_deployment.sh index 49644a4d..8fa38197 100644 --- a/infra/scripts/post_deployment.sh +++ b/infra/scripts/post_deployment.sh @@ -256,17 +256,42 @@ echo "============================================================" CU_ACCOUNT_NAME=$(azd env get-value CONTENT_UNDERSTANDING_ACCOUNT_NAME 2>/dev/null || echo "") +# Verify the account from the env value still exists; if not, fall back to discovering +# the AIServices account in the resource group. This protects against stale .env values +# left over from prior deployments (different template/fork) and against the env value +# pointing to a resource that no longer exists. +if [ -n "$CU_ACCOUNT_NAME" ]; then + if ! az cognitiveservices account show -g "$RESOURCE_GROUP" -n "$CU_ACCOUNT_NAME" --output none 2>/dev/null; then + echo " ⚠️ Cognitive Services account '$CU_ACCOUNT_NAME' from azd env was not found in resource group '$RESOURCE_GROUP'." + echo " The azd env value may be stale. Attempting to discover the AIServices account in the resource group..." + CU_ACCOUNT_NAME="" + fi +fi + +if [ -z "$CU_ACCOUNT_NAME" ]; then + DISCOVERED_CU_ACCOUNT=$(az cognitiveservices account list \ + -g "$RESOURCE_GROUP" \ + --query "[?kind=='AIServices'].name | [0]" \ + -o tsv 2>/dev/null || echo "") + if [ -n "$DISCOVERED_CU_ACCOUNT" ]; then + echo " Discovered AIServices account in resource group: $DISCOVERED_CU_ACCOUNT" + CU_ACCOUNT_NAME="$DISCOVERED_CU_ACCOUNT" + # Refresh the azd env so subsequent runs use the correct value. + azd env set CONTENT_UNDERSTANDING_ACCOUNT_NAME "$CU_ACCOUNT_NAME" >/dev/null 2>&1 || true + fi +fi + if [ -z "$CU_ACCOUNT_NAME" ]; then - echo " ⚠️ CONTENT_UNDERSTANDING_ACCOUNT_NAME not found in azd env. Skipping refresh." + echo " ⚠️ No Content Understanding (AIServices) account found in resource group '$RESOURCE_GROUP'. Skipping refresh." else echo " Refreshing account: $CU_ACCOUNT_NAME in resource group: $RESOURCE_GROUP" if az cognitiveservices account update \ -g "$RESOURCE_GROUP" \ -n "$CU_ACCOUNT_NAME" \ --tags refresh=true \ - --output none; then + --output none 2>/dev/null; then echo " ✅ Successfully refreshed Cognitive Services account '$CU_ACCOUNT_NAME'." else - echo " ❌ Failed to refresh Cognitive Services account '$CU_ACCOUNT_NAME'." + echo " ⚠️ Could not refresh Cognitive Services account '$CU_ACCOUNT_NAME'. Continuing — this step is non-fatal." fi fi From 1e1fc41bf3b7762f076fb93140799eaa159cbd5c Mon Sep 17 00:00:00 2001 From: Shubhangi-Microsoft Date: Tue, 9 Jun 2026 14:41:07 +0530 Subject: [PATCH 2/4] chore(infra): regenerate main.json with bicep 0.43.8 (no semantic change) Re-compiling infra/main.bicep with bicep CLI 0.43.8.12551 (was 0.42.1.51946) produces: - 48 lines of metadata stamp churn (compiler version + templateHash) - 4 lines of cosmetic ordering change in a dependsOn array (storageQueue and aiServices entries swap positions). ARM dependsOn arrays are unordered and resolved topologically, so the deployed graph is identical. No resources, parameters, outputs, modules, or logic changed. This keeps infra/main.json in sync with infra/main.bicep for the GitHub Actions deploy workflow (which uses main.json as its ARM template). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- infra/main.json | 52 ++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/infra/main.json b/infra/main.json index e8ba8e73..7aa9114e 100644 --- a/infra/main.json +++ b/infra/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "5885652317352749587" + "version": "0.43.8.12551", + "templateHash": "12545195410241248179" }, "name": "Content Processing Solution Accelerator", "description": "Bicep template to deploy the Content Processing Solution Accelerator with AVM compliance." @@ -337,8 +337,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "10219602196309243204" + "version": "0.43.8.12551", + "templateHash": "13206959925771644022" } }, "definitions": { @@ -19306,8 +19306,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "15098611015028470375" + "version": "0.43.8.12551", + "templateHash": "13200482898648544945" } }, "parameters": { @@ -23332,8 +23332,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "18123481228095028530" + "version": "0.43.8.12551", + "templateHash": "15729887991536611208" } }, "parameters": { @@ -23936,8 +23936,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "1869938830611166930" + "version": "0.43.8.12551", + "templateHash": "8672669912945312056" }, "name": "Container Registry Module" }, @@ -36183,8 +36183,8 @@ "avmContainerApp_API", "avmContainerApp_Workflow", "avmManagedIdentity", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageQueue)]", "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageBlob)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageQueue)]", "virtualNetwork" ] }, @@ -36314,8 +36314,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "18336251851332975005" + "version": "0.43.8.12551", + "templateHash": "9621562991003135575" }, "name": "Cognitive Services", "description": "This module deploys a Cognitive Service." @@ -37574,8 +37574,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "8883353547455396972" + "version": "0.43.8.12551", + "templateHash": "8864856500234357706" } }, "definitions": { @@ -39307,8 +39307,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "13560950051680758953" + "version": "0.43.8.12551", + "templateHash": "312284397710022090" } }, "definitions": { @@ -39461,8 +39461,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "2020223351407601593" + "version": "0.43.8.12551", + "templateHash": "276675105610077046" } }, "definitions": { @@ -39679,8 +39679,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "8883353547455396972" + "version": "0.43.8.12551", + "templateHash": "8864856500234357706" } }, "definitions": { @@ -41412,8 +41412,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "13560950051680758953" + "version": "0.43.8.12551", + "templateHash": "312284397710022090" } }, "definitions": { @@ -41566,8 +41566,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.42.1.51946", - "templateHash": "2020223351407601593" + "version": "0.43.8.12551", + "templateHash": "276675105610077046" } }, "definitions": { @@ -42487,9 +42487,9 @@ }, "dependsOn": [ "avmAiServices", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').aiServices)]", "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').contentUnderstanding)]", "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').openAI)]", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').aiServices)]", "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)]", "virtualNetwork" ] From f67f5f70786cd5655970db4dd23bd22839f0fc6e Mon Sep 17 00:00:00 2001 From: Shubhangi-Microsoft Date: Tue, 9 Jun 2026 16:33:37 +0530 Subject: [PATCH 3/4] fix(post-deploy): refuse to guess when multiple AIServices accounts exist Addresses Copilot review feedback on PR #615: enumerate all AIServices accounts in the resource group instead of blindly picking the first via `| [0]`. When exactly one is found, auto-recover and persist it to azd env. When multiple are found, emit a warning listing the candidates and ask the user to set CONTENT_UNDERSTANDING_ACCOUNT_NAME explicitly -- this prevents persisting the wrong account name into azd env, which would cause subsequent runs to refresh the wrong resource. Restructured both bash and PowerShell discovery blocks into a single if/elif/else chain so the "no account found" warning no longer prints a second time after the multi-account branch fires. Verified with mocked az/azd stubs across 0, 1, and 3-account scenarios: each path now prints exactly one outcome message. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- infra/scripts/post_deployment.ps1 | 22 +++++++++++++++------- infra/scripts/post_deployment.sh | 25 ++++++++++++++++--------- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/infra/scripts/post_deployment.ps1 b/infra/scripts/post_deployment.ps1 index 0aed3ff5..37fee1d7 100644 --- a/infra/scripts/post_deployment.ps1 +++ b/infra/scripts/post_deployment.ps1 @@ -268,18 +268,26 @@ if ($CU_ACCOUNT_NAME) { } if (-not $CU_ACCOUNT_NAME) { - $DiscoveredCuAccount = (az cognitiveservices account list -g $RESOURCE_GROUP --query "[?kind=='AIServices'].name | [0]" -o tsv 2>$null) - if ($DiscoveredCuAccount) { - Write-Host " Discovered AIServices account in resource group: $DiscoveredCuAccount" - $CU_ACCOUNT_NAME = $DiscoveredCuAccount + # Enumerate ALL AIServices accounts (not just the first). When the resource + # group contains exactly one we auto-recover; when it contains more than one + # we refuse to guess and ask the user to set the env value explicitly, to + # avoid persisting the wrong account name into azd env. + $CuAccounts = @(az cognitiveservices account list -g $RESOURCE_GROUP --query "[?kind=='AIServices'].name" -o tsv 2>$null) + $CuAccounts = @($CuAccounts | Where-Object { $_ -and $_.Trim() -ne "" }) + if ($CuAccounts.Count -eq 1) { + $CU_ACCOUNT_NAME = $CuAccounts[0] + Write-Host " Discovered AIServices account in resource group: $CU_ACCOUNT_NAME" # Refresh the azd env so subsequent runs use the correct value. try { azd env set CONTENT_UNDERSTANDING_ACCOUNT_NAME $CU_ACCOUNT_NAME 2>$null | Out-Null } catch { } + } elseif ($CuAccounts.Count -gt 1) { + Write-Host " [Warn] Multiple AIServices accounts found in resource group '$RESOURCE_GROUP': $($CuAccounts -join ', ')" + Write-Host " Please set CONTENT_UNDERSTANDING_ACCOUNT_NAME in azd env to the correct account name. Skipping refresh." + } else { + Write-Host " [Warn] No Content Understanding (AIServices) account found in resource group '$RESOURCE_GROUP'. Skipping refresh." } } -if (-not $CU_ACCOUNT_NAME) { - Write-Host " [Warn] No Content Understanding (AIServices) account found in resource group '$RESOURCE_GROUP'. Skipping refresh." -} else { +if ($CU_ACCOUNT_NAME) { Write-Host " Refreshing account: $CU_ACCOUNT_NAME in resource group: $RESOURCE_GROUP" az cognitiveservices account update -g $RESOURCE_GROUP -n $CU_ACCOUNT_NAME --tags refresh=true --output none 2>$null if ($LASTEXITCODE -eq 0) { diff --git a/infra/scripts/post_deployment.sh b/infra/scripts/post_deployment.sh index 8fa38197..614cd4eb 100644 --- a/infra/scripts/post_deployment.sh +++ b/infra/scripts/post_deployment.sh @@ -269,21 +269,28 @@ if [ -n "$CU_ACCOUNT_NAME" ]; then fi if [ -z "$CU_ACCOUNT_NAME" ]; then - DISCOVERED_CU_ACCOUNT=$(az cognitiveservices account list \ + # Enumerate ALL AIServices accounts (not just the first). When the resource + # group contains exactly one we auto-recover; when it contains more than one + # we refuse to guess and ask the user to set the env value explicitly, to + # avoid persisting the wrong account name into azd env. + mapfile -t CU_ACCOUNTS < <(az cognitiveservices account list \ -g "$RESOURCE_GROUP" \ - --query "[?kind=='AIServices'].name | [0]" \ - -o tsv 2>/dev/null || echo "") - if [ -n "$DISCOVERED_CU_ACCOUNT" ]; then - echo " Discovered AIServices account in resource group: $DISCOVERED_CU_ACCOUNT" - CU_ACCOUNT_NAME="$DISCOVERED_CU_ACCOUNT" + --query "[?kind=='AIServices'].name" \ + -o tsv 2>/dev/null || true) + if [ "${#CU_ACCOUNTS[@]}" -eq 1 ]; then + CU_ACCOUNT_NAME="${CU_ACCOUNTS[0]}" + echo " Discovered AIServices account in resource group: $CU_ACCOUNT_NAME" # Refresh the azd env so subsequent runs use the correct value. azd env set CONTENT_UNDERSTANDING_ACCOUNT_NAME "$CU_ACCOUNT_NAME" >/dev/null 2>&1 || true + elif [ "${#CU_ACCOUNTS[@]}" -gt 1 ]; then + echo " ⚠️ Multiple AIServices accounts found in resource group '$RESOURCE_GROUP': ${CU_ACCOUNTS[*]}" + echo " Please set CONTENT_UNDERSTANDING_ACCOUNT_NAME in azd env to the correct account name. Skipping refresh." + else + echo " ⚠️ No Content Understanding (AIServices) account found in resource group '$RESOURCE_GROUP'. Skipping refresh." fi fi -if [ -z "$CU_ACCOUNT_NAME" ]; then - echo " ⚠️ No Content Understanding (AIServices) account found in resource group '$RESOURCE_GROUP'. Skipping refresh." -else +if [ -n "$CU_ACCOUNT_NAME" ]; then echo " Refreshing account: $CU_ACCOUNT_NAME in resource group: $RESOURCE_GROUP" if az cognitiveservices account update \ -g "$RESOURCE_GROUP" \ From 0b5d1a701eecae876cebfd3b8db0d7f02d4d6f65 Mon Sep 17 00:00:00 2001 From: Shubhangi-Microsoft Date: Tue, 9 Jun 2026 16:49:44 +0530 Subject: [PATCH 4/4] fix(post-deploy): preserve stderr so transient CLI errors don't masquerade as resource-not-found Addresses Copilot review feedback on PR #615. stderr capture - `az cognitiveservices account show` previously discarded stderr and treated any non-zero exit as `account not found` - a transient auth or CLI error could wrongly clear CU_ACCOUNT_NAME and trigger discovery that persists a different account into azd env. Now we capture stderr, only mark stale when Azure actually reports the resource is missing (ResourceNotFound / was not found / could not be found), and otherwise log the error and keep the env value. - `az cognitiveservices account update` previously suppressed stderr too, hiding the actual CLI error on the non-fatal failure path. Now we capture and surface it in the warning message so deployment logs contain enough context to diagnose refresh failures. set -e safety - The script runs with `set -e`, so a failed `var=$(cmd)` would exit immediately, before we could inspect $?. Wrap the two new capture blocks with `set +e` / `set -e` so the error-handling paths actually run. bash 3.2 portability (macOS default) - Replace `mapfile` (bash 4+) with a portable `while IFS= read -r` loop so the discovery branch works on macOS too. Validated with a 7-preset harness (none, one, multi, stale-real, stale-trans, ok, update-fail) running the on-disk script under `set -e` against stubbed az/azd; `bash -n` passes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- infra/scripts/post_deployment.ps1 | 24 +++++++++++---- infra/scripts/post_deployment.sh | 49 ++++++++++++++++++++++++++----- 2 files changed, 61 insertions(+), 12 deletions(-) diff --git a/infra/scripts/post_deployment.ps1 b/infra/scripts/post_deployment.ps1 index 37fee1d7..4ed40a8e 100644 --- a/infra/scripts/post_deployment.ps1 +++ b/infra/scripts/post_deployment.ps1 @@ -259,11 +259,21 @@ try { # left over from prior deployments (different template/fork) and against the env value # pointing to a resource that no longer exists. if ($CU_ACCOUNT_NAME) { - az cognitiveservices account show -g $RESOURCE_GROUP -n $CU_ACCOUNT_NAME --output none 2>$null + # Capture stderr so we can distinguish a real "not found" response from a + # transient/auth/CLI failure. Only treat the env value as stale when Azure + # actually reports the resource is missing; for any other error keep the + # env value untouched and log the underlying error for diagnosability. + $ShowOutput = az cognitiveservices account show -g $RESOURCE_GROUP -n $CU_ACCOUNT_NAME --output none 2>&1 if ($LASTEXITCODE -ne 0) { - Write-Host " [Warn] Cognitive Services account '$CU_ACCOUNT_NAME' from azd env was not found in resource group '$RESOURCE_GROUP'." - Write-Host " The azd env value may be stale. Attempting to discover the AIServices account in the resource group..." - $CU_ACCOUNT_NAME = "" + $ShowOutputStr = ($ShowOutput | Out-String).Trim() + if ($ShowOutputStr -match '(?i)ResourceNotFound|was not found|could not be found') { + Write-Host " [Warn] Cognitive Services account '$CU_ACCOUNT_NAME' from azd env was not found in resource group '$RESOURCE_GROUP'." + Write-Host " The azd env value may be stale. Attempting to discover the AIServices account in the resource group..." + $CU_ACCOUNT_NAME = "" + } else { + Write-Host " [Warn] Could not verify Cognitive Services account '$CU_ACCOUNT_NAME' (transient or CLI error). Keeping env value and skipping discovery." + Write-Host " az error: $ShowOutputStr" + } } } @@ -289,10 +299,14 @@ if (-not $CU_ACCOUNT_NAME) { if ($CU_ACCOUNT_NAME) { Write-Host " Refreshing account: $CU_ACCOUNT_NAME in resource group: $RESOURCE_GROUP" - az cognitiveservices account update -g $RESOURCE_GROUP -n $CU_ACCOUNT_NAME --tags refresh=true --output none 2>$null + # Capture stderr so that any Azure CLI error is preserved in deployment + # logs even though this refresh step is non-fatal. + $UpdateOutput = az cognitiveservices account update -g $RESOURCE_GROUP -n $CU_ACCOUNT_NAME --tags refresh=true --output none 2>&1 if ($LASTEXITCODE -eq 0) { Write-Host " [OK] Successfully refreshed Cognitive Services account '$CU_ACCOUNT_NAME'." } else { + $UpdateOutputStr = ($UpdateOutput | Out-String).Trim() Write-Host " [Warn] Could not refresh Cognitive Services account '$CU_ACCOUNT_NAME'. Continuing - this step is non-fatal." + Write-Host " az error: $UpdateOutputStr" } } diff --git a/infra/scripts/post_deployment.sh b/infra/scripts/post_deployment.sh index 614cd4eb..cb4788e6 100644 --- a/infra/scripts/post_deployment.sh +++ b/infra/scripts/post_deployment.sh @@ -261,10 +261,29 @@ CU_ACCOUNT_NAME=$(azd env get-value CONTENT_UNDERSTANDING_ACCOUNT_NAME 2>/dev/nu # left over from prior deployments (different template/fork) and against the env value # pointing to a resource that no longer exists. if [ -n "$CU_ACCOUNT_NAME" ]; then - if ! az cognitiveservices account show -g "$RESOURCE_GROUP" -n "$CU_ACCOUNT_NAME" --output none 2>/dev/null; then - echo " ⚠️ Cognitive Services account '$CU_ACCOUNT_NAME' from azd env was not found in resource group '$RESOURCE_GROUP'." - echo " The azd env value may be stale. Attempting to discover the AIServices account in the resource group..." - CU_ACCOUNT_NAME="" + # Capture stderr so we can distinguish a real "not found" response from a + # transient/auth/CLI failure. Only treat the env value as stale when Azure + # actually reports the resource is missing; for any other error keep the + # env value untouched and log the underlying error for diagnosability. + # `set +e` is required because `set -e` (enabled at the top of the script) + # would otherwise exit the script as soon as `az ... show` returns non-zero, + # before we can inspect $? and decide whether to fall back to discovery. + set +e + CU_SHOW_ERR=$(az cognitiveservices account show \ + -g "$RESOURCE_GROUP" \ + -n "$CU_ACCOUNT_NAME" \ + --output none 2>&1) + CU_SHOW_EC=$? + set -e + if [ $CU_SHOW_EC -ne 0 ]; then + if echo "$CU_SHOW_ERR" | grep -qiE "ResourceNotFound|was not found|could not be found"; then + echo " ⚠️ Cognitive Services account '$CU_ACCOUNT_NAME' from azd env was not found in resource group '$RESOURCE_GROUP'." + echo " The azd env value may be stale. Attempting to discover the AIServices account in the resource group..." + CU_ACCOUNT_NAME="" + else + echo " ⚠️ Could not verify Cognitive Services account '$CU_ACCOUNT_NAME' (transient or CLI error). Keeping env value and skipping discovery." + echo " az error: $CU_SHOW_ERR" + fi fi fi @@ -273,7 +292,13 @@ if [ -z "$CU_ACCOUNT_NAME" ]; then # group contains exactly one we auto-recover; when it contains more than one # we refuse to guess and ask the user to set the env value explicitly, to # avoid persisting the wrong account name into azd env. - mapfile -t CU_ACCOUNTS < <(az cognitiveservices account list \ + # Use a portable `while read` loop instead of `mapfile`, because `mapfile` + # requires bash 4+ and the azd postprovision hook also runs on macOS where + # the default shell is still bash 3.2. + CU_ACCOUNTS=() + while IFS= read -r _cu_acct; do + [ -n "$_cu_acct" ] && CU_ACCOUNTS+=("$_cu_acct") + done < <(az cognitiveservices account list \ -g "$RESOURCE_GROUP" \ --query "[?kind=='AIServices'].name" \ -o tsv 2>/dev/null || true) @@ -292,13 +317,23 @@ fi if [ -n "$CU_ACCOUNT_NAME" ]; then echo " Refreshing account: $CU_ACCOUNT_NAME in resource group: $RESOURCE_GROUP" - if az cognitiveservices account update \ + # Capture stderr so that any Azure CLI error is preserved in deployment + # logs even though this refresh step is non-fatal. + # `set +e` is required because `set -e` (enabled at the top of the script) + # would otherwise exit the script as soon as `az ... update` returns + # non-zero, defeating the explicit "non-fatal" handling below. + set +e + CU_UPDATE_ERR=$(az cognitiveservices account update \ -g "$RESOURCE_GROUP" \ -n "$CU_ACCOUNT_NAME" \ --tags refresh=true \ - --output none 2>/dev/null; then + --output none 2>&1) + CU_UPDATE_EC=$? + set -e + if [ $CU_UPDATE_EC -eq 0 ]; then echo " ✅ Successfully refreshed Cognitive Services account '$CU_ACCOUNT_NAME'." else echo " ⚠️ Could not refresh Cognitive Services account '$CU_ACCOUNT_NAME'. Continuing — this step is non-fatal." + echo " az error: $CU_UPDATE_ERR" fi fi