|
29 | 29 | echo "============================================================" |
30 | 30 | fi |
31 | 31 |
|
| 32 | +if ! command -v az >/dev/null 2>&1; then |
| 33 | + echo "❌ Azure CLI (az) is not installed or not on PATH." >&2 |
| 34 | + echo " Install it from https://aka.ms/installazurecli, then re-run." >&2 |
| 35 | + exit 1 |
| 36 | +fi |
| 37 | + |
| 38 | +if ! command -v azd >/dev/null 2>&1; then |
| 39 | + echo "❌ Azure Developer CLI (azd) is not installed or not on PATH." >&2 |
| 40 | + echo " Install it from https://aka.ms/install-azd, then re-run." >&2 |
| 41 | + exit 1 |
| 42 | +fi |
| 43 | + |
| 44 | +if ! azd env get-values >/dev/null 2>&1; then |
| 45 | + echo "❌ No active azd environment found." >&2 |
| 46 | + echo " Run 'azd env list' and 'azd env select <name>', then re-run." >&2 |
| 47 | + exit 1 |
| 48 | +fi |
| 49 | + |
32 | 50 | # --- Load values from azd env ------------------------------------------------- |
33 | 51 | ENV_NAME="$(azd env get-value AZURE_ENV_NAME 2>/dev/null || echo "")" |
34 | 52 | RESOURCE_GROUP="$(azd env get-value AZURE_RESOURCE_GROUP 2>/dev/null || true)" |
@@ -97,6 +115,20 @@ retry() { |
97 | 115 | done |
98 | 116 | } |
99 | 117 |
|
| 118 | +# Generate a UUID in a macOS/Linux portable way. |
| 119 | +generate_uuid() { |
| 120 | + if command -v uuidgen >/dev/null 2>&1; then |
| 121 | + uuidgen |
| 122 | + elif command -v python3 >/dev/null 2>&1; then |
| 123 | + python3 -c 'import uuid; print(uuid.uuid4())' |
| 124 | + elif [[ -r /proc/sys/kernel/random/uuid ]]; then |
| 125 | + cat /proc/sys/kernel/random/uuid |
| 126 | + else |
| 127 | + echo "❌ Unable to generate UUID. Install uuidgen or python3." >&2 |
| 128 | + exit 1 |
| 129 | + fi |
| 130 | +} |
| 131 | + |
100 | 132 | # Print a preflight check result line |
101 | 133 | _check() { |
102 | 134 | local status="$1" # PASS | WARN | FAIL |
@@ -164,6 +196,15 @@ validate_prerequisites_and_permissions() { |
164 | 196 | fatal=true |
165 | 197 | fi |
166 | 198 |
|
| 199 | + # ── 3b. Python 3 available (used for authConfig JSON patching) ─── |
| 200 | + if command -v python3 >/dev/null 2>&1; then |
| 201 | + _check PASS "python3 available (required for authConfig patching)" |
| 202 | + else |
| 203 | + _check FAIL "python3 available (required for authConfig patching)" \ |
| 204 | + "Install Python 3 and ensure 'python3' is on PATH, then re-run." |
| 205 | + fatal=true |
| 206 | + fi |
| 207 | + |
167 | 208 | # ── 4. Contributor (or Owner) on the resource group ────────────── |
168 | 209 | local current_principal |
169 | 210 | current_principal="$(az ad signed-in-user show --query id -o tsv 2>/dev/null || true)" |
@@ -301,7 +342,7 @@ API_IDENTIFIER_URI="api://${API_CLIENT_ID}" |
301 | 342 | API_SCOPE_ID="$(az ad app show --id "$API_CLIENT_ID" \ |
302 | 343 | --query "api.oauth2PermissionScopes[?value=='user_impersonation'].id | [0]" -o tsv)" |
303 | 344 | if [[ -z "$API_SCOPE_ID" || "$API_SCOPE_ID" == "null" ]]; then |
304 | | - API_SCOPE_ID="$(cat /proc/sys/kernel/random/uuid)" |
| 345 | + API_SCOPE_ID="$(generate_uuid)" |
305 | 346 | cat > /tmp/api_scope_patch.json <<EOF |
306 | 347 | { |
307 | 348 | "identifierUris": ["$API_IDENTIFIER_URI"], |
@@ -365,7 +406,7 @@ WEB_IDENTIFIER_URI="api://${WEB_CLIENT_ID}" |
365 | 406 | # + add SPA redirect URI + declare required resource access on API scope + Graph User.Read |
366 | 407 | WEB_SCOPE_ID="$(az ad app show --id "$WEB_CLIENT_ID" \ |
367 | 408 | --query "api.oauth2PermissionScopes[?value=='user_impersonation'].id | [0]" -o tsv)" |
368 | | -[[ -z "$WEB_SCOPE_ID" || "$WEB_SCOPE_ID" == "null" ]] && WEB_SCOPE_ID="$(cat /proc/sys/kernel/random/uuid)" |
| 409 | +[[ -z "$WEB_SCOPE_ID" || "$WEB_SCOPE_ID" == "null" ]] && WEB_SCOPE_ID="$(generate_uuid)" |
369 | 410 |
|
370 | 411 | cat > /tmp/web_patch.json <<EOF |
371 | 412 | { |
|
0 commit comments