@@ -54,10 +54,145 @@ jobs:
5454 - name : Checkout Code
5555 uses : actions/checkout@v4
5656
57+ - name : Validate Workflow Input Parameters
58+ shell : bash
59+ env :
60+ INPUT_ENV_NAME : ${{ inputs.ENV_NAME }}
61+ INPUT_AZURE_ENV_OPENAI_LOCATION : ${{ inputs.AZURE_ENV_OPENAI_LOCATION }}
62+ INPUT_AZURE_LOCATION : ${{ inputs.AZURE_LOCATION }}
63+ INPUT_RESOURCE_GROUP_NAME : ${{ inputs.RESOURCE_GROUP_NAME }}
64+ INPUT_IMAGE_TAG : ${{ inputs.IMAGE_TAG }}
65+ INPUT_BUILD_DOCKER_IMAGE : ${{ inputs.BUILD_DOCKER_IMAGE }}
66+ INPUT_EXP : ${{ inputs.EXP }}
67+ INPUT_WAF_ENABLED : ${{ inputs.WAF_ENABLED }}
68+ INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID : ${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}
69+ INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID : ${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}
70+ run : |
71+ echo "🔍 Validating workflow input parameters..."
72+ VALIDATION_FAILED=false
73+
74+ # Validate ENV_NAME (required, alphanumeric and hyphens)
75+ if [[ -z "$INPUT_ENV_NAME" ]]; then
76+ echo "❌ ERROR: ENV_NAME is required but not provided"
77+ VALIDATION_FAILED=true
78+ elif [[ ! "$INPUT_ENV_NAME" =~ ^[a-zA-Z0-9-]+$ ]]; then
79+ echo "❌ ERROR: ENV_NAME '$INPUT_ENV_NAME' is invalid. Must contain only alphanumerics and hyphens"
80+ VALIDATION_FAILED=true
81+ else
82+ echo "✅ ENV_NAME: '$INPUT_ENV_NAME' is valid"
83+ fi
84+
85+ # Validate AZURE_ENV_OPENAI_LOCATION (required, Azure region format)
86+ if [[ -z "$INPUT_AZURE_ENV_OPENAI_LOCATION" ]]; then
87+ echo "❌ ERROR: AZURE_ENV_OPENAI_LOCATION is required but not provided"
88+ VALIDATION_FAILED=true
89+ elif [[ ! "$INPUT_AZURE_ENV_OPENAI_LOCATION" =~ ^[a-z0-9]+$ ]]; then
90+ echo "❌ ERROR: AZURE_ENV_OPENAI_LOCATION '$INPUT_AZURE_ENV_OPENAI_LOCATION' is invalid. Must contain only lowercase letters and numbers"
91+ VALIDATION_FAILED=true
92+ else
93+ echo "✅ AZURE_ENV_OPENAI_LOCATION: '$INPUT_AZURE_ENV_OPENAI_LOCATION' is valid"
94+ fi
95+
96+ # Validate AZURE_LOCATION (required, Azure region format)
97+ if [[ -z "$INPUT_AZURE_LOCATION" ]]; then
98+ echo "❌ ERROR: AZURE_LOCATION is required but not provided"
99+ VALIDATION_FAILED=true
100+ elif [[ ! "$INPUT_AZURE_LOCATION" =~ ^[a-z0-9]+$ ]]; then
101+ echo "❌ ERROR: AZURE_LOCATION '$INPUT_AZURE_LOCATION' is invalid. Must contain only lowercase letters and numbers"
102+ VALIDATION_FAILED=true
103+ else
104+ echo "✅ AZURE_LOCATION: '$INPUT_AZURE_LOCATION' is valid"
105+ fi
106+
107+ # Validate RESOURCE_GROUP_NAME (required, Azure naming convention)
108+ if [[ -z "$INPUT_RESOURCE_GROUP_NAME" ]]; then
109+ echo "❌ ERROR: RESOURCE_GROUP_NAME is required but not provided"
110+ VALIDATION_FAILED=true
111+ elif [[ ! "$INPUT_RESOURCE_GROUP_NAME" =~ ^[a-zA-Z0-9._\(\)-]+$ ]] || [[ "$INPUT_RESOURCE_GROUP_NAME" =~ \.$ ]]; then
112+ echo "❌ ERROR: RESOURCE_GROUP_NAME '$INPUT_RESOURCE_GROUP_NAME' is invalid. Must contain only alphanumerics, periods, underscores, hyphens, and parentheses. Cannot end with period."
113+ VALIDATION_FAILED=true
114+ elif [[ ${#INPUT_RESOURCE_GROUP_NAME} -gt 90 ]]; then
115+ echo "❌ ERROR: RESOURCE_GROUP_NAME '$INPUT_RESOURCE_GROUP_NAME' exceeds 90 characters"
116+ VALIDATION_FAILED=true
117+ else
118+ echo "✅ RESOURCE_GROUP_NAME: '$INPUT_RESOURCE_GROUP_NAME' is valid"
119+ fi
120+
121+ # Validate IMAGE_TAG (required, Docker tag pattern)
122+ if [[ -z "$INPUT_IMAGE_TAG" ]]; then
123+ echo "❌ ERROR: IMAGE_TAG is required but not provided"
124+ VALIDATION_FAILED=true
125+ elif [[ ! "$INPUT_IMAGE_TAG" =~ ^[a-zA-Z0-9_][a-zA-Z0-9._-]{0,127}$ ]]; then
126+ echo "❌ ERROR: IMAGE_TAG '$INPUT_IMAGE_TAG' is invalid. Must start with alphanumeric or underscore, max 128 characters"
127+ VALIDATION_FAILED=true
128+ else
129+ echo "✅ IMAGE_TAG: '$INPUT_IMAGE_TAG' is valid"
130+ fi
131+
132+ # Validate BUILD_DOCKER_IMAGE (required, must be 'true' or 'false')
133+ if [[ "$INPUT_BUILD_DOCKER_IMAGE" != "true" && "$INPUT_BUILD_DOCKER_IMAGE" != "false" ]]; then
134+ echo "❌ ERROR: BUILD_DOCKER_IMAGE must be 'true' or 'false', got: '$INPUT_BUILD_DOCKER_IMAGE'"
135+ VALIDATION_FAILED=true
136+ else
137+ echo "✅ BUILD_DOCKER_IMAGE: '$INPUT_BUILD_DOCKER_IMAGE' is valid"
138+ fi
139+
140+ # Validate EXP (required, must be 'true' or 'false')
141+ if [[ "$INPUT_EXP" != "true" && "$INPUT_EXP" != "false" ]]; then
142+ echo "❌ ERROR: EXP must be 'true' or 'false', got: '$INPUT_EXP'"
143+ VALIDATION_FAILED=true
144+ else
145+ echo "✅ EXP: '$INPUT_EXP' is valid"
146+ fi
147+
148+ # Validate WAF_ENABLED (must be 'true' or 'false')
149+ if [[ "$INPUT_WAF_ENABLED" != "true" && "$INPUT_WAF_ENABLED" != "false" ]]; then
150+ echo "❌ ERROR: WAF_ENABLED must be 'true' or 'false', got: '$INPUT_WAF_ENABLED'"
151+ VALIDATION_FAILED=true
152+ else
153+ echo "✅ WAF_ENABLED: '$INPUT_WAF_ENABLED' is valid"
154+ fi
155+
156+ # Validate AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID (optional, if provided must be valid Resource ID)
157+ if [[ -n "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" ]]; then
158+ if [[ ! "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/resourceGroups/[^/]+/providers/microsoft\.operationalinsights/workspaces/[^/]+$ ]]; then
159+ echo "❌ ERROR: AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID is invalid. Must be a valid Azure Resource ID format:"
160+ echo " /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.OperationalInsights/workspaces/{workspaceName}"
161+ echo " Got: '$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID'"
162+ VALIDATION_FAILED=true
163+ else
164+ echo "✅ AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: Valid Resource ID format"
165+ fi
166+ fi
167+
168+ # Validate AZURE_EXISTING_AI_PROJECT_RESOURCE_ID (optional, if provided must be valid Resource ID)
169+ if [[ -n "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" ]]; then
170+ if [[ ! "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/resourceGroups/[^/]+/providers/(Microsoft\.MachineLearningServices/(workspaces|projects)/[^/]+|Microsoft\.CognitiveServices/accounts/[^/]+/projects/[^/]+)$ ]]; then
171+ echo "❌ ERROR: AZURE_EXISTING_AI_PROJECT_RESOURCE_ID is invalid. Must be a valid Azure Resource ID format:"
172+ echo " /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.CognitiveServices/accounts/{accountName}/projects/{projectName}"
173+ echo " Got: '$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID'"
174+ VALIDATION_FAILED=true
175+ else
176+ echo "✅ AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: Valid Resource ID format"
177+ fi
178+ fi
179+
180+ # Fail workflow if any validation failed
181+ if [[ "$VALIDATION_FAILED" == "true" ]]; then
182+ echo ""
183+ echo "❌ Parameter validation failed. Please correct the errors above and try again."
184+ exit 1
185+ fi
186+
187+ echo ""
188+ echo "✅ All input parameters validated successfully!"
189+
57190 - name : Configure Parameters Based on WAF Setting
58191 shell : bash
192+ env :
193+ INPUT_WAF_ENABLED : ${{ inputs.WAF_ENABLED }}
59194 run : |
60- if [[ "${{ inputs.WAF_ENABLED }} " == "true" ]]; then
195+ if [[ "$INPUT_WAF_ENABLED " == "true" ]]; then
61196 cp infra/main.waf.parameters.json infra/main.parameters.json
62197 echo "✅ Successfully copied WAF parameters to main parameters file"
63198 else
@@ -87,44 +222,54 @@ jobs:
87222 - name : Deploy using azd up and extract values (Linux)
88223 id : get_output_linux
89224 shell : bash
225+ env :
226+ INPUT_ENV_NAME : ${{ inputs.ENV_NAME }}
227+ INPUT_AZURE_ENV_OPENAI_LOCATION : ${{ inputs.AZURE_ENV_OPENAI_LOCATION }}
228+ INPUT_AZURE_LOCATION : ${{ inputs.AZURE_LOCATION }}
229+ INPUT_RESOURCE_GROUP_NAME : ${{ inputs.RESOURCE_GROUP_NAME }}
230+ INPUT_IMAGE_TAG : ${{ inputs.IMAGE_TAG }}
231+ INPUT_BUILD_DOCKER_IMAGE : ${{ inputs.BUILD_DOCKER_IMAGE }}
232+ INPUT_EXP : ${{ inputs.EXP }}
233+ INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID : ${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}
234+ INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID : ${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}
90235 run : |
91236 set -e
92237 # Install azd (Azure Developer CLI)
93238 curl -fsSL https://aka.ms/install-azd.sh | bash
94239
95240 echo "Creating environment..."
96- azd env new ${{ inputs.ENV_NAME }} --no-prompt
97- echo "Environment created: ${{ inputs.ENV_NAME }} "
241+ azd env new $INPUT_ENV_NAME --no-prompt
242+ echo "Environment created: $INPUT_ENV_NAME "
98243
99244 echo "Setting default subscription..."
100245 azd config set defaults.subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }}
101246
102247 # Set additional parameters
103248 azd env set AZURE_SUBSCRIPTION_ID="${{ secrets.AZURE_SUBSCRIPTION_ID }}"
104- azd env set AZURE_ENV_OPENAI_LOCATION="${{ inputs.AZURE_ENV_OPENAI_LOCATION }} "
105- azd env set AZURE_LOCATION="${{ inputs.AZURE_LOCATION }} "
106- azd env set AZURE_RESOURCE_GROUP="${{ inputs.RESOURCE_GROUP_NAME }} "
107- azd env set AZURE_ENV_IMAGE_TAG="${{ inputs.IMAGE_TAG }} "
249+ azd env set AZURE_ENV_OPENAI_LOCATION="$INPUT_AZURE_ENV_OPENAI_LOCATION "
250+ azd env set AZURE_LOCATION="$INPUT_AZURE_LOCATION "
251+ azd env set AZURE_RESOURCE_GROUP="$INPUT_RESOURCE_GROUP_NAME "
252+ azd env set AZURE_ENV_IMAGE_TAG="$INPUT_IMAGE_TAG "
108253
109- if [[ "${{ inputs.BUILD_DOCKER_IMAGE }} " == "true" ]]; then
254+ if [[ "$INPUT_BUILD_DOCKER_IMAGE " == "true" ]]; then
110255 ACR_NAME=$(echo "${{ secrets.ACR_TEST_LOGIN_SERVER }}")
111256 azd env set AZURE_ENV_CONTAINER_REGISTRY_ENDPOINT="$ACR_NAME"
112257 echo "Set ACR name to: $ACR_NAME"
113258 else
114259 echo "Skipping ACR name configuration (using existing image)"
115260 fi
116261
117- if [[ "${{ inputs.EXP }} " == "true" ]]; then
262+ if [[ "$INPUT_EXP " == "true" ]]; then
118263 echo "✅ EXP ENABLED - Setting EXP parameters..."
119264
120- if [[ -n "${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }} " ]]; then
121- EXP_LOG_ANALYTICS_ID="${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }} "
265+ if [[ -n "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID " ]]; then
266+ EXP_LOG_ANALYTICS_ID="$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID "
122267 else
123268 EXP_LOG_ANALYTICS_ID="${{ secrets.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}"
124269 fi
125270
126- if [[ -n "${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }} " ]]; then
127- EXP_AI_PROJECT_ID="${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }} "
271+ if [[ -n "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID " ]]; then
272+ EXP_AI_PROJECT_ID="$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID "
128273 else
129274 EXP_AI_PROJECT_ID="${{ secrets.AZURE_ENV_FOUNDRY_PROJECT_ID }}"
130275 fi
@@ -169,13 +314,15 @@ jobs:
169314 echo "WEBAPP_URL=$WEBAPP_URL" >> $GITHUB_OUTPUT
170315
171316 - name : Run Post deployment scripts
317+ env :
318+ INPUT_RESOURCE_GROUP_NAME : ${{ inputs.RESOURCE_GROUP_NAME }}
172319 run : |
173320 set -e
174321 az account set --subscription "${{ secrets.AZURE_SUBSCRIPTION_ID }}"
175322
176323 # Set environment variables for selecting_team_config_and_data.sh
177324 export AZURE_SUBSCRIPTION_ID="${{ secrets.AZURE_SUBSCRIPTION_ID }}"
178- export AZURE_RESOURCE_GROUP="${{ inputs.RESOURCE_GROUP_NAME }} "
325+ export AZURE_RESOURCE_GROUP="$INPUT_RESOURCE_GROUP_NAME "
179326 export BACKEND_URL="${{ steps.get_output_linux.outputs.BACKEND_URL }}"
180327 export AZURE_STORAGE_ACCOUNT_NAME="${{ steps.get_output_linux.outputs.AZURE_STORAGE_ACCOUNT_NAME }}"
181328 export AZURE_STORAGE_CONTAINER_NAME="sample-dataset"
@@ -190,17 +337,34 @@ jobs:
190337 - name : Generate Deployment Summary
191338 if : always()
192339 shell : bash
340+ env :
341+ INPUT_RESOURCE_GROUP_NAME : ${{ inputs.RESOURCE_GROUP_NAME }}
342+ INPUT_WAF_ENABLED : ${{ inputs.WAF_ENABLED }}
343+ INPUT_EXP : ${{ inputs.EXP }}
344+ INPUT_AZURE_LOCATION : ${{ inputs.AZURE_LOCATION }}
345+ INPUT_AZURE_ENV_OPENAI_LOCATION : ${{ inputs.AZURE_ENV_OPENAI_LOCATION }}
346+ INPUT_IMAGE_TAG : ${{ inputs.IMAGE_TAG }}
193347 run : |
194348 echo "## 🚀 Deploy Job Summary (Linux)" >> $GITHUB_STEP_SUMMARY
195349 echo "" >> $GITHUB_STEP_SUMMARY
196350 echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
197351 echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY
198352 echo "| **Job Status** | ${{ job.status == 'success' && '✅ Success' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY
199- echo "| **Resource Group** | \`${{ inputs.RESOURCE_GROUP_NAME }}\` |" >> $GITHUB_STEP_SUMMARY
200- 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
201- echo "| **Azure Region (Infrastructure)** | \`${{ inputs.AZURE_LOCATION }}\` |" >> $GITHUB_STEP_SUMMARY
202- echo "| **Azure OpenAI Region** | \`${{ inputs.AZURE_ENV_OPENAI_LOCATION }}\` |" >> $GITHUB_STEP_SUMMARY
203- echo "| **Docker Image Tag** | \`${{ inputs.IMAGE_TAG }}\` |" >> $GITHUB_STEP_SUMMARY
353+ echo "| **Resource Group** | \`$INPUT_RESOURCE_GROUP_NAME\` |" >> $GITHUB_STEP_SUMMARY
354+ CONFIG_TYPE=""
355+ if [[ "$INPUT_WAF_ENABLED" == "true" && "$INPUT_EXP" == "true" ]]; then
356+ CONFIG_TYPE="WAF + EXP"
357+ elif [[ "$INPUT_WAF_ENABLED" == "true" && "$INPUT_EXP" != "true" ]]; then
358+ CONFIG_TYPE="WAF + Non-EXP"
359+ elif [[ "$INPUT_WAF_ENABLED" != "true" && "$INPUT_EXP" == "true" ]]; then
360+ CONFIG_TYPE="Non-WAF + EXP"
361+ else
362+ CONFIG_TYPE="Non-WAF + Non-EXP"
363+ fi
364+ echo "| **Configuration Type** | \`$CONFIG_TYPE\` |" >> $GITHUB_STEP_SUMMARY
365+ echo "| **Azure Region (Infrastructure)** | \`$INPUT_AZURE_LOCATION\` |" >> $GITHUB_STEP_SUMMARY
366+ echo "| **Azure OpenAI Region** | \`$INPUT_AZURE_ENV_OPENAI_LOCATION\` |" >> $GITHUB_STEP_SUMMARY
367+ echo "| **Docker Image Tag** | \`$INPUT_IMAGE_TAG\` |" >> $GITHUB_STEP_SUMMARY
204368 echo "" >> $GITHUB_STEP_SUMMARY
205369 if [[ "${{ job.status }}" == "success" ]]; then
206370 echo "### ✅ Deployment Details" >> $GITHUB_STEP_SUMMARY
0 commit comments