From 5dbb9862e645aabcf6616f4ecd2e1b39b7b689e3 Mon Sep 17 00:00:00 2001 From: oliverbeumkes-nhs Date: Tue, 24 Feb 2026 14:43:04 +0000 Subject: [PATCH 01/10] [PRM-691] Introduction of strict tagging when releasing --- .github/workflows/deploy-full.yml | 169 ----------------------------- .github/workflows/deploy-stack.yml | 36 ++---- 2 files changed, 12 insertions(+), 193 deletions(-) delete mode 100644 .github/workflows/deploy-full.yml diff --git a/.github/workflows/deploy-full.yml b/.github/workflows/deploy-full.yml deleted file mode 100644 index aa4f51e8..00000000 --- a/.github/workflows/deploy-full.yml +++ /dev/null @@ -1,169 +0,0 @@ -name: Deploy - Full - -run-name: "${{ inputs.environment }} | Terraform Apply? = ${{ inputs.is_deployment }}" - -on: - workflow_dispatch: - inputs: - environment: - default: "dev" - description: "Environment" - required: true - type: choice - options: - - dev - - pre-prod - - prod - is_deployment: - default: false - type: boolean - description: "Terraform Apply?" - -permissions: - pull-requests: write - id-token: write # This is required for requesting the JWT - contents: read # This is required for actions/checkout - -jobs: - deductions-ci: - name: Deploy Deductions Infrastructure - uses: ./.github/workflows/deploy-stack.yml - with: - stack: deductions - backend_key_alias: deductions-infra-${{ inputs.environment }} - environment: ${{ inputs.environment }} - is_deployment: ${{ inputs.is_deployment }} - lambdas_to_build: true - secrets: inherit - - deductions-cross-account: - name: Deploy Deductions Cross Account Infrastructure - uses: ./.github/workflows/deploy-stack.yml - with: - stack: deductions-cross-account - backend_key_alias: deductions-infra-cross-account-${{ inputs.environment }} - environment: ${{ inputs.environment }} - is_deployment: ${{ inputs.is_deployment }} - lambdas_to_build: true - secrets: inherit - - deductions-dashboard-ci: - name: Deploy Deductions Dashboard Infrastructure - uses: ./.github/workflows/deploy-stack.yml - needs: [deductions-ci] - with: - stack: deductions-dashboard - backend_key_alias: deductions-infra-dashboard-${{ inputs.environment }} - environment: ${{ inputs.environment }} - is_deployment: ${{ inputs.is_deployment }} - secrets: inherit - - mesh-forwarder-ci: - name: Deploy MESH Forwarder Infrastructure - needs: [deductions-ci, deductions-cross-account] - uses: ./.github/workflows/deploy-stack.yml - with: - stack: mesh-forwarder - ecr_alias: deductions/mesh-forwarder - environment: ${{ inputs.environment }} - is_deployment: ${{ inputs.is_deployment }} - secrets: inherit - - pds-adaptor-ci: - name: Deploy PDS Adaptor Infrastructure - needs: [deductions-ci, deductions-cross-account] - uses: ./.github/workflows/deploy-stack.yml - with: - stack: pds-adaptor - ecr_alias: deductions/pds-adaptor - environment: ${{ inputs.environment }} - is_deployment: ${{ inputs.is_deployment }} - secrets: inherit - - re-registration-service-ci: - name: Deploy Re-Registration Service Infrastructure - needs: [deductions-ci, deductions-cross-account] - uses: ./.github/workflows/deploy-stack.yml - with: - stack: re-registration-service - ecr_alias: repo/re-registration-service - environment: ${{ inputs.environment }} - is_deployment: ${{ inputs.is_deployment }} - secrets: inherit - - suspension-service-ci: - name: Deploy Suspension Service Infrastructure - needs: [deductions-ci, deductions-cross-account] - uses: ./.github/workflows/deploy-stack.yml - with: - stack: suspension-service - ecr_alias: repo/suspension-service - environment: ${{ inputs.environment }} - is_deployment: ${{ inputs.is_deployment }} - secrets: inherit - - nems-event-processor-ci: - name: Deploy NEMS Event Processor Infrastructure - needs: [deductions-ci, deductions-cross-account] - uses: ./.github/workflows/deploy-stack.yml - with: - stack: nems-event-processor - ecr_alias: deductions/nems-event-processor - environment: ${{ inputs.environment }} - is_deployment: ${{ inputs.is_deployment }} - secrets: inherit - - ehr-repo-ci: - name: EHR Repo Infrastructure - uses: ./.github/workflows/deploy-stack.yml - needs: [deductions-ci, deductions-cross-account] - with: - stack: ehr-repo - ecr_alias: deductions/ehr-repo - environment: ${{ inputs.environment }} - is_deployment: ${{ inputs.is_deployment }} - secrets: inherit - - ehr-out-service-ci: - name: Deploy EHR Out Service Infrastructure - uses: ./.github/workflows/deploy-stack.yml - needs: [deductions-ci, deductions-cross-account] - with: - stack: ehr-out-service - ecr_alias: deductions/ehr-out-service - environment: ${{ inputs.environment }} - is_deployment: ${{ inputs.is_deployment }} - secrets: inherit - - ehr-transfer-service-ci: - name: Deploy EHR Transfer Service Infrastructure - uses: ./.github/workflows/deploy-stack.yml - needs: [deductions-ci, deductions-cross-account] - with: - stack: ehr-transfer-service - ecr_alias: deductions/ehr-transfer-service - environment: ${{ inputs.environment }} - is_deployment: ${{ inputs.is_deployment }} - secrets: inherit - - gp2gp-messenger-ci: - name: Deploy GP2GP Messenger Infrastructure - uses: ./.github/workflows/deploy-stack.yml - needs: [deductions-ci, deductions-cross-account] - with: - stack: gp2gp-messenger - ecr_alias: deductions/gp2gp-messenger - environment: ${{ inputs.environment }} - is_deployment: ${{ inputs.is_deployment }} - secrets: inherit - - mhs-ci: - name: Deploy MHS Infrastructure - uses: ./.github/workflows/deploy-stack.yml - needs: [deductions-ci, deductions-cross-account] - with: - stack: mhs - backend_key_alias: mhs-${{ inputs.environment }}-repo - environment: ${{ inputs.environment }} - is_deployment: ${{ inputs.is_deployment }} - secrets: inherit diff --git a/.github/workflows/deploy-stack.yml b/.github/workflows/deploy-stack.yml index c61cfc46..7cafdb77 100644 --- a/.github/workflows/deploy-stack.yml +++ b/.github/workflows/deploy-stack.yml @@ -61,6 +61,10 @@ on: default: false type: boolean description: "Terraform Apply?" + is_release: + default: false + type: boolean + description: "Are we deploying a release version? If true, images will be promoted for a specific" ci_account: default: false description: "Are we deploying to the CI account?" @@ -84,6 +88,8 @@ jobs: - name: Checkout id: checkout uses: actions/checkout@v6 + with: + ref: refs/tags/${{ github.ref_name }} - name: Configure AWS Credentials id: creds @@ -100,40 +106,22 @@ jobs: with: registries: "${{ steps.creds.outputs.aws-account-id }},${{ secrets.AWS_SOURCE_ECR_ACCOUNT_ID }}" - - name: Get Most Recent ECR Image SHA Tag From Lower Environment - id: get-image-tag - env: - ECR_ALIAS: ${{ inputs.ecr_alias }} - run: | - LATEST_IMAGE_SHA=$(aws ecr describe-images \ - --registry-id ${{ secrets.AWS_SOURCE_ECR_ACCOUNT_ID }} \ - --repository-name $ECR_ALIAS \ - --output json | - jq -r ' - .imageDetails - | map(select(.imageTags != null and (.imageTags|length>0))) - | sort_by(.imagePushedAt) - | last - | .imageTags[] - | select(test("^[0-9a-f]{40}$")) - ' | head -n 1) - - echo "All image tags for $ECR_ALIAS: $LATEST_IMAGE_SHA" - echo "image_sha=$LATEST_IMAGE_SHA" >> $GITHUB_OUTPUT - - name: ECR Copy id: ecr-copy env: - IMAGE_SHA: "${{ steps.get-image-tag.outputs.image_sha }}" + IMAGE_SHA: ${{ github.sha }} + IMAGE_TAG: ${{ github.ref_name }} run: | source_repo=${{ secrets.AWS_SOURCE_ECR_ACCOUNT_ID }}.dkr.ecr.eu-west-2.amazonaws.com/${{ inputs.ecr_alias }} destination_repo=${{ steps.creds.outputs.aws-account-id }}.dkr.ecr.eu-west-2.amazonaws.com/${{ inputs.ecr_alias }} docker pull $source_repo:$IMAGE_SHA docker tag $source_repo:$IMAGE_SHA $destination_repo:$IMAGE_SHA - docker tag $source_repo:$IMAGE_SHA $destination_repo:${{ github.ref_name }} + docker tag $source_repo:$IMAGE_SHA $destination_repo:$IMAGE_TAG + docker tag $source_repo:$IMAGE_SHA $source_repo:$IMAGE_TAG docker push $destination_repo:$IMAGE_SHA - docker push $destination_repo:${{ github.ref_name }} + docker push $destination_repo:$IMAGE_TAG + docker push $source_repo:$IMAGE_TAG deploy_stack: environment: ${{ !inputs.ci_account && inputs.environment || 'ci_account' }} From a6ad6fc86837f48d25bd0b3b348b6b72f4fd7495 Mon Sep 17 00:00:00 2001 From: oliverbeumkes-nhs Date: Tue, 24 Feb 2026 14:44:37 +0000 Subject: [PATCH 02/10] [PRM-691] Introduction of strict tagging when releasing --- .github/workflows/deploy-full.yml | 168 ++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 .github/workflows/deploy-full.yml diff --git a/.github/workflows/deploy-full.yml b/.github/workflows/deploy-full.yml new file mode 100644 index 00000000..6b2e10a9 --- /dev/null +++ b/.github/workflows/deploy-full.yml @@ -0,0 +1,168 @@ +name: Deploy - Tagged version +run-name: "${{ inputs.environment }} | Terraform Apply? = ${{ inputs.is_deployment }} | Tag version: ${{ github.ref }}" + +on: + workflow_dispatch: + inputs: + environment: + default: "dev" + description: "Environment" + required: true + type: choice + options: + - dev + - pre-prod + - prod + is_deployment: + default: false + type: boolean + description: "Terraform Apply?" + +permissions: + pull-requests: write + id-token: write # This is required for requesting the JWT + contents: read # This is required for actions/checkout + +jobs: + deductions-ci: + name: Deploy Deductions Infrastructure + uses: ./.github/workflows/deploy-stack.yml + with: + stack: deductions + backend_key_alias: deductions-infra-${{ inputs.environment }} + environment: ${{ inputs.environment }} + is_deployment: ${{ inputs.is_deployment }} + lambdas_to_build: true + secrets: inherit + + deductions-cross-account: + name: Deploy Deductions Cross Account Infrastructure + uses: ./.github/workflows/deploy-stack.yml + with: + stack: deductions-cross-account + backend_key_alias: deductions-infra-cross-account-${{ inputs.environment }} + environment: ${{ inputs.environment }} + + lambdas_to_build: true + secrets: inherit + + deductions-dashboard-ci: + name: Deploy Deductions Dashboard Infrastructure + uses: ./.github/workflows/deploy-stack.yml + needs: [deductions-ci] + with: + stack: deductions-dashboard + backend_key_alias: deductions-infra-dashboard-${{ inputs.environment }} + environment: ${{ inputs.environment }} + is_deployment: ${{ inputs.is_deployment }} + secrets: inherit + + mesh-forwarder-ci: + name: Deploy MESH Forwarder Infrastructure + needs: [deductions-ci, deductions-cross-account] + uses: ./.github/workflows/deploy-stack.yml + with: + stack: mesh-forwarder + ecr_alias: deductions/mesh-forwarder + environment: ${{ inputs.environment }} + is_deployment: ${{ inputs.is_deployment }} + secrets: inherit + + pds-adaptor-ci: + name: Deploy PDS Adaptor Infrastructure + needs: [deductions-ci, deductions-cross-account] + uses: ./.github/workflows/deploy-stack.yml + with: + stack: pds-adaptor + ecr_alias: deductions/pds-adaptor + environment: ${{ inputs.environment }} + is_deployment: ${{ inputs.is_deployment }} + secrets: inherit + + re-registration-service-ci: + name: Deploy Re-Registration Service Infrastructure + needs: [deductions-ci, deductions-cross-account] + uses: ./.github/workflows/deploy-stack.yml + with: + stack: re-registration-service + ecr_alias: repo/re-registration-service + environment: ${{ inputs.environment }} + is_deployment: ${{ inputs.is_deployment }} + secrets: inherit + + suspension-service-ci: + name: Deploy Suspension Service Infrastructure + needs: [deductions-ci, deductions-cross-account] + uses: ./.github/workflows/deploy-stack.yml + with: + stack: suspension-service + ecr_alias: repo/suspension-service + environment: ${{ inputs.environment }} + is_deployment: ${{ inputs.is_deployment }} + secrets: inherit + + nems-event-processor-ci: + name: Deploy NEMS Event Processor Infrastructure + needs: [deductions-ci, deductions-cross-account] + uses: ./.github/workflows/deploy-stack.yml + with: + stack: nems-event-processor + ecr_alias: deductions/nems-event-processor + environment: ${{ inputs.environment }} + is_deployment: ${{ inputs.is_deployment }} + secrets: inherit + + ehr-repo-ci: + name: EHR Repo Infrastructure + uses: ./.github/workflows/deploy-stack.yml + needs: [deductions-ci, deductions-cross-account] + with: + stack: ehr-repo + ecr_alias: deductions/ehr-repo + environment: ${{ inputs.environment }} + is_deployment: ${{ inputs.is_deployment }} + secrets: inherit + + ehr-out-service-ci: + name: Deploy EHR Out Service Infrastructure + uses: ./.github/workflows/deploy-stack.yml + needs: [deductions-ci, deductions-cross-account] + with: + stack: ehr-out-service + ecr_alias: deductions/ehr-out-service + environment: ${{ inputs.environment }} + is_deployment: ${{ inputs.is_deployment }} + secrets: inherit + + ehr-transfer-service-ci: + name: Deploy EHR Transfer Service Infrastructure + uses: ./.github/workflows/deploy-stack.yml + needs: [deductions-ci, deductions-cross-account] + with: + stack: ehr-transfer-service + ecr_alias: deductions/ehr-transfer-service + environment: ${{ inputs.environment }} + is_deployment: ${{ inputs.is_deployment }} + secrets: inherit + + gp2gp-messenger-ci: + name: Deploy GP2GP Messenger Infrastructure + uses: ./.github/workflows/deploy-stack.yml + needs: [deductions-ci, deductions-cross-account] + with: + stack: gp2gp-messenger + ecr_alias: deductions/gp2gp-messenger + environment: ${{ inputs.environment }} + is_deployment: ${{ inputs.is_deployment }} + secrets: inherit + + mhs-ci: + name: Deploy MHS Infrastructure + uses: ./.github/workflows/deploy-stack.yml + needs: [deductions-ci, deductions-cross-account] + with: + stack: mhs + backend_key_alias: mhs-${{ inputs.environment }}-repo + environment: ${{ inputs.environment }} + is_deployment: ${{ inputs.is_deployment }} + secrets: inherit From b5e424b178e1305b31f943de98917b34ac534f2e Mon Sep 17 00:00:00 2001 From: oliverbeumkes-nhs Date: Tue, 24 Feb 2026 14:54:53 +0000 Subject: [PATCH 03/10] Added the is_deployment missing on deploy - full --- .github/workflows/deploy-full.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-full.yml b/.github/workflows/deploy-full.yml index 6b2e10a9..2968012b 100644 --- a/.github/workflows/deploy-full.yml +++ b/.github/workflows/deploy-full.yml @@ -42,7 +42,7 @@ jobs: stack: deductions-cross-account backend_key_alias: deductions-infra-cross-account-${{ inputs.environment }} environment: ${{ inputs.environment }} - + is_deployment: ${{ inputs.is_deployment }} lambdas_to_build: true secrets: inherit From be98883b4266eb22e702cd2a136409e10a6315df Mon Sep 17 00:00:00 2001 From: oliverbeumkes-nhs Date: Tue, 24 Feb 2026 15:06:01 +0000 Subject: [PATCH 04/10] Renamed Deploy Full to Deploy - Tagged Version --- .github/workflows/deploy-full.yml | 168 ------------------------------ 1 file changed, 168 deletions(-) delete mode 100644 .github/workflows/deploy-full.yml diff --git a/.github/workflows/deploy-full.yml b/.github/workflows/deploy-full.yml deleted file mode 100644 index 2968012b..00000000 --- a/.github/workflows/deploy-full.yml +++ /dev/null @@ -1,168 +0,0 @@ -name: Deploy - Tagged version -run-name: "${{ inputs.environment }} | Terraform Apply? = ${{ inputs.is_deployment }} | Tag version: ${{ github.ref }}" - -on: - workflow_dispatch: - inputs: - environment: - default: "dev" - description: "Environment" - required: true - type: choice - options: - - dev - - pre-prod - - prod - is_deployment: - default: false - type: boolean - description: "Terraform Apply?" - -permissions: - pull-requests: write - id-token: write # This is required for requesting the JWT - contents: read # This is required for actions/checkout - -jobs: - deductions-ci: - name: Deploy Deductions Infrastructure - uses: ./.github/workflows/deploy-stack.yml - with: - stack: deductions - backend_key_alias: deductions-infra-${{ inputs.environment }} - environment: ${{ inputs.environment }} - is_deployment: ${{ inputs.is_deployment }} - lambdas_to_build: true - secrets: inherit - - deductions-cross-account: - name: Deploy Deductions Cross Account Infrastructure - uses: ./.github/workflows/deploy-stack.yml - with: - stack: deductions-cross-account - backend_key_alias: deductions-infra-cross-account-${{ inputs.environment }} - environment: ${{ inputs.environment }} - is_deployment: ${{ inputs.is_deployment }} - lambdas_to_build: true - secrets: inherit - - deductions-dashboard-ci: - name: Deploy Deductions Dashboard Infrastructure - uses: ./.github/workflows/deploy-stack.yml - needs: [deductions-ci] - with: - stack: deductions-dashboard - backend_key_alias: deductions-infra-dashboard-${{ inputs.environment }} - environment: ${{ inputs.environment }} - is_deployment: ${{ inputs.is_deployment }} - secrets: inherit - - mesh-forwarder-ci: - name: Deploy MESH Forwarder Infrastructure - needs: [deductions-ci, deductions-cross-account] - uses: ./.github/workflows/deploy-stack.yml - with: - stack: mesh-forwarder - ecr_alias: deductions/mesh-forwarder - environment: ${{ inputs.environment }} - is_deployment: ${{ inputs.is_deployment }} - secrets: inherit - - pds-adaptor-ci: - name: Deploy PDS Adaptor Infrastructure - needs: [deductions-ci, deductions-cross-account] - uses: ./.github/workflows/deploy-stack.yml - with: - stack: pds-adaptor - ecr_alias: deductions/pds-adaptor - environment: ${{ inputs.environment }} - is_deployment: ${{ inputs.is_deployment }} - secrets: inherit - - re-registration-service-ci: - name: Deploy Re-Registration Service Infrastructure - needs: [deductions-ci, deductions-cross-account] - uses: ./.github/workflows/deploy-stack.yml - with: - stack: re-registration-service - ecr_alias: repo/re-registration-service - environment: ${{ inputs.environment }} - is_deployment: ${{ inputs.is_deployment }} - secrets: inherit - - suspension-service-ci: - name: Deploy Suspension Service Infrastructure - needs: [deductions-ci, deductions-cross-account] - uses: ./.github/workflows/deploy-stack.yml - with: - stack: suspension-service - ecr_alias: repo/suspension-service - environment: ${{ inputs.environment }} - is_deployment: ${{ inputs.is_deployment }} - secrets: inherit - - nems-event-processor-ci: - name: Deploy NEMS Event Processor Infrastructure - needs: [deductions-ci, deductions-cross-account] - uses: ./.github/workflows/deploy-stack.yml - with: - stack: nems-event-processor - ecr_alias: deductions/nems-event-processor - environment: ${{ inputs.environment }} - is_deployment: ${{ inputs.is_deployment }} - secrets: inherit - - ehr-repo-ci: - name: EHR Repo Infrastructure - uses: ./.github/workflows/deploy-stack.yml - needs: [deductions-ci, deductions-cross-account] - with: - stack: ehr-repo - ecr_alias: deductions/ehr-repo - environment: ${{ inputs.environment }} - is_deployment: ${{ inputs.is_deployment }} - secrets: inherit - - ehr-out-service-ci: - name: Deploy EHR Out Service Infrastructure - uses: ./.github/workflows/deploy-stack.yml - needs: [deductions-ci, deductions-cross-account] - with: - stack: ehr-out-service - ecr_alias: deductions/ehr-out-service - environment: ${{ inputs.environment }} - is_deployment: ${{ inputs.is_deployment }} - secrets: inherit - - ehr-transfer-service-ci: - name: Deploy EHR Transfer Service Infrastructure - uses: ./.github/workflows/deploy-stack.yml - needs: [deductions-ci, deductions-cross-account] - with: - stack: ehr-transfer-service - ecr_alias: deductions/ehr-transfer-service - environment: ${{ inputs.environment }} - is_deployment: ${{ inputs.is_deployment }} - secrets: inherit - - gp2gp-messenger-ci: - name: Deploy GP2GP Messenger Infrastructure - uses: ./.github/workflows/deploy-stack.yml - needs: [deductions-ci, deductions-cross-account] - with: - stack: gp2gp-messenger - ecr_alias: deductions/gp2gp-messenger - environment: ${{ inputs.environment }} - is_deployment: ${{ inputs.is_deployment }} - secrets: inherit - - mhs-ci: - name: Deploy MHS Infrastructure - uses: ./.github/workflows/deploy-stack.yml - needs: [deductions-ci, deductions-cross-account] - with: - stack: mhs - backend_key_alias: mhs-${{ inputs.environment }}-repo - environment: ${{ inputs.environment }} - is_deployment: ${{ inputs.is_deployment }} - secrets: inherit From 6293d10c602b58d12636142896f99e26d77f1025 Mon Sep 17 00:00:00 2001 From: oliverbeumkes-nhs Date: Tue, 24 Feb 2026 15:06:59 +0000 Subject: [PATCH 05/10] Renamed Deploy Full to Deploy - Tagged Version --- .github/workflows/deploy-tagged-version.yml | 168 ++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 .github/workflows/deploy-tagged-version.yml diff --git a/.github/workflows/deploy-tagged-version.yml b/.github/workflows/deploy-tagged-version.yml new file mode 100644 index 00000000..2968012b --- /dev/null +++ b/.github/workflows/deploy-tagged-version.yml @@ -0,0 +1,168 @@ +name: Deploy - Tagged version +run-name: "${{ inputs.environment }} | Terraform Apply? = ${{ inputs.is_deployment }} | Tag version: ${{ github.ref }}" + +on: + workflow_dispatch: + inputs: + environment: + default: "dev" + description: "Environment" + required: true + type: choice + options: + - dev + - pre-prod + - prod + is_deployment: + default: false + type: boolean + description: "Terraform Apply?" + +permissions: + pull-requests: write + id-token: write # This is required for requesting the JWT + contents: read # This is required for actions/checkout + +jobs: + deductions-ci: + name: Deploy Deductions Infrastructure + uses: ./.github/workflows/deploy-stack.yml + with: + stack: deductions + backend_key_alias: deductions-infra-${{ inputs.environment }} + environment: ${{ inputs.environment }} + is_deployment: ${{ inputs.is_deployment }} + lambdas_to_build: true + secrets: inherit + + deductions-cross-account: + name: Deploy Deductions Cross Account Infrastructure + uses: ./.github/workflows/deploy-stack.yml + with: + stack: deductions-cross-account + backend_key_alias: deductions-infra-cross-account-${{ inputs.environment }} + environment: ${{ inputs.environment }} + is_deployment: ${{ inputs.is_deployment }} + lambdas_to_build: true + secrets: inherit + + deductions-dashboard-ci: + name: Deploy Deductions Dashboard Infrastructure + uses: ./.github/workflows/deploy-stack.yml + needs: [deductions-ci] + with: + stack: deductions-dashboard + backend_key_alias: deductions-infra-dashboard-${{ inputs.environment }} + environment: ${{ inputs.environment }} + is_deployment: ${{ inputs.is_deployment }} + secrets: inherit + + mesh-forwarder-ci: + name: Deploy MESH Forwarder Infrastructure + needs: [deductions-ci, deductions-cross-account] + uses: ./.github/workflows/deploy-stack.yml + with: + stack: mesh-forwarder + ecr_alias: deductions/mesh-forwarder + environment: ${{ inputs.environment }} + is_deployment: ${{ inputs.is_deployment }} + secrets: inherit + + pds-adaptor-ci: + name: Deploy PDS Adaptor Infrastructure + needs: [deductions-ci, deductions-cross-account] + uses: ./.github/workflows/deploy-stack.yml + with: + stack: pds-adaptor + ecr_alias: deductions/pds-adaptor + environment: ${{ inputs.environment }} + is_deployment: ${{ inputs.is_deployment }} + secrets: inherit + + re-registration-service-ci: + name: Deploy Re-Registration Service Infrastructure + needs: [deductions-ci, deductions-cross-account] + uses: ./.github/workflows/deploy-stack.yml + with: + stack: re-registration-service + ecr_alias: repo/re-registration-service + environment: ${{ inputs.environment }} + is_deployment: ${{ inputs.is_deployment }} + secrets: inherit + + suspension-service-ci: + name: Deploy Suspension Service Infrastructure + needs: [deductions-ci, deductions-cross-account] + uses: ./.github/workflows/deploy-stack.yml + with: + stack: suspension-service + ecr_alias: repo/suspension-service + environment: ${{ inputs.environment }} + is_deployment: ${{ inputs.is_deployment }} + secrets: inherit + + nems-event-processor-ci: + name: Deploy NEMS Event Processor Infrastructure + needs: [deductions-ci, deductions-cross-account] + uses: ./.github/workflows/deploy-stack.yml + with: + stack: nems-event-processor + ecr_alias: deductions/nems-event-processor + environment: ${{ inputs.environment }} + is_deployment: ${{ inputs.is_deployment }} + secrets: inherit + + ehr-repo-ci: + name: EHR Repo Infrastructure + uses: ./.github/workflows/deploy-stack.yml + needs: [deductions-ci, deductions-cross-account] + with: + stack: ehr-repo + ecr_alias: deductions/ehr-repo + environment: ${{ inputs.environment }} + is_deployment: ${{ inputs.is_deployment }} + secrets: inherit + + ehr-out-service-ci: + name: Deploy EHR Out Service Infrastructure + uses: ./.github/workflows/deploy-stack.yml + needs: [deductions-ci, deductions-cross-account] + with: + stack: ehr-out-service + ecr_alias: deductions/ehr-out-service + environment: ${{ inputs.environment }} + is_deployment: ${{ inputs.is_deployment }} + secrets: inherit + + ehr-transfer-service-ci: + name: Deploy EHR Transfer Service Infrastructure + uses: ./.github/workflows/deploy-stack.yml + needs: [deductions-ci, deductions-cross-account] + with: + stack: ehr-transfer-service + ecr_alias: deductions/ehr-transfer-service + environment: ${{ inputs.environment }} + is_deployment: ${{ inputs.is_deployment }} + secrets: inherit + + gp2gp-messenger-ci: + name: Deploy GP2GP Messenger Infrastructure + uses: ./.github/workflows/deploy-stack.yml + needs: [deductions-ci, deductions-cross-account] + with: + stack: gp2gp-messenger + ecr_alias: deductions/gp2gp-messenger + environment: ${{ inputs.environment }} + is_deployment: ${{ inputs.is_deployment }} + secrets: inherit + + mhs-ci: + name: Deploy MHS Infrastructure + uses: ./.github/workflows/deploy-stack.yml + needs: [deductions-ci, deductions-cross-account] + with: + stack: mhs + backend_key_alias: mhs-${{ inputs.environment }}-repo + environment: ${{ inputs.environment }} + is_deployment: ${{ inputs.is_deployment }} + secrets: inherit From fad9a8ff8d6898c75e18e560c53d9fd4de417f3a Mon Sep 17 00:00:00 2001 From: oliverbeumkes-nhs Date: Tue, 24 Feb 2026 15:29:44 +0000 Subject: [PATCH 06/10] Creating override branch for PRM-691 override --- .github/workflows/deploy-stack.yml | 9 +- .github/workflows/deploy-tagged-version.yml | 18 +++ .../end-of-transfer-service.tfvars | 13 ++ test.sh | 129 ++++++++++++++++++ 4 files changed, 167 insertions(+), 2 deletions(-) create mode 100644 stacks/suspension-service/terraform/configs/end-of-transfer-service/end-of-transfer-service.tfvars create mode 100755 test.sh diff --git a/.github/workflows/deploy-stack.yml b/.github/workflows/deploy-stack.yml index 7cafdb77..851ffa2b 100644 --- a/.github/workflows/deploy-stack.yml +++ b/.github/workflows/deploy-stack.yml @@ -73,6 +73,11 @@ on: default: false description: "Do we need to build any lambdas before deploying?" type: boolean + override_tag: + default: "" + description: "Override tag to deploy (defaults to the github ref that triggered this workflow)" + required: false + type: string permissions: pull-requests: write @@ -110,7 +115,7 @@ jobs: id: ecr-copy env: IMAGE_SHA: ${{ github.sha }} - IMAGE_TAG: ${{ github.ref_name }} + IMAGE_TAG: ${{ inputs.override_tag || github.ref_name }} run: | source_repo=${{ secrets.AWS_SOURCE_ECR_ACCOUNT_ID }}.dkr.ecr.eu-west-2.amazonaws.com/${{ inputs.ecr_alias }} destination_repo=${{ steps.creds.outputs.aws-account-id }}.dkr.ecr.eu-west-2.amazonaws.com/${{ inputs.ecr_alias }} @@ -165,7 +170,7 @@ jobs: - name: Get Most Recent ECR Image Tag id: get-image-tag - if: inputs.ecr_alias + if: inputs.ecr_alias && !inputs.override_tag env: ECR_ALIAS: ${{ inputs.ecr_alias }} run: | diff --git a/.github/workflows/deploy-tagged-version.yml b/.github/workflows/deploy-tagged-version.yml index 2968012b..dc757905 100644 --- a/.github/workflows/deploy-tagged-version.yml +++ b/.github/workflows/deploy-tagged-version.yml @@ -17,6 +17,11 @@ on: default: false type: boolean description: "Terraform Apply?" + override_tag: + default: "" + description: "Override tag to deploy (defaults to the github ref that triggered this workflow)" + required: false + type: string permissions: pull-requests: write @@ -32,6 +37,7 @@ jobs: backend_key_alias: deductions-infra-${{ inputs.environment }} environment: ${{ inputs.environment }} is_deployment: ${{ inputs.is_deployment }} + override_tag: ${{ inputs.override_tag }} lambdas_to_build: true secrets: inherit @@ -43,6 +49,7 @@ jobs: backend_key_alias: deductions-infra-cross-account-${{ inputs.environment }} environment: ${{ inputs.environment }} is_deployment: ${{ inputs.is_deployment }} + override_tag: ${{ inputs.override_tag }} lambdas_to_build: true secrets: inherit @@ -55,6 +62,7 @@ jobs: backend_key_alias: deductions-infra-dashboard-${{ inputs.environment }} environment: ${{ inputs.environment }} is_deployment: ${{ inputs.is_deployment }} + override_tag: ${{ inputs.override_tag }} secrets: inherit mesh-forwarder-ci: @@ -66,6 +74,7 @@ jobs: ecr_alias: deductions/mesh-forwarder environment: ${{ inputs.environment }} is_deployment: ${{ inputs.is_deployment }} + override_tag: ${{ inputs.override_tag }} secrets: inherit pds-adaptor-ci: @@ -77,6 +86,7 @@ jobs: ecr_alias: deductions/pds-adaptor environment: ${{ inputs.environment }} is_deployment: ${{ inputs.is_deployment }} + override_tag: ${{ inputs.override_tag }} secrets: inherit re-registration-service-ci: @@ -88,6 +98,7 @@ jobs: ecr_alias: repo/re-registration-service environment: ${{ inputs.environment }} is_deployment: ${{ inputs.is_deployment }} + override_tag: ${{ inputs.override_tag }} secrets: inherit suspension-service-ci: @@ -99,6 +110,7 @@ jobs: ecr_alias: repo/suspension-service environment: ${{ inputs.environment }} is_deployment: ${{ inputs.is_deployment }} + override_tag: ${{ inputs.override_tag }} secrets: inherit nems-event-processor-ci: @@ -110,6 +122,7 @@ jobs: ecr_alias: deductions/nems-event-processor environment: ${{ inputs.environment }} is_deployment: ${{ inputs.is_deployment }} + override_tag: ${{ inputs.override_tag }} secrets: inherit ehr-repo-ci: @@ -121,6 +134,7 @@ jobs: ecr_alias: deductions/ehr-repo environment: ${{ inputs.environment }} is_deployment: ${{ inputs.is_deployment }} + override_tag: ${{ inputs.override_tag }} secrets: inherit ehr-out-service-ci: @@ -132,6 +146,7 @@ jobs: ecr_alias: deductions/ehr-out-service environment: ${{ inputs.environment }} is_deployment: ${{ inputs.is_deployment }} + override_tag: ${{ inputs.override_tag }} secrets: inherit ehr-transfer-service-ci: @@ -143,6 +158,7 @@ jobs: ecr_alias: deductions/ehr-transfer-service environment: ${{ inputs.environment }} is_deployment: ${{ inputs.is_deployment }} + override_tag: ${{ inputs.override_tag }} secrets: inherit gp2gp-messenger-ci: @@ -154,6 +170,7 @@ jobs: ecr_alias: deductions/gp2gp-messenger environment: ${{ inputs.environment }} is_deployment: ${{ inputs.is_deployment }} + override_tag: ${{ inputs.override_tag }} secrets: inherit mhs-ci: @@ -165,4 +182,5 @@ jobs: backend_key_alias: mhs-${{ inputs.environment }}-repo environment: ${{ inputs.environment }} is_deployment: ${{ inputs.is_deployment }} + override_tag: ${{ inputs.override_tag }} secrets: inherit diff --git a/stacks/suspension-service/terraform/configs/end-of-transfer-service/end-of-transfer-service.tfvars b/stacks/suspension-service/terraform/configs/end-of-transfer-service/end-of-transfer-service.tfvars new file mode 100644 index 00000000..874c1f2d --- /dev/null +++ b/stacks/suspension-service/terraform/configs/end-of-transfer-service/end-of-transfer-service.tfvars @@ -0,0 +1,13 @@ +environment = "dev" + +synthetic_patient_prefix = "96937" +process_only_synthetic_patients = false + +ecs_desired_count = 0 +repo_process_only_safe_listed_ods_codes = true +component_name = "end-of-transfer-service" +repo_name = "end-of-transfer-service" +metric_namespace = "EndOfTransferService" + +can_update_managing_organisation_to_repo = false +is_end_of_transfer_service = true diff --git a/test.sh b/test.sh new file mode 100755 index 00000000..9c547cce --- /dev/null +++ b/test.sh @@ -0,0 +1,129 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Usage: +# ./resolve_sha_from_tag_ecr.sh [region] +# +# Examples: +# ./resolve_sha_from_tag_ecr.sh my-service v1.2.3 eu-west-1 +# AWS_REGION=eu-west-1 ./resolve_sha_from_tag_ecr.sh my-service v1.2.3 +# +# Requirements: +# - awscli configured (creds + permissions to ecr:DescribeImages) +# - jq (optional; this script avoids jq by default) +# - docker (only if not DRY_RUN) +# +# Optional env: +# DRY_RUN=1 -> don't docker pull/tag/push +# SHA_TAG_REGEX='^sha-[0-9a-f]{7,40}$' -> override SHA tag matcher +# ECR_REGISTRY='123456789012.dkr.ecr.eu-west-1.amazonaws.com' -> if you want push/pull by full URI + +if [[ $# -lt 2 || $# -gt 3 ]]; then + echo "Usage: $0 [region]" + exit 1 +fi + +REPO="$1" +ROLLBACK_TAG="$2" +REGION="${3:-${AWS_REGION:-}}" + +if [[ -z "$REGION" ]]; then + echo "Region not set. Provide as 3rd arg or set AWS_REGION." + exit 1 +fi + +SHA_TAG_REGEX="${SHA_TAG_REGEX:-^[0-9a-f]{7,40}$}" + +echo "Repository: $REPO" +echo "Rollback tag: $ROLLBACK_TAG" +echo "Region: $REGION" +echo + +# 1) rollback tag -> digest +echo "Resolving digest for tag: $ROLLBACK_TAG ..." +DIGEST="$( + aws ecr describe-images \ + --region "$REGION" \ + --repository-name "$REPO" \ + --image-ids "imageTag=$ROLLBACK_TAG" \ + --query 'imageDetails[0].imageDigest' \ + --output text +)" + +if [[ -z "$DIGEST" || "$DIGEST" == "None" ]]; then + echo "Failed to resolve digest for tag: $ROLLBACK_TAG" + exit 1 +fi + +echo "Digest: $DIGEST" +echo + +# 2) digest -> all tags on that digest +echo "Fetching tags attached to digest..." +TAGS_RAW="$( + aws ecr describe-images \ + --region "$REGION" \ + --repository-name "$REPO" \ + --query "imageDetails[?imageDigest=='$DIGEST'].imageTags[]" \ + --output text +)" + +# TAGS_RAW will be a whitespace-separated list (or empty) +if [[ -z "$TAGS_RAW" ]]; then + echo "No tags found for digest: $DIGEST" + exit 2 +fi + +# 3) choose SHA-looking tag +SHA_TAG="" +for t in $TAGS_RAW; do + if [[ "$t" =~ $SHA_TAG_REGEX ]]; then + SHA_TAG="$t" + break + fi +done + +echo "Tags on digest: $TAGS_RAW" +echo + +if [[ -z "$SHA_TAG" ]]; then + echo "No tag matched SHA_TAG_REGEX: $SHA_TAG_REGEX" + echo "Set SHA_TAG_REGEX if your SHA tags are like 'sha-' etc." + exit 3 +fi + +echo "Resolved SHA tag: $SHA_TAG" +echo + +# 4) Optional docker retag/push +if [[ "${DRY_RUN:-0}" == "1" ]]; then + echo "DRY_RUN=1 set; not pulling/tagging/pushing." + exit 0 +fi + +# For docker operations, we need a full ECR image URI: +# .dkr.ecr..amazonaws.com/: +# +# You can provide ECR_REGISTRY explicitly, or we’ll discover it. +REGISTRY="${ECR_REGISTRY:-$( + aws sts get-caller-identity --query Account --output text +).dkr.ecr.${REGION}.amazonaws.com}" + +IMAGE_URI="${REGISTRY}/${REPO}" + +echo "Using registry: $REGISTRY" +echo "Logging in to ECR..." +aws ecr get-login-password --region "$REGION" \ + | docker login --username AWS --password-stdin "$REGISTRY" + +echo "Pulling rollback tag..." +docker pull "${IMAGE_URI}:${ROLLBACK_TAG}" + +echo "Tagging with SHA tag..." +docker tag "${IMAGE_URI}:${ROLLBACK_TAG}" "${IMAGE_URI}:${SHA_TAG}" + +echo "Pushing SHA tag..." +docker push "${IMAGE_URI}:${SHA_TAG}" + +echo +echo "Done." \ No newline at end of file From 50fe661934eab89cfad814c6ee108500c54536c7 Mon Sep 17 00:00:00 2001 From: oliverbeumkes-nhs Date: Tue, 24 Feb 2026 16:02:52 +0000 Subject: [PATCH 07/10] Refactored to check if image exists prior to promotion and deploy task definitions using the spicific tag specified --- .github/workflows/deploy-stack.yml | 44 +++++++++++++++++++----------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/.github/workflows/deploy-stack.yml b/.github/workflows/deploy-stack.yml index 7cafdb77..b8152fe8 100644 --- a/.github/workflows/deploy-stack.yml +++ b/.github/workflows/deploy-stack.yml @@ -61,10 +61,6 @@ on: default: false type: boolean description: "Terraform Apply?" - is_release: - default: false - type: boolean - description: "Are we deploying a release version? If true, images will be promoted for a specific" ci_account: default: false description: "Are we deploying to the CI account?" @@ -106,8 +102,31 @@ jobs: with: registries: "${{ steps.creds.outputs.aws-account-id }},${{ secrets.AWS_SOURCE_ECR_ACCOUNT_ID }}" - - name: ECR Copy + - name: Check if ECR image tag exists on destination account + id: ecr_check + shell: bash + env: + AWS_REGION: ${{ vars.AWS_REGION }} + ECR_ALIAS: ${{ inputs.ECR_ALIAS }} + IMAGE_TAG: ${{ github.ref_name }} + REGISTRY_ID: ${{ steps.creds.outputs.aws-account-id }} + run: | + set -euo pipefail + + if aws ecr describe-images \ + --repository-name "$ECR_ALIAS" \ + --region "$AWS_REGION" \ + --registry-id "$REGISTRY_ID" \ + --image-ids "imageTag=${IMAGE_TAG}" \ + --output text >/dev/null 2>&1; then + echo "exists=true" >> "$GITHUB_OUTPUT" + else + echo "exists=false" >> "$GITHUB_OUTPUT" + fi + + - name: ECR Copy (If image is not already promoted to destination account) id: ecr-copy + if: steps.ecr_check.outputs.exists == 'false' env: IMAGE_SHA: ${{ github.sha }} IMAGE_TAG: ${{ github.ref_name }} @@ -118,11 +137,9 @@ jobs: docker pull $source_repo:$IMAGE_SHA docker tag $source_repo:$IMAGE_SHA $destination_repo:$IMAGE_SHA docker tag $source_repo:$IMAGE_SHA $destination_repo:$IMAGE_TAG - docker tag $source_repo:$IMAGE_SHA $source_repo:$IMAGE_TAG docker push $destination_repo:$IMAGE_SHA docker push $destination_repo:$IMAGE_TAG - docker push $source_repo:$IMAGE_TAG - + deploy_stack: environment: ${{ !inputs.ci_account && inputs.environment || 'ci_account' }} env: @@ -163,9 +180,9 @@ jobs: promotion_iam_arn = "${PROMOTION_IAM_ARN}" EOF - - name: Get Most Recent ECR Image Tag + - name: Get Most Recent ECR Image Tag (Dev only) id: get-image-tag - if: inputs.ecr_alias + if: inputs.ecr_alias && inputs.environment == 'dev' env: ECR_ALIAS: ${{ inputs.ecr_alias }} run: | @@ -190,7 +207,7 @@ jobs: id: vars env: ECR_ALIAS: ${{ inputs.ecr_alias }} - IMAGE_TAG: ${{ steps.get-image-tag.outputs.image_tag || '' }} + IMAGE_TAG: ${{ inputs.environment == 'dev' && steps.get-image-tag.outputs.image_tag || github.ref_name }} run: | COMMON_ACCOUNT_ID=$(aws ssm get-parameter --name /repo/ci/user-input/external/aws-account-id --with-decryption | jq -r .Parameter.Value) cat > pipeline.auto.tfvars < Date: Thu, 5 Mar 2026 10:09:19 +0000 Subject: [PATCH 08/10] add override to dispatch --- .github/workflows/deploy-stack.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy-stack.yml b/.github/workflows/deploy-stack.yml index db162bc6..6a147124 100644 --- a/.github/workflows/deploy-stack.yml +++ b/.github/workflows/deploy-stack.yml @@ -35,6 +35,11 @@ on: - pds-adapter - mesh-forwarder - base-infra + override_tag: + default: "" + description: "Override tag to deploy (defaults to the github ref that triggered this workflow)" + required: false + type: string is_deployment: default: false type: boolean @@ -144,7 +149,7 @@ jobs: docker tag $source_repo:$IMAGE_SHA $destination_repo:$IMAGE_TAG docker push $destination_repo:$IMAGE_SHA docker push $destination_repo:$IMAGE_TAG - + deploy_stack: environment: ${{ !inputs.ci_account && inputs.environment || 'ci_account' }} env: From f1155ea5be5d1f0809d511436c56fc3135263df1 Mon Sep 17 00:00:00 2001 From: oliverbeumkes-nhs Date: Mon, 9 Mar 2026 09:47:31 +0000 Subject: [PATCH 09/10] [PRM-743] Add the deploy safelist file --- .github/workflows/deploy-safelist.yml | 58 ++++++++ .github/workflows/deploy-stack.yml | 115 ++++------------ .github/workflows/deploy-tagged-version.yml | 18 --- .../end-of-transfer-service.tfvars | 13 -- test.sh | 129 ------------------ 5 files changed, 85 insertions(+), 248 deletions(-) create mode 100644 .github/workflows/deploy-safelist.yml delete mode 100644 stacks/suspension-service/terraform/configs/end-of-transfer-service/end-of-transfer-service.tfvars delete mode 100755 test.sh diff --git a/.github/workflows/deploy-safelist.yml b/.github/workflows/deploy-safelist.yml new file mode 100644 index 00000000..f32db2d6 --- /dev/null +++ b/.github/workflows/deploy-safelist.yml @@ -0,0 +1,58 @@ +name: Deploy - Safelist Update +run-name: "${{ inputs.environment }} | Terraform Apply? = ${{ inputs.is_deployment }} | Tag version: ${{ github.ref }}" + +on: + workflow_dispatch: + inputs: + environment: + default: "dev" + description: "Environment" + required: true + type: choice + options: + - dev + - pre-prod + - prod + is_deployment: + default: false + type: boolean + description: "Terraform Apply?" + updated_safelist: + default: "" + type: string + required: true + description: "Comma-separated list of ODS codes to add to the safelist." + version_to_deploy: + type: string + required: true + description: "Version to deploy (e.g. 3.0.0). If not provided, the workflow version will be deployed." + +permissions: + pull-requests: write + id-token: write # This is required for requesting the JWT + contents: read # This is required for actions/checkout + +jobs: + suspension-service-ci: + name: Deploy Suspension Service Infrastructure + uses: ./.github/workflows/deploy-stack.yml + with: + stack: suspension-service + ecr_alias: repo/suspension-service + environment: ${{ inputs.environment }} + is_deployment: ${{ inputs.is_deployment }} + updated_safelist: ${{ inputs.updated_safelist }} + version_to_deploy: ${{ inputs.version_to_deploy }} + secrets: inherit + + gp2gp-messenger-ci: + name: Deploy GP2GP Messenger Infrastructure + uses: ./.github/workflows/deploy-stack.yml + with: + stack: gp2gp-messenger + ecr_alias: deductions/gp2gp-messenger + environment: ${{ inputs.environment }} + is_deployment: ${{ inputs.is_deployment }} + updated_safelist: ${{ inputs.updated_safelist }} + version_to_deploy: ${{ inputs.version_to_deploy }} + secrets: inherit diff --git a/.github/workflows/deploy-stack.yml b/.github/workflows/deploy-stack.yml index 6a147124..75a587de 100644 --- a/.github/workflows/deploy-stack.yml +++ b/.github/workflows/deploy-stack.yml @@ -35,11 +35,17 @@ on: - pds-adapter - mesh-forwarder - base-infra - override_tag: + version_to_deploy: default: "" - description: "Override tag to deploy (defaults to the github ref that triggered this workflow)" + description: "Version to deploy (e.g. 3.0.0). If not provided, the workflow version will be deployed." required: false + type: string + updated_safelist: + default: "" type: string + required: true + description: "Comma-separated list of ODS codes to add to the safelist." + is_deployment: default: false type: boolean @@ -74,20 +80,26 @@ on: default: false description: "Do we need to build any lambdas before deploying?" type: boolean - override_tag: + updated_safelist: + default: "" + type: string + required: true + description: "Comma-separated list of ODS codes to add to the safelist." + version_to_deploy: default: "" - description: "Override tag to deploy (defaults to the github ref that triggered this workflow)" + description: "Version to deploy (e.g. 3.0.0). If not provided, the workflow version will be deployed." required: false type: string + permissions: pull-requests: write id-token: write # This is required for requesting the JWT contents: read # This is required for actions/checkout jobs: - promote-images-from-source-ecr-account: + update_safelist: environment: ${{ inputs.environment }} - name: Promote images from source to current environment + name: Update Safelist in SSM Parameter Store if: ${{ inputs.is_deployment && inputs.environment != 'dev' && inputs.ecr_alias }} runs-on: ubuntu-latest steps: @@ -107,56 +119,20 @@ jobs: mask-aws-account-id: true # Needs the AmazonEC2ContainerRegistryPowerUser role - - name: Login to ECR - uses: aws-actions/amazon-ecr-login@v2 - with: - registries: "${{ steps.creds.outputs.aws-account-id }},${{ secrets.AWS_SOURCE_ECR_ACCOUNT_ID }}" - - - name: Check if ECR image tag exists on destination account - id: ecr_check - shell: bash + - name: Run command to update Safelist in SSM Parameter Store env: AWS_REGION: ${{ vars.AWS_REGION }} - ECR_ALIAS: ${{ inputs.ECR_ALIAS }} - IMAGE_TAG: ${{ inputs.override_tag }} - REGISTRY_ID: ${{ steps.creds.outputs.aws-account-id }} - run: | - set -euo pipefail - - if aws ecr describe-images \ - --repository-name "$ECR_ALIAS" \ - --region "$AWS_REGION" \ - --registry-id "$REGISTRY_ID" \ - --image-ids "imageTag=${IMAGE_TAG}" \ - --output text >/dev/null 2>&1; then - echo "exists=true" >> "$GITHUB_OUTPUT" - else - echo "exists=false" >> "$GITHUB_OUTPUT" - fi - - - name: ECR Copy (If image is not already promoted to destination account) - id: ecr-copy - if: steps.ecr_check.outputs.exists == 'false' - env: - IMAGE_SHA: ${{ github.sha }} - IMAGE_TAG: ${{ inputs.override_tag }} + PARAMETER_NAME: /repo/ndr/safelist + UPDATED_SAFELIST: ${{ inputs.updated_safelist }} run: | - source_repo=${{ secrets.AWS_SOURCE_ECR_ACCOUNT_ID }}.dkr.ecr.eu-west-2.amazonaws.com/${{ inputs.ecr_alias }} - destination_repo=${{ steps.creds.outputs.aws-account-id }}.dkr.ecr.eu-west-2.amazonaws.com/${{ inputs.ecr_alias }} - - docker pull $source_repo:$IMAGE_SHA - docker tag $source_repo:$IMAGE_SHA $destination_repo:$IMAGE_SHA - docker tag $source_repo:$IMAGE_SHA $destination_repo:$IMAGE_TAG - docker push $destination_repo:$IMAGE_SHA - docker push $destination_repo:$IMAGE_TAG - + aws ssm put-parameter --name "$PARAMETER_NAME" --value "$UPDATED_SAFELIST" --type String --overwrite --region "$AWS_REGION" + deploy_stack: - environment: ${{ !inputs.ci_account && inputs.environment || 'ci_account' }} + environment: ${{ inputs.environment }} env: - GITHUB_ENV: ${{ !inputs.ci_account && inputs.environment || 'ci_account' }} + GITHUB_ENV: ${{ inputs.environment }} runs-on: ubuntu-latest - needs: [promote-images-from-source-ecr-account] - if: always() && (needs.promote-images-from-source-ecr-account.result == 'skipped' || needs.promote-images-from-source-ecr-account.result == 'success') + needs: [update_safelist] defaults: run: working-directory: ./stacks/${{ inputs.stack }}/terraform @@ -176,48 +152,11 @@ jobs: aws-region: ${{ vars.AWS_REGION }} mask-aws-account-id: true role-skip-session-tagging: true - - - name: Setup Terraform variables for Deductions Cross Account - if: inputs.stack == 'deductions-cross-account' - env: - DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} - DOCKERHUB_ACCESS_TOKEN: ${{ secrets.DOCKERHUB_ACCESS_TOKEN }} - PROMOTION_IAM_ARN: ${{ secrets.PROMOTION_IAM_ARN }} - run: | - cat > pipeline-deductions-cross-account.auto.tfvars <0))) - | sort_by(.imagePushedAt) - | last - | .imageTags[] - | select(test("^[0-9a-f]{40}$")) - ' | head -n 1) - - echo "Found tag: $LATEST_IMAGE_SHA" - - echo "Most recent image tag for $ECR_ALIAS: $LATEST_IMAGE_SHA" - echo "image_tag=$LATEST_IMAGE_SHA" >> $GITHUB_OUTPUT - - name: Setup Terraform variables id: vars env: ECR_ALIAS: ${{ inputs.ecr_alias }} - IMAGE_TAG: ${{ inputs.environment == 'dev' && steps.get-image-tag.outputs.image_tag || inputs.override_tag }} + IMAGE_TAG: ${{ inputs.version_to_deploy }} run: | COMMON_ACCOUNT_ID=$(aws ssm get-parameter --name /repo/ci/user-input/external/aws-account-id --with-decryption | jq -r .Parameter.Value) cat > pipeline.auto.tfvars < [region] -# -# Examples: -# ./resolve_sha_from_tag_ecr.sh my-service v1.2.3 eu-west-1 -# AWS_REGION=eu-west-1 ./resolve_sha_from_tag_ecr.sh my-service v1.2.3 -# -# Requirements: -# - awscli configured (creds + permissions to ecr:DescribeImages) -# - jq (optional; this script avoids jq by default) -# - docker (only if not DRY_RUN) -# -# Optional env: -# DRY_RUN=1 -> don't docker pull/tag/push -# SHA_TAG_REGEX='^sha-[0-9a-f]{7,40}$' -> override SHA tag matcher -# ECR_REGISTRY='123456789012.dkr.ecr.eu-west-1.amazonaws.com' -> if you want push/pull by full URI - -if [[ $# -lt 2 || $# -gt 3 ]]; then - echo "Usage: $0 [region]" - exit 1 -fi - -REPO="$1" -ROLLBACK_TAG="$2" -REGION="${3:-${AWS_REGION:-}}" - -if [[ -z "$REGION" ]]; then - echo "Region not set. Provide as 3rd arg or set AWS_REGION." - exit 1 -fi - -SHA_TAG_REGEX="${SHA_TAG_REGEX:-^[0-9a-f]{7,40}$}" - -echo "Repository: $REPO" -echo "Rollback tag: $ROLLBACK_TAG" -echo "Region: $REGION" -echo - -# 1) rollback tag -> digest -echo "Resolving digest for tag: $ROLLBACK_TAG ..." -DIGEST="$( - aws ecr describe-images \ - --region "$REGION" \ - --repository-name "$REPO" \ - --image-ids "imageTag=$ROLLBACK_TAG" \ - --query 'imageDetails[0].imageDigest' \ - --output text -)" - -if [[ -z "$DIGEST" || "$DIGEST" == "None" ]]; then - echo "Failed to resolve digest for tag: $ROLLBACK_TAG" - exit 1 -fi - -echo "Digest: $DIGEST" -echo - -# 2) digest -> all tags on that digest -echo "Fetching tags attached to digest..." -TAGS_RAW="$( - aws ecr describe-images \ - --region "$REGION" \ - --repository-name "$REPO" \ - --query "imageDetails[?imageDigest=='$DIGEST'].imageTags[]" \ - --output text -)" - -# TAGS_RAW will be a whitespace-separated list (or empty) -if [[ -z "$TAGS_RAW" ]]; then - echo "No tags found for digest: $DIGEST" - exit 2 -fi - -# 3) choose SHA-looking tag -SHA_TAG="" -for t in $TAGS_RAW; do - if [[ "$t" =~ $SHA_TAG_REGEX ]]; then - SHA_TAG="$t" - break - fi -done - -echo "Tags on digest: $TAGS_RAW" -echo - -if [[ -z "$SHA_TAG" ]]; then - echo "No tag matched SHA_TAG_REGEX: $SHA_TAG_REGEX" - echo "Set SHA_TAG_REGEX if your SHA tags are like 'sha-' etc." - exit 3 -fi - -echo "Resolved SHA tag: $SHA_TAG" -echo - -# 4) Optional docker retag/push -if [[ "${DRY_RUN:-0}" == "1" ]]; then - echo "DRY_RUN=1 set; not pulling/tagging/pushing." - exit 0 -fi - -# For docker operations, we need a full ECR image URI: -# .dkr.ecr..amazonaws.com/: -# -# You can provide ECR_REGISTRY explicitly, or we’ll discover it. -REGISTRY="${ECR_REGISTRY:-$( - aws sts get-caller-identity --query Account --output text -).dkr.ecr.${REGION}.amazonaws.com}" - -IMAGE_URI="${REGISTRY}/${REPO}" - -echo "Using registry: $REGISTRY" -echo "Logging in to ECR..." -aws ecr get-login-password --region "$REGION" \ - | docker login --username AWS --password-stdin "$REGISTRY" - -echo "Pulling rollback tag..." -docker pull "${IMAGE_URI}:${ROLLBACK_TAG}" - -echo "Tagging with SHA tag..." -docker tag "${IMAGE_URI}:${ROLLBACK_TAG}" "${IMAGE_URI}:${SHA_TAG}" - -echo "Pushing SHA tag..." -docker push "${IMAGE_URI}:${SHA_TAG}" - -echo -echo "Done." \ No newline at end of file From 1e2c490d2e3212a5ab4a907e7a18b0d46034dca3 Mon Sep 17 00:00:00 2001 From: oliverbeumkes-nhs Date: Mon, 9 Mar 2026 11:11:04 +0000 Subject: [PATCH 10/10] move deploy-stack to temp deploy stack changes --- .../{deploy-stack.yml => temp-deploy-stack-changes.yml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{deploy-stack.yml => temp-deploy-stack-changes.yml} (99%) diff --git a/.github/workflows/deploy-stack.yml b/.github/workflows/temp-deploy-stack-changes.yml similarity index 99% rename from .github/workflows/deploy-stack.yml rename to .github/workflows/temp-deploy-stack-changes.yml index 75a587de..fda1e233 100644 --- a/.github/workflows/deploy-stack.yml +++ b/.github/workflows/temp-deploy-stack-changes.yml @@ -122,7 +122,7 @@ jobs: - name: Run command to update Safelist in SSM Parameter Store env: AWS_REGION: ${{ vars.AWS_REGION }} - PARAMETER_NAME: /repo/ndr/safelist + PARAMETER_NAME: /repo/${{ inputs.environment }}/user-input/external/safe-listed-ods-codes UPDATED_SAFELIST: ${{ inputs.updated_safelist }} run: | aws ssm put-parameter --name "$PARAMETER_NAME" --value "$UPDATED_SAFELIST" --type String --overwrite --region "$AWS_REGION"