Skip to content

Revert "[PRM-193] - first alias update #1

Revert "[PRM-193] - first alias update

Revert "[PRM-193] - first alias update #1

Workflow file for this run

name: "Deploy - Stack"

Check failure on line 1 in .github/workflows/deploy-stack.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/deploy-stack.yml

Invalid workflow file

(Line: 145, Col: 14): Unrecognized named-value: 'ECR_ALIAS'. Located at position 1 within expression: ECR_ALIAS
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