From b7189f42cd558dfedd7f985b641287c230b816a8 Mon Sep 17 00:00:00 2001 From: David Watson Date: Tue, 11 Feb 2025 17:37:08 +1100 Subject: [PATCH 1/5] Bash AAD scripts, fix admin issue with dev auth --- README.md | 2 +- docs/10-managed-identities.md | 7 +- docs/3-run-locally.md | 4 + docs/4-deploy-to-azure.md | 22 ++ scripts/add_localdev_roles.sh | 85 ++++++ scripts/appreg_setup.sh | 73 +++++ src/features/auth-page/auth-api.ts | 5 +- src/package-lock.json | 423 +++++++++++++++++++---------- 8 files changed, 468 insertions(+), 153 deletions(-) create mode 100755 scripts/add_localdev_roles.sh create mode 100755 scripts/appreg_setup.sh diff --git a/README.md b/README.md index beafd3b19..089552412 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # What's new - January 2025 A new year brings some much requested feature updates to one of our most popular AI chat repos! - **[Managed Identity-based security](/docs/10-managed-identities.md)**. This uses Azure's underlying RBAC and removes (almost) all keys/secrets. -- `appreg_setup.ps1` helper script to **[create the App Registration for you](/docs/5-add-identity.md#azure-ad-authentication-provider)** in Entra (if you have the permissions). Less copypasta means happier devs 🥰 +- `appreg_setup.ps1` and `appreg_setup.sh` helper scripts to **[create the App Registration for you](/docs/5-add-identity.md#azure-ad-authentication-provider)** in Entra (if you have the permissions). Less copypasta means happier devs 🥰 # Unleash the Power of Azure OpenAI diff --git a/docs/10-managed-identities.md b/docs/10-managed-identities.md index cb732a8ea..539b2af43 100644 --- a/docs/10-managed-identities.md +++ b/docs/10-managed-identities.md @@ -50,7 +50,12 @@ To deploy the application to Azure App Service with Managed Identities, follow t - Run this script to grant yourself RBAC permissions on the Azure resources so you can run AzureChat locally - In Powershell: ```powershell - PS> .\scripts\appreg_setup.ps1 + PS> .\scripts\add_localdev_roles.ps1 + ``` + - In Bash: + ```bash + > chmod +x .\scripts\add_localdev_roles.sh + > .\scripts\add_localdev_roles.sh ``` - You can now refer to the documentation to [run Azure Chat locally](3-run-locally.md). diff --git a/docs/3-run-locally.md b/docs/3-run-locally.md index b2c2cc6f7..9d9ce59bd 100644 --- a/docs/3-run-locally.md +++ b/docs/3-run-locally.md @@ -12,6 +12,10 @@ Clone this repository locally or fork to your GitHub account. Run all of the the 1. Change directory to the `src` folder 2. Rename/copy the file `.env.example` to `.env.local` and populate the environment variables based on the deployed resources in Azure. + + > **NOTE** + > If you have used the Azure Developer CLI to deploy the Azure infrastructure required for the solution ([using the directions here](./4-deploy-to-azure.md)), you can find the values for many the required environment variables in the `.env` file the `.azure\` directory. This generated file will not contain any keys, however it is recommended to use managed identities as described in "Setup your local development environment" on [this page](./10-managed-identities.md). + 3. Install npm packages by running `npm install` 4. Start the app by running `npm run dev` 5. Access the app on [http://localhost:3000](http://localhost:3000) diff --git a/docs/4-deploy-to-azure.md b/docs/4-deploy-to-azure.md index 4165f9c78..12799f72c 100644 --- a/docs/4-deploy-to-azure.md +++ b/docs/4-deploy-to-azure.md @@ -1,3 +1,25 @@ +# ☁️ Deploy to Azure - Azure Developer CLI (azd) + +To deploy the application to Azure using the Azure Developer CLI, follow the steps below. + +> [!IMPORTANT] +> This section will create Azure resources and deploy the solution from your local environment using the Azure Developer CLI. Note that you do not need to clone this repo to complete these steps. + +1. Download the [Azure Developer CLI](https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/overview) +1. If you have not cloned this repo, run `azd init -t microsoft/azurechat`. If you have cloned this repo, just run 'azd init' from the repo root directory. +1. Run `azd up` to provision and deploy the application + +```pwsh +azd init -t microsoft/azurechat +azd up + +# if you have already cloned the repo +azd up + +# if you are wanting to see logs run with debug flag +azd up --debug +``` + # ☁️ Deploy to Azure - GitHub Actions The following steps describes how the application can be deployed to Azure App service using GitHub Actions. diff --git a/scripts/add_localdev_roles.sh b/scripts/add_localdev_roles.sh new file mode 100755 index 000000000..f7d6386be --- /dev/null +++ b/scripts/add_localdev_roles.sh @@ -0,0 +1,85 @@ +#!/bin/bash +# filepath: /home/dwatson/wip/github/microsoft/azurechat/scripts/add_localdev_roles.sh + +echo -e "\nThis script will add the required IAM roles to allow the logged in user to run AzureChat locally." +echo "This will only work if you have used AZD to deploy the app, and have the required permissions to modify IAM." + +echo -e "\nLoading azd .env file from current environment..." +# Read the environment variables from azd and export them +while IFS= read -r line; do + # Only process lines with an equal sign + if [[ "$line" != *"="* ]]; then + continue + fi + + key="${line%%=*}" + value="${line#*=}" + # Remove leading and trailing quotes if they exist + value="${value%\"}" + value="${value#\"}" + export "$key"="$value" +done < <(azd env get-values) + +# Retrieve required environment variables +sub="${AZURE_SUBSCRIPTION_ID}" +rg="${AZURE_RESOURCE_GROUP}" +appName="${AZURE_WEBAPP_NAME}" +cosmosAccName="${AZURE_COSMOSDB_ACCOUNT_NAME}" +aillmName="${AZURE_OPENAI_API_INSTANCE_NAME}" +searchName="${AZURE_SEARCH_NAME}" +storageName="${AZURE_STORAGE_ACCOUNT_NAME}" +dalleName="${AZURE_OPENAI_DALLE_API_INSTANCE_NAME}" +docIntelName="${AZURE_DOCUMENT_INTELLIGENCE_NAME}" + +echo "Resource Group: $rg" +echo "App Host Name: $appName" +echo "CosmosDB Account: $cosmosAccName" +echo "OpenAI LLM Instance: $aillmName" +echo "OpenAI DALL-E Instance: $dalleName" +echo "Storage Account: $storageName" +echo "Document Intelligence: $docIntelName" +echo "Search Service: $searchName" + +# Get currently logged in user details using az and jq +userId=$(az ad signed-in-user show --query "id" -o tsv) +userPrincipalName=$(az ad signed-in-user show --query "userPrincipalName" -o tsv) + +echo -e "\nLogged-in user: $userPrincipalName (ID: $userId)" + +read -p $'\nDoes this look ok? \nEnter "y" to continue, anything else to exit: ' response +if [[ "$response" != "y" ]]; then + exit +fi + +echo -e "\nAdding 'Cosmos DB Built-in Data Contributor' role on $cosmosAccName" +az cosmosdb sql role assignment create --account-name "$cosmosAccName" \ + --resource-group "$rg" \ + --scope "/" \ + --principal-id "$userId" \ + --role-definition-id "00000000-0000-0000-0000-000000000002" + +aillmNameScope="/subscriptions/$sub/resourceGroups/$rg/providers/Microsoft.CognitiveServices/accounts/$aillmName" +dalleScope="/subscriptions/$sub/resourceGroups/$rg/providers/Microsoft.CognitiveServices/accounts/$dalleName" +storageScope="/subscriptions/$sub/resourceGroups/$rg/providers/Microsoft.Storage/storageAccounts/$storageName" +searchScope="/subscriptions/$sub/resourceGroups/$rg/providers/Microsoft.Search/searchServices/$searchName" +docIntelScope="/subscriptions/$sub/resourceGroups/$rg/providers/Microsoft.CognitiveServices/accounts/$docIntelName" + +echo -e "\nAdding 'Cognitive Services OpenAI User' role on $aillmName" +az role assignment create --assignee "$userId" --role "Cognitive Services OpenAI User" --scope "$aillmNameScope" + +echo -e "\nAdding 'Cognitive Services OpenAI User' role on $dalleName" +az role assignment create --assignee "$userId" --role "Cognitive Services OpenAI User" --scope "$dalleScope" + +echo -e "\nAdding 'Storage Blob Data Contributor' role on $storageName" +az role assignment create --assignee "$userId" --role "Storage Blob Data Contributor" --scope "$storageScope" + +echo -e "\nAdding 'Cognitive Services User' role on $docIntelName" +az role assignment create --assignee "$userId" --role "Cognitive Services User" --scope "$docIntelScope" + +echo -e "\nAdding 'Search Service Contributor' role on $searchName" +az role assignment create --assignee "$userId" --role "Search Service Contributor" --scope "$searchScope" + +echo -e "\nAdding 'Search Index Data Contributor' role on $searchName" +az role assignment create --assignee "$userId" --role "Search Index Data Contributor" --scope "$searchScope" + +echo "All done!" \ No newline at end of file diff --git a/scripts/appreg_setup.sh b/scripts/appreg_setup.sh new file mode 100755 index 000000000..57d9a3139 --- /dev/null +++ b/scripts/appreg_setup.sh @@ -0,0 +1,73 @@ +#!/bin/bash +# filepath: /home/dwatson/wip/github/microsoft/azurechat/scripts/appreg_setup.sh + +# Parse parameters +showsecret_flag="false" +webappname="" + +while [[ "$#" -gt 0 ]]; do + case $1 in + -w|--webappname) + webappname="$2" + shift + ;; + -showsecret) + showsecret_flag="true" + ;; + *) + echo "Unknown parameter passed: $1" + exit 1 + ;; + esac + shift +done + +if [[ -z "$webappname" ]]; then + echo "" + echo "Usage: $0 -w [-showsecret]" + echo "No arguments provided. Please provide the web app name from the Azure portal (e.g. azurechat-ulg3yy5ybjhdq)." + exit 1 +fi + +tenantid=$(az account show --query tenantId --output tsv | tr -d '[:space:]') + +echo "About to create a new App Registration called ${webappname}-app in Microsoft Entra tenant $tenantid" +echo "NOTE: This will only work if you have the necessary permissions in the tenant." + +read -p "Do you wish to proceed (y/n)? " choice +if [[ "$choice" != "y" && "$choice" != "Y" ]]; then + echo "Exiting." + exit 1 +fi + +clientid=$(az ad app create --display-name "${webappname}-app" --sign-in-audience AzureADMyOrg --query appId --output tsv | tr -d '[:space:]') +echo "> Creating app registration with client id $clientid ..." + +objectid=$(az ad app show --id $clientid --query id --output tsv | tr -d '[:space:]') +echo "Done. Object id is $objectid" + +echo "> Creating client secret... (you can ignore credential warnings)" +clientsecret=$(az ad app credential reset --id $clientid --append --display-name mysecret --years 1 --query password --output tsv | tr -d '[:space:]') +echo "Done." + +redirecturl="https://${webappname}.azurewebsites.net/api/auth/callback/azure-ad" +graphurl="https://graph.microsoft.com/v1.0/applications/${objectid}" +echo "> Updating redirect url to $redirecturl..." +az rest --method PATCH --uri $graphurl --body "{'web':{'redirectUris':['${redirecturl}']}}" +echo "Done." + +rg=$(az webapp list --query "[?name=='${webappname}'].resourceGroup" --output tsv | tr -d '[:space:]') +echo "> Found the app resource group: $rg" + +echo "> Updating app settings with client id, tenant id, and client secret..." +az webapp config appsettings set -n "$webappname" -g "$rg" --settings "AZURE_AD_CLIENT_ID=$clientid" "AZURE_AD_TENANT_ID=$tenantid" "AZURE_AD_CLIENT_SECRET=$clientsecret" --output none +echo "Done." + +echo "AZURE_AD_CLIENT_ID=$clientid" +echo "AZURE_AD_TENANT_ID=$tenantid" +if [[ "$showsecret_flag" == "true" ]]; then + echo "AZURE_AD_CLIENT_SECRET=$clientsecret" + echo "^^ Ensure you clear your console history to remove this secret" +fi + +echo "> Setup complete." \ No newline at end of file diff --git a/src/features/auth-page/auth-api.ts b/src/features/auth-page/auth-api.ts index a70aaca47..8883f23da 100644 --- a/src/features/auth-page/auth-api.ts +++ b/src/features/auth-page/auth-api.ts @@ -75,12 +75,13 @@ const configureIdentityProvider = () => { id: hashValue(email), name: username, email: email, - isAdmin: false, + isAdmin: adminEmails?.includes(email), image: "", }; console.log( "=== DEV USER LOGGED IN:\n", - JSON.stringify(user, null, 2) + JSON.stringify(user, null, 2, + ) ); return user; }, diff --git a/src/package-lock.json b/src/package-lock.json index 2fdc29900..1817e43ae 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -10,8 +10,9 @@ "dependencies": { "@azure/ai-form-recognizer": "^5.0.0", "@azure/cosmos": "^4.0.0", - "@azure/identity": "^4.0.0", + "@azure/identity": "^4.4.1", "@azure/keyvault-secrets": "^4.7.0", + "@azure/openai": "^2.0.0-beta.2", "@azure/search-documents": "^12.0.0", "@azure/storage-blob": "^12.17.0", "@codemirror/lang-javascript": "^6.2.1", @@ -41,7 +42,7 @@ "next": "14.0.4", "next-auth": "^4.24.5", "next-themes": "^0.2.1", - "openai": "^4.26.0", + "openai": "^4.67.1", "react": "^18", "react-dom": "^18", "react-syntax-highlighter": "^15.5.0", @@ -84,6 +85,35 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@azure-rest/core-client": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@azure-rest/core-client/-/core-client-2.3.3.tgz", + "integrity": "sha512-fTj4eanz7+ph0reoS4VaqFXP9PUkiTWOq+RVrgaNiUpHn0p6RgHRM+eSo7EnB89KGmIRg6gUpFjxModmjXVUPg==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.3.0", + "@azure/core-rest-pipeline": "^1.5.0", + "@azure/core-tracing": "^1.0.1", + "@azure/core-util": "^1.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure-rest/core-client/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@azure/abort-controller": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.1.0.tgz", @@ -115,33 +145,59 @@ } }, "node_modules/@azure/core-auth": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.5.0.tgz", - "integrity": "sha512-udzoBuYG1VBoHVohDTrvKjyzel34zt77Bhp7dQntVGGD0ehVq48owENbBG8fIgkHRNUBQH5k1r0hpoMu5L8+kw==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.9.0.tgz", + "integrity": "sha512-FPwHpZywuyasDSLMqJ6fhbOK3TqUdviZNF8OqRGA4W5Ewib2lEEZ+pBsYcBa88B2NGO/SEnYPGhyBqNlE8ilSw==", + "license": "MIT", "dependencies": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-util": "^1.1.0", - "tslib": "^2.2.0" + "@azure/abort-controller": "^2.0.0", + "@azure/core-util": "^1.11.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-auth/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@azure/core-client": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.7.3.tgz", - "integrity": "sha512-kleJ1iUTxcO32Y06dH9Pfi9K4U+Tlb111WXEnbt7R/ne+NLRwppZiTGJuTD5VVoxTMK5NTbEtm5t2vcdNCFe2g==", + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.9.2.tgz", + "integrity": "sha512-kRdry/rav3fUKHl/aDLd/pDLcB+4pOFwPPTVEExuMyaI5r+JBbMWqRbCY1pn5BniDaU3lRxO9eaQ1AmSMehl/w==", + "license": "MIT", "dependencies": { - "@azure/abort-controller": "^1.0.0", + "@azure/abort-controller": "^2.0.0", "@azure/core-auth": "^1.4.0", "@azure/core-rest-pipeline": "^1.9.1", "@azure/core-tracing": "^1.0.0", - "@azure/core-util": "^1.0.0", + "@azure/core-util": "^1.6.1", "@azure/logger": "^1.0.0", - "tslib": "^2.2.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-client/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@azure/core-http": { @@ -227,33 +283,56 @@ } }, "node_modules/@azure/core-rest-pipeline": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.13.0.tgz", - "integrity": "sha512-a62aP/wppgmnfIkJLfcB4ssPBcH94WzrzPVJ3tlJt050zX4lfmtnvy95D3igDo3f31StO+9BgPrzvkj4aOxnoA==", + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.19.0.tgz", + "integrity": "sha512-bM3308LRyg5g7r3Twprtqww0R/r7+GyVxj4BafcmVPo4WQoGt5JXuaqxHEFjw2o3rvFZcUPiqJMg6WuvEEeVUA==", + "license": "MIT", "dependencies": { - "@azure/abort-controller": "^1.1.0", - "@azure/core-auth": "^1.4.0", + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.8.0", "@azure/core-tracing": "^1.0.1", - "@azure/core-util": "^1.3.0", + "@azure/core-util": "^1.11.0", "@azure/logger": "^1.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "tslib": "^2.2.0" + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, + "node_modules/@azure/core-rest-pipeline/node_modules/agent-base": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/@azure/core-rest-pipeline/node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", "dependencies": { - "agent-base": "6", + "agent-base": "^7.1.2", "debug": "4" }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/@azure/core-tracing": { @@ -268,15 +347,28 @@ } }, "node_modules/@azure/core-util": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.6.1.tgz", - "integrity": "sha512-h5taHeySlsV9qxuK64KZxy4iln1BtMYlNt5jbuEFN3UFSAd1EwKg/Gjl5a6tZ/W8t6li3xPnutOx7zbDyXnPmQ==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.11.0.tgz", + "integrity": "sha512-DxOSLua+NdpWoSqULhjDyAZTXFdP/LKkqtYuxxz1SCN289zk3OG8UOpnCQAz/tygyACBtWp/BoO72ptK7msY8g==", + "license": "MIT", "dependencies": { - "@azure/abort-controller": "^1.0.0", - "tslib": "^2.2.0" + "@azure/abort-controller": "^2.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-util/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, "node_modules/@azure/cosmos": { @@ -311,19 +403,20 @@ } }, "node_modules/@azure/identity": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.0.0.tgz", - "integrity": "sha512-gtPYxIL0kI39Dw4t3HvlbfhOdXqKD2MqDgynlklF0j728j51dcKgRo6FLX0QzpBw/1gGfLxjMXqq3nKOSQ2lmA==", - "dependencies": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-auth": "^1.5.0", - "@azure/core-client": "^1.4.0", - "@azure/core-rest-pipeline": "^1.1.0", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.6.0.tgz", + "integrity": "sha512-ANpO1iAvcZmpD4QY7/kaE/P2n66pRXsDp3nMUC6Ow3c9KfXOZF7qMU9VgqPw8m7adP7TVIbVyrCEmD9cth3KQQ==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.9.0", + "@azure/core-client": "^1.9.2", + "@azure/core-rest-pipeline": "^1.17.0", "@azure/core-tracing": "^1.0.0", - "@azure/core-util": "^1.0.0", + "@azure/core-util": "^1.11.0", "@azure/logger": "^1.0.0", - "@azure/msal-browser": "^3.5.0", - "@azure/msal-node": "^2.5.1", + "@azure/msal-browser": "^4.0.1", + "@azure/msal-node": "^2.15.0", "events": "^3.0.0", "jws": "^4.0.0", "open": "^8.0.0", @@ -334,6 +427,18 @@ "node": ">=18.0.0" } }, + "node_modules/@azure/identity/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@azure/keyvault-secrets": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/@azure/keyvault-secrets/-/keyvault-secrets-4.7.0.tgz", @@ -380,30 +485,33 @@ } }, "node_modules/@azure/msal-browser": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-3.7.0.tgz", - "integrity": "sha512-ktDB/Gf7UDgYBJOnoIlh70lxIo4e1/D2UgHuayB4RntN1IlusfTtIVH3k8NpJMdl+38tfTXIaUoR+qlr5voZEg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-4.2.0.tgz", + "integrity": "sha512-MXQjgAgjg/2VRKV+UPWHESoZPcue2ZvWKfpBLCyTUyixP+mhCl0q5D1+xDiwBGV3lru2poKZVZDQAOE40wKmWg==", + "license": "MIT", "dependencies": { - "@azure/msal-common": "14.6.0" + "@azure/msal-common": "15.1.1" }, "engines": { "node": ">=0.8.0" } }, "node_modules/@azure/msal-common": { - "version": "14.6.0", - "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.6.0.tgz", - "integrity": "sha512-AGusT/JvxdzJIYi5u0n97cmhd3pUT6UuI6rEkT5iDeT2FGcV0/EB8pk+dy6GLPpYg9vhDCuyoYrEZGd+2UeCCQ==", + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-15.1.1.tgz", + "integrity": "sha512-bvLWYq9fleAcTJ6H+hfkG91On6vI/UhGyOB7Z6r0Bsa+KTL3zPtigmGCOJgdxrEklOYD88X9SehexLDH/5NRKQ==", + "license": "MIT", "engines": { "node": ">=0.8.0" } }, "node_modules/@azure/msal-node": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.6.1.tgz", - "integrity": "sha512-wYwz83pWatTNWUCkTi3cAOXbchad5FnZz/pbZz7b8Z6FuEqohXcTtg6BLip9SmcjN6FlbwUdJIZYOof2v1Gnrg==", + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.16.2.tgz", + "integrity": "sha512-An7l1hEr0w1HMMh1LU+rtDtqL7/jw74ORlc9Wnh06v7TU/xpG39/Zdr1ZJu3QpjUfKJ+E0/OXMW8DRSWTlh7qQ==", + "license": "MIT", "dependencies": { - "@azure/msal-common": "14.6.0", + "@azure/msal-common": "14.16.0", "jsonwebtoken": "^9.0.0", "uuid": "^8.3.0" }, @@ -411,14 +519,37 @@ "node": ">=16" } }, + "node_modules/@azure/msal-node/node_modules/@azure/msal-common": { + "version": "14.16.0", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.16.0.tgz", + "integrity": "sha512-1KOZj9IpcDSwpNiQNjt0jDYZpQvNZay7QAEi/5DLubay40iGYtLzya/jbjRPLyOTZhEKyL1MzPuw2HqBCjceYA==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/@azure/msal-node/node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } }, + "node_modules/@azure/openai": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@azure/openai/-/openai-2.0.0.tgz", + "integrity": "sha512-zSNhwarYbqg3P048uKMjEjbge41OnAgmiiE1elCHVsuCCXRyz2BXnHMJkW6WR6ZKQy5NHswJNUNSWsuqancqFA==", + "license": "MIT", + "dependencies": { + "@azure-rest/core-client": "^2.2.0", + "tslib": "^2.6.3" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@azure/search-documents": { "version": "12.0.0", "resolved": "https://registry.npmjs.org/@azure/search-documents/-/search-documents-12.0.0.tgz", @@ -2428,14 +2559,6 @@ "node": ">=4" } }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "engines": { - "node": ">= 10" - } - }, "node_modules/@types/hast": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.8.tgz", @@ -3067,11 +3190,6 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, - "node_modules/base-64": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", - "integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==" - }, "node_modules/bent": { "version": "7.3.12", "resolved": "https://registry.npmjs.org/bent/-/bent-7.3.12.tgz", @@ -3261,14 +3379,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/charenc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", - "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", - "engines": { - "node": "*" - } - }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -3441,14 +3551,6 @@ "node": ">= 8" } }, - "node_modules/crypt": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", - "engines": { - "node": "*" - } - }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -3575,15 +3677,6 @@ "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" }, - "node_modules/digest-fetch": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/digest-fetch/-/digest-fetch-1.3.0.tgz", - "integrity": "sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA==", - "dependencies": { - "base-64": "^0.1.0", - "md5": "^2.3.0" - } - }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -4733,16 +4826,25 @@ } }, "node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" + "agent-base": "^7.1.0", + "debug": "^4.3.4" }, "engines": { - "node": ">= 6" + "node": ">= 14" + } + }, + "node_modules/http-proxy-agent/node_modules/agent-base": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", + "license": "MIT", + "engines": { + "node": ">= 14" } }, "node_modules/https-proxy-agent": { @@ -4938,11 +5040,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -5347,6 +5444,7 @@ "version": "9.0.2", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "license": "MIT", "dependencies": { "jws": "^3.2.2", "lodash.includes": "^4.3.0", @@ -5368,6 +5466,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "license": "MIT", "dependencies": { "buffer-equal-constant-time": "1.0.1", "ecdsa-sig-formatter": "1.0.11", @@ -5378,6 +5477,7 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "license": "MIT", "dependencies": { "jwa": "^1.4.1", "safe-buffer": "^5.0.1" @@ -5493,22 +5593,26 @@ "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" }, "node_modules/lodash.isboolean": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" }, "node_modules/lodash.isinteger": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" }, "node_modules/lodash.isnumber": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" }, "node_modules/lodash.isplainobject": { "version": "4.0.6", @@ -5518,7 +5622,8 @@ "node_modules/lodash.isstring": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" }, "node_modules/lodash.merge": { "version": "4.6.2", @@ -5528,7 +5633,8 @@ "node_modules/lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" }, "node_modules/loose-envify": { "version": "1.4.0", @@ -5573,16 +5679,6 @@ "react": "^16.5.1 || ^17.0.0 || ^18.0.0" } }, - "node_modules/md5": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", - "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", - "dependencies": { - "charenc": "0.0.2", - "crypt": "0.0.2", - "is-buffer": "~1.1.6" - } - }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -5616,6 +5712,27 @@ "ws": "^7.5.6" } }, + "node_modules/microsoft-cognitiveservices-speech-sdk/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -6056,22 +6173,33 @@ } }, "node_modules/openai": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/openai/-/openai-4.26.0.tgz", - "integrity": "sha512-HPC7tgYdeP38F3uHA5WgnoXZyGbAp9jgcIo23p6It+q/07u4C+NZ8xHKlMShsPbDDmFRpPsa3vdbXYpbhJH3eg==", + "version": "4.83.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.83.0.tgz", + "integrity": "sha512-fmTsqud0uTtRKsPC7L8Lu55dkaTwYucqncDHzVvO64DKOpNTuiYwjbR/nVgpapXuYy8xSnhQQPUm+3jQaxICgw==", + "license": "Apache-2.0", "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", - "digest-fetch": "^1.3.0", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", - "node-fetch": "^2.6.7", - "web-streams-polyfill": "^3.2.1" + "node-fetch": "^2.6.7" }, "bin": { "openai": "bin/cli" + }, + "peerDependencies": { + "ws": "^8.18.0", + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + }, + "zod": { + "optional": true + } } }, "node_modules/openai/node_modules/@types/node": { @@ -7361,9 +7489,10 @@ } }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" }, "node_modules/tunnel": { "version": "0.0.6", @@ -7647,14 +7776,6 @@ "node": ">=10.13.0" } }, - "node_modules/web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", - "engines": { - "node": ">= 8" - } - }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -7766,15 +7887,18 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "license": "MIT", + "optional": true, + "peer": true, "engines": { - "node": ">=8.3.0" + "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -7839,9 +7963,10 @@ } }, "node_modules/zod": { - "version": "3.22.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", - "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "version": "3.24.1", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz", + "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" } From 3eda59f6bdcbe203b136053e071c69e69b89d877 Mon Sep 17 00:00:00 2001 From: David Watson Date: Wed, 12 Feb 2025 10:03:58 +1100 Subject: [PATCH 2/5] Remove unused keyvault and app service key config when key auth disabled --- infra/resources.bicep | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/infra/resources.bicep b/infra/resources.bicep index 64bbf60d2..5f1646117 100644 --- a/infra/resources.bicep +++ b/infra/resources.bicep @@ -155,7 +155,7 @@ resource webApp 'Microsoft.Web/sites@2020-06-01' = { } { name: 'AZURE_OPENAI_DALLE_API_KEY' - value: '@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::AZURE_OPENAI_DALLE_API_KEY.name})' + value: disableLocalAuth ? '' :'@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::AZURE_OPENAI_DALLE_API_KEY.name})' } { name: 'AZURE_OPENAI_DALLE_API_INSTANCE_NAME' @@ -183,11 +183,11 @@ resource webApp 'Microsoft.Web/sites@2020-06-01' = { } { name: 'AZURE_COSMOSDB_KEY' - value: '@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::AZURE_COSMOSDB_KEY.name})' + value: disableLocalAuth ? '' :'@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::AZURE_COSMOSDB_KEY.name})' } { name: 'AZURE_SEARCH_API_KEY' - value: '@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::AZURE_SEARCH_API_KEY.name})' + value: disableLocalAuth ? '' :'@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::AZURE_SEARCH_API_KEY.name})' } { name: 'AZURE_SEARCH_NAME' @@ -203,7 +203,7 @@ resource webApp 'Microsoft.Web/sites@2020-06-01' = { } { name: 'AZURE_DOCUMENT_INTELLIGENCE_KEY' - value: '@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::AZURE_DOCUMENT_INTELLIGENCE_KEY.name})' + value: disableLocalAuth ? '' :'@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::AZURE_DOCUMENT_INTELLIGENCE_KEY.name})' } { name: 'AZURE_SPEECH_REGION' @@ -219,7 +219,7 @@ resource webApp 'Microsoft.Web/sites@2020-06-01' = { } { name: 'AZURE_STORAGE_ACCOUNT_KEY' - value: '@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::AZURE_STORAGE_ACCOUNT_KEY.name})' + value: disableLocalAuth ? '' :'@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::AZURE_STORAGE_ACCOUNT_KEY.name})' } ] } @@ -282,7 +282,7 @@ resource kv 'Microsoft.KeyVault/vaults@2021-06-01-preview' = { enabledForTemplateDeployment: false } - resource AZURE_OPENAI_API_KEY 'secrets' = { + resource AZURE_OPENAI_API_KEY 'secrets' = if (!disableLocalAuth) { name: 'AZURE-OPENAI-API-KEY' properties: { contentType: 'text/plain' @@ -290,7 +290,7 @@ resource kv 'Microsoft.KeyVault/vaults@2021-06-01-preview' = { } } - resource AZURE_OPENAI_DALLE_API_KEY 'secrets' = { + resource AZURE_OPENAI_DALLE_API_KEY 'secrets' = if (!disableLocalAuth){ name: 'AZURE-OPENAI-DALLE-API-KEY' properties: { contentType: 'text/plain' @@ -306,7 +306,7 @@ resource kv 'Microsoft.KeyVault/vaults@2021-06-01-preview' = { } } - resource AZURE_COSMOSDB_KEY 'secrets' = { + resource AZURE_COSMOSDB_KEY 'secrets' = if (!disableLocalAuth){ name: 'AZURE-COSMOSDB-KEY' properties: { contentType: 'text/plain' @@ -314,7 +314,7 @@ resource kv 'Microsoft.KeyVault/vaults@2021-06-01-preview' = { } } - resource AZURE_DOCUMENT_INTELLIGENCE_KEY 'secrets' = { + resource AZURE_DOCUMENT_INTELLIGENCE_KEY 'secrets' = if (!disableLocalAuth){ name: 'AZURE-DOCUMENT-INTELLIGENCE-KEY' properties: { contentType: 'text/plain' @@ -330,7 +330,7 @@ resource kv 'Microsoft.KeyVault/vaults@2021-06-01-preview' = { } } - resource AZURE_SEARCH_API_KEY 'secrets' = { + resource AZURE_SEARCH_API_KEY 'secrets' = if (!disableLocalAuth){ name: 'AZURE-SEARCH-API-KEY' properties: { contentType: 'text/plain' @@ -338,7 +338,7 @@ resource kv 'Microsoft.KeyVault/vaults@2021-06-01-preview' = { } } - resource AZURE_STORAGE_ACCOUNT_KEY 'secrets' = { + resource AZURE_STORAGE_ACCOUNT_KEY 'secrets' = if (!disableLocalAuth){ name: 'AZURE-STORAGE-ACCOUNT-KEY' properties: { contentType: 'text/plain' From 77a25cd640b79c77e5ea343e903a31bb731af827 Mon Sep 17 00:00:00 2001 From: David Watson Date: Wed, 12 Feb 2025 13:40:44 +1100 Subject: [PATCH 3/5] Completely remove redundany app config settings --- infra/resources.bicep | 211 +++++++++++++++++++++--------------------- 1 file changed, 108 insertions(+), 103 deletions(-) diff --git a/infra/resources.bicep b/infra/resources.bicep index 5f1646117..ff8053977 100644 --- a/infra/resources.bicep +++ b/infra/resources.bicep @@ -106,6 +106,113 @@ resource appServicePlan 'Microsoft.Web/serverfarms@2020-06-01' = { kind: 'linux' } +var appSettingsCommon = [ + { + name: 'USE_MANAGED_IDENTITIES' + value: disableLocalAuth + } + + { + name: 'AZURE_KEY_VAULT_NAME' + value: keyVaultName + } + { + name: 'SCM_DO_BUILD_DURING_DEPLOYMENT' + value: 'true' + } + { + name: 'AZURE_OPENAI_API_INSTANCE_NAME' + value: openai_name + } + { + name: 'AZURE_OPENAI_API_DEPLOYMENT_NAME' + value: chatGptDeploymentName + } + { + name: 'AZURE_OPENAI_API_EMBEDDINGS_DEPLOYMENT_NAME' + value: embeddingDeploymentName + } + { + name: 'AZURE_OPENAI_API_VERSION' + value: openai_api_version + } + { + name: 'AZURE_OPENAI_DALLE_API_INSTANCE_NAME' + value: openai_dalle_name + } + { + name: 'AZURE_OPENAI_DALLE_API_DEPLOYMENT_NAME' + value: dalleDeploymentName + } + { + name: 'AZURE_OPENAI_DALLE_API_VERSION' + value: dalleApiVersion + } + { + name: 'NEXTAUTH_SECRET' + value: '@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::NEXTAUTH_SECRET.name})' + } + { + name: 'NEXTAUTH_URL' + value: 'https://${webapp_name}.azurewebsites.net' + } + { + name: 'AZURE_COSMOSDB_URI' + value: cosmosDbAccount.properties.documentEndpoint + } + { + name: 'AZURE_SEARCH_NAME' + value: search_name + } + { + name: 'AZURE_SEARCH_INDEX_NAME' + value: searchServiceIndexName + } + { + name: 'AZURE_DOCUMENT_INTELLIGENCE_ENDPOINT' + value: 'https://${form_recognizer_name}.cognitiveservices.azure.com/' + } + { + name: 'AZURE_SPEECH_REGION' + value: location + } + { + name: 'AZURE_SPEECH_KEY' + value: '@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::AZURE_SPEECH_KEY.name})' + } + { + name: 'AZURE_STORAGE_ACCOUNT_NAME' + value: storage_name + } + ] + +var appSettingsWithLocalAuth = disableLocalAuth ? [] : [ + { + name: 'AZURE_OPENAI_API_KEY' + value: '@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::AZURE_OPENAI_API_KEY.name})' + } + { + name: 'AZURE_OPENAI_DALLE_API_KEY' + value: '@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::AZURE_OPENAI_DALLE_API_KEY.name})' + } + { + name: 'AZURE_COSMOSDB_KEY' + value: '@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::AZURE_COSMOSDB_KEY.name})' + } + { + name: 'AZURE_SEARCH_API_KEY' + value: '@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::AZURE_SEARCH_API_KEY.name})' + } + { + name: 'AZURE_DOCUMENT_INTELLIGENCE_KEY' + value: '@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::AZURE_DOCUMENT_INTELLIGENCE_KEY.name})' + } + { + name: 'AZURE_STORAGE_ACCOUNT_KEY' + value: '@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::AZURE_STORAGE_ACCOUNT_KEY.name})' + } +] + resource webApp 'Microsoft.Web/sites@2020-06-01' = { name: webapp_name location: location @@ -119,109 +226,7 @@ resource webApp 'Microsoft.Web/sites@2020-06-01' = { appCommandLine: 'next start' ftpsState: 'Disabled' minTlsVersion: '1.2' - appSettings: [ - { - name: 'USE_MANAGED_IDENTITIES' - value: disableLocalAuth - } - - { - name: 'AZURE_KEY_VAULT_NAME' - value: keyVaultName - } - { - name: 'SCM_DO_BUILD_DURING_DEPLOYMENT' - value: 'true' - } - { - name: 'AZURE_OPENAI_API_KEY' - value: disableLocalAuth ? '' :'@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::AZURE_OPENAI_API_KEY.name})' - } - { - name: 'AZURE_OPENAI_API_INSTANCE_NAME' - value: openai_name - } - { - name: 'AZURE_OPENAI_API_DEPLOYMENT_NAME' - value: chatGptDeploymentName - } - { - name: 'AZURE_OPENAI_API_EMBEDDINGS_DEPLOYMENT_NAME' - value: embeddingDeploymentName - } - { - name: 'AZURE_OPENAI_API_VERSION' - value: openai_api_version - } - { - name: 'AZURE_OPENAI_DALLE_API_KEY' - value: disableLocalAuth ? '' :'@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::AZURE_OPENAI_DALLE_API_KEY.name})' - } - { - name: 'AZURE_OPENAI_DALLE_API_INSTANCE_NAME' - value: openai_dalle_name - } - { - name: 'AZURE_OPENAI_DALLE_API_DEPLOYMENT_NAME' - value: dalleDeploymentName - } - { - name: 'AZURE_OPENAI_DALLE_API_VERSION' - value: dalleApiVersion - } - { - name: 'NEXTAUTH_SECRET' - value: '@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::NEXTAUTH_SECRET.name})' - } - { - name: 'NEXTAUTH_URL' - value: 'https://${webapp_name}.azurewebsites.net' - } - { - name: 'AZURE_COSMOSDB_URI' - value: cosmosDbAccount.properties.documentEndpoint - } - { - name: 'AZURE_COSMOSDB_KEY' - value: disableLocalAuth ? '' :'@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::AZURE_COSMOSDB_KEY.name})' - } - { - name: 'AZURE_SEARCH_API_KEY' - value: disableLocalAuth ? '' :'@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::AZURE_SEARCH_API_KEY.name})' - } - { - name: 'AZURE_SEARCH_NAME' - value: search_name - } - { - name: 'AZURE_SEARCH_INDEX_NAME' - value: searchServiceIndexName - } - { - name: 'AZURE_DOCUMENT_INTELLIGENCE_ENDPOINT' - value: 'https://${form_recognizer_name}.cognitiveservices.azure.com/' - } - { - name: 'AZURE_DOCUMENT_INTELLIGENCE_KEY' - value: disableLocalAuth ? '' :'@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::AZURE_DOCUMENT_INTELLIGENCE_KEY.name})' - } - { - name: 'AZURE_SPEECH_REGION' - value: location - } - { - name: 'AZURE_SPEECH_KEY' - value: '@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::AZURE_SPEECH_KEY.name})' - } - { - name: 'AZURE_STORAGE_ACCOUNT_NAME' - value: storage_name - } - { - name: 'AZURE_STORAGE_ACCOUNT_KEY' - value: disableLocalAuth ? '' :'@Microsoft.KeyVault(VaultName=${kv.name};SecretName=${kv::AZURE_STORAGE_ACCOUNT_KEY.name})' - } - ] + appSettings: concat(appSettingsCommon, appSettingsWithLocalAuth) } } identity: { type: 'SystemAssigned'} From 7cc332f4274a864b5779ee801c77193ee9c3863e Mon Sep 17 00:00:00 2001 From: David Watson Date: Thu, 13 Feb 2025 09:47:43 +1100 Subject: [PATCH 4/5] Update documentation for Azure Developer CLI and clean up script comments --- docs/2-run-locally.md | 2 +- docs/4-deploy-to-azure.md | 22 +++++++--------------- scripts/add_localdev_roles.sh | 1 - scripts/appreg_setup.sh | 1 - 4 files changed, 8 insertions(+), 18 deletions(-) diff --git a/docs/2-run-locally.md b/docs/2-run-locally.md index fd4946789..f8f59c244 100644 --- a/docs/2-run-locally.md +++ b/docs/2-run-locally.md @@ -14,7 +14,7 @@ Clone this repository locally or fork to your GitHub account. Run all of the the 2. Rename/copy the file `.env.example` to `.env.local` and populate the environment variables based on the deployed resources in Azure. > **NOTE** - > If you have used the Azure Developer CLI to deploy the Azure infrastructure required for the solution ([using the directions here](./4-deploy-to-azure.md)), you can find the values for many the required environment variables in the `.env` file the `.azure\` directory. This generated file will not contain any keys, however it is recommended to use managed identities as described in "Setup your local development environment" on [this page](./10-managed-identities.md). + > If you have used the Azure Developer CLI to deploy the Azure infrastructure required for the solution ([using the directions here](./4-deploy-to-azure.md)), you can find the values for many the required environment variables in the `.env` file the `.azure\` directory. This generated file will not contain any keys, however it is recommended to use managed identities as described in "Setup your local development environment" on [this page](./9-managed-identities.md). 3. Install npm packages by running `npm install` 4. Start the app by running `npm run dev` diff --git a/docs/4-deploy-to-azure.md b/docs/4-deploy-to-azure.md index 952485ffd..2bb74c536 100644 --- a/docs/4-deploy-to-azure.md +++ b/docs/4-deploy-to-azure.md @@ -1,24 +1,16 @@ # ☁️ Deploy to Azure - Azure Developer CLI (azd) -To deploy the application to Azure using the Azure Developer CLI, follow the steps below. - -> [!IMPORTANT] -> This section will create Azure resources and deploy the solution from your local environment using the Azure Developer CLI. Note that you do not need to clone this repo to complete these steps. +To deploy the application to Azure using the Azure Developer CLI, follow the steps below. You can do this without cloning the repository, but instructions are also provided for those who have cloned the repository. 1. Download the [Azure Developer CLI](https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/overview) -1. If you have not cloned this repo, run `azd init -t microsoft/azurechat`. If you have cloned this repo, just run 'azd init' from the repo root directory. -1. Run `azd up` to provision and deploy the application - -```pwsh -azd init -t microsoft/azurechat -azd up -# if you have already cloned the repo -azd up +2. **If you have not cloned this repo**: + 1. Run `azd init -t microsoft/azurechat` + 1. Run `azd up` to provision and deploy the application -# if you are wanting to see logs run with debug flag -azd up --debug -``` +2. **If you have cloned this repo**: + 1. Run `azd init` from the repo root directory + 1. Run `azd up` to provision and deploy the application # ☁️ Deploy to Azure - GitHub Actions diff --git a/scripts/add_localdev_roles.sh b/scripts/add_localdev_roles.sh index f7d6386be..dbfda5030 100755 --- a/scripts/add_localdev_roles.sh +++ b/scripts/add_localdev_roles.sh @@ -1,5 +1,4 @@ #!/bin/bash -# filepath: /home/dwatson/wip/github/microsoft/azurechat/scripts/add_localdev_roles.sh echo -e "\nThis script will add the required IAM roles to allow the logged in user to run AzureChat locally." echo "This will only work if you have used AZD to deploy the app, and have the required permissions to modify IAM." diff --git a/scripts/appreg_setup.sh b/scripts/appreg_setup.sh index 57d9a3139..46cbd51a0 100755 --- a/scripts/appreg_setup.sh +++ b/scripts/appreg_setup.sh @@ -1,5 +1,4 @@ #!/bin/bash -# filepath: /home/dwatson/wip/github/microsoft/azurechat/scripts/appreg_setup.sh # Parse parameters showsecret_flag="false" From 57357c0ef08edc03f26ec8a57e4ea4295cfe5646 Mon Sep 17 00:00:00 2001 From: David Watson Date: Fri, 14 Feb 2025 09:22:48 +1100 Subject: [PATCH 5/5] Refine identity provider setup instructions and enhance local development guidance in documentation --- azure.yaml | 2 +- docs/9-managed-identities.md | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/azure.yaml b/azure.yaml index 93a558561..f482a933f 100644 --- a/azure.yaml +++ b/azure.yaml @@ -12,7 +12,7 @@ hooks: postdeploy: posix: shell: sh - run: echo -e "\n\033[0;36mTo complete the application setup you will need to configure an identity provider\033[0m\n(see the "Production App Setup" documentation at https://github.com/microsoft/azurechat/blob/main/docs/3-add-identity.md)\n" + run: echo "\n\033[0;36mTo complete the application setup you will need to configure an identity provider\033[0m\n(see the "Production App Setup" documentation at https://github.com/microsoft/azurechat/blob/main/docs/3-add-identity.md)\n" interactive: true continueOnError: false windows: diff --git a/docs/9-managed-identities.md b/docs/9-managed-identities.md index a9f17f0b6..14bdcae58 100644 --- a/docs/9-managed-identities.md +++ b/docs/9-managed-identities.md @@ -44,10 +44,13 @@ To deploy the application to Azure App Service with Managed Identities, follow t 1. **Update the Parameter**: - Set the parameter `disableLocalAuth` to `true` in [`infra/main.bicep`](/infra/main.bicep) (or [`infra/main.json`](/infra/main.json) for ARM deployment) to use Managed Identities. -2. **Deploy as normal**: +2. **Deploy resources using azd**: - refer to the [README](../README.md) 3. **(Optional) Setup your local development environment**: - - Run this script to grant yourself RBAC permissions on the Azure resources so you can run AzureChat locally + + Run this script to grant yourself RBAC permissions on the Azure resources so you can run AzureChat locally with managed identities. + + If you haven't already done so then you will need to login to Azure using the Azure CLI command `az login` - In Powershell: ```powershell PS> .\scripts\add_localdev_roles.ps1 @@ -57,7 +60,7 @@ To deploy the application to Azure App Service with Managed Identities, follow t > chmod +x .\scripts\add_localdev_roles.sh > .\scripts\add_localdev_roles.sh ``` - - You can now refer to the documentation to [run Azure Chat locally](2-run-locally.md). + You can now refer to the documentation to [run Azure Chat locally](2-run-locally.md). ## Conclusion