|
86 | 86 | - cron: "0 11,23 * * *" # Runs at 11:00 AM and 11:00 PM GMT |
87 | 87 |
|
88 | 88 | jobs: |
| 89 | + validate-inputs: |
| 90 | + runs-on: ubuntu-latest |
| 91 | + outputs: |
| 92 | + validation_passed: ${{ steps.validate.outputs.passed }} |
| 93 | + azure_location: ${{ steps.validate.outputs.azure_location }} |
| 94 | + resource_group_name: ${{ steps.validate.outputs.resource_group_name }} |
| 95 | + waf_enabled: ${{ steps.validate.outputs.waf_enabled }} |
| 96 | + exp: ${{ steps.validate.outputs.exp }} |
| 97 | + build_docker_image: ${{ steps.validate.outputs.build_docker_image }} |
| 98 | + cleanup_resources: ${{ steps.validate.outputs.cleanup_resources }} |
| 99 | + run_e2e_tests: ${{ steps.validate.outputs.run_e2e_tests }} |
| 100 | + azure_env_log_analytics_workspace_id: ${{ steps.validate.outputs.azure_env_log_analytics_workspace_id }} |
| 101 | + azure_existing_ai_project_resource_id: ${{ steps.validate.outputs.azure_existing_ai_project_resource_id }} |
| 102 | + existing_webapp_url: ${{ steps.validate.outputs.existing_webapp_url }} |
| 103 | + steps: |
| 104 | + - name: Validate Workflow Input Parameters |
| 105 | + id: validate |
| 106 | + shell: bash |
| 107 | + env: |
| 108 | + INPUT_AZURE_LOCATION: ${{ github.event.inputs.azure_location }} |
| 109 | + INPUT_RESOURCE_GROUP_NAME: ${{ github.event.inputs.resource_group_name }} |
| 110 | + INPUT_WAF_ENABLED: ${{ github.event.inputs.waf_enabled }} |
| 111 | + INPUT_EXP: ${{ github.event.inputs.EXP }} |
| 112 | + INPUT_BUILD_DOCKER_IMAGE: ${{ github.event.inputs.build_docker_image }} |
| 113 | + INPUT_CLEANUP_RESOURCES: ${{ github.event.inputs.cleanup_resources }} |
| 114 | + INPUT_RUN_E2E_TESTS: ${{ github.event.inputs.run_e2e_tests }} |
| 115 | + INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ github.event.inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID }} |
| 116 | + INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ github.event.inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID }} |
| 117 | + INPUT_EXISTING_WEBAPP_URL: ${{ github.event.inputs.existing_webapp_url }} |
| 118 | + run: | |
| 119 | + echo "🔍 Validating workflow input parameters..." |
| 120 | + VALIDATION_FAILED=false |
| 121 | + |
| 122 | + # Validate azure_location (Azure region format) |
| 123 | + LOCATION="${INPUT_AZURE_LOCATION:-australiaeast}" |
| 124 | + |
| 125 | + if [[ ! "$LOCATION" =~ ^[a-z0-9]+$ ]]; then |
| 126 | + echo "❌ ERROR: azure_location '$LOCATION' is invalid. Must contain only lowercase letters and numbers" |
| 127 | + VALIDATION_FAILED=true |
| 128 | + else |
| 129 | + echo "✅ azure_location: '$LOCATION' is valid" |
| 130 | + fi |
| 131 | + |
| 132 | + # Validate resource_group_name (Azure naming convention, optional) |
| 133 | + if [[ -n "$INPUT_RESOURCE_GROUP_NAME" ]]; then |
| 134 | + if [[ ! "$INPUT_RESOURCE_GROUP_NAME" =~ ^[a-zA-Z0-9._\(\)-]+$ ]] || [[ "$INPUT_RESOURCE_GROUP_NAME" =~ \.$ ]]; then |
| 135 | + echo "❌ ERROR: resource_group_name '$INPUT_RESOURCE_GROUP_NAME' is invalid. Must contain only alphanumerics, periods, underscores, hyphens, and parentheses. Cannot end with period." |
| 136 | + VALIDATION_FAILED=true |
| 137 | + elif [[ ${#INPUT_RESOURCE_GROUP_NAME} -gt 90 ]]; then |
| 138 | + echo "❌ ERROR: resource_group_name '$INPUT_RESOURCE_GROUP_NAME' exceeds 90 characters (length: ${#INPUT_RESOURCE_GROUP_NAME})" |
| 139 | + VALIDATION_FAILED=true |
| 140 | + else |
| 141 | + echo "✅ resource_group_name: '$INPUT_RESOURCE_GROUP_NAME' is valid" |
| 142 | + fi |
| 143 | + else |
| 144 | + echo "✅ resource_group_name: Not provided (will be auto-generated)" |
| 145 | + fi |
| 146 | + |
| 147 | + # Validate waf_enabled (boolean) |
| 148 | + WAF_ENABLED="${INPUT_WAF_ENABLED:-false}" |
| 149 | + if [[ "$WAF_ENABLED" != "true" && "$WAF_ENABLED" != "false" ]]; then |
| 150 | + echo "❌ ERROR: waf_enabled must be 'true' or 'false', got: '$WAF_ENABLED'" |
| 151 | + VALIDATION_FAILED=true |
| 152 | + else |
| 153 | + echo "✅ waf_enabled: '$WAF_ENABLED' is valid" |
| 154 | + fi |
| 155 | + |
| 156 | + # Validate EXP (boolean) |
| 157 | + EXP_ENABLED="${INPUT_EXP:-false}" |
| 158 | + if [[ "$EXP_ENABLED" != "true" && "$EXP_ENABLED" != "false" ]]; then |
| 159 | + echo "❌ ERROR: EXP must be 'true' or 'false', got: '$EXP_ENABLED'" |
| 160 | + VALIDATION_FAILED=true |
| 161 | + else |
| 162 | + echo "✅ EXP: '$EXP_ENABLED' is valid" |
| 163 | + fi |
| 164 | + |
| 165 | + # Validate build_docker_image (boolean) |
| 166 | + BUILD_DOCKER="${INPUT_BUILD_DOCKER_IMAGE:-false}" |
| 167 | + if [[ "$BUILD_DOCKER" != "true" && "$BUILD_DOCKER" != "false" ]]; then |
| 168 | + echo "❌ ERROR: build_docker_image must be 'true' or 'false', got: '$BUILD_DOCKER'" |
| 169 | + VALIDATION_FAILED=true |
| 170 | + else |
| 171 | + echo "✅ build_docker_image: '$BUILD_DOCKER' is valid" |
| 172 | + fi |
| 173 | + |
| 174 | + # Validate cleanup_resources (boolean) |
| 175 | + CLEANUP_RESOURCES="${INPUT_CLEANUP_RESOURCES:-false}" |
| 176 | + if [[ "$CLEANUP_RESOURCES" != "true" && "$CLEANUP_RESOURCES" != "false" ]]; then |
| 177 | + echo "❌ ERROR: cleanup_resources must be 'true' or 'false', got: '$CLEANUP_RESOURCES'" |
| 178 | + VALIDATION_FAILED=true |
| 179 | + else |
| 180 | + echo "✅ cleanup_resources: '$CLEANUP_RESOURCES' is valid" |
| 181 | + fi |
| 182 | + |
| 183 | + # Validate run_e2e_tests (specific allowed values) |
| 184 | + TEST_OPTION="${INPUT_RUN_E2E_TESTS:-GoldenPath-Testing}" |
| 185 | + if [[ "$TEST_OPTION" != "GoldenPath-Testing" && "$TEST_OPTION" != "Smoke-Testing" && "$TEST_OPTION" != "None" ]]; then |
| 186 | + echo "❌ ERROR: run_e2e_tests must be one of: GoldenPath-Testing, Smoke-Testing, None, got: '$TEST_OPTION'" |
| 187 | + VALIDATION_FAILED=true |
| 188 | + else |
| 189 | + echo "✅ run_e2e_tests: '$TEST_OPTION' is valid" |
| 190 | + fi |
| 191 | + |
| 192 | + # Validate AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID (optional, Azure Resource ID format) |
| 193 | + if [[ -n "$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" ]]; then |
| 194 | + 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 |
| 195 | + echo "❌ ERROR: AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID is invalid. Must be a valid Azure Resource ID format:" |
| 196 | + echo " /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.OperationalInsights/workspaces/{workspaceName}" |
| 197 | + echo " Got: '$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID'" |
| 198 | + VALIDATION_FAILED=true |
| 199 | + else |
| 200 | + echo "✅ AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: Valid Resource ID format" |
| 201 | + fi |
| 202 | + else |
| 203 | + echo "✅ AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: Not provided (optional)" |
| 204 | + fi |
| 205 | + |
| 206 | + # Validate AZURE_EXISTING_AI_PROJECT_RESOURCE_ID (optional, Azure Resource ID format) |
| 207 | + if [[ -n "$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" ]]; then |
| 208 | + 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 |
| 209 | + echo "❌ ERROR: AZURE_EXISTING_AI_PROJECT_RESOURCE_ID is invalid. Must be a valid Azure Resource ID format:" |
| 210 | + echo " /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.CognitiveServices/accounts/{accountName}/projects/{projectName}" |
| 211 | + echo " Got: '$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID'" |
| 212 | + VALIDATION_FAILED=true |
| 213 | + else |
| 214 | + echo "✅ AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: Valid Resource ID format" |
| 215 | + fi |
| 216 | + else |
| 217 | + echo "✅ AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: Not provided (optional)" |
| 218 | + fi |
| 219 | + |
| 220 | + # Validate existing_webapp_url (optional, must start with https) |
| 221 | + if [[ -n "$INPUT_EXISTING_WEBAPP_URL" ]]; then |
| 222 | + if [[ ! "$INPUT_EXISTING_WEBAPP_URL" =~ ^https:// ]]; then |
| 223 | + echo "❌ ERROR: existing_webapp_url must start with 'https://', got: '$INPUT_EXISTING_WEBAPP_URL'" |
| 224 | + VALIDATION_FAILED=true |
| 225 | + else |
| 226 | + echo "✅ existing_webapp_url: '$INPUT_EXISTING_WEBAPP_URL' is valid" |
| 227 | + fi |
| 228 | + else |
| 229 | + echo "✅ existing_webapp_url: Not provided (will perform deployment)" |
| 230 | + fi |
| 231 | + |
| 232 | + # Fail workflow if any validation failed |
| 233 | + if [[ "$VALIDATION_FAILED" == "true" ]]; then |
| 234 | + echo "" |
| 235 | + echo "❌ Parameter validation failed. Please correct the errors above and try again." |
| 236 | + exit 1 |
| 237 | + fi |
| 238 | + |
| 239 | + echo "" |
| 240 | + echo "✅ All input parameters validated successfully!" |
| 241 | + |
| 242 | + # Output validated values |
| 243 | + echo "passed=true" >> $GITHUB_OUTPUT |
| 244 | + echo "azure_location=$LOCATION" >> $GITHUB_OUTPUT |
| 245 | + echo "resource_group_name=$INPUT_RESOURCE_GROUP_NAME" >> $GITHUB_OUTPUT |
| 246 | + echo "waf_enabled=$WAF_ENABLED" >> $GITHUB_OUTPUT |
| 247 | + echo "exp=$EXP_ENABLED" >> $GITHUB_OUTPUT |
| 248 | + echo "build_docker_image=$BUILD_DOCKER" >> $GITHUB_OUTPUT |
| 249 | + echo "cleanup_resources=$CLEANUP_RESOURCES" >> $GITHUB_OUTPUT |
| 250 | + echo "run_e2e_tests=$TEST_OPTION" >> $GITHUB_OUTPUT |
| 251 | + echo "azure_env_log_analytics_workspace_id=$INPUT_AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID" >> $GITHUB_OUTPUT |
| 252 | + echo "azure_existing_ai_project_resource_id=$INPUT_AZURE_EXISTING_AI_PROJECT_RESOURCE_ID" >> $GITHUB_OUTPUT |
| 253 | + echo "existing_webapp_url=$INPUT_EXISTING_WEBAPP_URL" >> $GITHUB_OUTPUT |
| 254 | +
|
89 | 255 | Run: |
| 256 | + needs: validate-inputs |
| 257 | + if: needs.validate-inputs.outputs.validation_passed == 'true' |
90 | 258 | uses: ./.github/workflows/deploy-orchestrator.yml |
91 | 259 | with: |
92 | 260 | runner_os: ubuntu-latest |
93 | | - azure_location: ${{ github.event.inputs.azure_location || 'australiaeast' }} |
94 | | - resource_group_name: ${{ github.event.inputs.resource_group_name || '' }} |
95 | | - waf_enabled: ${{ github.event.inputs.waf_enabled == 'true' }} |
96 | | - EXP: ${{ github.event.inputs.EXP == 'true' }} |
97 | | - build_docker_image: ${{ github.event.inputs.build_docker_image == 'true' }} |
98 | | - cleanup_resources: ${{ github.event.inputs.cleanup_resources == 'true' }} |
99 | | - run_e2e_tests: ${{ github.event.inputs.run_e2e_tests || 'GoldenPath-Testing' }} |
100 | | - AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ github.event.inputs.AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID || '' }} |
101 | | - AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ github.event.inputs.AZURE_EXISTING_AI_PROJECT_RESOURCE_ID || '' }} |
102 | | - existing_webapp_url: ${{ github.event.inputs.existing_webapp_url || '' }} |
| 261 | + azure_location: ${{ needs.validate-inputs.outputs.azure_location || 'australiaeast' }} |
| 262 | + resource_group_name: ${{ needs.validate-inputs.outputs.resource_group_name || '' }} |
| 263 | + waf_enabled: ${{ needs.validate-inputs.outputs.waf_enabled == 'true' }} |
| 264 | + EXP: ${{ needs.validate-inputs.outputs.exp == 'true' }} |
| 265 | + build_docker_image: ${{ needs.validate-inputs.outputs.build_docker_image == 'true' }} |
| 266 | + cleanup_resources: ${{ needs.validate-inputs.outputs.cleanup_resources == 'true' }} |
| 267 | + run_e2e_tests: ${{ needs.validate-inputs.outputs.run_e2e_tests || 'GoldenPath-Testing' }} |
| 268 | + AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID: ${{ needs.validate-inputs.outputs.azure_env_log_analytics_workspace_id || '' }} |
| 269 | + AZURE_EXISTING_AI_PROJECT_RESOURCE_ID: ${{ needs.validate-inputs.outputs.azure_existing_ai_project_resource_id || '' }} |
| 270 | + existing_webapp_url: ${{ needs.validate-inputs.outputs.existing_webapp_url || '' }} |
103 | 271 | trigger_type: ${{ github.event_name }} |
104 | 272 | secrets: inherit |
0 commit comments