Revert "[PRM-193] - email and alerting alias check update #2
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: "Deploy - Stack" | ||
| on: | ||
| workflow_call: | ||
| inputs: | ||
| environment: | ||
| description: "Which Environment settings to use" | ||
| required: true | ||
| type: string | ||
| default: "dev" | ||
| is_deployment: | ||
| description: "Is workflow run on deployment" | ||
| type: boolean | ||
| default: false | ||
| terraform_stack: | ||
| description: "Which terraform stack directory to run" | ||
| type: string | ||
| required: true | ||
| build_lambda: | ||
| description: "Does the workflow need a lambdas build" | ||
| type: boolean | ||
| default: false | ||
| image_tag: | ||
| description: "Does the workflow need an image tag" | ||
| type: string | ||
| git_ref: | ||
| description: "The git_ref to checkout" | ||
| type: string | ||
| default: main | ||
| ecr_alias: | ||
| description: "ECR Repository Alias" | ||
| type: string | ||
| required: false | ||
| workflow_dispatch: | ||
| inputs: | ||
| environment: | ||
| description: "Which Environment settings to use" | ||
| required: true | ||
| type: string | ||
| default: "dev" | ||
| is_deployment: | ||
| description: "Is workflow run on deployment" | ||
| type: boolean | ||
| default: false | ||
| terraform_stack: | ||
| description: "Which terraform stack directory to run" | ||
| type: choice | ||
| options: | ||
| - email-and-alerting | ||
| - gp2gp-dashboard | ||
| - spine-exporter | ||
| - ods-downloader | ||
| - transfer-classifier | ||
| - metrics-calculator | ||
| - reports-generator | ||
| - validate_metrics | ||
| - step_function | ||
| required: true | ||
| build_lambda: | ||
| description: "Does the workflow need a lambdas build" | ||
| type: boolean | ||
| default: false | ||
| image_tag: | ||
| description: "Does the workflow need an image tag" | ||
| type: choice | ||
| options: | ||
| - gp2gp-dashboard | ||
| - spine_exporter | ||
| - ods_downloader | ||
| - transfer_classifier | ||
| - metrics_calculator | ||
| - reports_generator | ||
| git_ref: | ||
| description: "The git_ref to deploy" | ||
| type: string | ||
| default: main | ||
| jobs: | ||
| terraform_plan_and_apply: | ||
| runs-on: ubuntu-latest | ||
| environment: ${{ inputs.environment }} | ||
| defaults: | ||
| run: | ||
| working-directory: ./stacks/${{ inputs.terraform_stack }}/terraform | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v5 | ||
| with: | ||
| repository: NHSDigital/gp2gp-reporting-infrastructure | ||
| ref: ${{ inputs.git_ref }} | ||
| - name: Configure AWS Credentials | ||
| uses: aws-actions/configure-aws-credentials@v5 | ||
| with: | ||
| aws-region: ${{ vars.AWS_REGION }} | ||
| role-to-assume: ${{ inputs.is_deployment && secrets.AWS_ASSUME_ROLE || secrets.AWS_ASSUME_ROLE_READ_ONLY }} | ||
| role-skip-session-tagging: true | ||
| mask-aws-account-id: true | ||
| - name: Setup Python 3.14 | ||
| uses: actions/setup-python@v6 | ||
| with: | ||
| python-version: 3.14 | ||
| - name: Build Lambda Zip | ||
| if: inputs.build_lambda && inputs.terraform_stack | ||
| run: | | ||
| cd $GITHUB_WORKSPACE | ||
| chmod +x ./tasks_github_actions.sh | ||
| ./tasks_github_actions.sh build-lambdas | ||
| - name: Setup Terraform | ||
| uses: hashicorp/setup-terraform@v3 | ||
| with: | ||
| terraform_version: latest | ||
| - name: Terraform Format | ||
| id: fmt | ||
| run: terraform fmt -check | ||
| - name: Terraform Init | ||
| id: init | ||
| run: | | ||
| terraform init -no-color -backend-config="key=data-pipeline/${{ inputs.terraform_stack }}/terraform.tfstate" \ | ||
| -backend-config="bucket=${{ secrets.AWS_STATE_BUCKET }}" \ | ||
| -backend-config="dynamodb_table=${{ secrets.AWS_STATE_LOCK_TABLE }}" | ||
| shell: bash | ||
| - name: Terraform Validate | ||
| id: validate | ||
| run: terraform validate -no-color | ||
| - name: Setup Terraform variables | ||
| id: vars | ||
| run: |- | ||
| cat > pipeline.auto.tfvars <<EOF | ||
| environment = "${{ vars.AWS_ENVIRONMENT }}" | ||
| EOF | ||
| - name: Setup Terraform variables for Image Tag | ||
| id: vars-image-tag | ||
| if: inputs.image_tag | ||
| env: | ||
| ECR_ALIAS: ${{inputs.ecr_alias}} | ||
| run: |- | ||
| IMAGE_TAG=$(aws ecr describe-images --repository-name ${{ secrets.AWS_ECR_REPOSITORY }}${{ ECR_ALIAS }} --query 'sort_by(imageDetails,& imagePushedAt)[-1].imageTags[0]') | ||
| cat > pipeline.auto.tfvars <<EOF | ||
| ${{ inputs.image_tag }}_image_tag = $IMAGE_TAG | ||
| environment = "${{ vars.AWS_ENVIRONMENT }}" | ||
| EOF | ||
| - name: Setup Terraform variables for Build Lambda | ||
| id: update-lambdas-build-references | ||
| if: inputs.build_lambda | ||
| run: |- | ||
| image_key="${{ inputs.image_tag }}" | ||
| aws_env="${{ vars.AWS_ENVIRONMENT }}" | ||
| cat > pipeline.auto.tfvars <<EOF | ||
| environment = "$aws_env" | ||
| log_alerts_pipeline_error_lambda_zip = "$GITHUB_WORKSPACE/lambdas/build/log_alerts_pipeline_error.zip" | ||
| log_alerts_technical_failures_above_threshold_lambda_zip = "$GITHUB_WORKSPACE/lambdas/build/log_alerts_technical_failures_above_threshold.zip" | ||
| gp2gp_dashboard_alert_lambda_zip = "$GITHUB_WORKSPACE/lambdas/build/gp2gp_dashboard_alert.zip" | ||
| email_report_lambda_zip = "$GITHUB_WORKSPACE/lambdas/build/email_report.zip" | ||
| validate_metrics_lambda_zip = "$GITHUB_WORKSPACE/lambdas/build/validate_metrics.zip" | ||
| store_asid_lookup_lambda_zip = "$GITHUB_WORKSPACE/lambdas/build/store_asid_lookup.zip" | ||
| region = "${{ vars.AWS_REGION }}" | ||
| EOF | ||
| if [[ -n "$image_key" ]]; then | ||
| IMAGE_TAG=$(aws ecr describe-images --repository-name ${{ secrets.AWS_ECR_REPOSITORY }}${{ inputs.terraform_stack }} --query 'sort_by(imageDetails,& imagePushedAt)[-1].imageTags[0]') | ||
| image_tag=$IMAGE_TAG | ||
| echo "${image_key}_image_tag = $image_tag" >> pipeline.auto.tfvars | ||
| cat pipeline.auto.tfvars | ||
| fi | ||
| - name: Terraform Plan | ||
| id: plan | ||
| run: | | ||
| terraform plan -input=false -no-color -var-file="../vars/${{ vars.AWS_ENVIRONMENT }}.tfvars" -out ${{ vars.AWS_ENVIRONMENT }}.tfplan > plan_output.txt 2>&1 | ||
| terraform show -no-color ${{ vars.AWS_ENVIRONMENT }}.tfplan > tfplan.txt 2>&1 | ||
| # Mask sensitive URLs in the Terraform Plan output | ||
| grep -Eo 'https://[a-zA-Z0-9.-]+\.execute-api\.[a-zA-Z0-9.-]+\.amazonaws\.com/[a-zA-Z0-9/._-]*' tfplan.txt | while read -r api_url; do | ||
| if [ -n "$api_url" ]; then | ||
| echo "::add-mask::$api_url" | ||
| fi | ||
| done || echo "No api URLs found to mask." | ||
| # Mask Lambda invocation URLs | ||
| grep -Eo 'https://[a-zA-Z0-9.-]+\.lambda\.amazonaws\.com/[a-zA-Z0-9/._-]+' tfplan.txt | while read -r lambda_url; do | ||
| if [ -n "$lambda_url" ]; then | ||
| echo "::add-mask::$lambda_url" | ||
| fi | ||
| done || echo "No Lambda URLs found to mask." | ||
| # Mask AWS account IDs (12-digit numbers) | ||
| grep -Eo '[0-9]{12}' tfplan.txt | while read -r account_id; do | ||
| if [ -n "$account_id" ]; then | ||
| echo "::add-mask::$account_id" | ||
| fi | ||
| done || echo "No Account IDs found to mask." | ||
| # Mask GitHub secrets | ||
| echo "::add-mask::${{ secrets.AWS_ASSUME_ROLE }}" | ||
| echo "::add-mask::${{ secrets.GITHUB_TOKEN }}" | ||
| # Output the sanitized plan to logs | ||
| cat plan_output.txt | ||
| echo "summary=$(grep -E 'Plan: [0-9]+ to add, [0-9]+ to change, [0-9]+ to destroy\.|No changes\. Your infrastructure matches the configuration\.' tfplan.txt | sed 's/.*No changes\. Your infrastructure matches the configuration/Plan: no changes/g' | sed 's/.*Plan: //g' | sed 's/\..*//g')" >> $GITHUB_OUTPUT | ||
| shell: bash | ||
| - name: Truncate Plan Output | ||
| id: plan-truncated | ||
| if: success() || failure() | ||
| env: | ||
| LENGTH: 64512 | ||
| run: | | ||
| PLAN_FULL=$(grep -v 'Refreshing state...' <<'EOF' | ||
| ${{ steps.plan.outputs.stdout }} | ||
| ${{ steps.plan.outputs.stderr }} | ||
| EOF | ||
| ) | ||
| # Optionally redact sensitive strings in the PLAN_FULL variable | ||
| PLAN_FULL=$(echo "$PLAN_FULL" | sed -E 's#arn:aws:iam::[0-9]{12}:role/[a-zA-Z0-9_-]+#[REDACTED_IAM_ROLE_ARN]#g') | ||
| PLAN_FULL=$(echo "$PLAN_FULL" | sed -E 's/[0-9]{12}/[REDACTED_AWS_ACCOUNT_ID]/g') | ||
| PLAN_FULL=$(echo "$PLAN_FULL" | sed -E 's#https://[a-zA-Z0-9.-]+\.lambda\.amazonaws\.com/[a-zA-Z0-9/._-]+#[REDACTED_LAMBDA_URL]#g') | ||
| PLAN_FULL=$(echo "$PLAN_FULL" | sed -E 's#https://[a-zA-Z0-9.-]+\.execute-api\.[a-zA-Z0-9.-]+\.amazonaws\.com/[a-zA-Z0-9/._-]*#[REDACTED_API_GATEWAY_URL]#g') | ||
| echo "PLAN<<EOF" >> $GITHUB_ENV | ||
| echo "${PLAN_FULL::$LENGTH}" >> $GITHUB_ENV | ||
| [ ${#PLAN_FULL} -gt $LENGTH ] && echo "(truncated - see workflow logs for full output)" >> $GITHUB_ENV | ||
| echo "EOF" >> $GITHUB_ENV | ||
| working-directory: ./stacks/${{ inputs.terraform_stack }}/terraform | ||
| shell: bash | ||
| - name: Add PR comment | ||
| uses: actions/github-script@v8 | ||
| if: github.event_name == 'pull_request' && (success() || failure()) | ||
| with: | ||
| github-token: ${{ secrets.GITHUB_TOKEN }} | ||
| script: | | ||
| // 1. Retrieve existing bot comments for the PR | ||
| const { data: comments } = await github.rest.issues.listComments({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: context.issue.number, | ||
| }) | ||
| const botComment = comments.find(comment => { | ||
| return comment.user.type === 'Bot' && comment.body.includes('Report for ${{ inputs.terraform_stack }} on environment: ${{ vars.AWS_ENVIRONMENT }}') | ||
| }) | ||
| // 2. Prepare format of the comment | ||
| const output = `### Report for ${{ inputs.terraform_stack }} on environment: ${{ vars.AWS_ENVIRONMENT }} | ||
| #### Terraform Format and Style 🖌\`${{ steps.fmt.outcome }}\` | ||
| <details><summary>Format Output</summary> | ||
| \`\`\`\n | ||
| ${{ steps.fmt.outputs.stdout }} | ||
| \`\`\` | ||
| </details> | ||
| #### Terraform Initialization ⚙️\`${{ steps.init.outcome }}\` | ||
| <details><summary>Initialization Output</summary> | ||
| \`\`\`\n | ||
| ${{ steps.init.outputs.stdout }} | ||
| \`\`\` | ||
| </details> | ||
| #### Terraform Validation 🤖\`${{ steps.validate.outcome }}\` | ||
| <details><summary>Validation Output</summary> | ||
| \`\`\`\n | ||
| ${{ steps.validate.outputs.stdout }} | ||
| \`\`\` | ||
| </details> | ||
| #### Terraform Plan 📖\`${{ steps.plan.outcome }}\` | ||
| <details><summary>Show Plan (${{ steps.plan.outputs.summary }})</summary> | ||
| \`\`\`\n | ||
| ${{ steps.plan.outputs.stdout }} | ||
| \`\`\` | ||
| </details>`; | ||
| // 3. If we have a comment, update it, otherwise create a new one | ||
| if (botComment) { | ||
| github.rest.issues.deleteComment({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| comment_id: botComment.id, | ||
| body: output | ||
| }) | ||
| } | ||
| github.rest.issues.createComment({ | ||
| issue_number: context.issue.number, | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| body: output | ||
| }) | ||
| - name: Terraform Apply | ||
| if: github.ref == 'refs/heads/main' && inputs.is_deployment && inputs.environment != 'prod' | ||
| run: terraform apply -auto-approve -input=false ${{ vars.AWS_ENVIRONMENT }}.tfplan | ||