From 80a71175c275be8e7f59ec01de8c691281dc789e Mon Sep 17 00:00:00 2001 From: Jhuliano Skittberg Moreno Date: Fri, 21 Aug 2026 11:16:47 +0200 Subject: [PATCH 1/4] feat(PLT-3863): add incident hotfix deploy support with war-room notifications --- .../workflows/frontend-deploy-workflow.yml | 56 ++++++++++++++++++- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/.github/workflows/frontend-deploy-workflow.yml b/.github/workflows/frontend-deploy-workflow.yml index aaba358..a2b0592 100644 --- a/.github/workflows/frontend-deploy-workflow.yml +++ b/.github/workflows/frontend-deploy-workflow.yml @@ -276,6 +276,12 @@ on: description: 'Slack channel for deployment notifications (e.g., tfprod-deploy)' type: string default: 'tfprod-deploy' + + # Incident hotfix + incident-number: + description: 'Incident ticket number (e.g. INC-1234). When set, validates INC-* format and posts a war-room notification before deploying.' + type: string + default: '' secrets: GH_TOKEN: required: true @@ -636,17 +642,20 @@ jobs: - integration-tests - cypress-functional - cypress-visual + - war-room-notification # Deploy only if: # - Build succeeded # - Each test job succeeded, OR was skipped (disabled via input OR skipped as already # verified on the PR). Failure or cancellation still blocks the deploy. + # - War-room notification succeeded (when incident-number is set), or was skipped (normal deploy) if: | always() && needs.build.result == 'success' && (needs.unit-tests.result == 'success' || needs.unit-tests.result == 'skipped') && (needs.integration-tests.result == 'success' || needs.integration-tests.result == 'skipped') && (needs.cypress-functional.result == 'success' || needs.cypress-functional.result == 'skipped') && - (needs.cypress-visual.result == 'success' || needs.cypress-visual.result == 'skipped') + (needs.cypress-visual.result == 'success' || needs.cypress-visual.result == 'skipped') && + (needs.war-room-notification.result == 'success' || needs.war-room-notification.result == 'skipped') runs-on: ${{ fromJSON(inputs.runner) }} timeout-minutes: ${{ inputs.deploy-timeout }} permissions: @@ -751,14 +760,42 @@ jobs: echo "📝 Commit: ${{ github.sha }}" echo "📋 Workflow: frontend-deploy-workflow-v2 (v2)" - # Job 9: Slack Notifications (runs after deploy completes) + # Job 9: War-room notification (incident hotfix deploys only) + war-room-notification: + name: 🚨 War-room notification + if: inputs.incident-number != '' + needs: [build] + runs-on: ubuntu-latest + timeout-minutes: 2 + + steps: + - name: Validate incident number + run: | + if [[ ! "${{ inputs.incident-number }}" =~ ^[Ii][Nn][Cc]- ]]; then + echo "::error::incident-number must start with 'INC-' (got: ${{ inputs.incident-number }})" + exit 1 + fi + + - name: Post to #war-room + uses: slackapi/slack-github-action@v3 + with: + method: chat.postMessage + token: ${{ secrets.SLACK_OAUTH_TOKEN }} + payload: | + { + "channel": "war-room", + "text": "🚨🚨🚨 Deployment due to incident ${{ inputs.incident-number }} of `${{ inputs.app-name }}@${{ github.sha }}` (branch `${{ github.ref_name }}`) to production by *${{ github.actor }}* (<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|logs>) <@tech-delivery-experience>", + "username": "Deploy Notifier" + } + + # Job 10: Slack Notifications (runs after deploy completes) notify-slack: name: 📢 Notify Slack if: always() && inputs.slack-channel != '' && needs.deploy.result != 'cancelled' needs: [deploy] runs-on: ubuntu-latest timeout-minutes: 2 - + steps: - name: Send deployment notification uses: Typeform/.github/shared-actions/slack-deployment-notification@v1 @@ -772,3 +809,16 @@ jobs: github-server-url: ${{ github.server_url }} github-run-id: ${{ github.run_id }} SLACK_BOT_TOKEN: ${{ secrets.SLACK_OAUTH_TOKEN }} + + - name: Send incident result to #war-room + if: inputs.incident-number != '' + uses: slackapi/slack-github-action@v3 + with: + method: chat.postMessage + token: ${{ secrets.SLACK_OAUTH_TOKEN }} + payload: | + { + "channel": "war-room", + "text": "${{ needs.deploy.result == 'success' && '✅' || '❌' }} Incident deployment ${{ needs.deploy.result }} — `${{ inputs.app-name }}` (${{ inputs.incident-number }}) (<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|logs>)", + "username": "Deploy Notifier" + } From d6b0b30e0fd27e3fbe0339a8ec46728849e6f7b9 Mon Sep 17 00:00:00 2001 From: Jhuliano Skittberg Moreno Date: Fri, 21 Aug 2026 11:17:39 +0200 Subject: [PATCH 2/4] chore: remove war-room result notification, tfprod-deploy is sufficient --- .github/workflows/frontend-deploy-workflow.yml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/.github/workflows/frontend-deploy-workflow.yml b/.github/workflows/frontend-deploy-workflow.yml index a2b0592..085f5d2 100644 --- a/.github/workflows/frontend-deploy-workflow.yml +++ b/.github/workflows/frontend-deploy-workflow.yml @@ -810,15 +810,3 @@ jobs: github-run-id: ${{ github.run_id }} SLACK_BOT_TOKEN: ${{ secrets.SLACK_OAUTH_TOKEN }} - - name: Send incident result to #war-room - if: inputs.incident-number != '' - uses: slackapi/slack-github-action@v3 - with: - method: chat.postMessage - token: ${{ secrets.SLACK_OAUTH_TOKEN }} - payload: | - { - "channel": "war-room", - "text": "${{ needs.deploy.result == 'success' && '✅' || '❌' }} Incident deployment ${{ needs.deploy.result }} — `${{ inputs.app-name }}` (${{ inputs.incident-number }}) (<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|logs>)", - "username": "Deploy Notifier" - } From fb980c5b015034c0784b5778298b500f21ab9dbb Mon Sep 17 00:00:00 2001 From: Jhuliano Skittberg Moreno Date: Fri, 21 Aug 2026 11:33:02 +0200 Subject: [PATCH 3/4] Fix step name on incident workflow --- .github/workflows/frontend-deploy-workflow.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/frontend-deploy-workflow.yml b/.github/workflows/frontend-deploy-workflow.yml index 085f5d2..cde99b7 100644 --- a/.github/workflows/frontend-deploy-workflow.yml +++ b/.github/workflows/frontend-deploy-workflow.yml @@ -776,7 +776,7 @@ jobs: exit 1 fi - - name: Post to #war-room + - name: Post to war-room uses: slackapi/slack-github-action@v3 with: method: chat.postMessage From 7368652fc44b23fd97ab3957856c52121bc9034c Mon Sep 17 00:00:00 2001 From: Jhuliano Skittberg Moreno Date: Fri, 21 Aug 2026 11:49:04 +0200 Subject: [PATCH 4/4] fix(PLT-3863): prevent script injection in war-room-notification run step --- .github/workflows/frontend-deploy-workflow.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/frontend-deploy-workflow.yml b/.github/workflows/frontend-deploy-workflow.yml index cde99b7..c8c4d0d 100644 --- a/.github/workflows/frontend-deploy-workflow.yml +++ b/.github/workflows/frontend-deploy-workflow.yml @@ -770,9 +770,11 @@ jobs: steps: - name: Validate incident number + env: + INCIDENT_NUMBER: ${{ inputs.incident-number }} run: | - if [[ ! "${{ inputs.incident-number }}" =~ ^[Ii][Nn][Cc]- ]]; then - echo "::error::incident-number must start with 'INC-' (got: ${{ inputs.incident-number }})" + if [[ ! "$INCIDENT_NUMBER" =~ ^[Ii][Nn][Cc]-[0-9]+$ ]]; then + echo "::error::incident-number must match INC- (got: $INCIDENT_NUMBER)" exit 1 fi