From 77b46fc1be6e12f42254061b14a3ce39de40da93 Mon Sep 17 00:00:00 2001
From: Vamshi-Microsoft
Date: Fri, 9 Jan 2026 11:50:53 +0530
Subject: [PATCH 01/10] Add validation step for Inputs and Map Inputs to env
---
.github/workflows/job-cleanup-deployment.yml | 146 +++++++++
.github/workflows/job-deploy-linux.yml | 201 ++++++++++--
.github/workflows/job-deploy-windows.yml | 215 +++++++++++--
.github/workflows/job-deploy.yml | 234 ++++++++++++--
.github/workflows/job-send-notification.yml | 310 ++++++++++++++++---
5 files changed, 992 insertions(+), 114 deletions(-)
diff --git a/.github/workflows/job-cleanup-deployment.yml b/.github/workflows/job-cleanup-deployment.yml
index 6b920a4e..a53cc82f 100644
--- a/.github/workflows/job-cleanup-deployment.yml
+++ b/.github/workflows/job-cleanup-deployment.yml
@@ -52,6 +52,152 @@ jobs:
ENV_NAME: ${{ inputs.ENV_NAME }}
IMAGE_TAG: ${{ inputs.IMAGE_TAG }}
steps:
+ - name: Validate Workflow Input Parameters
+ shell: bash
+ env:
+ INPUT_RUNNER_OS: ${{ inputs.runner_os }}
+ INPUT_TRIGGER_TYPE: ${{ inputs.trigger_type }}
+ INPUT_CLEANUP_RESOURCES: ${{ inputs.cleanup_resources }}
+ INPUT_EXISTING_WEBAPP_URL: ${{ inputs.existing_webapp_url }}
+ INPUT_RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }}
+ INPUT_AZURE_LOCATION: ${{ inputs.AZURE_LOCATION }}
+ INPUT_AZURE_ENV_OPENAI_LOCATION: ${{ inputs.AZURE_ENV_OPENAI_LOCATION }}
+ INPUT_ENV_NAME: ${{ inputs.ENV_NAME }}
+ INPUT_IMAGE_TAG: ${{ inputs.IMAGE_TAG }}
+ run: |
+ echo "đ Validating workflow input parameters..."
+ VALIDATION_FAILED=false
+
+ # Validate runner_os (required, must be specific values)
+ if [[ -z "$INPUT_RUNNER_OS" ]]; then
+ echo "â ERROR: runner_os is required but not provided"
+ VALIDATION_FAILED=true
+ else
+ ALLOWED_RUNNER_OS=("ubuntu-latest" "windows-latest")
+ if [[ ! " ${ALLOWED_RUNNER_OS[@]} " =~ " ${INPUT_RUNNER_OS} " ]]; then
+ echo "â ERROR: runner_os '$INPUT_RUNNER_OS' is invalid. Allowed values: ${ALLOWED_RUNNER_OS[*]}"
+ VALIDATION_FAILED=true
+ else
+ echo "â
runner_os: '$INPUT_RUNNER_OS' is valid"
+ fi
+ fi
+
+ # Validate trigger_type (required - alphanumeric with underscores)
+ if [[ -z "$INPUT_TRIGGER_TYPE" ]]; then
+ echo "â ERROR: trigger_type is required but was not provided"
+ VALIDATION_FAILED=true
+ elif [[ ! "$INPUT_TRIGGER_TYPE" =~ ^[a-zA-Z0-9_]+$ ]]; then
+ echo "â ERROR: trigger_type '$INPUT_TRIGGER_TYPE' is invalid. Must contain only alphanumeric characters and underscores"
+ VALIDATION_FAILED=true
+ else
+ echo "â
trigger_type: '$INPUT_TRIGGER_TYPE' is valid"
+ fi
+
+ # Validate cleanup_resources (boolean)
+ if [[ "$INPUT_CLEANUP_RESOURCES" != "true" && "$INPUT_CLEANUP_RESOURCES" != "false" ]]; then
+ echo "â ERROR: cleanup_resources must be 'true' or 'false', got: '$INPUT_CLEANUP_RESOURCES'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
cleanup_resources: '$INPUT_CLEANUP_RESOURCES' is valid"
+ fi
+
+ # Validate existing_webapp_url (must start with https if provided)
+ if [[ -n "$INPUT_EXISTING_WEBAPP_URL" ]]; then
+ if [[ ! "$INPUT_EXISTING_WEBAPP_URL" =~ ^https:// ]]; then
+ echo "â ERROR: existing_webapp_url must start with 'https://', got: '$INPUT_EXISTING_WEBAPP_URL'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
existing_webapp_url: '$INPUT_EXISTING_WEBAPP_URL' is valid"
+ fi
+ fi
+
+ # Validate RESOURCE_GROUP_NAME (required, Azure resource group naming convention)
+ if [[ -z "$INPUT_RESOURCE_GROUP_NAME" ]]; then
+ echo "â ERROR: RESOURCE_GROUP_NAME is required but not provided"
+ VALIDATION_FAILED=true
+ else
+ if [[ ! "$INPUT_RESOURCE_GROUP_NAME" =~ ^[a-zA-Z0-9._\(\)-]+$ ]] || [[ "$INPUT_RESOURCE_GROUP_NAME" =~ \.$ ]]; then
+ echo "â ERROR: RESOURCE_GROUP_NAME '$INPUT_RESOURCE_GROUP_NAME' is invalid. Must contain only alphanumerics, periods, underscores, hyphens, and parentheses. Cannot end with period."
+ VALIDATION_FAILED=true
+ elif [[ ${#INPUT_RESOURCE_GROUP_NAME} -gt 90 ]]; then
+ echo "â ERROR: RESOURCE_GROUP_NAME '$INPUT_RESOURCE_GROUP_NAME' exceeds 90 characters"
+ VALIDATION_FAILED=true
+ else
+ echo "â
RESOURCE_GROUP_NAME: '$INPUT_RESOURCE_GROUP_NAME' is valid"
+ fi
+ fi
+
+ # Validate AZURE_LOCATION (required)
+ if [[ -z "$INPUT_AZURE_LOCATION" ]]; then
+ echo "â ERROR: AZURE_LOCATION is required but not provided"
+ VALIDATION_FAILED=true
+ else
+ # Azure location should be lowercase alphanumeric (e.g., eastus, westeurope)
+ if [[ ! "$INPUT_AZURE_LOCATION" =~ ^[a-z0-9]+$ ]]; then
+ echo "â ERROR: AZURE_LOCATION '$INPUT_AZURE_LOCATION' is invalid. Should be lowercase alphanumeric (e.g., 'eastus', 'westeurope')"
+ VALIDATION_FAILED=true
+ else
+ echo "â
AZURE_LOCATION: '$INPUT_AZURE_LOCATION' is valid"
+ fi
+ fi
+
+ # Validate AZURE_ENV_OPENAI_LOCATION (required)
+ if [[ -z "$INPUT_AZURE_ENV_OPENAI_LOCATION" ]]; then
+ echo "â ERROR: AZURE_ENV_OPENAI_LOCATION is required but not provided"
+ VALIDATION_FAILED=true
+ else
+ # Azure location should be lowercase alphanumeric
+ if [[ ! "$INPUT_AZURE_ENV_OPENAI_LOCATION" =~ ^[a-z0-9]+$ ]]; then
+ echo "â ERROR: AZURE_ENV_OPENAI_LOCATION '$INPUT_AZURE_ENV_OPENAI_LOCATION' is invalid. Should be lowercase alphanumeric (e.g., 'eastus', 'westeurope')"
+ VALIDATION_FAILED=true
+ else
+ echo "â
AZURE_ENV_OPENAI_LOCATION: '$INPUT_AZURE_ENV_OPENAI_LOCATION' is valid"
+ fi
+ fi
+
+ # Validate ENV_NAME (required, alphanumeric with hyphens)
+ if [[ -z "$INPUT_ENV_NAME" ]]; then
+ echo "â ERROR: ENV_NAME is required but not provided"
+ VALIDATION_FAILED=true
+ else
+ if [[ ! "$INPUT_ENV_NAME" =~ ^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$|^[a-zA-Z0-9]$ ]]; then
+ echo "â ERROR: ENV_NAME '$INPUT_ENV_NAME' is invalid. Must start and end with alphanumeric, can contain hyphens"
+ VALIDATION_FAILED=true
+ elif [[ ${#INPUT_ENV_NAME} -gt 64 ]]; then
+ echo "â ERROR: ENV_NAME '$INPUT_ENV_NAME' exceeds 64 characters"
+ VALIDATION_FAILED=true
+ else
+ echo "â
ENV_NAME: '$INPUT_ENV_NAME' is valid"
+ fi
+ fi
+
+ # Validate IMAGE_TAG (required)
+ if [[ -z "$INPUT_IMAGE_TAG" ]]; then
+ echo "â ERROR: IMAGE_TAG is required but not provided"
+ VALIDATION_FAILED=true
+ else
+ # Docker image tag validation (alphanumeric, dots, dashes, underscores, max 128 chars)
+ if [[ ! "$INPUT_IMAGE_TAG" =~ ^[a-zA-Z0-9._-]+$ ]]; then
+ echo "â ERROR: IMAGE_TAG '$INPUT_IMAGE_TAG' is invalid. Must contain only alphanumerics, dots, dashes, and underscores"
+ VALIDATION_FAILED=true
+ elif [[ ${#INPUT_IMAGE_TAG} -gt 128 ]]; then
+ echo "â ERROR: IMAGE_TAG '$INPUT_IMAGE_TAG' exceeds 128 characters"
+ VALIDATION_FAILED=true
+ else
+ echo "â
IMAGE_TAG: '$INPUT_IMAGE_TAG' is valid"
+ fi
+ fi
+
+ # Fail workflow if any validation failed
+ if [[ "$VALIDATION_FAILED" == "true" ]]; then
+ echo ""
+ echo "â Parameter validation failed. Please correct the errors above and try again."
+ exit 1
+ fi
+
+ echo ""
+ echo "â
All input parameters validated successfully!"
+
- name: Setup Azure CLI
shell: bash
run: |
diff --git a/.github/workflows/job-deploy-linux.yml b/.github/workflows/job-deploy-linux.yml
index 41c0362b..d78963b0 100644
--- a/.github/workflows/job-deploy-linux.yml
+++ b/.github/workflows/job-deploy-linux.yml
@@ -47,13 +47,148 @@ jobs:
outputs:
CONTAINER_WEB_APPURL: ${{ steps.get_output_linux.outputs.CONTAINER_WEB_APPURL }}
steps:
+ - name: Validate Workflow Input Parameters
+ shell: bash
+ env:
+ INPUT_ENV_NAME: ${{ inputs.ENV_NAME }}
+ INPUT_AZURE_ENV_OPENAI_LOCATION: ${{ inputs.AZURE_ENV_OPENAI_LOCATION }}
+ INPUT_AZURE_LOCATION: ${{ inputs.AZURE_LOCATION }}
+ INPUT_RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }}
+ INPUT_IMAGE_TAG: ${{ inputs.IMAGE_TAG }}
+ INPUT_BUILD_DOCKER_IMAGE: ${{ inputs.BUILD_DOCKER_IMAGE }}
+ INPUT_EXP: ${{ inputs.EXP }}
+ INPUT_WAF_ENABLED: ${{ inputs.WAF_ENABLED }}
+ INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}
+ INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}
+ run: |
+ echo "đ Validating workflow input parameters..."
+ VALIDATION_FAILED=false
+
+ # Validate ENV_NAME (required, alphanumeric and hyphens)
+ if [[ -z "$INPUT_ENV_NAME" ]]; then
+ echo "â ERROR: ENV_NAME is required but not provided"
+ VALIDATION_FAILED=true
+ elif [[ ! "$INPUT_ENV_NAME" =~ ^[a-zA-Z0-9-]+$ ]]; then
+ echo "â ERROR: ENV_NAME '$INPUT_ENV_NAME' is invalid. Must contain only alphanumerics and hyphens"
+ VALIDATION_FAILED=true
+ else
+ echo "â
ENV_NAME: '$INPUT_ENV_NAME' is valid"
+ fi
+
+ # Validate AZURE_ENV_OPENAI_LOCATION (required, Azure region format)
+ if [[ -z "$INPUT_AZURE_ENV_OPENAI_LOCATION" ]]; then
+ echo "â ERROR: AZURE_ENV_OPENAI_LOCATION is required but not provided"
+ VALIDATION_FAILED=true
+ elif [[ ! "$INPUT_AZURE_ENV_OPENAI_LOCATION" =~ ^[a-z0-9]+$ ]]; then
+ echo "â ERROR: AZURE_ENV_OPENAI_LOCATION '$INPUT_AZURE_ENV_OPENAI_LOCATION' is invalid. Must contain only lowercase letters and numbers"
+ VALIDATION_FAILED=true
+ else
+ echo "â
AZURE_ENV_OPENAI_LOCATION: '$INPUT_AZURE_ENV_OPENAI_LOCATION' is valid"
+ fi
+
+ # Validate AZURE_LOCATION (required, Azure region format)
+ if [[ -z "$INPUT_AZURE_LOCATION" ]]; then
+ echo "â ERROR: AZURE_LOCATION is required but not provided"
+ VALIDATION_FAILED=true
+ elif [[ ! "$INPUT_AZURE_LOCATION" =~ ^[a-z0-9]+$ ]]; then
+ echo "â ERROR: AZURE_LOCATION '$INPUT_AZURE_LOCATION' is invalid. Must contain only lowercase letters and numbers"
+ VALIDATION_FAILED=true
+ else
+ echo "â
AZURE_LOCATION: '$INPUT_AZURE_LOCATION' is valid"
+ fi
+
+ # Validate RESOURCE_GROUP_NAME (required, Azure naming convention)
+ if [[ -z "$INPUT_RESOURCE_GROUP_NAME" ]]; then
+ echo "â ERROR: RESOURCE_GROUP_NAME is required but not provided"
+ VALIDATION_FAILED=true
+ elif [[ ! "$INPUT_RESOURCE_GROUP_NAME" =~ ^[a-zA-Z0-9._\(\)-]+$ ]] || [[ "$INPUT_RESOURCE_GROUP_NAME" =~ \.$ ]]; then
+ echo "â ERROR: RESOURCE_GROUP_NAME '$INPUT_RESOURCE_GROUP_NAME' is invalid. Must contain only alphanumerics, periods, underscores, hyphens, and parentheses. Cannot end with period."
+ VALIDATION_FAILED=true
+ elif [[ ${#INPUT_RESOURCE_GROUP_NAME} -gt 90 ]]; then
+ echo "â ERROR: RESOURCE_GROUP_NAME '$INPUT_RESOURCE_GROUP_NAME' exceeds 90 characters"
+ VALIDATION_FAILED=true
+ else
+ echo "â
RESOURCE_GROUP_NAME: '$INPUT_RESOURCE_GROUP_NAME' is valid"
+ fi
+
+ # Validate IMAGE_TAG (required, Docker tag pattern)
+ if [[ -z "$INPUT_IMAGE_TAG" ]]; then
+ echo "â ERROR: IMAGE_TAG is required but not provided"
+ VALIDATION_FAILED=true
+ elif [[ ! "$INPUT_IMAGE_TAG" =~ ^[a-zA-Z0-9_][a-zA-Z0-9._-]{0,127}$ ]]; then
+ echo "â ERROR: IMAGE_TAG '$INPUT_IMAGE_TAG' is invalid. Must start with alphanumeric or underscore, max 128 characters"
+ VALIDATION_FAILED=true
+ else
+ echo "â
IMAGE_TAG: '$INPUT_IMAGE_TAG' is valid"
+ fi
+
+ # Validate BUILD_DOCKER_IMAGE (required, must be 'true' or 'false')
+ if [[ "$INPUT_BUILD_DOCKER_IMAGE" != "true" && "$INPUT_BUILD_DOCKER_IMAGE" != "false" ]]; then
+ echo "â ERROR: BUILD_DOCKER_IMAGE must be 'true' or 'false', got: '$INPUT_BUILD_DOCKER_IMAGE'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
BUILD_DOCKER_IMAGE: '$INPUT_BUILD_DOCKER_IMAGE' is valid"
+ fi
+
+ # Validate EXP (required, must be 'true' or 'false')
+ if [[ "$INPUT_EXP" != "true" && "$INPUT_EXP" != "false" ]]; then
+ echo "â ERROR: EXP must be 'true' or 'false', got: '$INPUT_EXP'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
EXP: '$INPUT_EXP' is valid"
+ fi
+
+ # Validate WAF_ENABLED (must be 'true' or 'false')
+ if [[ "$INPUT_WAF_ENABLED" != "true" && "$INPUT_WAF_ENABLED" != "false" ]]; then
+ echo "â ERROR: WAF_ENABLED must be 'true' or 'false', got: '$INPUT_WAF_ENABLED'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
WAF_ENABLED: '$INPUT_WAF_ENABLED' is valid"
+ fi
+
+ # Validate AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID (optional, if provided must be valid Resource ID)
+ if [[ -n "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" ]]; then
+ if [[ ! "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/resourceGroups/[^/]+/providers/microsoft\.operationalinsights/workspaces/[^/]+$ ]]; then
+ echo "â ERROR: AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID is invalid. Must be a valid Azure Resource ID format:"
+ echo " /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.OperationalInsights/workspaces/{workspaceName}"
+ echo " Got: '$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: Valid Resource ID format"
+ fi
+ fi
+
+ # Validate AZURE_EXISTING_AI_PROJECT_RESOURCE_ID (optional, if provided must be valid Resource ID)
+ if [[ -n "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" ]]; then
+ if [[ ! "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/resourceGroups/[^/]+/providers/(Microsoft\.MachineLearningServices/(workspaces|projects)/[^/]+|Microsoft\.CognitiveServices/accounts/[^/]+/projects/[^/]+)$ ]]; then
+ echo "â ERROR: AZURE_EXISTING_AI_PROJECT_RESOURCE_ID is invalid. Must be a valid Azure Resource ID format:"
+ echo " /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.CognitiveServices/accounts/{accountName}/projects/{projectName}"
+ echo " Got: '$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: Valid Resource ID format"
+ fi
+ fi
+
+ # Fail workflow if any validation failed
+ if [[ "$VALIDATION_FAILED" == "true" ]]; then
+ echo ""
+ echo "â Parameter validation failed. Please correct the errors above and try again."
+ exit 1
+ fi
+
+ echo ""
+ echo "â
All input parameters validated successfully!"
+
- name: Checkout Code
uses: actions/checkout@v4
- name: Configure Parameters Based on WAF Setting
shell: bash
+ env:
+ WAF_ENABLED: ${{ inputs.WAF_ENABLED }}
run: |
- if [[ "${{ inputs.WAF_ENABLED }}" == "true" ]]; then
+ if [[ "$WAF_ENABLED" == "true" ]]; then
cp infra/main.waf.parameters.json infra/main.parameters.json
echo "â
Successfully copied WAF parameters to main parameters file"
else
@@ -83,11 +218,21 @@ jobs:
- name: Deploy using azd up and extract values (Linux)
id: get_output_linux
shell: bash
+ env:
+ ENV_NAME: ${{ inputs.ENV_NAME }}
+ AZURE_ENV_OPENAI_LOCATION: ${{ inputs.AZURE_ENV_OPENAI_LOCATION }}
+ AZURE_LOCATION: ${{ inputs.AZURE_LOCATION }}
+ RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }}
+ IMAGE_TAG: ${{ inputs.IMAGE_TAG }}
+ BUILD_DOCKER_IMAGE: ${{ inputs.BUILD_DOCKER_IMAGE }}
+ EXP: ${{ inputs.EXP }}
+ AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}
+ AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}
run: |
set -e
echo "Starting azd deployment..."
- echo "EXP: ${{ inputs.EXP }}"
- echo "Using Docker Image Tag: ${{ inputs.IMAGE_TAG }}"
+ echo "EXP: $EXP"
+ echo "Using Docker Image Tag: $IMAGE_TAG"
# Install azd (Azure Developer CLI)
curl -fsSL https://aka.ms/install-azd.sh | bash
@@ -96,20 +241,20 @@ jobs:
current_date=$(date -u +"%Y-%m-%dT%H:%M:%S.%7NZ")
echo "Creating environment..."
- azd env new ${{ inputs.ENV_NAME }} --no-prompt
- echo "Environment created: ${{ inputs.ENV_NAME }}"
+ azd env new $ENV_NAME --no-prompt
+ echo "Environment created: $ENV_NAME"
echo "Setting default subscription..."
azd config set defaults.subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }}
# Set additional parameters
azd env set AZURE_SUBSCRIPTION_ID="${{ secrets.AZURE_SUBSCRIPTION_ID }}"
- azd env set AZURE_ENV_AI_DEPLOYMENTS_LOCATION="${{ inputs.AZURE_ENV_OPENAI_LOCATION }}"
- azd env set AZURE_LOCATION="${{ inputs.AZURE_LOCATION }}"
- azd env set AZURE_RESOURCE_GROUP="${{ inputs.RESOURCE_GROUP_NAME }}"
- azd env set AZURE_ENV_CONTAINER_IMAGE_TAG="${{ inputs.IMAGE_TAG }}"
+ azd env set AZURE_ENV_AI_DEPLOYMENTS_LOCATION="$AZURE_ENV_OPENAI_LOCATION"
+ azd env set AZURE_LOCATION="$AZURE_LOCATION"
+ azd env set AZURE_RESOURCE_GROUP="$RESOURCE_GROUP_NAME"
+ azd env set AZURE_ENV_CONTAINER_IMAGE_TAG="$IMAGE_TAG"
- if [[ "${{ inputs.BUILD_DOCKER_IMAGE }}" == "true" ]]; then
+ if [[ "$BUILD_DOCKER_IMAGE" == "true" ]]; then
ACR_NAME=$(echo "${{ secrets.ACR_TEST_LOGIN_SERVER }}")
azd env set AZURE_ENV_CONTAINER_REGISTRY_ENDPOINT="$ACR_NAME"
echo "Set ACR name to: $ACR_NAME"
@@ -117,17 +262,17 @@ jobs:
echo "Skipping ACR name configuration (using existing image)"
fi
- if [[ "${{ inputs.EXP }}" == "true" ]]; then
+ if [[ "$EXP" == "true" ]]; then
echo "â
EXP ENABLED - Setting EXP parameters..."
- if [[ -n "${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}" ]]; then
- EXP_LOG_ANALYTICS_ID="${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}"
+ if [[ -n "$AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" ]]; then
+ EXP_LOG_ANALYTICS_ID="$AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID"
else
EXP_LOG_ANALYTICS_ID="${{ secrets.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}"
fi
- if [[ -n "${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}" ]]; then
- EXP_AI_PROJECT_ID="${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}"
+ if [[ -n "$AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" ]]; then
+ EXP_AI_PROJECT_ID="$AZURE_EXISTING_AI_PROJECT_RESOURCE_ID"
else
EXP_AI_PROJECT_ID="${{ secrets.AZURE_ENV_FOUNDRY_PROJECT_ID }}"
fi
@@ -189,33 +334,45 @@ jobs:
- name: Disable Auth in Web App
shell: bash
+ env:
+ RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }}
run: |
az containerapp update --name ${{ env.CONTAINER_WEB_APPNAME }} \
- --resource-group ${{ inputs.RESOURCE_GROUP_NAME }} \
+ --resource-group $RESOURCE_GROUP_NAME \
--set-env-vars APP_AUTH_ENABLED=false
- name: Disable Auth in API App
shell: bash
+ env:
+ RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }}
run: |
sleep 30
az containerapp update --name ${{ env.CONTAINER_API_APPNAME }} \
- --resource-group ${{ inputs.RESOURCE_GROUP_NAME }} \
+ --resource-group $RESOURCE_GROUP_NAME \
--set-env-vars APP_AUTH_ENABLED=false
- name: Generate Deployment Summary
if: always()
shell: bash
+ env:
+ RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }}
+ WAF_ENABLED: ${{ inputs.WAF_ENABLED }}
+ EXP: ${{ inputs.EXP }}
+ AZURE_LOCATION: ${{ inputs.AZURE_LOCATION }}
+ AZURE_ENV_OPENAI_LOCATION: ${{ inputs.AZURE_ENV_OPENAI_LOCATION }}
+ IMAGE_TAG: ${{ inputs.IMAGE_TAG }}
+ CONFIG_TYPE: ${{ inputs.WAF_ENABLED == 'true' && inputs.EXP == 'true' && 'WAF + EXP' || inputs.WAF_ENABLED == 'true' && inputs.EXP != 'true' && 'WAF + Non-EXP' || inputs.WAF_ENABLED != 'true' && inputs.EXP == 'true' && 'Non-WAF + EXP' || 'Non-WAF + Non-EXP' }}
run: |
echo "## đ Deploy Job Summary (Linux)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| **Job Status** | ${{ job.status == 'success' && 'â
Success' || 'â Failed' }} |" >> $GITHUB_STEP_SUMMARY
- echo "| **Resource Group** | \`${{ inputs.RESOURCE_GROUP_NAME }}\` |" >> $GITHUB_STEP_SUMMARY
- echo "| **Configuration Type** | \`${{ inputs.WAF_ENABLED == 'true' && inputs.EXP == 'true' && 'WAF + EXP' || inputs.WAF_ENABLED == 'true' && inputs.EXP != 'true' && 'WAF + Non-EXP' || inputs.WAF_ENABLED != 'true' && inputs.EXP == 'true' && 'Non-WAF + EXP' || 'Non-WAF + Non-EXP' }}\` |" >> $GITHUB_STEP_SUMMARY
- echo "| **Azure Region (Infrastructure)** | \`${{ inputs.AZURE_LOCATION }}\` |" >> $GITHUB_STEP_SUMMARY
- echo "| **Azure OpenAI Region** | \`${{ inputs.AZURE_ENV_OPENAI_LOCATION }}\` |" >> $GITHUB_STEP_SUMMARY
- echo "| **Docker Image Tag** | \`${{ inputs.IMAGE_TAG }}\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Resource Group** | \`$RESOURCE_GROUP_NAME\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Configuration Type** | \`$CONFIG_TYPE\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Azure Region (Infrastructure)** | \`$AZURE_LOCATION\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Azure OpenAI Region** | \`$AZURE_ENV_OPENAI_LOCATION\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Docker Image Tag** | \`$IMAGE_TAG\` |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [[ "${{ job.status }}" == "success" ]]; then
echo "### â
Deployment Details" >> $GITHUB_STEP_SUMMARY
diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml
index 4fc84f87..660e7369 100644
--- a/.github/workflows/job-deploy-windows.yml
+++ b/.github/workflows/job-deploy-windows.yml
@@ -47,13 +47,148 @@ jobs:
outputs:
CONTAINER_WEB_APPURL: ${{ steps.get_output_windows.outputs.CONTAINER_WEB_APPURL }}
steps:
+ - name: Validate Workflow Input Parameters
+ shell: bash
+ env:
+ INPUT_ENV_NAME: ${{ inputs.ENV_NAME }}
+ INPUT_AZURE_ENV_OPENAI_LOCATION: ${{ inputs.AZURE_ENV_OPENAI_LOCATION }}
+ INPUT_AZURE_LOCATION: ${{ inputs.AZURE_LOCATION }}
+ INPUT_RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }}
+ INPUT_IMAGE_TAG: ${{ inputs.IMAGE_TAG }}
+ INPUT_BUILD_DOCKER_IMAGE: ${{ inputs.BUILD_DOCKER_IMAGE }}
+ INPUT_EXP: ${{ inputs.EXP }}
+ INPUT_WAF_ENABLED: ${{ inputs.WAF_ENABLED }}
+ INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}
+ INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}
+ run: |
+ echo "đ Validating workflow input parameters..."
+ VALIDATION_FAILED=false
+
+ # Validate ENV_NAME (required, alphanumeric and hyphens)
+ if [[ -z "$INPUT_ENV_NAME" ]]; then
+ echo "â ERROR: ENV_NAME is required but not provided"
+ VALIDATION_FAILED=true
+ elif [[ ! "$INPUT_ENV_NAME" =~ ^[a-zA-Z0-9-]+$ ]]; then
+ echo "â ERROR: ENV_NAME '$INPUT_ENV_NAME' is invalid. Must contain only alphanumerics and hyphens"
+ VALIDATION_FAILED=true
+ else
+ echo "â
ENV_NAME: '$INPUT_ENV_NAME' is valid"
+ fi
+
+ # Validate AZURE_ENV_OPENAI_LOCATION (required, Azure region format)
+ if [[ -z "$INPUT_AZURE_ENV_OPENAI_LOCATION" ]]; then
+ echo "â ERROR: AZURE_ENV_OPENAI_LOCATION is required but not provided"
+ VALIDATION_FAILED=true
+ elif [[ ! "$INPUT_AZURE_ENV_OPENAI_LOCATION" =~ ^[a-z0-9]+$ ]]; then
+ echo "â ERROR: AZURE_ENV_OPENAI_LOCATION '$INPUT_AZURE_ENV_OPENAI_LOCATION' is invalid. Must contain only lowercase letters and numbers"
+ VALIDATION_FAILED=true
+ else
+ echo "â
AZURE_ENV_OPENAI_LOCATION: '$INPUT_AZURE_ENV_OPENAI_LOCATION' is valid"
+ fi
+
+ # Validate AZURE_LOCATION (required, Azure region format)
+ if [[ -z "$INPUT_AZURE_LOCATION" ]]; then
+ echo "â ERROR: AZURE_LOCATION is required but not provided"
+ VALIDATION_FAILED=true
+ elif [[ ! "$INPUT_AZURE_LOCATION" =~ ^[a-z0-9]+$ ]]; then
+ echo "â ERROR: AZURE_LOCATION '$INPUT_AZURE_LOCATION' is invalid. Must contain only lowercase letters and numbers"
+ VALIDATION_FAILED=true
+ else
+ echo "â
AZURE_LOCATION: '$INPUT_AZURE_LOCATION' is valid"
+ fi
+
+ # Validate RESOURCE_GROUP_NAME (required, Azure naming convention)
+ if [[ -z "$INPUT_RESOURCE_GROUP_NAME" ]]; then
+ echo "â ERROR: RESOURCE_GROUP_NAME is required but not provided"
+ VALIDATION_FAILED=true
+ elif [[ ! "$INPUT_RESOURCE_GROUP_NAME" =~ ^[a-zA-Z0-9._\(\)-]+$ ]] || [[ "$INPUT_RESOURCE_GROUP_NAME" =~ \.$ ]]; then
+ echo "â ERROR: RESOURCE_GROUP_NAME '$INPUT_RESOURCE_GROUP_NAME' is invalid. Must contain only alphanumerics, periods, underscores, hyphens, and parentheses. Cannot end with period."
+ VALIDATION_FAILED=true
+ elif [[ ${#INPUT_RESOURCE_GROUP_NAME} -gt 90 ]]; then
+ echo "â ERROR: RESOURCE_GROUP_NAME '$INPUT_RESOURCE_GROUP_NAME' exceeds 90 characters"
+ VALIDATION_FAILED=true
+ else
+ echo "â
RESOURCE_GROUP_NAME: '$INPUT_RESOURCE_GROUP_NAME' is valid"
+ fi
+
+ # Validate IMAGE_TAG (required, Docker tag pattern)
+ if [[ -z "$INPUT_IMAGE_TAG" ]]; then
+ echo "â ERROR: IMAGE_TAG is required but not provided"
+ VALIDATION_FAILED=true
+ elif [[ ! "$INPUT_IMAGE_TAG" =~ ^[a-zA-Z0-9_][a-zA-Z0-9._-]{0,127}$ ]]; then
+ echo "â ERROR: IMAGE_TAG '$INPUT_IMAGE_TAG' is invalid. Must start with alphanumeric or underscore, max 128 characters"
+ VALIDATION_FAILED=true
+ else
+ echo "â
IMAGE_TAG: '$INPUT_IMAGE_TAG' is valid"
+ fi
+
+ # Validate BUILD_DOCKER_IMAGE (required, must be 'true' or 'false')
+ if [[ "$INPUT_BUILD_DOCKER_IMAGE" != "true" && "$INPUT_BUILD_DOCKER_IMAGE" != "false" ]]; then
+ echo "â ERROR: BUILD_DOCKER_IMAGE must be 'true' or 'false', got: '$INPUT_BUILD_DOCKER_IMAGE'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
BUILD_DOCKER_IMAGE: '$INPUT_BUILD_DOCKER_IMAGE' is valid"
+ fi
+
+ # Validate EXP (required, must be 'true' or 'false')
+ if [[ "$INPUT_EXP" != "true" && "$INPUT_EXP" != "false" ]]; then
+ echo "â ERROR: EXP must be 'true' or 'false', got: '$INPUT_EXP'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
EXP: '$INPUT_EXP' is valid"
+ fi
+
+ # Validate WAF_ENABLED (must be 'true' or 'false')
+ if [[ "$INPUT_WAF_ENABLED" != "true" && "$INPUT_WAF_ENABLED" != "false" ]]; then
+ echo "â ERROR: WAF_ENABLED must be 'true' or 'false', got: '$INPUT_WAF_ENABLED'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
WAF_ENABLED: '$INPUT_WAF_ENABLED' is valid"
+ fi
+
+ # Validate AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID (optional, if provided must be valid Resource ID)
+ if [[ -n "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" ]]; then
+ if [[ ! "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/resourceGroups/[^/]+/providers/microsoft\.operationalinsights/workspaces/[^/]+$ ]]; then
+ echo "â ERROR: AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID is invalid. Must be a valid Azure Resource ID format:"
+ echo " /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.OperationalInsights/workspaces/{workspaceName}"
+ echo " Got: '$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: Valid Resource ID format"
+ fi
+ fi
+
+ # Validate AZURE_EXISTING_AI_PROJECT_RESOURCE_ID (optional, if provided must be valid Resource ID)
+ if [[ -n "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" ]]; then
+ if [[ ! "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/resourceGroups/[^/]+/providers/(Microsoft\.MachineLearningServices/(workspaces|projects)/[^/]+|Microsoft\.CognitiveServices/accounts/[^/]+/projects/[^/]+)$ ]]; then
+ echo "â ERROR: AZURE_EXISTING_AI_PROJECT_RESOURCE_ID is invalid. Must be a valid Azure Resource ID format:"
+ echo " /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.CognitiveServices/accounts/{accountName}/projects/{projectName}"
+ echo " Got: '$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: Valid Resource ID format"
+ fi
+ fi
+
+ # Fail workflow if any validation failed
+ if [[ "$VALIDATION_FAILED" == "true" ]]; then
+ echo ""
+ echo "â Parameter validation failed. Please correct the errors above and try again."
+ exit 1
+ fi
+
+ echo ""
+ echo "â
All input parameters validated successfully!"
+
- name: Checkout Code
uses: actions/checkout@v4
- name: Configure Parameters Based on WAF Setting
shell: bash
+ env:
+ WAF_ENABLED: ${{ inputs.WAF_ENABLED }}
run: |
- if [[ "${{ inputs.WAF_ENABLED }}" == "true" ]]; then
+ if [[ "$WAF_ENABLED" == "true" ]]; then
cp infra/main.waf.parameters.json infra/main.parameters.json
echo "â
Successfully copied WAF parameters to main parameters file"
else
@@ -75,28 +210,38 @@ jobs:
- name: Deploy using azd up and extract values (Windows)
id: get_output_windows
shell: pwsh
+ env:
+ ENV_NAME: ${{ inputs.ENV_NAME }}
+ AZURE_ENV_OPENAI_LOCATION: ${{ inputs.AZURE_ENV_OPENAI_LOCATION }}
+ AZURE_LOCATION: ${{ inputs.AZURE_LOCATION }}
+ RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }}
+ IMAGE_TAG: ${{ inputs.IMAGE_TAG }}
+ BUILD_DOCKER_IMAGE: ${{ inputs.BUILD_DOCKER_IMAGE }}
+ EXP: ${{ inputs.EXP }}
+ AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}
+ AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}
run: |
$ErrorActionPreference = "Stop"
Write-Host "Starting azd deployment..."
- Write-Host "EXP: ${{ inputs.EXP }}"
- Write-Host "Using Docker Image Tag: ${{ inputs.IMAGE_TAG }}"
+ Write-Host "EXP: $env:EXP"
+ Write-Host "Using Docker Image Tag: $env:IMAGE_TAG"
Write-Host "Creating environment..."
- azd env new ${{ inputs.ENV_NAME }} --no-prompt
- Write-Host "Environment created: ${{ inputs.ENV_NAME }}"
+ azd env new $env:ENV_NAME --no-prompt
+ Write-Host "Environment created: $env:ENV_NAME"
Write-Host "Setting default subscription..."
azd config set defaults.subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }}
# Set additional parameters
azd env set AZURE_SUBSCRIPTION_ID="${{ secrets.AZURE_SUBSCRIPTION_ID }}"
- azd env set AZURE_ENV_AI_DEPLOYMENTS_LOCATION="${{ inputs.AZURE_ENV_OPENAI_LOCATION }}"
- azd env set AZURE_LOCATION="${{ inputs.AZURE_LOCATION }}"
- azd env set AZURE_RESOURCE_GROUP="${{ inputs.RESOURCE_GROUP_NAME }}"
- azd env set AZURE_ENV_CONTAINER_IMAGE_TAG="${{ inputs.IMAGE_TAG }}"
+ azd env set AZURE_ENV_AI_DEPLOYMENTS_LOCATION="$env:AZURE_ENV_OPENAI_LOCATION"
+ azd env set AZURE_LOCATION="$env:AZURE_LOCATION"
+ azd env set AZURE_RESOURCE_GROUP="$env:RESOURCE_GROUP_NAME"
+ azd env set AZURE_ENV_CONTAINER_IMAGE_TAG="$env:IMAGE_TAG"
# Set ACR name only when building Docker image
- if ("${{ inputs.BUILD_DOCKER_IMAGE }}" -eq "true") {
+ if ($env:BUILD_DOCKER_IMAGE -eq "true") {
# Extract ACR name from login server and set as environment variable
$ACR_NAME = "${{ secrets.ACR_TEST_LOGIN_SERVER }}"
azd env set AZURE_ENV_CONTAINER_REGISTRY_ENDPOINT="$ACR_NAME"
@@ -105,18 +250,18 @@ jobs:
Write-Host "Skipping ACR name configuration (using existing image)"
}
- if ("${{ inputs.EXP }}" -eq "true") {
+ if ($env:EXP -eq "true") {
Write-Host "â
EXP ENABLED - Setting EXP parameters..."
# Set EXP variables dynamically
- if ("${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}" -ne "") {
- $EXP_LOG_ANALYTICS_ID = "${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}"
+ if ($env:AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID -ne "") {
+ $EXP_LOG_ANALYTICS_ID = $env:AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID
} else {
$EXP_LOG_ANALYTICS_ID = "${{ secrets.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}"
}
- if ("${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}" -ne "") {
- $EXP_AI_PROJECT_ID = "${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}"
+ if ($env:AZURE_EXISTING_AI_PROJECT_RESOURCE_ID -ne "") {
+ $EXP_AI_PROJECT_ID = $env:AZURE_EXISTING_AI_PROJECT_RESOURCE_ID
} else {
$EXP_AI_PROJECT_ID = "${{ secrets.AZURE_ENV_FOUNDRY_PROJECT_ID }}"
}
@@ -178,35 +323,59 @@ jobs:
- name: Disable Auth in Web App
shell: bash
+ env:
+ RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }}
run: |
az containerapp update --name ${{ env.CONTAINER_WEB_APPNAME }} \
- --resource-group ${{ inputs.RESOURCE_GROUP_NAME }} \
+ --resource-group $RESOURCE_GROUP_NAME \
--set-env-vars APP_AUTH_ENABLED=false
- name: Disable Auth in API App
shell: bash
+ env:
+ RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }}
run: |
sleep 30
az containerapp update --name ${{ env.CONTAINER_API_APPNAME }} \
- --resource-group ${{ inputs.RESOURCE_GROUP_NAME }} \
+ --resource-group $RESOURCE_GROUP_NAME \
--set-env-vars APP_AUTH_ENABLED=false
- name: Generate Deployment Summary
if: always()
shell: bash
+ env:
+ RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }}
+ AZURE_LOCATION: ${{ inputs.AZURE_LOCATION }}
+ AZURE_ENV_OPENAI_LOCATION: ${{ inputs.AZURE_ENV_OPENAI_LOCATION }}
+ IMAGE_TAG: ${{ inputs.IMAGE_TAG }}
+ WAF_ENABLED: ${{ inputs.WAF_ENABLED }}
+ EXP: ${{ inputs.EXP }}
+ JOB_STATUS: ${{ job.status }}
run: |
echo "## đ Deploy Job Summary (Windows)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| **Job Status** | ${{ job.status == 'success' && 'â
Success' || 'â Failed' }} |" >> $GITHUB_STEP_SUMMARY
- echo "| **Configuration Type** | \`${{ inputs.WAF_ENABLED == 'true' && inputs.EXP == 'true' && 'WAF + EXP' || inputs.WAF_ENABLED == 'true' && inputs.EXP != 'true' && 'WAF + Non-EXP' || inputs.WAF_ENABLED != 'true' && inputs.EXP == 'true' && 'Non-WAF + EXP' || 'Non-WAF + Non-EXP' }}\` |" >> $GITHUB_STEP_SUMMARY
- echo "| **Resource Group** | \`${{ inputs.RESOURCE_GROUP_NAME }}\` |" >> $GITHUB_STEP_SUMMARY
- echo "| **Azure Region (Infrastructure)** | \`${{ inputs.AZURE_LOCATION }}\` |" >> $GITHUB_STEP_SUMMARY
- echo "| **Azure OpenAI Region** | \`${{ inputs.AZURE_ENV_OPENAI_LOCATION }}\` |" >> $GITHUB_STEP_SUMMARY
- echo "| **Docker Image Tag** | \`${{ inputs.IMAGE_TAG }}\` |" >> $GITHUB_STEP_SUMMARY
+
+ # Determine configuration type
+ if [[ "$WAF_ENABLED" == "true" && "$EXP" == "true" ]]; then
+ CONFIG_TYPE="WAF + EXP"
+ elif [[ "$WAF_ENABLED" == "true" && "$EXP" != "true" ]]; then
+ CONFIG_TYPE="WAF + Non-EXP"
+ elif [[ "$WAF_ENABLED" != "true" && "$EXP" == "true" ]]; then
+ CONFIG_TYPE="Non-WAF + EXP"
+ else
+ CONFIG_TYPE="Non-WAF + Non-EXP"
+ fi
+
+ echo "| **Configuration Type** | \`$CONFIG_TYPE\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Resource Group** | \`$RESOURCE_GROUP_NAME\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Azure Region (Infrastructure)** | \`$AZURE_LOCATION\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Azure OpenAI Region** | \`$AZURE_ENV_OPENAI_LOCATION\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Docker Image Tag** | \`$IMAGE_TAG\` |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
- if [ "${{ job.status }}" == "success" ]; then
+ if [ "$JOB_STATUS" == "success" ]; then
echo "### â
Deployment Details" >> $GITHUB_STEP_SUMMARY
echo "- **Container Web App URL**: [${{ env.CONTAINER_WEB_APPURL }}](${{ env.CONTAINER_WEB_APPURL }})" >> $GITHUB_STEP_SUMMARY
echo "- **Container API App URL**: [${{ env.CONTAINER_API_APPURL }}](${{ env.CONTAINER_API_APPURL }})" >> $GITHUB_STEP_SUMMARY
diff --git a/.github/workflows/job-deploy.yml b/.github/workflows/job-deploy.yml
index 1d9c3a5e..e1642c42 100644
--- a/.github/workflows/job-deploy.yml
+++ b/.github/workflows/job-deploy.yml
@@ -112,18 +112,191 @@ jobs:
QUOTA_FAILED: ${{ steps.quota_failure_output.outputs.QUOTA_FAILED }}
steps:
+
+ - name: Validate Workflow Input Parameters
+ shell: bash
+ env:
+ INPUT_TRIGGER_TYPE: ${{ inputs.trigger_type }}
+ INPUT_RUNNER_OS: ${{ inputs.runner_os }}
+ INPUT_BUILD_DOCKER_IMAGE: ${{ inputs.build_docker_image }}
+ INPUT_AZURE_LOCATION: ${{ inputs.azure_location }}
+ INPUT_RESOURCE_GROUP_NAME: ${{ inputs.resource_group_name }}
+ INPUT_WAF_ENABLED: ${{ inputs.waf_enabled }}
+ INPUT_EXP: ${{ inputs.EXP }}
+ INPUT_CLEANUP_RESOURCES: ${{ inputs.cleanup_resources }}
+ INPUT_RUN_E2E_TESTS: ${{ inputs.run_e2e_tests }}
+ INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}
+ INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}
+ INPUT_EXISTING_WEBAPP_URL: ${{ inputs.existing_webapp_url }}
+ INPUT_DOCKER_IMAGE_TAG: ${{ inputs.docker_image_tag }}
+ run: |
+ echo "đ Validating workflow input parameters..."
+ VALIDATION_FAILED=false
+
+ # Validate trigger_type (required - alphanumeric with underscores)
+ if [[ -z "$INPUT_TRIGGER_TYPE" ]]; then
+ echo "â ERROR: trigger_type is required but was not provided"
+ VALIDATION_FAILED=true
+ elif [[ ! "$INPUT_TRIGGER_TYPE" =~ ^[a-zA-Z0-9_]+$ ]]; then
+ echo "â ERROR: trigger_type '$INPUT_TRIGGER_TYPE' is invalid. Must contain only alphanumeric characters and underscores"
+ VALIDATION_FAILED=true
+ else
+ echo "â
trigger_type: '$INPUT_TRIGGER_TYPE' is valid"
+ fi
+
+ # Validate runner_os (required - must be specific values)
+ ALLOWED_RUNNER_OS=("ubuntu-latest" "windows-latest")
+ if [[ -z "$INPUT_RUNNER_OS" ]]; then
+ echo "â ERROR: runner_os is required but was not provided"
+ VALIDATION_FAILED=true
+ elif [[ ! " ${ALLOWED_RUNNER_OS[@]} " =~ " ${INPUT_RUNNER_OS} " ]]; then
+ echo "â ERROR: runner_os '$INPUT_RUNNER_OS' is invalid. Allowed values: ${ALLOWED_RUNNER_OS[*]}"
+ VALIDATION_FAILED=true
+ else
+ echo "â
runner_os: '$INPUT_RUNNER_OS' is valid"
+ fi
+
+ # Validate build_docker_image (boolean)
+ if [[ "$INPUT_BUILD_DOCKER_IMAGE" != "true" && "$INPUT_BUILD_DOCKER_IMAGE" != "false" ]]; then
+ echo "â ERROR: build_docker_image must be 'true' or 'false', got: '$INPUT_BUILD_DOCKER_IMAGE'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
build_docker_image: '$INPUT_BUILD_DOCKER_IMAGE' is valid"
+ fi
+
+ # Validate azure_location (Azure region format)
+ if [[ -n "$INPUT_AZURE_LOCATION" ]]; then
+ if [[ ! "$INPUT_AZURE_LOCATION" =~ ^[a-z0-9]+$ ]]; then
+ echo "â ERROR: azure_location '$INPUT_AZURE_LOCATION' is invalid. Must contain only lowercase letters and numbers (e.g., 'australiaeast', 'westus2')"
+ VALIDATION_FAILED=true
+ else
+ echo "â
azure_location: '$INPUT_AZURE_LOCATION' is valid"
+ fi
+ fi
+
+ # Validate resource_group_name (Azure resource group naming convention)
+ if [[ -n "$INPUT_RESOURCE_GROUP_NAME" ]]; then
+ if [[ ! "$INPUT_RESOURCE_GROUP_NAME" =~ ^[a-zA-Z0-9._\(\)-]+$ ]] || [[ "$INPUT_RESOURCE_GROUP_NAME" =~ \.$ ]]; then
+ echo "â ERROR: resource_group_name '$INPUT_RESOURCE_GROUP_NAME' is invalid. Must contain only alphanumerics, periods, underscores, hyphens, and parentheses. Cannot end with period."
+ VALIDATION_FAILED=true
+ elif [[ ${#INPUT_RESOURCE_GROUP_NAME} -gt 90 ]]; then
+ echo "â ERROR: resource_group_name '$INPUT_RESOURCE_GROUP_NAME' exceeds 90 characters"
+ VALIDATION_FAILED=true
+ else
+ echo "â
resource_group_name: '$INPUT_RESOURCE_GROUP_NAME' is valid"
+ fi
+ fi
+
+ # Validate waf_enabled (boolean)
+ if [[ "$INPUT_WAF_ENABLED" != "true" && "$INPUT_WAF_ENABLED" != "false" ]]; then
+ echo "â ERROR: waf_enabled must be 'true' or 'false', got: '$INPUT_WAF_ENABLED'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
waf_enabled: '$INPUT_WAF_ENABLED' is valid"
+ fi
+
+ # Validate EXP (boolean)
+ if [[ "$INPUT_EXP" != "true" && "$INPUT_EXP" != "false" ]]; then
+ echo "â ERROR: EXP must be 'true' or 'false', got: '$INPUT_EXP'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
EXP: '$INPUT_EXP' is valid"
+ fi
+
+ # Validate cleanup_resources (boolean)
+ if [[ "$INPUT_CLEANUP_RESOURCES" != "true" && "$INPUT_CLEANUP_RESOURCES" != "false" ]]; then
+ echo "â ERROR: cleanup_resources must be 'true' or 'false', got: '$INPUT_CLEANUP_RESOURCES'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
cleanup_resources: '$INPUT_CLEANUP_RESOURCES' is valid"
+ fi
+
+ # Validate run_e2e_tests (specific allowed values)
+ if [[ -n "$INPUT_RUN_E2E_TESTS" ]]; then
+ ALLOWED_VALUES=("None" "GoldenPath-Testing" "Smoke-Testing")
+ if [[ ! " ${ALLOWED_VALUES[@]} " =~ " ${INPUT_RUN_E2E_TESTS} " ]]; then
+ echo "â ERROR: run_e2e_tests '$INPUT_RUN_E2E_TESTS' is invalid. Allowed values: ${ALLOWED_VALUES[*]}"
+ VALIDATION_FAILED=true
+ else
+ echo "â
run_e2e_tests: '$INPUT_RUN_E2E_TESTS' is valid"
+ fi
+ fi
+
+ # Validate AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID (Azure Resource ID format)
+ if [[ -n "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" ]]; then
+ if [[ ! "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/resourceGroups/[^/]+/providers/microsoft\.operationalinsights/workspaces/[^/]+$ ]]; then
+ echo "â ERROR: AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID is invalid. Must be a valid Azure Resource ID format:"
+ echo " /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.OperationalInsights/workspaces/{workspaceName}"
+ echo " Got: '$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: Valid Resource ID format"
+ fi
+ fi
+
+ # Validate AZURE_EXISTING_AI_PROJECT_RESOURCE_ID (Azure Resource ID format)
+ if [[ -n "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" ]]; then
+ if [[ ! "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/resourceGroups/[^/]+/providers/(Microsoft\.MachineLearningServices/(workspaces|projects)/[^/]+|Microsoft\.CognitiveServices/accounts/[^/]+/projects/[^/]+)$ ]]; then
+ echo "â ERROR: AZURE_EXISTING_AI_PROJECT_RESOURCE_ID is invalid. Must be a valid Azure Resource ID format:"
+ echo " /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.CognitiveServices/accounts/{accountName}/projects/{projectName}"
+ echo " Got: '$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: Valid Resource ID format"
+ fi
+ fi
+
+ # Validate existing_webapp_url (must start with https)
+ if [[ -n "$INPUT_EXISTING_WEBAPP_URL" ]]; then
+ if [[ ! "$INPUT_EXISTING_WEBAPP_URL" =~ ^https:// ]]; then
+ echo "â ERROR: existing_webapp_url must start with 'https://', got: '$INPUT_EXISTING_WEBAPP_URL'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
existing_webapp_url: '$INPUT_EXISTING_WEBAPP_URL' is valid"
+ fi
+ fi
+
+ # Validate docker_image_tag (Docker tag pattern)
+ if [[ -n "$INPUT_DOCKER_IMAGE_TAG" ]]; then
+ # Docker tags: lowercase and uppercase letters, digits, underscores, periods, and hyphens
+ # Cannot start with period or hyphen, max 128 characters
+ if [[ ! "$INPUT_DOCKER_IMAGE_TAG" =~ ^[a-zA-Z0-9_][a-zA-Z0-9._-]{0,127}$ ]]; then
+ echo "â ERROR: docker_image_tag '$INPUT_DOCKER_IMAGE_TAG' is invalid. Must:"
+ echo " - Start with alphanumeric or underscore"
+ echo " - Contain only alphanumerics, underscores, periods, hyphens"
+ echo " - Be max 128 characters"
+ VALIDATION_FAILED=true
+ else
+ echo "â
docker_image_tag: '$INPUT_DOCKER_IMAGE_TAG' is valid"
+ fi
+ fi
+
+ # Fail workflow if any validation failed
+ if [[ "$VALIDATION_FAILED" == "true" ]]; then
+ echo ""
+ echo "â Parameter validation failed. Please correct the errors above and try again."
+ exit 1
+ fi
+
+ echo ""
+ echo "â
All input parameters validated successfully!"
+
- name: Validate and Auto-Configure EXP
shell: bash
+ env:
+ INPUT_EXP: ${{ inputs.EXP }}
+ INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}
+ INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}
run: |
echo "đ Validating EXP configuration..."
- if [[ "${{ inputs.EXP }}" != "true" ]]; then
- if [[ -n "${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}" ]] || [[ -n "${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}" ]]; then
+ if [[ "$INPUT_EXP" != "true" ]]; then
+ if [[ -n "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" ]] || [[ -n "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" ]]; then
echo "đ§ AUTO-ENABLING EXP: EXP parameter values were provided but EXP was not explicitly enabled."
echo ""
echo "You provided values for:"
- [[ -n "${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}" ]] && echo " - Azure Log Analytics Workspace ID: '${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}'"
- [[ -n "${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}" ]] && echo " - Azure AI Project Resource ID: '${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}'"
+ [[ -n "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" ]] && echo " - Azure Log Analytics Workspace ID: '$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID'"
+ [[ -n "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" ]] && echo " - Azure AI Project Resource ID: '$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID'"
echo ""
echo "â
Automatically enabling EXP to use these values."
echo "EXP=true" >> $GITHUB_ENV
@@ -175,13 +348,16 @@ jobs:
- name: Set Deployment Region
id: set_region
shell: bash
+ env:
+ INPUT_TRIGGER_TYPE: ${{ inputs.trigger_type }}
+ INPUT_AZURE_LOCATION: ${{ inputs.azure_location }}
run: |
echo "Selected Region from Quota Check: $VALID_REGION"
echo "AZURE_ENV_OPENAI_LOCATION=$VALID_REGION" >> $GITHUB_ENV
echo "AZURE_ENV_OPENAI_LOCATION=$VALID_REGION" >> $GITHUB_OUTPUT
- if [[ "${{ inputs.trigger_type }}" == "workflow_dispatch" && -n "${{ inputs.azure_location }}" ]]; then
- USER_SELECTED_LOCATION="${{ inputs.azure_location }}"
+ if [[ "$INPUT_TRIGGER_TYPE" == "workflow_dispatch" && -n "$INPUT_AZURE_LOCATION" ]]; then
+ USER_SELECTED_LOCATION="$INPUT_AZURE_LOCATION"
echo "Using user-selected Azure location: $USER_SELECTED_LOCATION"
echo "AZURE_LOCATION=$USER_SELECTED_LOCATION" >> $GITHUB_ENV
echo "AZURE_LOCATION=$USER_SELECTED_LOCATION" >> $GITHUB_OUTPUT
@@ -194,11 +370,13 @@ jobs:
- name: Generate Resource Group Name
id: generate_rg_name
shell: bash
+ env:
+ INPUT_RESOURCE_GROUP_NAME: ${{ inputs.resource_group_name }}
run: |
# Check if a resource group name was provided as input
- if [[ -n "${{ inputs.resource_group_name }}" ]]; then
- echo "Using provided Resource Group name: ${{ inputs.resource_group_name }}"
- echo "RESOURCE_GROUP_NAME=${{ inputs.resource_group_name }}" >> $GITHUB_ENV
+ if [[ -n "$INPUT_RESOURCE_GROUP_NAME" ]]; then
+ echo "Using provided Resource Group name: $INPUT_RESOURCE_GROUP_NAME"
+ echo "RESOURCE_GROUP_NAME=$INPUT_RESOURCE_GROUP_NAME" >> $GITHUB_ENV
else
echo "Generating a unique resource group name..."
ACCL_NAME="cp" # Account name as specified
@@ -296,33 +474,43 @@ jobs:
- name: Display Workflow Configuration to GitHub Summary
shell: bash
+ env:
+ INPUT_TRIGGER_TYPE: ${{ inputs.trigger_type }}
+ INPUT_RUNNER_OS: ${{ inputs.runner_os }}
+ INPUT_AZURE_LOCATION: ${{ inputs.azure_location }}
+ INPUT_RESOURCE_GROUP_NAME: ${{ inputs.resource_group_name }}
+ EVENT_NAME: ${{ github.event_name }}
+ WAF_STATUS: ${{ env.WAF_ENABLED == 'true' && 'â
Yes' || 'â No' }}
+ EXP_STATUS: ${{ env.EXP == 'true' && 'â
Yes' || 'â No' }}
+ CLEANUP_STATUS: ${{ env.CLEANUP_RESOURCES == 'true' && 'â
Yes' || 'â No' }}
+ BUILD_DOCKER_STATUS: ${{ env.BUILD_DOCKER_IMAGE == 'true' && 'â
Yes' || 'â No' }}
run: |
echo "## đ Workflow Configuration Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Configuration | Value |" >> $GITHUB_STEP_SUMMARY
echo "|---------------|-------|" >> $GITHUB_STEP_SUMMARY
- echo "| **Trigger Type** | \`${{ github.event_name }}\` |" >> $GITHUB_STEP_SUMMARY
- echo "| **Branch** | \`${{ env.BRANCH_NAME }}\` |" >> $GITHUB_STEP_SUMMARY
- echo "| **Runner OS** | \`${{ inputs.runner_os }}\` |" >> $GITHUB_STEP_SUMMARY
- echo "| **WAF Enabled** | ${{ env.WAF_ENABLED == 'true' && 'â
Yes' || 'â No' }} |" >> $GITHUB_STEP_SUMMARY
- echo "| **EXP Enabled** | ${{ env.EXP == 'true' && 'â
Yes' || 'â No' }} |" >> $GITHUB_STEP_SUMMARY
- echo "| **Run E2E Tests** | \`${{ env.RUN_E2E_TESTS }}\` |" >> $GITHUB_STEP_SUMMARY
- echo "| **Cleanup Resources** | ${{ env.CLEANUP_RESOURCES == 'true' && 'â
Yes' || 'â No' }} |" >> $GITHUB_STEP_SUMMARY
- echo "| **Build Docker Image** | ${{ env.BUILD_DOCKER_IMAGE == 'true' && 'â
Yes' || 'â No' }} |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Trigger Type** | \`$EVENT_NAME\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Branch** | \`$BRANCH_NAME\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Runner OS** | \`$INPUT_RUNNER_OS\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **WAF Enabled** | $WAF_STATUS |" >> $GITHUB_STEP_SUMMARY
+ echo "| **EXP Enabled** | $EXP_STATUS |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Run E2E Tests** | \`$RUN_E2E_TESTS\` |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Cleanup Resources** | $CLEANUP_STATUS |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Build Docker Image** | $BUILD_DOCKER_STATUS |" >> $GITHUB_STEP_SUMMARY
- if [[ "${{ inputs.trigger_type }}" == "workflow_dispatch" && -n "${{ inputs.azure_location }}" ]]; then
- echo "| **Azure Location** | \`${{ inputs.azure_location }}\` (User Selected) |" >> $GITHUB_STEP_SUMMARY
+ if [[ "$INPUT_TRIGGER_TYPE" == "workflow_dispatch" && -n "$INPUT_AZURE_LOCATION" ]]; then
+ echo "| **Azure Location** | \`$INPUT_AZURE_LOCATION\` (User Selected) |" >> $GITHUB_STEP_SUMMARY
fi
- if [[ -n "${{ inputs.resource_group_name }}" ]]; then
- echo "| **Resource Group** | \`${{ inputs.resource_group_name }}\` (Pre-specified) |" >> $GITHUB_STEP_SUMMARY
+ if [[ -n "$INPUT_RESOURCE_GROUP_NAME" ]]; then
+ echo "| **Resource Group** | \`$INPUT_RESOURCE_GROUP_NAME\` (Pre-specified) |" >> $GITHUB_STEP_SUMMARY
else
- echo "| **Resource Group** | \`${{ env.RESOURCE_GROUP_NAME }}\` (Auto-generated) |" >> $GITHUB_STEP_SUMMARY
+ echo "| **Resource Group** | \`$RESOURCE_GROUP_NAME\` (Auto-generated) |" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
- if [[ "${{ inputs.trigger_type }}" != "workflow_dispatch" ]]; then
+ if [[ "$INPUT_TRIGGER_TYPE" != "workflow_dispatch" ]]; then
echo "âšī¸ **Note:** Automatic Trigger - Using Non-WAF + Non-EXP configuration" >> $GITHUB_STEP_SUMMARY
else
echo "âšī¸ **Note:** Manual Trigger - Using user-specified configuration" >> $GITHUB_STEP_SUMMARY
diff --git a/.github/workflows/job-send-notification.yml b/.github/workflows/job-send-notification.yml
index fe971270..0dd920c0 100644
--- a/.github/workflows/job-send-notification.yml
+++ b/.github/workflows/job-send-notification.yml
@@ -75,18 +75,176 @@ jobs:
env:
accelerator_name: "Content Processing"
steps:
+ - name: Validate Workflow Input Parameters
+ shell: bash
+ env:
+ INPUT_TRIGGER_TYPE: ${{ inputs.trigger_type }}
+ INPUT_WAF_ENABLED: ${{ inputs.waf_enabled }}
+ INPUT_EXP: ${{ inputs.EXP }}
+ INPUT_RUN_E2E_TESTS: ${{ inputs.run_e2e_tests }}
+ INPUT_EXISTING_WEBAPP_URL: ${{ inputs.existing_webapp_url }}
+ INPUT_DEPLOY_RESULT: ${{ inputs.deploy_result }}
+ INPUT_E2E_TEST_RESULT: ${{ inputs.e2e_test_result }}
+ INPUT_CONTAINER_WEB_APPURL: ${{ inputs.CONTAINER_WEB_APPURL }}
+ INPUT_RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }}
+ INPUT_QUOTA_FAILED: ${{ inputs.QUOTA_FAILED }}
+ INPUT_TEST_SUCCESS: ${{ inputs.TEST_SUCCESS }}
+ INPUT_TEST_REPORT_URL: ${{ inputs.TEST_REPORT_URL }}
+ run: |
+ echo "đ Validating workflow input parameters..."
+ VALIDATION_FAILED=false
+
+ # Validate trigger_type (required - alphanumeric with underscores)
+ if [[ -z "$INPUT_TRIGGER_TYPE" ]]; then
+ echo "â ERROR: trigger_type is required but was not provided"
+ VALIDATION_FAILED=true
+ elif [[ ! "$INPUT_TRIGGER_TYPE" =~ ^[a-zA-Z0-9_]+$ ]]; then
+ echo "â ERROR: trigger_type '$INPUT_TRIGGER_TYPE' is invalid. Must contain only alphanumeric characters and underscores"
+ VALIDATION_FAILED=true
+ else
+ echo "â
trigger_type: '$INPUT_TRIGGER_TYPE' is valid"
+ fi
+
+ # Validate waf_enabled (boolean)
+ if [[ "$INPUT_WAF_ENABLED" != "true" && "$INPUT_WAF_ENABLED" != "false" ]]; then
+ echo "â ERROR: waf_enabled must be 'true' or 'false', got: '$INPUT_WAF_ENABLED'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
waf_enabled: '$INPUT_WAF_ENABLED' is valid"
+ fi
+
+ # Validate EXP (boolean)
+ if [[ "$INPUT_EXP" != "true" && "$INPUT_EXP" != "false" ]]; then
+ echo "â ERROR: EXP must be 'true' or 'false', got: '$INPUT_EXP'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
EXP: '$INPUT_EXP' is valid"
+ fi
+
+ # Validate run_e2e_tests (specific allowed values)
+ if [[ -n "$INPUT_RUN_E2E_TESTS" ]]; then
+ ALLOWED_VALUES=("None" "GoldenPath-Testing" "Smoke-Testing")
+ if [[ ! " ${ALLOWED_VALUES[@]} " =~ " ${INPUT_RUN_E2E_TESTS} " ]]; then
+ echo "â ERROR: run_e2e_tests '$INPUT_RUN_E2E_TESTS' is invalid. Allowed values: ${ALLOWED_VALUES[*]}"
+ VALIDATION_FAILED=true
+ else
+ echo "â
run_e2e_tests: '$INPUT_RUN_E2E_TESTS' is valid"
+ fi
+ fi
+
+ # Validate existing_webapp_url (must start with https if provided)
+ if [[ -n "$INPUT_EXISTING_WEBAPP_URL" ]]; then
+ if [[ ! "$INPUT_EXISTING_WEBAPP_URL" =~ ^https:// ]]; then
+ echo "â ERROR: existing_webapp_url must start with 'https://', got: '$INPUT_EXISTING_WEBAPP_URL'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
existing_webapp_url: '$INPUT_EXISTING_WEBAPP_URL' is valid"
+ fi
+ fi
+
+ # Validate deploy_result (required, must be specific values)
+ if [[ -z "$INPUT_DEPLOY_RESULT" ]]; then
+ echo "â ERROR: deploy_result is required but not provided"
+ VALIDATION_FAILED=true
+ else
+ ALLOWED_DEPLOY_RESULTS=("success" "failure" "skipped")
+ if [[ ! " ${ALLOWED_DEPLOY_RESULTS[@]} " =~ " ${INPUT_DEPLOY_RESULT} " ]]; then
+ echo "â ERROR: deploy_result '$INPUT_DEPLOY_RESULT' is invalid. Allowed values: ${ALLOWED_DEPLOY_RESULTS[*]}"
+ VALIDATION_FAILED=true
+ else
+ echo "â
deploy_result: '$INPUT_DEPLOY_RESULT' is valid"
+ fi
+ fi
+
+ # Validate e2e_test_result (required, must be specific values)
+ if [[ -z "$INPUT_E2E_TEST_RESULT" ]]; then
+ echo "â ERROR: e2e_test_result is required but not provided"
+ VALIDATION_FAILED=true
+ else
+ ALLOWED_TEST_RESULTS=("success" "failure" "skipped")
+ if [[ ! " ${ALLOWED_TEST_RESULTS[@]} " =~ " ${INPUT_E2E_TEST_RESULT} " ]]; then
+ echo "â ERROR: e2e_test_result '$INPUT_E2E_TEST_RESULT' is invalid. Allowed values: ${ALLOWED_TEST_RESULTS[*]}"
+ VALIDATION_FAILED=true
+ else
+ echo "â
e2e_test_result: '$INPUT_E2E_TEST_RESULT' is valid"
+ fi
+ fi
+
+ # Validate CONTAINER_WEB_APPURL (must start with https if provided)
+ if [[ -n "$INPUT_CONTAINER_WEB_APPURL" ]]; then
+ if [[ ! "$INPUT_CONTAINER_WEB_APPURL" =~ ^https:// ]]; then
+ echo "â ERROR: CONTAINER_WEB_APPURL must start with 'https://', got: '$INPUT_CONTAINER_WEB_APPURL'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
CONTAINER_WEB_APPURL: '$INPUT_CONTAINER_WEB_APPURL' is valid"
+ fi
+ fi
+
+ # Validate RESOURCE_GROUP_NAME (Azure resource group naming convention if provided)
+ if [[ -n "$INPUT_RESOURCE_GROUP_NAME" ]]; then
+ if [[ ! "$INPUT_RESOURCE_GROUP_NAME" =~ ^[a-zA-Z0-9._\(\)-]+$ ]] || [[ "$INPUT_RESOURCE_GROUP_NAME" =~ \.$ ]]; then
+ echo "â ERROR: RESOURCE_GROUP_NAME '$INPUT_RESOURCE_GROUP_NAME' is invalid. Must contain only alphanumerics, periods, underscores, hyphens, and parentheses. Cannot end with period."
+ VALIDATION_FAILED=true
+ elif [[ ${#INPUT_RESOURCE_GROUP_NAME} -gt 90 ]]; then
+ echo "â ERROR: RESOURCE_GROUP_NAME '$INPUT_RESOURCE_GROUP_NAME' exceeds 90 characters"
+ VALIDATION_FAILED=true
+ else
+ echo "â
RESOURCE_GROUP_NAME: '$INPUT_RESOURCE_GROUP_NAME' is valid"
+ fi
+ fi
+
+ # Validate QUOTA_FAILED (must be 'true' or 'false')
+ if [[ "$INPUT_QUOTA_FAILED" != "true" && "$INPUT_QUOTA_FAILED" != "false" ]]; then
+ echo "â ERROR: QUOTA_FAILED must be 'true' or 'false', got: '$INPUT_QUOTA_FAILED'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
QUOTA_FAILED: '$INPUT_QUOTA_FAILED' is valid"
+ fi
+
+ # Validate TEST_SUCCESS (must be 'true' or 'false' or empty)
+ if [[ -n "$INPUT_TEST_SUCCESS" ]]; then
+ if [[ "$INPUT_TEST_SUCCESS" != "true" && "$INPUT_TEST_SUCCESS" != "false" ]]; then
+ echo "â ERROR: TEST_SUCCESS must be 'true', 'false', or empty, got: '$INPUT_TEST_SUCCESS'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
TEST_SUCCESS: '$INPUT_TEST_SUCCESS' is valid"
+ fi
+ fi
+
+ # Validate TEST_REPORT_URL (must start with https if provided)
+ if [[ -n "$INPUT_TEST_REPORT_URL" ]]; then
+ if [[ ! "$INPUT_TEST_REPORT_URL" =~ ^https:// ]]; then
+ echo "â ERROR: TEST_REPORT_URL must start with 'https://', got: '$INPUT_TEST_REPORT_URL'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
TEST_REPORT_URL: '$INPUT_TEST_REPORT_URL' is valid"
+ fi
+ fi
+
+ # Fail workflow if any validation failed
+ if [[ "$VALIDATION_FAILED" == "true" ]]; then
+ echo ""
+ echo "â Parameter validation failed. Please correct the errors above and try again."
+ exit 1
+ fi
+
+ echo ""
+ echo "â
All input parameters validated successfully!"
+
- name: Determine Test Suite Display Name
id: test_suite
shell: bash
+ env:
+ RUN_E2E_TESTS: ${{ env.RUN_E2E_TESTS }}
run: |
- if [ "${{ env.RUN_E2E_TESTS }}" = "GoldenPath-Testing" ]; then
+ if [ "$RUN_E2E_TESTS" = "GoldenPath-Testing" ]; then
TEST_SUITE_NAME="Golden Path Testing"
- elif [ "${{ env.RUN_E2E_TESTS }}" = "Smoke-Testing" ]; then
+ elif [ "$RUN_E2E_TESTS" = "Smoke-Testing" ]; then
TEST_SUITE_NAME="Smoke Testing"
- elif [ "${{ env.RUN_E2E_TESTS }}" = "None" ]; then
+ elif [ "$RUN_E2E_TESTS" = "None" ]; then
TEST_SUITE_NAME="None"
else
- TEST_SUITE_NAME="${{ env.RUN_E2E_TESTS }}"
+ TEST_SUITE_NAME="$RUN_E2E_TESTS"
fi
echo "TEST_SUITE_NAME=$TEST_SUITE_NAME" >> $GITHUB_OUTPUT
echo "Test Suite: $TEST_SUITE_NAME"
@@ -94,131 +252,191 @@ jobs:
- name: Send Quota Failure Notification
if: inputs.deploy_result == 'failure' && inputs.QUOTA_FAILED == 'true'
shell: bash
+ env:
+ DEPLOY_RESULT: ${{ inputs.deploy_result }}
+ QUOTA_FAILED: ${{ inputs.QUOTA_FAILED }}
+ ACCELERATOR_NAME: ${{ env.accelerator_name }}
+ GPT_MIN_CAPACITY: ${{ env.GPT_MIN_CAPACITY }}
+ AZURE_REGIONS: ${{ vars.AZURE_REGIONS }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
+ GITHUB_RUN_ID: ${{ github.run_id }}
+ LOGICAPP_URL: ${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}
run: |
- RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
+ RUN_URL="https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
EMAIL_BODY=$(cat <Dear Team,
We would like to inform you that the ${{ env.accelerator_name }} deployment has failed due to insufficient quota in the requested regions.
Issue Details:
âĸ Quota check failed for GPT model
âĸ Required GPT Capacity: ${{ env.GPT_MIN_CAPACITY }}
âĸ Checked Regions: ${{ vars.AZURE_REGIONS }}
Run URL: ${RUN_URL}
Please resolve the quota issue and retry the deployment.
Best regards,
Your Automation Team
",
- "subject": "${{ env.accelerator_name }} Pipeline - Failed (Insufficient Quota)"
+ "body": "Dear Team,
We would like to inform you that the ${ACCELERATOR_NAME} deployment has failed due to insufficient quota in the requested regions.
Issue Details:
âĸ Quota check failed for GPT model
âĸ Required GPT Capacity: ${GPT_MIN_CAPACITY}
âĸ Checked Regions: ${AZURE_REGIONS}
Run URL: ${RUN_URL}
Please resolve the quota issue and retry the deployment.
Best regards,
Your Automation Team
",
+ "subject": "${ACCELERATOR_NAME} Pipeline - Failed (Insufficient Quota)"
}
EOF
)
- curl -X POST "${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}" \
+ curl -X POST "${LOGICAPP_URL}" \
-H "Content-Type: application/json" \
-d "$EMAIL_BODY" || echo "Failed to send quota failure notification"
- name: Send Deployment Failure Notification
if: inputs.deploy_result == 'failure' && inputs.QUOTA_FAILED != 'true'
shell: bash
+ env:
+ DEPLOY_RESULT: ${{ inputs.deploy_result }}
+ QUOTA_FAILED: ${{ inputs.QUOTA_FAILED }}
+ RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }}
+ ACCELERATOR_NAME: ${{ env.accelerator_name }}
+ WAF_ENABLED: ${{ env.WAF_ENABLED }}
+ EXP: ${{ env.EXP }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
+ GITHUB_RUN_ID: ${{ github.run_id }}
+ LOGICAPP_URL: ${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}
run: |
- RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
- RESOURCE_GROUP="${{ inputs.RESOURCE_GROUP_NAME }}"
+ RUN_URL="https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
+ RESOURCE_GROUP="${RESOURCE_GROUP_NAME}"
EMAIL_BODY=$(cat <Dear Team,We would like to inform you that the ${{ env.accelerator_name }} deployment process has encountered an issue and has failed to complete successfully.
Deployment Details:
âĸ Resource Group: ${RESOURCE_GROUP}
âĸ WAF Enabled: ${{ env.WAF_ENABLED }}
âĸ EXP Enabled: ${{ env.EXP }}
Run URL: ${RUN_URL}
Please investigate the deployment failure at your earliest convenience.
Best regards,
Your Automation Team
",
- "subject": "${{ env.accelerator_name }} Pipeline - Failed"
+ "body": "Dear Team,
We would like to inform you that the ${ACCELERATOR_NAME} deployment process has encountered an issue and has failed to complete successfully.
Deployment Details:
âĸ Resource Group: ${RESOURCE_GROUP}
âĸ WAF Enabled: ${WAF_ENABLED}
âĸ EXP Enabled: ${EXP}
Run URL: ${RUN_URL}
Please investigate the deployment failure at your earliest convenience.
Best regards,
Your Automation Team
",
+ "subject": "${ACCELERATOR_NAME} Pipeline - Failed"
}
EOF
)
- curl -X POST "${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}" \
+ curl -X POST "${LOGICAPP_URL}" \
-H "Content-Type: application/json" \
-d "$EMAIL_BODY" || echo "Failed to send deployment failure notification"
- name: Send Success Notification
if: inputs.deploy_result == 'success' && (inputs.e2e_test_result == 'skipped' || inputs.TEST_SUCCESS == 'true')
shell: bash
+ env:
+ DEPLOY_RESULT: ${{ inputs.deploy_result }}
+ E2E_TEST_RESULT: ${{ inputs.e2e_test_result }}
+ TEST_SUCCESS: ${{ inputs.TEST_SUCCESS }}
+ CONTAINER_WEB_APPURL: ${{ inputs.CONTAINER_WEB_APPURL }}
+ EXISTING_WEBAPP_URL: ${{ inputs.existing_webapp_url }}
+ RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }}
+ TEST_REPORT_URL: ${{ inputs.TEST_REPORT_URL }}
+ TEST_SUITE_NAME: ${{ steps.test_suite.outputs.TEST_SUITE_NAME }}
+ ACCELERATOR_NAME: ${{ env.accelerator_name }}
+ WAF_ENABLED: ${{ env.WAF_ENABLED }}
+ EXP: ${{ env.EXP }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
+ GITHUB_RUN_ID: ${{ github.run_id }}
+ LOGICAPP_URL: ${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}
run: |
- RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
- WEBAPP_URL="${{ inputs.CONTAINER_WEB_APPURL || inputs.existing_webapp_url }}"
- RESOURCE_GROUP="${{ inputs.RESOURCE_GROUP_NAME }}"
- TEST_REPORT_URL="${{ inputs.TEST_REPORT_URL }}"
- TEST_SUITE_NAME="${{ steps.test_suite.outputs.TEST_SUITE_NAME }}"
+ RUN_URL="https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
+ WEBAPP_URL="${CONTAINER_WEB_APPURL:-${EXISTING_WEBAPP_URL}}"
+ RESOURCE_GROUP="${RESOURCE_GROUP_NAME}"
- if [ "${{ inputs.e2e_test_result }}" = "skipped" ]; then
+ if [ "${E2E_TEST_RESULT}" = "skipped" ]; then
EMAIL_BODY=$(cat <Dear Team,We would like to inform you that the ${{ env.accelerator_name }} deployment has completed successfully.
Deployment Details:
âĸ Resource Group: ${RESOURCE_GROUP}
âĸ Web App URL: ${WEBAPP_URL}
âĸ E2E Tests: Skipped (as configured)
Configuration:
âĸ WAF Enabled: ${{ env.WAF_ENABLED }}
âĸ EXP Enabled: ${{ env.EXP }}
Run URL: ${RUN_URL}
Best regards,
Your Automation Team
",
- "subject": "${{ env.accelerator_name }} Pipeline - Deployment Success"
+ "body": "Dear Team,
We would like to inform you that the ${ACCELERATOR_NAME} deployment has completed successfully.
Deployment Details:
âĸ Resource Group: ${RESOURCE_GROUP}
âĸ Web App URL: ${WEBAPP_URL}
âĸ E2E Tests: Skipped (as configured)
Configuration:
âĸ WAF Enabled: ${WAF_ENABLED}
âĸ EXP Enabled: ${EXP}
Run URL: ${RUN_URL}
Best regards,
Your Automation Team
",
+ "subject": "${ACCELERATOR_NAME} Pipeline - Deployment Success"
}
EOF
)
else
EMAIL_BODY=$(cat <Dear Team,We would like to inform you that the ${{ env.accelerator_name }} deployment and testing process has completed successfully.
Deployment Details:
âĸ Resource Group: ${RESOURCE_GROUP}
âĸ Web App URL: ${WEBAPP_URL}
âĸ E2E Tests: Passed â
âĸ Test Suite: ${TEST_SUITE_NAME}
âĸ Test Report: View Report
Configuration:
âĸ WAF Enabled: ${{ env.WAF_ENABLED }}
âĸ EXP Enabled: ${{ env.EXP }}
Run URL: ${RUN_URL}
Best regards,
Your Automation Team
",
- "subject": "${{ env.accelerator_name }} Pipeline - Test Automation - Success"
+ "body": "Dear Team,
We would like to inform you that the ${ACCELERATOR_NAME} deployment and testing process has completed successfully.
Deployment Details:
âĸ Resource Group: ${RESOURCE_GROUP}
âĸ Web App URL: ${WEBAPP_URL}
âĸ E2E Tests: Passed â
âĸ Test Suite: ${TEST_SUITE_NAME}
âĸ Test Report: View Report
Configuration:
âĸ WAF Enabled: ${WAF_ENABLED}
âĸ EXP Enabled: ${EXP}
Run URL: ${RUN_URL}
Best regards,
Your Automation Team
",
+ "subject": "${ACCELERATOR_NAME} Pipeline - Test Automation - Success"
}
EOF
)
fi
- curl -X POST "${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}" \
+ curl -X POST "${LOGICAPP_URL}" \
-H "Content-Type: application/json" \
-d "$EMAIL_BODY" || echo "Failed to send success notification"
- name: Send Test Failure Notification
if: inputs.deploy_result == 'success' && inputs.e2e_test_result != 'skipped' && inputs.TEST_SUCCESS != 'true'
shell: bash
+ env:
+ DEPLOY_RESULT: ${{ inputs.deploy_result }}
+ E2E_TEST_RESULT: ${{ inputs.e2e_test_result }}
+ TEST_SUCCESS: ${{ inputs.TEST_SUCCESS }}
+ TEST_REPORT_URL: ${{ inputs.TEST_REPORT_URL }}
+ CONTAINER_WEB_APPURL: ${{ inputs.CONTAINER_WEB_APPURL }}
+ EXISTING_WEBAPP_URL: ${{ inputs.existing_webapp_url }}
+ RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }}
+ TEST_SUITE_NAME: ${{ steps.test_suite.outputs.TEST_SUITE_NAME }}
+ ACCELERATOR_NAME: ${{ env.accelerator_name }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
+ GITHUB_RUN_ID: ${{ github.run_id }}
+ LOGICAPP_URL: ${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}
run: |
- RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
- TEST_REPORT_URL="${{ inputs.TEST_REPORT_URL }}"
- WEBAPP_URL="${{ inputs.CONTAINER_WEB_APPURL || inputs.existing_webapp_url }}"
- RESOURCE_GROUP="${{ inputs.RESOURCE_GROUP_NAME }}"
- TEST_SUITE_NAME="${{ steps.test_suite.outputs.TEST_SUITE_NAME }}"
+ RUN_URL="https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
+ WEBAPP_URL="${CONTAINER_WEB_APPURL:-${EXISTING_WEBAPP_URL}}"
+ RESOURCE_GROUP="${RESOURCE_GROUP_NAME}"
EMAIL_BODY=$(cat <Dear Team,We would like to inform you that ${{ env.accelerator_name }} accelerator test automation process has encountered issues and failed to complete successfully.
Deployment Details:
âĸ Resource Group: ${RESOURCE_GROUP}
âĸ Web App URL: ${WEBAPP_URL}
âĸ Deployment Status: â
Success
âĸ E2E Tests: â Failed
âĸ Test Suite: ${TEST_SUITE_NAME}
Test Details:
âĸ Test Report: View Report
Run URL: ${RUN_URL}
Please investigate the matter at your earliest convenience.
Best regards,
Your Automation Team
",
- "subject": "${{ env.accelerator_name }} Pipeline - Test Automation - Failed"
+ "body": "Dear Team,
We would like to inform you that ${ACCELERATOR_NAME} accelerator test automation process has encountered issues and failed to complete successfully.
Deployment Details:
âĸ Resource Group: ${RESOURCE_GROUP}
âĸ Web App URL: ${WEBAPP_URL}
âĸ Deployment Status: â
Success
âĸ E2E Tests: â Failed
âĸ Test Suite: ${TEST_SUITE_NAME}
Test Details:
âĸ Test Report: View Report
Run URL: ${RUN_URL}
Please investigate the matter at your earliest convenience.
Best regards,
Your Automation Team
",
+ "subject": "${ACCELERATOR_NAME} Pipeline - Test Automation - Failed"
}
EOF
)
- curl -X POST "${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}" \
+ curl -X POST "${LOGICAPP_URL}" \
-H "Content-Type: application/json" \
-d "$EMAIL_BODY" || echo "Failed to send test failure notification"
- name: Send Existing URL Success Notification
if: inputs.deploy_result == 'skipped' && inputs.existing_webapp_url != '' && inputs.e2e_test_result == 'success' && (inputs.TEST_SUCCESS == 'true' || inputs.TEST_SUCCESS == '')
shell: bash
+ env:
+ DEPLOY_RESULT: ${{ inputs.deploy_result }}
+ EXISTING_WEBAPP_URL: ${{ inputs.existing_webapp_url }}
+ E2E_TEST_RESULT: ${{ inputs.e2e_test_result }}
+ TEST_SUCCESS: ${{ inputs.TEST_SUCCESS }}
+ TEST_REPORT_URL: ${{ inputs.TEST_REPORT_URL }}
+ TEST_SUITE_NAME: ${{ steps.test_suite.outputs.TEST_SUITE_NAME }}
+ ACCELERATOR_NAME: ${{ env.accelerator_name }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
+ GITHUB_RUN_ID: ${{ github.run_id }}
+ LOGICAPP_URL: ${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}
run: |
- RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
- EXISTING_URL="${{ inputs.existing_webapp_url }}"
- TEST_REPORT_URL="${{ inputs.TEST_REPORT_URL }}"
- TEST_SUITE_NAME="${{ steps.test_suite.outputs.TEST_SUITE_NAME }}"
+ RUN_URL="https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
+ EXISTING_URL="${EXISTING_WEBAPP_URL}"
EMAIL_BODY=$(cat <Dear Team,The ${{ env.accelerator_name }} pipeline executed against the existing WebApp URL and testing process has completed successfully.
Test Results:
âĸ Status: â
Passed
âĸ Test Suite: ${TEST_SUITE_NAME}
${TEST_REPORT_URL:+âĸ Test Report: View Report}
âĸ Target URL: ${EXISTING_URL}
Deployment: Skipped
Run URL: ${RUN_URL}
Best regards,
Your Automation Team
",
- "subject": "${{ env.accelerator_name }} Pipeline - Test Automation Passed (Existing URL)"
+ "body": "Dear Team,
The ${ACCELERATOR_NAME} pipeline executed against the existing WebApp URL and testing process has completed successfully.
Test Results:
âĸ Status: â
Passed
âĸ Test Suite: ${TEST_SUITE_NAME}
${TEST_REPORT_URL:+âĸ Test Report: View Report}
âĸ Target URL: ${EXISTING_URL}
Deployment: Skipped
Run URL: ${RUN_URL}
Best regards,
Your Automation Team
",
+ "subject": "${ACCELERATOR_NAME} Pipeline - Test Automation Passed (Existing URL)"
}
EOF
)
- curl -X POST "${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}" \
+ curl -X POST "${LOGICAPP_URL}" \
-H "Content-Type: application/json" \
-d "$EMAIL_BODY" || echo "Failed to send existing URL success notification"
- name: Send Existing URL Test Failure Notification
if: inputs.deploy_result == 'skipped' && inputs.existing_webapp_url != '' && inputs.e2e_test_result == 'failure'
shell: bash
+ env:
+ DEPLOY_RESULT: ${{ inputs.deploy_result }}
+ EXISTING_WEBAPP_URL: ${{ inputs.existing_webapp_url }}
+ E2E_TEST_RESULT: ${{ inputs.e2e_test_result }}
+ TEST_REPORT_URL: ${{ inputs.TEST_REPORT_URL }}
+ TEST_SUITE_NAME: ${{ steps.test_suite.outputs.TEST_SUITE_NAME }}
+ ACCELERATOR_NAME: ${{ env.accelerator_name }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
+ GITHUB_RUN_ID: ${{ github.run_id }}
+ LOGICAPP_URL: ${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}
run: |
- RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
- EXISTING_URL="${{ inputs.existing_webapp_url }}"
- TEST_REPORT_URL="${{ inputs.TEST_REPORT_URL }}"
- TEST_SUITE_NAME="${{ steps.test_suite.outputs.TEST_SUITE_NAME }}"
+ RUN_URL="https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
+ EXISTING_URL="${EXISTING_WEBAPP_URL}"
EMAIL_BODY=$(cat <Dear Team,The ${{ env.accelerator_name }} pipeline executed against the existing WebApp URL and the test automation has encountered issues and failed to complete successfully.
Failure Details:
âĸ Target URL: ${EXISTING_URL}
${TEST_REPORT_URL:+âĸ Test Report: View Report}
âĸ Test Suite: ${TEST_SUITE_NAME}
âĸ Deployment: Skipped
Run URL: ${RUN_URL}
Best regards,
Your Automation Team
",
- "subject": "${{ env.accelerator_name }} Pipeline - Test Automation Failed (Existing URL)"
+ "body": "Dear Team,
The ${ACCELERATOR_NAME} pipeline executed against the existing WebApp URL and the test automation has encountered issues and failed to complete successfully.
Failure Details:
âĸ Target URL: ${EXISTING_URL}
${TEST_REPORT_URL:+âĸ Test Report: View Report}
âĸ Test Suite: ${TEST_SUITE_NAME}
âĸ Deployment: Skipped
Run URL: ${RUN_URL}
Best regards,
Your Automation Team
",
+ "subject": "${ACCELERATOR_NAME} Pipeline - Test Automation Failed (Existing URL)"
}
EOF
)
- curl -X POST "${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}" \
+ curl -X POST "${LOGICAPP_URL}" \
-H "Content-Type: application/json" \
-d "$EMAIL_BODY" || echo "Failed to send existing URL test failure notification"
From 5781e126bdc98cebb5f6c1925b0bbe19125f7536 Mon Sep 17 00:00:00 2001
From: Vamshi-Microsoft
Date: Fri, 9 Jan 2026 11:56:16 +0530
Subject: [PATCH 02/10] Add Permissions
---
.github/workflows/build-docker-image.yml | 4 ++++
.github/workflows/deploy-linux.yml | 4 +++-
.github/workflows/deploy-orchestrator.yml | 4 +++-
.github/workflows/deploy-windows.yml | 4 +++-
.github/workflows/deploy.yml | 4 +++-
.github/workflows/job-cleanup-deployment.yml | 4 +++-
.github/workflows/job-deploy-linux.yml | 4 +++-
.github/workflows/job-deploy-windows.yml | 4 +++-
.github/workflows/job-deploy.yml | 4 +++-
.github/workflows/job-docker-build.yml | 4 +++-
.github/workflows/job-send-notification.yml | 4 +++-
.github/workflows/pylint.yml | 4 +++-
.github/workflows/test-automation-v2.yml | 4 +++-
.github/workflows/test-automation.yml | 4 +++-
.github/workflows/test.yml | 4 +++-
15 files changed, 46 insertions(+), 14 deletions(-)
diff --git a/.github/workflows/build-docker-image.yml b/.github/workflows/build-docker-image.yml
index edeabddb..eef429e6 100644
--- a/.github/workflows/build-docker-image.yml
+++ b/.github/workflows/build-docker-image.yml
@@ -45,6 +45,10 @@ on:
- '.github/workflows/build-docker-image.yml'
workflow_dispatch:
+permissions:
+ contents: read
+ actions: read
+
jobs:
build-and-push:
runs-on: ubuntu-latest
diff --git a/.github/workflows/deploy-linux.yml b/.github/workflows/deploy-linux.yml
index e863b2e5..60c025a2 100644
--- a/.github/workflows/deploy-linux.yml
+++ b/.github/workflows/deploy-linux.yml
@@ -92,7 +92,9 @@ on:
schedule:
- cron: '0 9,21 * * *' # Runs at 9:00 AM and 9:00 PM GMT
-
+permissions:
+ contents: read
+ actions: read
jobs:
Run:
uses: ./.github/workflows/deploy-orchestrator.yml
diff --git a/.github/workflows/deploy-orchestrator.yml b/.github/workflows/deploy-orchestrator.yml
index a86d1116..6eca9baa 100644
--- a/.github/workflows/deploy-orchestrator.yml
+++ b/.github/workflows/deploy-orchestrator.yml
@@ -64,7 +64,9 @@ on:
env:
AZURE_DEV_COLLECT_TELEMETRY: ${{ vars.AZURE_DEV_COLLECT_TELEMETRY }}
-
+permissions:
+ contents: read
+ actions: read
jobs:
docker-build:
uses: ./.github/workflows/job-docker-build.yml
diff --git a/.github/workflows/deploy-windows.yml b/.github/workflows/deploy-windows.yml
index 6fdc223b..7c4d9d8a 100644
--- a/.github/workflows/deploy-windows.yml
+++ b/.github/workflows/deploy-windows.yml
@@ -75,7 +75,9 @@ on:
# schedule:
# - cron: '0 9,21 * * *' # Runs at 9:00 AM and 9:00 PM GMT
-
+permissions:
+ contents: read
+ actions: read
jobs:
Run:
uses: ./.github/workflows/deploy-orchestrator.yml
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index aa5d63d0..200c35e4 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -14,7 +14,9 @@ on:
schedule:
- cron: "0 9,21 * * *" # Runs at 9:00 AM and 9:00 PM GMT
workflow_dispatch:
-
+permissions:
+ contents: read
+ actions: read
jobs:
deploy:
runs-on: ubuntu-latest
diff --git a/.github/workflows/job-cleanup-deployment.yml b/.github/workflows/job-cleanup-deployment.yml
index a53cc82f..f4df28f5 100644
--- a/.github/workflows/job-cleanup-deployment.yml
+++ b/.github/workflows/job-cleanup-deployment.yml
@@ -40,7 +40,9 @@ on:
description: 'Docker Image Tag'
required: true
type: string
-
+permissions:
+ contents: read
+ actions: read
jobs:
cleanup-deployment:
runs-on: ${{ inputs.runner_os }}
diff --git a/.github/workflows/job-deploy-linux.yml b/.github/workflows/job-deploy-linux.yml
index d78963b0..791af146 100644
--- a/.github/workflows/job-deploy-linux.yml
+++ b/.github/workflows/job-deploy-linux.yml
@@ -38,7 +38,9 @@ on:
CONTAINER_WEB_APPURL:
description: "Container Web App URL"
value: ${{ jobs.deploy-linux.outputs.CONTAINER_WEB_APPURL }}
-
+permissions:
+ contents: read
+ actions: read
jobs:
deploy-linux:
runs-on: ubuntu-latest
diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml
index 660e7369..3573c8f3 100644
--- a/.github/workflows/job-deploy-windows.yml
+++ b/.github/workflows/job-deploy-windows.yml
@@ -38,7 +38,9 @@ on:
CONTAINER_WEB_APPURL:
description: "Container Web App URL"
value: ${{ jobs.deploy-windows.outputs.CONTAINER_WEB_APPURL }}
-
+permissions:
+ contents: read
+ actions: read
jobs:
deploy-windows:
runs-on: windows-latest
diff --git a/.github/workflows/job-deploy.yml b/.github/workflows/job-deploy.yml
index e1642c42..6af0cb1a 100644
--- a/.github/workflows/job-deploy.yml
+++ b/.github/workflows/job-deploy.yml
@@ -97,7 +97,9 @@ env:
CLEANUP_RESOURCES: ${{ inputs.trigger_type != 'workflow_dispatch' || inputs.cleanup_resources }}
RUN_E2E_TESTS: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.run_e2e_tests || 'GoldenPath-Testing') || 'GoldenPath-Testing' }}
BUILD_DOCKER_IMAGE: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.build_docker_image || false) || false }}
-
+permissions:
+ contents: read
+ actions: read
jobs:
azure-setup:
name: Azure Setup
diff --git a/.github/workflows/job-docker-build.yml b/.github/workflows/job-docker-build.yml
index 316b65e3..185ac7e8 100644
--- a/.github/workflows/job-docker-build.yml
+++ b/.github/workflows/job-docker-build.yml
@@ -19,7 +19,9 @@ on:
env:
BRANCH_NAME: ${{ github.event.workflow_run.head_branch || github.head_ref || github.ref_name }}
-
+permissions:
+ contents: read
+ actions: read
jobs:
docker-build:
if: inputs.trigger_type == 'workflow_dispatch' && inputs.build_docker_image == true
diff --git a/.github/workflows/job-send-notification.yml b/.github/workflows/job-send-notification.yml
index 0dd920c0..ff8e3f13 100644
--- a/.github/workflows/job-send-notification.yml
+++ b/.github/workflows/job-send-notification.yml
@@ -67,7 +67,9 @@ env:
WAF_ENABLED: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.waf_enabled || false) || false }}
EXP: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.EXP || false) || false }}
RUN_E2E_TESTS: ${{ inputs.trigger_type == 'workflow_dispatch' && (inputs.run_e2e_tests || 'GoldenPath-Testing') || 'GoldenPath-Testing' }}
-
+permissions:
+ contents: read
+ actions: read
jobs:
send-notification:
runs-on: ubuntu-latest
diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml
index 0411a85c..638fda67 100644
--- a/.github/workflows/pylint.yml
+++ b/.github/workflows/pylint.yml
@@ -9,7 +9,9 @@ on:
- 'src/**/requirements.txt'
- 'src/**/pyproject.toml'
- '.github/workflows/pylint.yml'
-
+permissions:
+ contents: read
+ actions: read
jobs:
build:
runs-on: ubuntu-latest
diff --git a/.github/workflows/test-automation-v2.yml b/.github/workflows/test-automation-v2.yml
index e0a33d02..4ec41a0b 100644
--- a/.github/workflows/test-automation-v2.yml
+++ b/.github/workflows/test-automation-v2.yml
@@ -24,7 +24,9 @@ env:
url: ${{ inputs.CP_WEB_URL }}
accelerator_name: "Content Processing"
test_suite: ${{ inputs.TEST_SUITE }}
-
+permissions:
+ contents: read
+ actions: read
jobs:
test:
runs-on: ubuntu-latest
diff --git a/.github/workflows/test-automation.yml b/.github/workflows/test-automation.yml
index 1790e625..1112a225 100644
--- a/.github/workflows/test-automation.yml
+++ b/.github/workflows/test-automation.yml
@@ -14,7 +14,9 @@ env:
url: ${{ inputs.CP_WEB_URL }}
CP_RG: ${{ inputs.CP_RG }}
accelerator_name: "Content Processing"
-
+permissions:
+ contents: read
+ actions: read
jobs:
test:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 390db316..dd375649 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -32,7 +32,9 @@ on:
- 'src/**/pytest.ini'
- 'src/**/conftest.py'
- '.github/workflows/test.yml'
-
+permissions:
+ contents: read
+ actions: read
jobs:
backend_tests:
runs-on: ubuntu-latest
From 2e15a189917711852acbecd2cfaad9a7c308a2ac Mon Sep 17 00:00:00 2001
From: Vamshi-Microsoft
Date: Fri, 9 Jan 2026 12:01:35 +0530
Subject: [PATCH 03/10] Remove export command
---
.github/workflows/deploy.yml | 23 +++++++++++------------
.github/workflows/job-deploy-linux.yml | 8 ++++----
.github/workflows/job-deploy-windows.yml | 1 -
.github/workflows/job-deploy.yml | 15 +++++++--------
4 files changed, 22 insertions(+), 25 deletions(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 200c35e4..c3254f14 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -47,14 +47,14 @@ jobs:
- name: Run Quota Check
id: quota-check
+ env:
+ AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
+ AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
+ AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
+ AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
+ GPT_MIN_CAPACITY: "100"
+ AZURE_REGIONS: ${{ vars.AZURE_REGIONS }}
run: |
- export AZURE_CLIENT_ID=${{ secrets.AZURE_CLIENT_ID }}
- export AZURE_TENANT_ID=${{ secrets.AZURE_TENANT_ID }}
- export AZURE_CLIENT_SECRET=${{ secrets.AZURE_CLIENT_SECRET }}
- export AZURE_SUBSCRIPTION_ID="${{ secrets.AZURE_SUBSCRIPTION_ID }}"
- export GPT_MIN_CAPACITY="100"
- export AZURE_REGIONS="${{ vars.AZURE_REGIONS }}"
-
chmod +x infra/scripts/checkquota.sh
if ! infra/scripts/checkquota.sh; then
# If quota check fails due to insufficient quota, set the flag
@@ -171,18 +171,17 @@ jobs:
echo "â
Deployment succeeded."
echo "$DEPLOY_OUTPUT"
- # Export variables only after successful deploy
- export CONTAINER_API_APPURL=$(echo "$DEPLOY_OUTPUT" | jq -r '.containeR_API_APP_FQDN.value')
+ CONTAINER_API_APPURL=$(echo "$DEPLOY_OUTPUT" | jq -r '.containeR_API_APP_FQDN.value')
echo "CONTAINER_API_APPURL=$CONTAINER_API_APPURL" >> $GITHUB_ENV
- export CONTAINER_API_APPNAME=$(echo "$DEPLOY_OUTPUT" | jq -r '.containeR_API_APP_NAME.value')
+ CONTAINER_API_APPNAME=$(echo "$DEPLOY_OUTPUT" | jq -r '.containeR_API_APP_NAME.value')
echo "CONTAINER_API_APPNAME=$CONTAINER_API_APPNAME" >> $GITHUB_ENV
- export CONTAINER_WEB_APPURL="https://$(echo "$DEPLOY_OUTPUT" | jq -r '.containeR_WEB_APP_FQDN.value')"
+ CONTAINER_WEB_APPURL="https://$(echo "$DEPLOY_OUTPUT" | jq -r '.containeR_WEB_APP_FQDN.value')"
echo "CONTAINER_WEB_APPURL=$CONTAINER_WEB_APPURL" >> $GITHUB_ENV
echo "CONTAINER_WEB_APPURL=$CONTAINER_WEB_APPURL" >> $GITHUB_OUTPUT
- export CONTAINER_WEB_APPNAME=$(echo "$DEPLOY_OUTPUT" | jq -r '.containeR_WEB_APP_NAME.value')
+ CONTAINER_WEB_APPNAME=$(echo "$DEPLOY_OUTPUT" | jq -r '.containeR_WEB_APP_NAME.value')
echo "CONTAINER_WEB_APPNAME=$CONTAINER_WEB_APPNAME" >> $GITHUB_ENV
- name: Register schemas
diff --git a/.github/workflows/job-deploy-linux.yml b/.github/workflows/job-deploy-linux.yml
index 791af146..569205d6 100644
--- a/.github/workflows/job-deploy-linux.yml
+++ b/.github/workflows/job-deploy-linux.yml
@@ -301,17 +301,17 @@ jobs:
exit 1
fi
- export CONTAINER_API_APPURL="https://$(echo "$DEPLOY_OUTPUT" | jq -r '.CONTAINER_API_APP_FQDN // empty')"
+ CONTAINER_API_APPURL="https://$(echo "$DEPLOY_OUTPUT" | jq -r '.CONTAINER_API_APP_FQDN // empty')"
echo "CONTAINER_API_APPURL=$CONTAINER_API_APPURL" >> $GITHUB_ENV
- export CONTAINER_API_APPNAME=$(echo "$DEPLOY_OUTPUT" | jq -r '.CONTAINER_API_APP_NAME // empty')
+ CONTAINER_API_APPNAME=$(echo "$DEPLOY_OUTPUT" | jq -r '.CONTAINER_API_APP_NAME // empty')
echo "CONTAINER_API_APPNAME=$CONTAINER_API_APPNAME" >> $GITHUB_ENV
- export CONTAINER_WEB_APPURL="https://$(echo "$DEPLOY_OUTPUT" | jq -r '.CONTAINER_WEB_APP_FQDN // empty')"
+ CONTAINER_WEB_APPURL="https://$(echo "$DEPLOY_OUTPUT" | jq -r '.CONTAINER_WEB_APP_FQDN // empty')"
echo "CONTAINER_WEB_APPURL=$CONTAINER_WEB_APPURL" >> $GITHUB_ENV
echo "CONTAINER_WEB_APPURL=$CONTAINER_WEB_APPURL" >> $GITHUB_OUTPUT
- export CONTAINER_WEB_APPNAME=$(echo "$DEPLOY_OUTPUT" | jq -r '.CONTAINER_WEB_APP_NAME // empty')
+ CONTAINER_WEB_APPNAME=$(echo "$DEPLOY_OUTPUT" | jq -r '.CONTAINER_WEB_APP_NAME // empty')
echo "CONTAINER_WEB_APPNAME=$CONTAINER_WEB_APPNAME" >> $GITHUB_ENV
- name: Register schemas (Linux)
diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml
index 3573c8f3..abf62d65 100644
--- a/.github/workflows/job-deploy-windows.yml
+++ b/.github/workflows/job-deploy-windows.yml
@@ -291,7 +291,6 @@ jobs:
exit 1
}
- # Export variables only after successful deploy
$CONTAINER_API_APPURL = "https://$($DEPLOY_OUTPUT.CONTAINER_API_APP_FQDN)"
"CONTAINER_API_APPURL=$CONTAINER_API_APPURL" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
diff --git a/.github/workflows/job-deploy.yml b/.github/workflows/job-deploy.yml
index 6af0cb1a..f5b29d1c 100644
--- a/.github/workflows/job-deploy.yml
+++ b/.github/workflows/job-deploy.yml
@@ -317,15 +317,14 @@ jobs:
- name: Run Quota Check
id: quota-check
- shell: bash
+ env:
+ AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
+ AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
+ AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
+ AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
+ GPT_MIN_CAPACITY: ${{ env.GPT_MIN_CAPACITY }}
+ AZURE_REGIONS: ${{ vars.AZURE_REGIONS }}
run: |
- export AZURE_CLIENT_ID=${{ secrets.AZURE_CLIENT_ID }}
- export AZURE_TENANT_ID=${{ secrets.AZURE_TENANT_ID }}
- export AZURE_CLIENT_SECRET=${{ secrets.AZURE_CLIENT_SECRET }}
- export AZURE_SUBSCRIPTION_ID="${{ secrets.AZURE_SUBSCRIPTION_ID }}"
- export GPT_MIN_CAPACITY=${{ env.GPT_MIN_CAPACITY }}
- export AZURE_REGIONS="${{ vars.AZURE_REGIONS }}"
-
chmod +x infra/scripts/checkquota.sh
if ! infra/scripts/checkquota.sh; then
if grep -q "No region with sufficient quota found" infra/scripts/checkquota.sh; then
From cb82ae07cf20a98996b9027542e32def37e00c51 Mon Sep 17 00:00:00 2001
From: Vamshi-Microsoft
Date: Fri, 9 Jan 2026 12:07:36 +0530
Subject: [PATCH 04/10] refactor: remove Curl Azure CLI setup steps and replace
with Azure setup actions
---
.github/workflows/deploy.yml | 12 +-----------
.github/workflows/job-cleanup-deployment.yml | 8 --------
.github/workflows/job-deploy-linux.yml | 16 ++--------------
3 files changed, 3 insertions(+), 33 deletions(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index c3254f14..0a6db726 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -35,10 +35,6 @@ jobs:
- name: Checkout Code
uses: actions/checkout@v5
- - name: Setup Azure CLI
- run: |
- curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
- az --version # Verify installation
- name: Login to Azure
run: |
@@ -141,10 +137,7 @@ jobs:
run: |
set -e
echo "Fetching deployment output..."
-
- # Install azd (Azure Developer CLI)
- curl -fsSL https://aka.ms/install-azd.sh | bash
-
+
# Generate current timestamp in desired format: YYYY-MM-DDTHH:MM:SS.SSSSSSSZ
current_date=$(date -u +"%Y-%m-%dT%H:%M:%S.%7NZ")
@@ -304,9 +297,6 @@ jobs:
AZURE_LOCATION: ${{ needs.deploy.outputs.AZURE_LOCATION }}
ENVIRONMENT_NAME: ${{ needs.deploy.outputs.ENVIRONMENT_NAME }}
steps:
- - name: Setup Azure CLI
- run: curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
-
- name: Login to Azure
run: |
az login --service-principal -u ${{ secrets.AZURE_CLIENT_ID }} -p ${{ secrets.AZURE_CLIENT_SECRET }} --tenant ${{ secrets.AZURE_TENANT_ID }}
diff --git a/.github/workflows/job-cleanup-deployment.yml b/.github/workflows/job-cleanup-deployment.yml
index f4df28f5..0467b9e0 100644
--- a/.github/workflows/job-cleanup-deployment.yml
+++ b/.github/workflows/job-cleanup-deployment.yml
@@ -199,14 +199,6 @@ jobs:
echo ""
echo "â
All input parameters validated successfully!"
-
- - name: Setup Azure CLI
- shell: bash
- run: |
- if [[ "${{ runner.os }}" == "Linux" ]]; then
- curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
- fi
- az --version
- name: Login to Azure
shell: bash
diff --git a/.github/workflows/job-deploy-linux.yml b/.github/workflows/job-deploy-linux.yml
index 569205d6..c8a291b3 100644
--- a/.github/workflows/job-deploy-linux.yml
+++ b/.github/workflows/job-deploy-linux.yml
@@ -197,17 +197,8 @@ jobs:
echo "đ§ Configuring Non-WAF deployment - using default main.parameters.json..."
fi
- - name: Setup Azure CLI
- shell: bash
- run: |
- curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
-
- - name: Setup Azure Developer CLI (Linux)
- if: runner.os == 'Linux'
- shell: bash
- run: |
- curl -fsSL https://aka.ms/install-azd.sh | sudo bash
- azd version
+ - name: Install azd
+ uses: Azure/setup-azd@v2
- name: Login to AZD
id: login-azure
@@ -235,9 +226,6 @@ jobs:
echo "Starting azd deployment..."
echo "EXP: $EXP"
echo "Using Docker Image Tag: $IMAGE_TAG"
-
- # Install azd (Azure Developer CLI)
- curl -fsSL https://aka.ms/install-azd.sh | bash
# Generate current timestamp in desired format: YYYY-MM-DDTHH:MM:SS.SSSSSSSZ
current_date=$(date -u +"%Y-%m-%dT%H:%M:%S.%7NZ")
From 08615de820e20bc84c735638c4519f8c4ba4e70c Mon Sep 17 00:00:00 2001
From: Vamshi-Microsoft
Date: Tue, 13 Jan 2026 14:55:49 +0530
Subject: [PATCH 05/10] ci: fixed Pipeline failures
---
.github/workflows/deploy-linux.yml | 188 ++++++++++++++++++--
.github/workflows/deploy-windows.yml | 188 ++++++++++++++++++--
.github/workflows/job-deploy-linux.yml | 4 +-
.github/workflows/job-deploy-windows.yml | 4 +-
.github/workflows/job-deploy.yml | 47 ++---
.github/workflows/job-send-notification.yml | 6 +-
6 files changed, 390 insertions(+), 47 deletions(-)
diff --git a/.github/workflows/deploy-linux.yml b/.github/workflows/deploy-linux.yml
index 60c025a2..d65a3c16 100644
--- a/.github/workflows/deploy-linux.yml
+++ b/.github/workflows/deploy-linux.yml
@@ -96,19 +96,187 @@ permissions:
contents: read
actions: read
jobs:
+ validate-inputs:
+ runs-on: ubuntu-latest
+ outputs:
+ validation_passed: ${{ steps.validate.outputs.passed }}
+ azure_location: ${{ steps.validate.outputs.azure_location }}
+ resource_group_name: ${{ steps.validate.outputs.resource_group_name }}
+ waf_enabled: ${{ steps.validate.outputs.waf_enabled }}
+ exp: ${{ steps.validate.outputs.exp }}
+ build_docker_image: ${{ steps.validate.outputs.build_docker_image }}
+ cleanup_resources: ${{ steps.validate.outputs.cleanup_resources }}
+ run_e2e_tests: ${{ steps.validate.outputs.run_e2e_tests }}
+ azure_env_log_analytics_workspace_id: ${{ steps.validate.outputs.azure_env_log_analytics_workspace_id }}
+ azure_existing_ai_project_resource_id: ${{ steps.validate.outputs.azure_existing_ai_project_resource_id }}
+ existing_webapp_url: ${{ steps.validate.outputs.existing_webapp_url }}
+ steps:
+ - name: Validate Workflow Input Parameters
+ id: validate
+ shell: bash
+ env:
+ INPUT_AZURE_LOCATION: ${{ github.event.inputs.azure_location }}
+ INPUT_RESOURCE_GROUP_NAME: ${{ github.event.inputs.resource_group_name }}
+ INPUT_WAF_ENABLED: ${{ github.event.inputs.waf_enabled }}
+ INPUT_EXP: ${{ github.event.inputs.EXP }}
+ INPUT_BUILD_DOCKER_IMAGE: ${{ github.event.inputs.build_docker_image }}
+ INPUT_CLEANUP_RESOURCES: ${{ github.event.inputs.cleanup_resources }}
+ INPUT_RUN_E2E_TESTS: ${{ github.event.inputs.run_e2e_tests }}
+ INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ github.event.inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}
+ INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ github.event.inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}
+ INPUT_EXISTING_WEBAPP_URL: ${{ github.event.inputs.existing_webapp_url }}
+ run: |
+ echo "đ Validating workflow input parameters..."
+ VALIDATION_FAILED=false
+
+ # Validate azure_location (Azure region format)
+ LOCATION="${INPUT_AZURE_LOCATION:-australiaeast}"
+
+ if [[ ! "$LOCATION" =~ ^[a-z0-9]+$ ]]; then
+ echo "â ERROR: azure_location '$LOCATION' is invalid. Must contain only lowercase letters and numbers"
+ VALIDATION_FAILED=true
+ else
+ echo "â
azure_location: '$LOCATION' is valid"
+ fi
+
+ # Validate resource_group_name (Azure naming convention, optional)
+ if [[ -n "$INPUT_RESOURCE_GROUP_NAME" ]]; then
+ if [[ ! "$INPUT_RESOURCE_GROUP_NAME" =~ ^[a-zA-Z0-9._\(\)-]+$ ]] || [[ "$INPUT_RESOURCE_GROUP_NAME" =~ \.$ ]]; then
+ echo "â ERROR: resource_group_name '$INPUT_RESOURCE_GROUP_NAME' is invalid. Must contain only alphanumerics, periods, underscores, hyphens, and parentheses. Cannot end with period."
+ VALIDATION_FAILED=true
+ elif [[ ${#INPUT_RESOURCE_GROUP_NAME} -gt 90 ]]; then
+ echo "â ERROR: resource_group_name '$INPUT_RESOURCE_GROUP_NAME' exceeds 90 characters (length: ${#INPUT_RESOURCE_GROUP_NAME})"
+ VALIDATION_FAILED=true
+ else
+ echo "â
resource_group_name: '$INPUT_RESOURCE_GROUP_NAME' is valid"
+ fi
+ else
+ echo "â
resource_group_name: Not provided (will be auto-generated)"
+ fi
+
+ # Validate waf_enabled (boolean)
+ WAF_ENABLED="${INPUT_WAF_ENABLED:-false}"
+ if [[ "$WAF_ENABLED" != "true" && "$WAF_ENABLED" != "false" ]]; then
+ echo "â ERROR: waf_enabled must be 'true' or 'false', got: '$WAF_ENABLED'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
waf_enabled: '$WAF_ENABLED' is valid"
+ fi
+
+ # Validate EXP (boolean)
+ EXP_ENABLED="${INPUT_EXP:-false}"
+ if [[ "$EXP_ENABLED" != "true" && "$EXP_ENABLED" != "false" ]]; then
+ echo "â ERROR: EXP must be 'true' or 'false', got: '$EXP_ENABLED'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
EXP: '$EXP_ENABLED' is valid"
+ fi
+
+ # Validate build_docker_image (boolean)
+ BUILD_DOCKER="${INPUT_BUILD_DOCKER_IMAGE:-false}"
+ if [[ "$BUILD_DOCKER" != "true" && "$BUILD_DOCKER" != "false" ]]; then
+ echo "â ERROR: build_docker_image must be 'true' or 'false', got: '$BUILD_DOCKER'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
build_docker_image: '$BUILD_DOCKER' is valid"
+ fi
+
+ # Validate cleanup_resources (boolean)
+ CLEANUP_RESOURCES="${INPUT_CLEANUP_RESOURCES:-false}"
+ if [[ "$CLEANUP_RESOURCES" != "true" && "$CLEANUP_RESOURCES" != "false" ]]; then
+ echo "â ERROR: cleanup_resources must be 'true' or 'false', got: '$CLEANUP_RESOURCES'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
cleanup_resources: '$CLEANUP_RESOURCES' is valid"
+ fi
+
+ # Validate run_e2e_tests (specific allowed values)
+ TEST_OPTION="${INPUT_RUN_E2E_TESTS:-GoldenPath-Testing}"
+ if [[ "$TEST_OPTION" != "GoldenPath-Testing" && "$TEST_OPTION" != "Smoke-Testing" && "$TEST_OPTION" != "None" ]]; then
+ echo "â ERROR: run_e2e_tests must be one of: GoldenPath-Testing, Smoke-Testing, None, got: '$TEST_OPTION'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
run_e2e_tests: '$TEST_OPTION' is valid"
+ fi
+
+ # Validate AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID (optional, Azure Resource ID format)
+ if [[ -n "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" ]]; then
+ if [[ ! "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/[Rr]esource[Gg]roups/[^/]+/providers/[Mm]icrosoft\.[Oo]perational[Ii]nsights/[Ww]orkspaces/[^/]+$ ]]; then
+ echo "â ERROR: AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID is invalid. Must be a valid Azure Resource ID format:"
+ echo " /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.OperationalInsights/workspaces/{workspaceName}"
+ echo " Got: '$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: Valid Resource ID format"
+ fi
+ else
+ echo "â
AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: Not provided (optional)"
+ fi
+
+ # Validate AZURE_EXISTING_AI_PROJECT_RESOURCE_ID (optional, Azure Resource ID format)
+ if [[ -n "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" ]]; then
+ if [[ ! "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/[Rr]esource[Gg]roups/[^/]+/providers/([Mm]icrosoft\.[Mm]achine[Ll]earning[Ss]ervices/([Ww]orkspaces|[Pp]rojects)/[^/]+|[Mm]icrosoft\.[Cc]ognitive[Ss]ervices/[Aa]ccounts/[^/]+/[Pp]rojects/[^/]+)$ ]]; then
+ echo "â ERROR: AZURE_EXISTING_AI_PROJECT_RESOURCE_ID is invalid. Must be a valid Azure Resource ID format:"
+ echo " /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.CognitiveServices/accounts/{accountName}/projects/{projectName}"
+ echo " Got: '$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: Valid Resource ID format"
+ fi
+ else
+ echo "â
AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: Not provided (optional)"
+ fi
+
+ # Validate existing_webapp_url (optional, must start with https)
+ if [[ -n "$INPUT_EXISTING_WEBAPP_URL" ]]; then
+ if [[ ! "$INPUT_EXISTING_WEBAPP_URL" =~ ^https:// ]]; then
+ echo "â ERROR: existing_webapp_url must start with 'https://', got: '$INPUT_EXISTING_WEBAPP_URL'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
existing_webapp_url: '$INPUT_EXISTING_WEBAPP_URL' is valid"
+ fi
+ else
+ echo "â
existing_webapp_url: Not provided (will perform deployment)"
+ fi
+
+ # Fail workflow if any validation failed
+ if [[ "$VALIDATION_FAILED" == "true" ]]; then
+ echo ""
+ echo "â Parameter validation failed. Please correct the errors above and try again."
+ exit 1
+ fi
+
+ echo ""
+ echo "â
All input parameters validated successfully!"
+
+ # Output validated values
+ echo "passed=true" >> $GITHUB_OUTPUT
+ echo "azure_location=$LOCATION" >> $GITHUB_OUTPUT
+ echo "resource_group_name=$INPUT_RESOURCE_GROUP_NAME" >> $GITHUB_OUTPUT
+ echo "waf_enabled=$WAF_ENABLED" >> $GITHUB_OUTPUT
+ echo "exp=$EXP_ENABLED" >> $GITHUB_OUTPUT
+ echo "build_docker_image=$BUILD_DOCKER" >> $GITHUB_OUTPUT
+ echo "cleanup_resources=$CLEANUP_RESOURCES" >> $GITHUB_OUTPUT
+ echo "run_e2e_tests=$TEST_OPTION" >> $GITHUB_OUTPUT
+ echo "azure_env_log_analytics_workspace_id=$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" >> $GITHUB_OUTPUT
+ echo "azure_existing_ai_project_resource_id=$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" >> $GITHUB_OUTPUT
+ echo "existing_webapp_url=$INPUT_EXISTING_WEBAPP_URL" >> $GITHUB_OUTPUT
+
Run:
+ needs: validate-inputs
+ if: needs.validate-inputs.outputs.validation_passed == 'true'
uses: ./.github/workflows/deploy-orchestrator.yml
with:
runner_os: ubuntu-latest
- azure_location: ${{ github.event.inputs.azure_location || 'australiaeast' }}
- resource_group_name: ${{ github.event.inputs.resource_group_name || '' }}
- waf_enabled: ${{ github.event.inputs.waf_enabled == 'true' }}
- EXP: ${{ github.event.inputs.EXP == 'true' }}
- build_docker_image: ${{ github.event.inputs.build_docker_image == 'true' }}
- cleanup_resources: ${{ github.event.inputs.cleanup_resources == 'true' }}
- run_e2e_tests: ${{ github.event.inputs.run_e2e_tests || 'GoldenPath-Testing' }}
- AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ github.event.inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID || '' }}
- AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ github.event.inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID || '' }}
- existing_webapp_url: ${{ github.event.inputs.existing_webapp_url || '' }}
+ azure_location: ${{ needs.validate-inputs.outputs.azure_location || 'australiaeast' }}
+ resource_group_name: ${{ needs.validate-inputs.outputs.resource_group_name || '' }}
+ waf_enabled: ${{ needs.validate-inputs.outputs.waf_enabled == 'true' }}
+ EXP: ${{ needs.validate-inputs.outputs.exp == 'true' }}
+ build_docker_image: ${{ needs.validate-inputs.outputs.build_docker_image == 'true' }}
+ cleanup_resources: ${{ needs.validate-inputs.outputs.cleanup_resources == 'true' }}
+ run_e2e_tests: ${{ needs.validate-inputs.outputs.run_e2e_tests || 'GoldenPath-Testing' }}
+ AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ needs.validate-inputs.outputs.azure_env_log_analytics_workspace_id || '' }}
+ AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ needs.validate-inputs.outputs.azure_existing_ai_project_resource_id || '' }}
+ existing_webapp_url: ${{ needs.validate-inputs.outputs.existing_webapp_url || '' }}
trigger_type: ${{ github.event_name }}
secrets: inherit
diff --git a/.github/workflows/deploy-windows.yml b/.github/workflows/deploy-windows.yml
index 7c4d9d8a..491cb1a7 100644
--- a/.github/workflows/deploy-windows.yml
+++ b/.github/workflows/deploy-windows.yml
@@ -79,19 +79,187 @@ permissions:
contents: read
actions: read
jobs:
+ validate-inputs:
+ runs-on: ubuntu-latest
+ outputs:
+ validation_passed: ${{ steps.validate.outputs.passed }}
+ azure_location: ${{ steps.validate.outputs.azure_location }}
+ resource_group_name: ${{ steps.validate.outputs.resource_group_name }}
+ waf_enabled: ${{ steps.validate.outputs.waf_enabled }}
+ exp: ${{ steps.validate.outputs.exp }}
+ build_docker_image: ${{ steps.validate.outputs.build_docker_image }}
+ cleanup_resources: ${{ steps.validate.outputs.cleanup_resources }}
+ run_e2e_tests: ${{ steps.validate.outputs.run_e2e_tests }}
+ azure_env_log_analytics_workspace_id: ${{ steps.validate.outputs.azure_env_log_analytics_workspace_id }}
+ azure_existing_ai_project_resource_id: ${{ steps.validate.outputs.azure_existing_ai_project_resource_id }}
+ existing_webapp_url: ${{ steps.validate.outputs.existing_webapp_url }}
+ steps:
+ - name: Validate Workflow Input Parameters
+ id: validate
+ shell: bash
+ env:
+ INPUT_AZURE_LOCATION: ${{ github.event.inputs.azure_location }}
+ INPUT_RESOURCE_GROUP_NAME: ${{ github.event.inputs.resource_group_name }}
+ INPUT_WAF_ENABLED: ${{ github.event.inputs.waf_enabled }}
+ INPUT_EXP: ${{ github.event.inputs.EXP }}
+ INPUT_BUILD_DOCKER_IMAGE: ${{ github.event.inputs.build_docker_image }}
+ INPUT_CLEANUP_RESOURCES: ${{ github.event.inputs.cleanup_resources }}
+ INPUT_RUN_E2E_TESTS: ${{ github.event.inputs.run_e2e_tests }}
+ INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ github.event.inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}
+ INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ github.event.inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}
+ INPUT_EXISTING_WEBAPP_URL: ${{ github.event.inputs.existing_webapp_url }}
+ run: |
+ echo "đ Validating workflow input parameters..."
+ VALIDATION_FAILED=false
+
+ # Validate azure_location (Azure region format)
+ LOCATION="${INPUT_AZURE_LOCATION:-australiaeast}"
+
+ if [[ ! "$LOCATION" =~ ^[a-z0-9]+$ ]]; then
+ echo "â ERROR: azure_location '$LOCATION' is invalid. Must contain only lowercase letters and numbers"
+ VALIDATION_FAILED=true
+ else
+ echo "â
azure_location: '$LOCATION' is valid"
+ fi
+
+ # Validate resource_group_name (Azure naming convention, optional)
+ if [[ -n "$INPUT_RESOURCE_GROUP_NAME" ]]; then
+ if [[ ! "$INPUT_RESOURCE_GROUP_NAME" =~ ^[a-zA-Z0-9._\(\)-]+$ ]] || [[ "$INPUT_RESOURCE_GROUP_NAME" =~ \.$ ]]; then
+ echo "â ERROR: resource_group_name '$INPUT_RESOURCE_GROUP_NAME' is invalid. Must contain only alphanumerics, periods, underscores, hyphens, and parentheses. Cannot end with period."
+ VALIDATION_FAILED=true
+ elif [[ ${#INPUT_RESOURCE_GROUP_NAME} -gt 90 ]]; then
+ echo "â ERROR: resource_group_name '$INPUT_RESOURCE_GROUP_NAME' exceeds 90 characters (length: ${#INPUT_RESOURCE_GROUP_NAME})"
+ VALIDATION_FAILED=true
+ else
+ echo "â
resource_group_name: '$INPUT_RESOURCE_GROUP_NAME' is valid"
+ fi
+ else
+ echo "â
resource_group_name: Not provided (will be auto-generated)"
+ fi
+
+ # Validate waf_enabled (boolean)
+ WAF_ENABLED="${INPUT_WAF_ENABLED:-false}"
+ if [[ "$WAF_ENABLED" != "true" && "$WAF_ENABLED" != "false" ]]; then
+ echo "â ERROR: waf_enabled must be 'true' or 'false', got: '$WAF_ENABLED'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
waf_enabled: '$WAF_ENABLED' is valid"
+ fi
+
+ # Validate EXP (boolean)
+ EXP_ENABLED="${INPUT_EXP:-false}"
+ if [[ "$EXP_ENABLED" != "true" && "$EXP_ENABLED" != "false" ]]; then
+ echo "â ERROR: EXP must be 'true' or 'false', got: '$EXP_ENABLED'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
EXP: '$EXP_ENABLED' is valid"
+ fi
+
+ # Validate build_docker_image (boolean)
+ BUILD_DOCKER="${INPUT_BUILD_DOCKER_IMAGE:-false}"
+ if [[ "$BUILD_DOCKER" != "true" && "$BUILD_DOCKER" != "false" ]]; then
+ echo "â ERROR: build_docker_image must be 'true' or 'false', got: '$BUILD_DOCKER'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
build_docker_image: '$BUILD_DOCKER' is valid"
+ fi
+
+ # Validate cleanup_resources (boolean)
+ CLEANUP_RESOURCES="${INPUT_CLEANUP_RESOURCES:-false}"
+ if [[ "$CLEANUP_RESOURCES" != "true" && "$CLEANUP_RESOURCES" != "false" ]]; then
+ echo "â ERROR: cleanup_resources must be 'true' or 'false', got: '$CLEANUP_RESOURCES'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
cleanup_resources: '$CLEANUP_RESOURCES' is valid"
+ fi
+
+ # Validate run_e2e_tests (specific allowed values)
+ TEST_OPTION="${INPUT_RUN_E2E_TESTS:-GoldenPath-Testing}"
+ if [[ "$TEST_OPTION" != "GoldenPath-Testing" && "$TEST_OPTION" != "Smoke-Testing" && "$TEST_OPTION" != "None" ]]; then
+ echo "â ERROR: run_e2e_tests must be one of: GoldenPath-Testing, Smoke-Testing, None, got: '$TEST_OPTION'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
run_e2e_tests: '$TEST_OPTION' is valid"
+ fi
+
+ # Validate AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID (optional, Azure Resource ID format)
+ if [[ -n "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" ]]; then
+ if [[ ! "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/[Rr]esource[Gg]roups/[^/]+/providers/[Mm]icrosoft\.[Oo]perational[Ii]nsights/[Ww]orkspaces/[^/]+$ ]]; then
+ echo "â ERROR: AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID is invalid. Must be a valid Azure Resource ID format:"
+ echo " /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.OperationalInsights/workspaces/{workspaceName}"
+ echo " Got: '$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: Valid Resource ID format"
+ fi
+ else
+ echo "â
AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: Not provided (optional)"
+ fi
+
+ # Validate AZURE_EXISTING_AI_PROJECT_RESOURCE_ID (optional, Azure Resource ID format)
+ if [[ -n "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" ]]; then
+ if [[ ! "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/[Rr]esource[Gg]roups/[^/]+/providers/([Mm]icrosoft\.[Mm]achine[Ll]earning[Ss]ervices/([Ww]orkspaces|[Pp]rojects)/[^/]+|[Mm]icrosoft\.[Cc]ognitive[Ss]ervices/[Aa]ccounts/[^/]+/[Pp]rojects/[^/]+)$ ]]; then
+ echo "â ERROR: AZURE_EXISTING_AI_PROJECT_RESOURCE_ID is invalid. Must be a valid Azure Resource ID format:"
+ echo " /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.CognitiveServices/accounts/{accountName}/projects/{projectName}"
+ echo " Got: '$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: Valid Resource ID format"
+ fi
+ else
+ echo "â
AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: Not provided (optional)"
+ fi
+
+ # Validate existing_webapp_url (optional, must start with https)
+ if [[ -n "$INPUT_EXISTING_WEBAPP_URL" ]]; then
+ if [[ ! "$INPUT_EXISTING_WEBAPP_URL" =~ ^https:// ]]; then
+ echo "â ERROR: existing_webapp_url must start with 'https://', got: '$INPUT_EXISTING_WEBAPP_URL'"
+ VALIDATION_FAILED=true
+ else
+ echo "â
existing_webapp_url: '$INPUT_EXISTING_WEBAPP_URL' is valid"
+ fi
+ else
+ echo "â
existing_webapp_url: Not provided (will perform deployment)"
+ fi
+
+ # Fail workflow if any validation failed
+ if [[ "$VALIDATION_FAILED" == "true" ]]; then
+ echo ""
+ echo "â Parameter validation failed. Please correct the errors above and try again."
+ exit 1
+ fi
+
+ echo ""
+ echo "â
All input parameters validated successfully!"
+
+ # Output validated values
+ echo "passed=true" >> $GITHUB_OUTPUT
+ echo "azure_location=$LOCATION" >> $GITHUB_OUTPUT
+ echo "resource_group_name=$INPUT_RESOURCE_GROUP_NAME" >> $GITHUB_OUTPUT
+ echo "waf_enabled=$WAF_ENABLED" >> $GITHUB_OUTPUT
+ echo "exp=$EXP_ENABLED" >> $GITHUB_OUTPUT
+ echo "build_docker_image=$BUILD_DOCKER" >> $GITHUB_OUTPUT
+ echo "cleanup_resources=$CLEANUP_RESOURCES" >> $GITHUB_OUTPUT
+ echo "run_e2e_tests=$TEST_OPTION" >> $GITHUB_OUTPUT
+ echo "azure_env_log_analytics_workspace_id=$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" >> $GITHUB_OUTPUT
+ echo "azure_existing_ai_project_resource_id=$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" >> $GITHUB_OUTPUT
+ echo "existing_webapp_url=$INPUT_EXISTING_WEBAPP_URL" >> $GITHUB_OUTPUT
+
Run:
+ needs: validate-inputs
+ if: needs.validate-inputs.outputs.validation_passed == 'true'
uses: ./.github/workflows/deploy-orchestrator.yml
with:
runner_os: windows-latest
- azure_location: ${{ github.event.inputs.azure_location || 'australiaeast' }}
- resource_group_name: ${{ github.event.inputs.resource_group_name || '' }}
- waf_enabled: ${{ github.event.inputs.waf_enabled == 'true' }}
- EXP: ${{ github.event.inputs.EXP == 'true' }}
- build_docker_image: ${{ github.event.inputs.build_docker_image == 'true' }}
- cleanup_resources: ${{ github.event.inputs.cleanup_resources == 'true' }}
- run_e2e_tests: ${{ github.event.inputs.run_e2e_tests || 'GoldenPath-Testing' }}
- AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ github.event.inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID || '' }}
- AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ github.event.inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID || '' }}
- existing_webapp_url: ${{ github.event.inputs.existing_webapp_url || '' }}
+ azure_location: ${{ needs.validate-inputs.outputs.azure_location || 'australiaeast' }}
+ resource_group_name: ${{ needs.validate-inputs.outputs.resource_group_name || '' }}
+ waf_enabled: ${{ needs.validate-inputs.outputs.waf_enabled == 'true' }}
+ EXP: ${{ needs.validate-inputs.outputs.exp == 'true' }}
+ build_docker_image: ${{ needs.validate-inputs.outputs.build_docker_image == 'true' }}
+ cleanup_resources: ${{ needs.validate-inputs.outputs.cleanup_resources == 'true' }}
+ run_e2e_tests: ${{ needs.validate-inputs.outputs.run_e2e_tests || 'GoldenPath-Testing' }}
+ AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ needs.validate-inputs.outputs.azure_env_log_analytics_workspace_id || '' }}
+ AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ needs.validate-inputs.outputs.azure_existing_ai_project_resource_id || '' }}
+ existing_webapp_url: ${{ needs.validate-inputs.outputs.existing_webapp_url || '' }}
trigger_type: ${{ github.event_name }}
secrets: inherit
diff --git a/.github/workflows/job-deploy-linux.yml b/.github/workflows/job-deploy-linux.yml
index c8a291b3..214cb6c7 100644
--- a/.github/workflows/job-deploy-linux.yml
+++ b/.github/workflows/job-deploy-linux.yml
@@ -150,7 +150,7 @@ jobs:
# Validate AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID (optional, if provided must be valid Resource ID)
if [[ -n "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" ]]; then
- if [[ ! "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/resourceGroups/[^/]+/providers/microsoft\.operationalinsights/workspaces/[^/]+$ ]]; then
+ if [[ ! "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/[Rr]esource[Gg]roups/[^/]+/providers/[Mm]icrosoft\.[Oo]perational[Ii]nsights/[Ww]orkspaces/[^/]+$ ]]; then
echo "â ERROR: AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID is invalid. Must be a valid Azure Resource ID format:"
echo " /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.OperationalInsights/workspaces/{workspaceName}"
echo " Got: '$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID'"
@@ -162,7 +162,7 @@ jobs:
# Validate AZURE_EXISTING_AI_PROJECT_RESOURCE_ID (optional, if provided must be valid Resource ID)
if [[ -n "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" ]]; then
- if [[ ! "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/resourceGroups/[^/]+/providers/(Microsoft\.MachineLearningServices/(workspaces|projects)/[^/]+|Microsoft\.CognitiveServices/accounts/[^/]+/projects/[^/]+)$ ]]; then
+ if [[ ! "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/[Rr]esource[Gg]roups/[^/]+/providers/([Mm]icrosoft\.[Mm]achine[Ll]earning[Ss]ervices/([Ww]orkspaces|[Pp]rojects)/[^/]+|[Mm]icrosoft\.[Cc]ognitive[Ss]ervices/[Aa]ccounts/[^/]+/[Pp]rojects/[^/]+)$ ]]; then
echo "â ERROR: AZURE_EXISTING_AI_PROJECT_RESOURCE_ID is invalid. Must be a valid Azure Resource ID format:"
echo " /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.CognitiveServices/accounts/{accountName}/projects/{projectName}"
echo " Got: '$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID'"
diff --git a/.github/workflows/job-deploy-windows.yml b/.github/workflows/job-deploy-windows.yml
index abf62d65..7b0ce43f 100644
--- a/.github/workflows/job-deploy-windows.yml
+++ b/.github/workflows/job-deploy-windows.yml
@@ -150,7 +150,7 @@ jobs:
# Validate AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID (optional, if provided must be valid Resource ID)
if [[ -n "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" ]]; then
- if [[ ! "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/resourceGroups/[^/]+/providers/microsoft\.operationalinsights/workspaces/[^/]+$ ]]; then
+ if [[ ! "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/[Rr]esource[Gg]roups/[^/]+/providers/[Mm]icrosoft\.[Oo]perational[Ii]nsights/[Ww]orkspaces/[^/]+$ ]]; then
echo "â ERROR: AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID is invalid. Must be a valid Azure Resource ID format:"
echo " /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.OperationalInsights/workspaces/{workspaceName}"
echo " Got: '$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID'"
@@ -162,7 +162,7 @@ jobs:
# Validate AZURE_EXISTING_AI_PROJECT_RESOURCE_ID (optional, if provided must be valid Resource ID)
if [[ -n "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" ]]; then
- if [[ ! "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/resourceGroups/[^/]+/providers/(Microsoft\.MachineLearningServices/(workspaces|projects)/[^/]+|Microsoft\.CognitiveServices/accounts/[^/]+/projects/[^/]+)$ ]]; then
+ if [[ ! "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/[Rr]esource[Gg]roups/[^/]+/providers/([Mm]icrosoft\.[Mm]achine[Ll]earning[Ss]ervices/([Ww]orkspaces|[Pp]rojects)/[^/]+|[Mm]icrosoft\.[Cc]ognitive[Ss]ervices/[Aa]ccounts/[^/]+/[Pp]rojects/[^/]+)$ ]]; then
echo "â ERROR: AZURE_EXISTING_AI_PROJECT_RESOURCE_ID is invalid. Must be a valid Azure Resource ID format:"
echo " /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.CognitiveServices/accounts/{accountName}/projects/{projectName}"
echo " Got: '$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID'"
diff --git a/.github/workflows/job-deploy.yml b/.github/workflows/job-deploy.yml
index f5b29d1c..c30c1390 100644
--- a/.github/workflows/job-deploy.yml
+++ b/.github/workflows/job-deploy.yml
@@ -112,7 +112,7 @@ jobs:
AZURE_ENV_OPENAI_LOCATION: ${{ steps.set_region.outputs.AZURE_ENV_OPENAI_LOCATION }}
IMAGE_TAG: ${{ steps.determine_image_tag.outputs.IMAGE_TAG }}
QUOTA_FAILED: ${{ steps.quota_failure_output.outputs.QUOTA_FAILED }}
-
+ EXP_ENABLED: ${{ steps.configure_exp.outputs.EXP_ENABLED }}
steps:
- name: Validate Workflow Input Parameters
@@ -226,7 +226,7 @@ jobs:
# Validate AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID (Azure Resource ID format)
if [[ -n "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" ]]; then
- if [[ ! "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/resourceGroups/[^/]+/providers/microsoft\.operationalinsights/workspaces/[^/]+$ ]]; then
+ if [[ ! "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/[Rr]esource[Gg]roups/[^/]+/providers/[Mm]icrosoft\.[Oo]perational[Ii]nsights/[Ww]orkspaces/[^/]+$ ]]; then
echo "â ERROR: AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID is invalid. Must be a valid Azure Resource ID format:"
echo " /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.OperationalInsights/workspaces/{workspaceName}"
echo " Got: '$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID'"
@@ -238,7 +238,7 @@ jobs:
# Validate AZURE_EXISTING_AI_PROJECT_RESOURCE_ID (Azure Resource ID format)
if [[ -n "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" ]]; then
- if [[ ! "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/resourceGroups/[^/]+/providers/(Microsoft\.MachineLearningServices/(workspaces|projects)/[^/]+|Microsoft\.CognitiveServices/accounts/[^/]+/projects/[^/]+)$ ]]; then
+ if [[ ! "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/[Rr]esource[Gg]roups/[^/]+/providers/([Mm]icrosoft\.[Mm]achine[Ll]earning[Ss]ervices/([Ww]orkspaces|[Pp]rojects)/[^/]+|[Mm]icrosoft\.[Cc]ognitive[Ss]ervices/[Aa]ccounts/[^/]+/[Pp]rojects/[^/]+)$ ]]; then
echo "â ERROR: AZURE_EXISTING_AI_PROJECT_RESOURCE_ID is invalid. Must be a valid Azure Resource ID format:"
echo " /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.CognitiveServices/accounts/{accountName}/projects/{projectName}"
echo " Got: '$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID'"
@@ -284,28 +284,35 @@ jobs:
echo "â
All input parameters validated successfully!"
- name: Validate and Auto-Configure EXP
+ id: configure_exp
shell: bash
env:
INPUT_EXP: ${{ inputs.EXP }}
- INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}
- INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}
+ INPUT_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}
+ INPUT_AI_PROJECT_RESOURCE_ID: ${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}
run: |
echo "đ Validating EXP configuration..."
- if [[ "$INPUT_EXP" != "true" ]]; then
- if [[ -n "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" ]] || [[ -n "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" ]]; then
- echo "đ§ AUTO-ENABLING EXP: EXP parameter values were provided but EXP was not explicitly enabled."
- echo ""
- echo "You provided values for:"
- [[ -n "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" ]] && echo " - Azure Log Analytics Workspace ID: '$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID'"
- [[ -n "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" ]] && echo " - Azure AI Project Resource ID: '$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID'"
- echo ""
- echo "â
Automatically enabling EXP to use these values."
- echo "EXP=true" >> $GITHUB_ENV
- echo "đ EXP has been automatically enabled for this deployment."
- fi
+ EXP_ENABLED="false"
+
+ if [[ "$INPUT_EXP" == "true" ]]; then
+ EXP_ENABLED="true"
+ echo "â
EXP explicitly enabled by user input"
+ elif [[ -n "$INPUT_LOG_ANALYTICS_WORKSPACE_ID" ]] || [[ -n "$INPUT_AI_PROJECT_RESOURCE_ID" ]]; then
+ echo "đ§ AUTO-ENABLING EXP: EXP parameter values were provided but EXP was not explicitly enabled."
+ echo ""
+ echo "You provided values for:"
+ [[ -n "$INPUT_LOG_ANALYTICS_WORKSPACE_ID" ]] && echo " - Azure Log Analytics Workspace ID: '$INPUT_LOG_ANALYTICS_WORKSPACE_ID'"
+ [[ -n "$INPUT_AI_PROJECT_RESOURCE_ID" ]] && echo " - Azure AI Project Resource ID: '$INPUT_AI_PROJECT_RESOURCE_ID'"
+ echo ""
+ echo "â
Automatically enabling EXP to use these values."
+ EXP_ENABLED="true"
fi
+ echo "EXP_ENABLED=$EXP_ENABLED" >> $GITHUB_ENV
+ echo "EXP_ENABLED=$EXP_ENABLED" >> $GITHUB_OUTPUT
+ echo "Final EXP status: $EXP_ENABLED"
+
- name: Checkout Code
uses: actions/checkout@v4
@@ -482,7 +489,7 @@ jobs:
INPUT_RESOURCE_GROUP_NAME: ${{ inputs.resource_group_name }}
EVENT_NAME: ${{ github.event_name }}
WAF_STATUS: ${{ env.WAF_ENABLED == 'true' && 'â
Yes' || 'â No' }}
- EXP_STATUS: ${{ env.EXP == 'true' && 'â
Yes' || 'â No' }}
+ EXP_STATUS: ${{ steps.configure_exp.outputs.EXP_ENABLED == 'true' && 'â
Yes' || 'â No' }}
CLEANUP_STATUS: ${{ env.CLEANUP_RESOURCES == 'true' && 'â
Yes' || 'â No' }}
BUILD_DOCKER_STATUS: ${{ env.BUILD_DOCKER_IMAGE == 'true' && 'â
Yes' || 'â No' }}
run: |
@@ -529,7 +536,7 @@ jobs:
RESOURCE_GROUP_NAME: ${{ needs.azure-setup.outputs.RESOURCE_GROUP_NAME }}
IMAGE_TAG: ${{ needs.azure-setup.outputs.IMAGE_TAG }}
BUILD_DOCKER_IMAGE: ${{ inputs.build_docker_image || 'false' }}
- EXP: ${{ inputs.EXP || 'false' }}
+ EXP: ${{ needs.azure-setup.outputs.EXP_ENABLED }}
WAF_ENABLED: ${{ inputs.waf_enabled == true && 'true' || 'false' }}
AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}
AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}
@@ -547,7 +554,7 @@ jobs:
RESOURCE_GROUP_NAME: ${{ needs.azure-setup.outputs.RESOURCE_GROUP_NAME }}
IMAGE_TAG: ${{ needs.azure-setup.outputs.IMAGE_TAG }}
BUILD_DOCKER_IMAGE: ${{ inputs.build_docker_image || 'false' }}
- EXP: ${{ inputs.EXP || 'false' }}
+ EXP: ${{ needs.azure-setup.outputs.EXP_ENABLED }}
WAF_ENABLED: ${{ inputs.waf_enabled == true && 'true' || 'false' }}
AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}
AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}
diff --git a/.github/workflows/job-send-notification.yml b/.github/workflows/job-send-notification.yml
index ff8e3f13..2f43ca53 100644
--- a/.github/workflows/job-send-notification.yml
+++ b/.github/workflows/job-send-notification.yml
@@ -195,9 +195,9 @@ jobs:
fi
fi
- # Validate QUOTA_FAILED (must be 'true' or 'false')
- if [[ "$INPUT_QUOTA_FAILED" != "true" && "$INPUT_QUOTA_FAILED" != "false" ]]; then
- echo "â ERROR: QUOTA_FAILED must be 'true' or 'false', got: '$INPUT_QUOTA_FAILED'"
+ # Validate QUOTA_FAILED (must be 'true', 'false', or empty string)
+ if [[ "$INPUT_QUOTA_FAILED" != "true" && "$INPUT_QUOTA_FAILED" != "false" && "$INPUT_QUOTA_FAILED" != "" ]]; then
+ echo "â ERROR: QUOTA_FAILED must be 'true', 'false', or empty string, got: '$INPUT_QUOTA_FAILED'"
VALIDATION_FAILED=true
else
echo "â
QUOTA_FAILED: '$INPUT_QUOTA_FAILED' is valid"
From 3b7540cdcc1d589cf17c2041f66d3bbc95bb5ec1 Mon Sep 17 00:00:00 2001
From: Vamshi-Microsoft
Date: Tue, 13 Jan 2026 15:01:28 +0530
Subject: [PATCH 06/10] Minor fix
---
.github/workflows/job-deploy-linux.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/job-deploy-linux.yml b/.github/workflows/job-deploy-linux.yml
index 214cb6c7..1c7ac1fc 100644
--- a/.github/workflows/job-deploy-linux.yml
+++ b/.github/workflows/job-deploy-linux.yml
@@ -150,7 +150,7 @@ jobs:
# Validate AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID (optional, if provided must be valid Resource ID)
if [[ -n "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" ]]; then
- if [[ ! "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/[Rr]esource[Gg]roups/[^/]+/providers/[Mm]icrosoft\.[Oo]perational[Ii]nsights/[Ww]orkspaces/[^/]+$ ]]; then
+ if [[ ! "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/[Rr]esource[Gg]roups/[^/]+/providers/[Mm]icrosoft\.[Oo]perational[Ii]nsights/[Ww]orkspaces/[^/]+$ ]]; then
echo "â ERROR: AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID is invalid. Must be a valid Azure Resource ID format:"
echo " /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.OperationalInsights/workspaces/{workspaceName}"
echo " Got: '$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID'"
From 3d41816f44cf35cf76cde1e92473134245ae5b79 Mon Sep 17 00:00:00 2001
From: Vamshi-Microsoft
Date: Tue, 13 Jan 2026 15:11:18 +0530
Subject: [PATCH 07/10] Changed Job condition from Always to !Cancelled
---
.github/workflows/deploy-orchestrator.yml | 8 ++++----
.github/workflows/job-deploy.yml | 4 ++--
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/.github/workflows/deploy-orchestrator.yml b/.github/workflows/deploy-orchestrator.yml
index 6eca9baa..f8a4d7e6 100644
--- a/.github/workflows/deploy-orchestrator.yml
+++ b/.github/workflows/deploy-orchestrator.yml
@@ -76,7 +76,7 @@ jobs:
secrets: inherit
deploy:
- if: always() && (inputs.trigger_type != 'workflow_dispatch' || inputs.existing_webapp_url == '' || inputs.existing_webapp_url == null)
+ if: "!cancelled() && (needs.docker-build.result == 'success' || needs.docker-build.result == 'skipped') && (inputs.trigger_type != 'workflow_dispatch' || inputs.existing_webapp_url == '' || inputs.existing_webapp_url == null)"
needs: docker-build
uses: ./.github/workflows/job-deploy.yml
with:
@@ -96,7 +96,7 @@ jobs:
secrets: inherit
e2e-test:
- if: always() && ((needs.deploy.result == 'success' && needs.deploy.outputs.CONTAINER_WEB_APPURL != '') || (inputs.existing_webapp_url != '' && inputs.existing_webapp_url != null)) && (inputs.trigger_type != 'workflow_dispatch' || (inputs.run_e2e_tests != 'None' && inputs.run_e2e_tests != '' && inputs.run_e2e_tests != null))
+ if: "!cancelled() && ((needs.deploy.result == 'success' && needs.deploy.outputs.CONTAINER_WEB_APPURL != '') || (inputs.existing_webapp_url != '' && inputs.existing_webapp_url != null)) && (inputs.trigger_type != 'workflow_dispatch' || (inputs.run_e2e_tests != 'None' && inputs.run_e2e_tests != '' && inputs.run_e2e_tests != null))"
needs: [docker-build, deploy]
uses: ./.github/workflows/test-automation-v2.yml
with:
@@ -105,7 +105,7 @@ jobs:
secrets: inherit
send-notification:
- if: always()
+ if: "!cancelled()"
needs: [docker-build, deploy, e2e-test]
uses: ./.github/workflows/job-send-notification.yml
with:
@@ -124,7 +124,7 @@ jobs:
secrets: inherit
cleanup-deployment:
- if: always() && needs.deploy.result == 'success' && needs.deploy.outputs.RESOURCE_GROUP_NAME != '' && inputs.existing_webapp_url == '' && (inputs.trigger_type != 'workflow_dispatch' || inputs.cleanup_resources)
+ if: "!cancelled() && needs.deploy.result == 'success' && needs.deploy.outputs.RESOURCE_GROUP_NAME != '' && inputs.existing_webapp_url == '' && (inputs.trigger_type != 'workflow_dispatch' || inputs.cleanup_resources)"
needs: [docker-build, deploy, e2e-test]
uses: ./.github/workflows/job-cleanup-deployment.yml
with:
diff --git a/.github/workflows/job-deploy.yml b/.github/workflows/job-deploy.yml
index c30c1390..40ed81e9 100644
--- a/.github/workflows/job-deploy.yml
+++ b/.github/workflows/job-deploy.yml
@@ -527,7 +527,7 @@ jobs:
deploy-linux:
name: Deploy on Linux
needs: azure-setup
- if: inputs.runner_os == 'ubuntu-latest' && always() && needs.azure-setup.result == 'success'
+ if: inputs.runner_os == 'ubuntu-latest' && !cancelled() && needs.azure-setup.result == 'success'
uses: ./.github/workflows/job-deploy-linux.yml
with:
ENV_NAME: ${{ needs.azure-setup.outputs.ENV_NAME }}
@@ -545,7 +545,7 @@ jobs:
deploy-windows:
name: Deploy on Windows
needs: azure-setup
- if: inputs.runner_os == 'windows-latest' && always() && needs.azure-setup.result == 'success'
+ if: inputs.runner_os == 'windows-latest' && !cancelled() && needs.azure-setup.result == 'success'
uses: ./.github/workflows/job-deploy-windows.yml
with:
ENV_NAME: ${{ needs.azure-setup.outputs.ENV_NAME }}
From 59b207e13372e50a3385a0af487e1bf3f94bc46d Mon Sep 17 00:00:00 2001
From: Vamshi-Microsoft
Date: Fri, 16 Jan 2026 14:47:22 +0530
Subject: [PATCH 08/10] Pass Exp to Notification Job
---
.github/workflows/deploy-orchestrator.yml | 2 +-
.github/workflows/job-deploy.yml | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/deploy-orchestrator.yml b/.github/workflows/deploy-orchestrator.yml
index f8a4d7e6..20858bd2 100644
--- a/.github/workflows/deploy-orchestrator.yml
+++ b/.github/workflows/deploy-orchestrator.yml
@@ -111,7 +111,7 @@ jobs:
with:
trigger_type: ${{ inputs.trigger_type }}
waf_enabled: ${{ inputs.waf_enabled }}
- EXP: ${{ inputs.EXP }}
+ EXP: ${{ needs.deploy.outputs.EXP_ENABLED }}
run_e2e_tests: ${{ inputs.run_e2e_tests }}
existing_webapp_url: ${{ inputs.existing_webapp_url }}
deploy_result: ${{ needs.deploy.result }}
diff --git a/.github/workflows/job-deploy.yml b/.github/workflows/job-deploy.yml
index 40ed81e9..5e3440c5 100644
--- a/.github/workflows/job-deploy.yml
+++ b/.github/workflows/job-deploy.yml
@@ -88,6 +88,9 @@ on:
QUOTA_FAILED:
description: "Quota Check Failed Flag"
value: ${{ jobs.azure-setup.outputs.QUOTA_FAILED }}
+ EXP_ENABLED:
+ description: "EXP Flag"
+ value: ${{ jobs.azure-setup.outputs.EXP_ENABLED }}
env:
GPT_MIN_CAPACITY: 100
From b9c65d22d6631cc36850d24cc4d96bdfa9e626c2 Mon Sep 17 00:00:00 2001
From: Vamshi-Microsoft
Date: Fri, 16 Jan 2026 17:09:14 +0530
Subject: [PATCH 09/10] refactor: update EXP input handling in deployment
workflows
---
.github/workflows/deploy-orchestrator.yml | 2 +-
.github/workflows/job-deploy.yml | 3 ---
2 files changed, 1 insertion(+), 4 deletions(-)
diff --git a/.github/workflows/deploy-orchestrator.yml b/.github/workflows/deploy-orchestrator.yml
index 20858bd2..f8a4d7e6 100644
--- a/.github/workflows/deploy-orchestrator.yml
+++ b/.github/workflows/deploy-orchestrator.yml
@@ -111,7 +111,7 @@ jobs:
with:
trigger_type: ${{ inputs.trigger_type }}
waf_enabled: ${{ inputs.waf_enabled }}
- EXP: ${{ needs.deploy.outputs.EXP_ENABLED }}
+ EXP: ${{ inputs.EXP }}
run_e2e_tests: ${{ inputs.run_e2e_tests }}
existing_webapp_url: ${{ inputs.existing_webapp_url }}
deploy_result: ${{ needs.deploy.result }}
diff --git a/.github/workflows/job-deploy.yml b/.github/workflows/job-deploy.yml
index 5e3440c5..40ed81e9 100644
--- a/.github/workflows/job-deploy.yml
+++ b/.github/workflows/job-deploy.yml
@@ -88,9 +88,6 @@ on:
QUOTA_FAILED:
description: "Quota Check Failed Flag"
value: ${{ jobs.azure-setup.outputs.QUOTA_FAILED }}
- EXP_ENABLED:
- description: "EXP Flag"
- value: ${{ jobs.azure-setup.outputs.EXP_ENABLED }}
env:
GPT_MIN_CAPACITY: 100
From 90d492ea01ac8e3477427ecdf4162b7ea229358e Mon Sep 17 00:00:00 2001
From: "Prekshith D J (Persistent Systems Inc)"
Date: Wed, 28 Jan 2026 12:03:30 +0530
Subject: [PATCH 10/10] Fix the issue with devcontainer
---
.devcontainer/Dockerfile | 3 +++
1 file changed, 3 insertions(+)
diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
index fda78e10..f88097e4 100644
--- a/.devcontainer/Dockerfile
+++ b/.devcontainer/Dockerfile
@@ -7,6 +7,9 @@ FROM ghcr.io/astral-sh/uv:$UV_VERSION AS uv
# Use Debian-based VS Code Dev Container as base
FROM mcr.microsoft.com/vscode/devcontainers/base:$DEBIAN_VERSION
+# Remove Yarn repository to avoid GPG key expiration issue
+RUN rm -f /etc/apt/sources.list.d/yarn.list
+
# Install dependencies and Node.js 20+ from NodeSource
RUN apt-get update \
&& apt-get install -y --no-install-recommends \