Skip to content

Commit 97cf33c

Browse files
Add validation step for Inputs and Map Inputs to env
1 parent c787e63 commit 97cf33c

4 files changed

Lines changed: 792 additions & 77 deletions

File tree

.github/workflows/job-deploy-linux.yml

Lines changed: 199 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,147 @@ jobs:
4747
outputs:
4848
WEB_APPURL: ${{ steps.get_output_linux.outputs.WEB_APPURL }}
4949
steps:
50+
- name: Validate Workflow Input Parameters
51+
shell: bash
52+
env:
53+
INPUT_ENV_NAME: ${{ inputs.ENV_NAME }}
54+
INPUT_AZURE_ENV_OPENAI_LOCATION: ${{ inputs.AZURE_ENV_OPENAI_LOCATION }}
55+
INPUT_AZURE_LOCATION: ${{ inputs.AZURE_LOCATION }}
56+
INPUT_RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }}
57+
INPUT_IMAGE_TAG: ${{ inputs.IMAGE_TAG }}
58+
INPUT_BUILD_DOCKER_IMAGE: ${{ inputs.BUILD_DOCKER_IMAGE }}
59+
INPUT_EXP: ${{ inputs.EXP }}
60+
INPUT_WAF_ENABLED: ${{ inputs.WAF_ENABLED }}
61+
INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}
62+
INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}
63+
run: |
64+
echo "🔍 Validating workflow input parameters..."
65+
VALIDATION_FAILED=false
66+
67+
# Validate ENV_NAME (required, alphanumeric and hyphens)
68+
if [[ -z "$INPUT_ENV_NAME" ]]; then
69+
echo "❌ ERROR: ENV_NAME is required but not provided"
70+
VALIDATION_FAILED=true
71+
elif [[ ! "$INPUT_ENV_NAME" =~ ^[a-zA-Z0-9-]+$ ]]; then
72+
echo "❌ ERROR: ENV_NAME '$INPUT_ENV_NAME' is invalid. Must contain only alphanumerics and hyphens"
73+
VALIDATION_FAILED=true
74+
else
75+
echo "✅ ENV_NAME: '$INPUT_ENV_NAME' is valid"
76+
fi
77+
78+
# Validate AZURE_ENV_OPENAI_LOCATION (required, Azure region format)
79+
if [[ -z "$INPUT_AZURE_ENV_OPENAI_LOCATION" ]]; then
80+
echo "❌ ERROR: AZURE_ENV_OPENAI_LOCATION is required but not provided"
81+
VALIDATION_FAILED=true
82+
elif [[ ! "$INPUT_AZURE_ENV_OPENAI_LOCATION" =~ ^[a-z0-9]+$ ]]; then
83+
echo "❌ ERROR: AZURE_ENV_OPENAI_LOCATION '$INPUT_AZURE_ENV_OPENAI_LOCATION' is invalid. Must contain only lowercase letters and numbers"
84+
VALIDATION_FAILED=true
85+
else
86+
echo "✅ AZURE_ENV_OPENAI_LOCATION: '$INPUT_AZURE_ENV_OPENAI_LOCATION' is valid"
87+
fi
88+
89+
# Validate AZURE_LOCATION (required, Azure region format)
90+
if [[ -z "$INPUT_AZURE_LOCATION" ]]; then
91+
echo "❌ ERROR: AZURE_LOCATION is required but not provided"
92+
VALIDATION_FAILED=true
93+
elif [[ ! "$INPUT_AZURE_LOCATION" =~ ^[a-z0-9]+$ ]]; then
94+
echo "❌ ERROR: AZURE_LOCATION '$INPUT_AZURE_LOCATION' is invalid. Must contain only lowercase letters and numbers"
95+
VALIDATION_FAILED=true
96+
else
97+
echo "✅ AZURE_LOCATION: '$INPUT_AZURE_LOCATION' is valid"
98+
fi
99+
100+
# Validate RESOURCE_GROUP_NAME (required, Azure naming convention)
101+
if [[ -z "$INPUT_RESOURCE_GROUP_NAME" ]]; then
102+
echo "❌ ERROR: RESOURCE_GROUP_NAME is required but not provided"
103+
VALIDATION_FAILED=true
104+
elif [[ ! "$INPUT_RESOURCE_GROUP_NAME" =~ ^[a-zA-Z0-9._\(\)-]+$ ]] || [[ "$INPUT_RESOURCE_GROUP_NAME" =~ \.$ ]]; then
105+
echo "❌ ERROR: RESOURCE_GROUP_NAME '$INPUT_RESOURCE_GROUP_NAME' is invalid. Must contain only alphanumerics, periods, underscores, hyphens, and parentheses. Cannot end with period."
106+
VALIDATION_FAILED=true
107+
elif [[ ${#INPUT_RESOURCE_GROUP_NAME} -gt 90 ]]; then
108+
echo "❌ ERROR: RESOURCE_GROUP_NAME '$INPUT_RESOURCE_GROUP_NAME' exceeds 90 characters"
109+
VALIDATION_FAILED=true
110+
else
111+
echo "✅ RESOURCE_GROUP_NAME: '$INPUT_RESOURCE_GROUP_NAME' is valid"
112+
fi
113+
114+
# Validate IMAGE_TAG (required, Docker tag pattern)
115+
if [[ -z "$INPUT_IMAGE_TAG" ]]; then
116+
echo "❌ ERROR: IMAGE_TAG is required but not provided"
117+
VALIDATION_FAILED=true
118+
elif [[ ! "$INPUT_IMAGE_TAG" =~ ^[a-zA-Z0-9_][a-zA-Z0-9._-]{0,127}$ ]]; then
119+
echo "❌ ERROR: IMAGE_TAG '$INPUT_IMAGE_TAG' is invalid. Must start with alphanumeric or underscore, max 128 characters"
120+
VALIDATION_FAILED=true
121+
else
122+
echo "✅ IMAGE_TAG: '$INPUT_IMAGE_TAG' is valid"
123+
fi
124+
125+
# Validate BUILD_DOCKER_IMAGE (required, must be 'true' or 'false')
126+
if [[ "$INPUT_BUILD_DOCKER_IMAGE" != "true" && "$INPUT_BUILD_DOCKER_IMAGE" != "false" ]]; then
127+
echo "❌ ERROR: BUILD_DOCKER_IMAGE must be 'true' or 'false', got: '$INPUT_BUILD_DOCKER_IMAGE'"
128+
VALIDATION_FAILED=true
129+
else
130+
echo "✅ BUILD_DOCKER_IMAGE: '$INPUT_BUILD_DOCKER_IMAGE' is valid"
131+
fi
132+
133+
# Validate EXP (required, must be 'true' or 'false')
134+
if [[ "$INPUT_EXP" != "true" && "$INPUT_EXP" != "false" ]]; then
135+
echo "❌ ERROR: EXP must be 'true' or 'false', got: '$INPUT_EXP'"
136+
VALIDATION_FAILED=true
137+
else
138+
echo "✅ EXP: '$INPUT_EXP' is valid"
139+
fi
140+
141+
# Validate WAF_ENABLED (must be 'true' or 'false')
142+
if [[ "$INPUT_WAF_ENABLED" != "true" && "$INPUT_WAF_ENABLED" != "false" ]]; then
143+
echo "❌ ERROR: WAF_ENABLED must be 'true' or 'false', got: '$INPUT_WAF_ENABLED'"
144+
VALIDATION_FAILED=true
145+
else
146+
echo "✅ WAF_ENABLED: '$INPUT_WAF_ENABLED' is valid"
147+
fi
148+
149+
# Validate AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID (optional, if provided must be valid Resource ID)
150+
if [[ -n "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" ]]; then
151+
if [[ ! "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/resourceGroups/[^/]+/providers/microsoft\.operationalinsights/workspaces/[^/]+$ ]]; then
152+
echo "❌ ERROR: AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID is invalid. Must be a valid Azure Resource ID format:"
153+
echo " /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.OperationalInsights/workspaces/{workspaceName}"
154+
echo " Got: '$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID'"
155+
VALIDATION_FAILED=true
156+
else
157+
echo "✅ AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: Valid Resource ID format"
158+
fi
159+
fi
160+
161+
# Validate AZURE_EXISTING_AI_PROJECT_RESOURCE_ID (optional, if provided must be valid Resource ID)
162+
if [[ -n "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" ]]; then
163+
if [[ ! "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" =~ ^/subscriptions/[a-fA-F0-9-]+/resourceGroups/[^/]+/providers/(Microsoft\.MachineLearningServices/(workspaces|projects)/[^/]+|Microsoft\.CognitiveServices/accounts/[^/]+/projects/[^/]+)$ ]]; then
164+
echo "❌ ERROR: AZURE_EXISTING_AI_PROJECT_RESOURCE_ID is invalid. Must be a valid Azure Resource ID format:"
165+
echo " /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.CognitiveServices/accounts/{accountName}/projects/{projectName}"
166+
echo " Got: '$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID'"
167+
VALIDATION_FAILED=true
168+
else
169+
echo "✅ AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: Valid Resource ID format"
170+
fi
171+
fi
172+
173+
# Fail workflow if any validation failed
174+
if [[ "$VALIDATION_FAILED" == "true" ]]; then
175+
echo ""
176+
echo "❌ Parameter validation failed. Please correct the errors above and try again."
177+
exit 1
178+
fi
179+
180+
echo ""
181+
echo "✅ All input parameters validated successfully!"
50182
- name: Checkout Code
51183
uses: actions/checkout@v4
52184

53185
- name: Configure Parameters Based on WAF Setting
54186
shell: bash
187+
env:
188+
WAF_ENABLED: ${{ inputs.WAF_ENABLED }}
55189
run: |
56-
if [[ "${{ inputs.WAF_ENABLED }}" == "true" ]]; then
190+
if [[ "$WAF_ENABLED" == "true" ]]; then
57191
cp infra/main.waf.parameters.json infra/main.parameters.json
58192
echo "✅ Successfully copied WAF parameters to main parameters file"
59193
else
@@ -83,45 +217,55 @@ jobs:
83217
- name: Deploy using azd up and extract values (Linux)
84218
id: get_output_linux
85219
shell: bash
220+
env:
221+
ENV_NAME: ${{ inputs.ENV_NAME }}
222+
AZURE_ENV_OPENAI_LOCATION: ${{ inputs.AZURE_ENV_OPENAI_LOCATION }}
223+
AZURE_LOCATION: ${{ inputs.AZURE_LOCATION }}
224+
RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }}
225+
IMAGE_TAG: ${{ inputs.IMAGE_TAG }}
226+
BUILD_DOCKER_IMAGE: ${{ inputs.BUILD_DOCKER_IMAGE }}
227+
EXP: ${{ inputs.EXP }}
228+
INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}
229+
INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}
86230
run: |
87231
set -e
88232
89233
echo "Creating environment..."
90-
azd env new ${{ inputs.ENV_NAME }} --no-prompt
91-
echo "Environment created: ${{ inputs.ENV_NAME }}"
234+
azd env new "$ENV_NAME" --no-prompt
235+
echo "Environment created: $ENV_NAME"
92236
93237
echo "Setting default subscription..."
94-
azd config set defaults.subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }}
238+
azd config set defaults.subscription "${{ secrets.AZURE_SUBSCRIPTION_ID }}"
95239
96240
# Set additional parameters
97241
azd env set AZURE_SUBSCRIPTION_ID="${{ secrets.AZURE_SUBSCRIPTION_ID }}"
98-
azd env set AZURE_ENV_OPENAI_LOCATION="${{ inputs.AZURE_ENV_OPENAI_LOCATION }}"
99-
azd env set AZURE_LOCATION="${{ inputs.AZURE_LOCATION }}"
100-
azd env set AZURE_RESOURCE_GROUP="${{ inputs.RESOURCE_GROUP_NAME }}"
101-
azd env set AZURE_ENV_IMAGETAG="${{ inputs.IMAGE_TAG }}"
242+
azd env set AZURE_ENV_OPENAI_LOCATION="$AZURE_ENV_OPENAI_LOCATION"
243+
azd env set AZURE_LOCATION="$AZURE_LOCATION"
244+
azd env set AZURE_RESOURCE_GROUP="$RESOURCE_GROUP_NAME"
245+
azd env set AZURE_ENV_IMAGETAG="$IMAGE_TAG"
102246
103247
# Set ACR name only when building Docker image
104-
if [[ "${{ inputs.BUILD_DOCKER_IMAGE }}" == "true" ]]; then
248+
if [[ "$BUILD_DOCKER_IMAGE" == "true" ]]; then
105249
# Extract ACR name from login server and set as environment variable
106-
ACR_NAME=$(echo "${{ secrets.ACR_TEST_USERNAME }}")
250+
ACR_NAME="${{ secrets.ACR_TEST_USERNAME }}"
107251
azd env set AZURE_ENV_ACR_NAME="$ACR_NAME"
108252
echo "Set ACR name to: $ACR_NAME"
109253
else
110254
echo "Skipping ACR name configuration (using existing image)"
111255
fi
112256
113-
if [[ "${{ inputs.EXP }}" == "true" ]]; then
257+
if [[ "$EXP" == "true" ]]; then
114258
echo "✅ EXP ENABLED - Setting EXP parameters..."
115259
116260
# Set EXP variables dynamically
117-
if [[ -n "${{ github.event.inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}" ]]; then
118-
EXP_LOG_ANALYTICS_ID="${{ github.event.inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}"
261+
if [[ -n "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" ]]; then
262+
EXP_LOG_ANALYTICS_ID="$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID"
119263
else
120264
EXP_LOG_ANALYTICS_ID="${{ secrets.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}"
121265
fi
122266
123-
if [[ -n "${{ github.event.inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}" ]]; then
124-
EXP_AI_PROJECT_ID="${{ github.event.inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}"
267+
if [[ -n "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" ]]; then
268+
EXP_AI_PROJECT_ID="$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID"
125269
else
126270
EXP_AI_PROJECT_ID="${{ secrets.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}"
127271
fi
@@ -132,7 +276,7 @@ jobs:
132276
azd env set AZURE_EXISTING_AI_PROJECT_RESOURCE_ID="$EXP_AI_PROJECT_ID"
133277
else
134278
echo "❌ EXP DISABLED - Skipping EXP parameters"
135-
if [[ -n "${{ github.event.inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }}" ]] || [[ -n "${{ github.event.inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }}" ]]; then
279+
if [[ -n "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" ]] || [[ -n "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" ]]; then
136280
echo "⚠️ Warning: EXP parameter values provided but EXP is disabled. These values will be ignored."
137281
fi
138282
fi
@@ -181,9 +325,10 @@ jobs:
181325
id: post_deploy
182326
env:
183327
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
328+
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
184329
run: |
185330
set -e
186-
az account set --subscription "${{ secrets.AZURE_SUBSCRIPTION_ID }}"
331+
az account set --subscription "$AZURE_SUBSCRIPTION_ID"
187332
188333
echo "Running post-deployment script..."
189334
@@ -194,26 +339,54 @@ jobs:
194339
"$AZURE_COSMOSDB_ACCOUNT" \
195340
"$RESOURCE_GROUP_NAME" \
196341
"$AI_SEARCH_SERVICE_NAME" \
197-
"${{ secrets.AZURE_CLIENT_ID }}" \
342+
"$AZURE_CLIENT_ID" \
198343
"$AI_FOUNDRY_RESOURCE_ID"
199344
200345
- name: Generate Deploy Job Summary
201346
if: always()
347+
env:
348+
RESOURCE_GROUP_NAME: ${{ inputs.RESOURCE_GROUP_NAME }}
349+
WAF_ENABLED: ${{ inputs.WAF_ENABLED }}
350+
EXP: ${{ inputs.EXP }}
351+
AZURE_LOCATION: ${{ inputs.AZURE_LOCATION }}
352+
AZURE_ENV_OPENAI_LOCATION: ${{ inputs.AZURE_ENV_OPENAI_LOCATION }}
353+
IMAGE_TAG: ${{ inputs.IMAGE_TAG }}
354+
JOB_STATUS: ${{ job.status }}
355+
WEB_APPURL: ${{ steps.get_output_linux.outputs.WEB_APPURL }}
202356
run: |
203357
echo "## 🚀 Deploy Job Summary (Linux)" >> $GITHUB_STEP_SUMMARY
204358
echo "" >> $GITHUB_STEP_SUMMARY
205359
echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
206360
echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY
207-
echo "| **Job Status** | ${{ job.status == 'success' && '✅ Success' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY
208-
echo "| **Resource Group** | \`${{ inputs.RESOURCE_GROUP_NAME }}\` |" >> $GITHUB_STEP_SUMMARY
209-
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
210-
echo "| **Azure Region (Infrastructure)** | \`${{ inputs.AZURE_LOCATION }}\` |" >> $GITHUB_STEP_SUMMARY
211-
echo "| **Azure OpenAI Region** | \`${{ inputs.AZURE_ENV_OPENAI_LOCATION }}\` |" >> $GITHUB_STEP_SUMMARY
212-
echo "| **Docker Image Tag** | \`${{ inputs.IMAGE_TAG }}\` |" >> $GITHUB_STEP_SUMMARY
361+
362+
if [[ "$JOB_STATUS" == "success" ]]; then
363+
echo "| **Job Status** | ✅ Success |" >> $GITHUB_STEP_SUMMARY
364+
else
365+
echo "| **Job Status** | ❌ Failed |" >> $GITHUB_STEP_SUMMARY
366+
fi
367+
368+
echo "| **Resource Group** | \`$RESOURCE_GROUP_NAME\` |" >> $GITHUB_STEP_SUMMARY
369+
370+
# Determine configuration type
371+
if [[ "$WAF_ENABLED" == "true" && "$EXP" == "true" ]]; then
372+
CONFIG_TYPE="WAF + EXP"
373+
elif [[ "$WAF_ENABLED" == "true" && "$EXP" != "true" ]]; then
374+
CONFIG_TYPE="WAF + Non-EXP"
375+
elif [[ "$WAF_ENABLED" != "true" && "$EXP" == "true" ]]; then
376+
CONFIG_TYPE="Non-WAF + EXP"
377+
else
378+
CONFIG_TYPE="Non-WAF + Non-EXP"
379+
fi
380+
echo "| **Configuration Type** | \`$CONFIG_TYPE\` |" >> $GITHUB_STEP_SUMMARY
381+
382+
echo "| **Azure Region (Infrastructure)** | \`$AZURE_LOCATION\` |" >> $GITHUB_STEP_SUMMARY
383+
echo "| **Azure OpenAI Region** | \`$AZURE_ENV_OPENAI_LOCATION\` |" >> $GITHUB_STEP_SUMMARY
384+
echo "| **Docker Image Tag** | \`$IMAGE_TAG\` |" >> $GITHUB_STEP_SUMMARY
213385
echo "" >> $GITHUB_STEP_SUMMARY
214-
if [[ "${{ job.status }}" == "success" ]]; then
386+
387+
if [[ "$JOB_STATUS" == "success" ]]; then
215388
echo "### ✅ Deployment Details" >> $GITHUB_STEP_SUMMARY
216-
echo "- **Web App URL**: [${{ steps.get_output_linux.outputs.WEB_APPURL }}](${{ steps.get_output_linux.outputs.WEB_APPURL }})" >> $GITHUB_STEP_SUMMARY
389+
echo "- **Web App URL**: [$WEB_APPURL]($WEB_APPURL)" >> $GITHUB_STEP_SUMMARY
217390
echo "- Successfully deployed to Azure with all resources configured" >> $GITHUB_STEP_SUMMARY
218391
echo "- Post-deployment scripts executed successfully" >> $GITHUB_STEP_SUMMARY
219392
else

0 commit comments

Comments
 (0)