From cb1836c7b9547e78b1bafc828a1d21c6f0266094 Mon Sep 17 00:00:00 2001 From: anthony-nhs <121869075+anthony-nhs@users.noreply.github.com> Date: Fri, 20 Mar 2026 09:01:05 +0000 Subject: [PATCH 01/18] Chore: [AEA-0000] - move to common dev container (#1885) ## Summary - Routine Change ### Details - move to common dev container --- .devcontainer/Dockerfile | 76 ++----- .devcontainer/devcontainer.json | 157 +++++++------- .github/scripts/call_mark_jira_released.sh | 14 -- .github/scripts/create_env_release_notes.sh | 18 -- .../scripts/create_int_rc_release_notes.sh | 20 -- .github/scripts/get_current_dev_tag.sh | 5 - .github/scripts/get_target_deployed_tag.sh | 10 - .github/workflows/cdk_package_code.yml | 41 ++-- .github/workflows/ci.yml | 52 ++--- .github/workflows/pull_request.yml | 45 ++-- .github/workflows/release.yml | 75 +++---- .github/workflows/release_all_stacks.yml | 202 ++++-------------- .github/workflows/run_regression_tests.yml | 40 ++-- .pre-commit-config.yaml | 2 +- .tool-versions | 7 - .tool-versions.asdf | 2 - Makefile | 17 +- poetry.lock | 52 +---- pyproject.toml | 1 - scripts/check_python_licenses.sh | 13 -- scripts/run_cfn_guard.sh | 27 --- 21 files changed, 225 insertions(+), 651 deletions(-) delete mode 100755 .github/scripts/call_mark_jira_released.sh delete mode 100755 .github/scripts/create_env_release_notes.sh delete mode 100755 .github/scripts/create_int_rc_release_notes.sh delete mode 100755 .github/scripts/get_current_dev_tag.sh delete mode 100755 .github/scripts/get_target_deployed_tag.sh delete mode 100644 .tool-versions delete mode 100644 .tool-versions.asdf delete mode 100755 scripts/check_python_licenses.sh delete mode 100755 scripts/run_cfn_guard.sh diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index c63c52fdee..c5c86da51d 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,65 +1,15 @@ -FROM mcr.microsoft.com/devcontainers/base:ubuntu -ARG TARGETARCH -ENV TARGETARCH=${TARGETARCH} - -ARG ASDF_VERSION -COPY .tool-versions.asdf /tmp/.tool-versions.asdf - -# Add amd64 architecture if on arm64 -RUN if [ "$TARGETARCH" == "arm64" ] || [ "$TARGETARCH" == "aarch64" ]; then dpkg --add-architecture amd64; fi - -RUN apt-get update \ - && export DEBIAN_FRONTEND=noninteractive \ - && apt-get -y dist-upgrade \ - && apt-get -y install --no-install-recommends htop vim curl git build-essential \ - libffi-dev libssl-dev libxml2-dev libxslt1-dev libjpeg8-dev libbz2-dev \ - zlib1g-dev unixodbc unixodbc-dev libsecret-1-0 libsecret-1-dev libsqlite3-dev \ - jq apt-transport-https ca-certificates gnupg-agent \ - software-properties-common bash-completion python3-pip make libbz2-dev \ - libreadline-dev libsqlite3-dev wget llvm libncurses5-dev libncursesw5-dev \ - xz-utils tk-dev liblzma-dev netcat-traditional libyaml-dev uuid-runtime xxd unzip - -# install aws stuff -# Download correct AWS CLI for arch -RUN if [ "$TARGETARCH" = "arm64" ] || [ "$TARGETARCH" == "aarch64" ]; then \ - wget -O /tmp/awscliv2.zip "https://awscli.amazonaws.com/awscli-exe-linux-aarch64.zip"; \ +ARG IMAGE_NAME=node_24_python_3_14 +ARG IMAGE_VERSION=latest +FROM ghcr.io/nhsdigital/eps-devcontainers/${IMAGE_NAME}:${IMAGE_VERSION} + +USER root +# specify DOCKER_GID to force container docker group id to match host +RUN if [ -n "${DOCKER_GID}" ]; then \ + if ! getent group docker; then \ + groupadd -g ${DOCKER_GID} docker; \ else \ - wget -O /tmp/awscliv2.zip "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip"; \ + groupmod -g ${DOCKER_GID} docker; \ fi && \ - unzip /tmp/awscliv2.zip -d /tmp/aws-cli && \ - /tmp/aws-cli/aws/install && \ - rm /tmp/awscliv2.zip && rm -rf /tmp/aws-cli - -# Install ASDF -RUN ASDF_VERSION=$(awk '!/^#/ && NF {print $1; exit}' /tmp/.tool-versions.asdf) && \ - wget -O /tmp/asdf.tar.gz https://github.com/asdf-vm/asdf/releases/download/v${ASDF_VERSION}/asdf-v${ASDF_VERSION}-linux-amd64.tar.gz; \ - tar -xvzf /tmp/asdf.tar.gz; \ - mv asdf /usr/bin - -USER vscode - -ENV PATH="/home/vscode/.asdf/shims/:$PATH" -RUN \ - echo 'PATH="/home/vscode/.asdf/shims/:$PATH"' >> ~/.bashrc; \ - echo '. <(asdf completion bash)' >> ~/.bashrc; \ - echo '# Install Ruby Gems to ~/gems' >> ~/.bashrc; \ - echo 'export GEM_HOME="$HOME/gems"' >> ~/.bashrc; \ - echo 'export PATH="$HOME/gems/bin:$PATH"' >> ~/.bashrc; - -# Install ASDF plugins -RUN asdf plugin add python; \ - asdf plugin add poetry https://github.com/asdf-community/asdf-poetry.git; \ - asdf plugin add shellcheck https://github.com/luizm/asdf-shellcheck.git; \ - asdf plugin add nodejs https://github.com/asdf-vm/asdf-nodejs.git; \ - asdf plugin add direnv; \ - asdf plugin add actionlint; \ - asdf plugin add ruby https://github.com/asdf-vm/asdf-ruby.git - - -WORKDIR /workspaces/eps-prescription-tracker-ui -ADD .tool-versions /workspaces/eps-prescription-tracker-ui/.tool-versions -ADD .tool-versions /home/vscode/.tool-versions - -# install python before poetry to ensure correct python version is used -RUN asdf install python; \ - asdf install + usermod -aG docker vscode; \ + fi + diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 46c458faef..90f376085d 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,86 +1,77 @@ -// For format details, see https://aka.ms/devcontainer.json. For config options, see the -// README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu { - "name": "Ubuntu", - // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile - "build": { - "dockerfile": "Dockerfile", - "context": "..", - "args": {} - }, - "mounts": [ - "source=${env:HOME}${env:USERPROFILE}/.aws,target=/home/vscode/.aws,type=bind", - "source=${env:HOME}${env:USERPROFILE}/.ssh,target=/home/vscode/.ssh,type=bind", - "source=${env:HOME}${env:USERPROFILE}/.gnupg,target=/home/vscode/.gnupg,type=bind", - "source=${env:HOME}${env:USERPROFILE}/.npmrc,target=/home/vscode/.npmrc,type=bind" - ], - "runArgs": [ - "--network=host" - ], - "remoteEnv": { "LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}" }, - "postAttachCommand": "docker build -f https://raw.githubusercontent.com/NHSDigital/eps-workflow-quality-checks/refs/tags/v4.0.4/dockerfiles/nhsd-git-secrets.dockerfile -t git-secrets . && poetry run pre-commit install --install-hooks -f", - "features": { - "ghcr.io/devcontainers/features/docker-outside-of-docker:1": { - "version": "latest", - "moby": "true", - "installDockerBuildx": "true" - }, - "ghcr.io/devcontainers/features/github-cli:1": {} - }, - "customizations": { - "vscode": { - "extensions": [ - "AmazonWebServices.aws-toolkit-vscode", - "redhat.vscode-yaml", - "ms-python.python", - "ms-python.flake8", - "eamodio.gitlens", - "github.vscode-pull-request-github", - "orta.vscode-jest", - "42crunch.vscode-openapi", - "mermade.openapi-lint", - "christian-kohler.npm-intellisense", - "dbaeumer.vscode-eslint", - "lfm.vscode-makefile-term", - "GrapeCity.gc-excelviewer", - "redhat.vscode-xml", - "streetsidesoftware.code-spell-checker", - "timonwong.shellcheck", - "mkhl.direnv", - "github.vscode-github-actions", - "Gruntfuggly.todo-tree", - "ms-vscode.makefile-tools" + "name": "eps-prescription-tracker-ui", + "build": { + "dockerfile": "Dockerfile", + "context": "..", + "args": { + "DOCKER_GID": "${env:DOCKER_GID:}", + "IMAGE_NAME": "node_24_python_3_14", + "IMAGE_VERSION": "v1.0.7", + "USER_UID": "${localEnv:USER_ID:}", + "USER_GID": "${localEnv:GROUP_ID:}" + } + }, + "mounts": [ + "source=${env:HOME}${env:USERPROFILE}/.aws,target=/home/vscode/.aws,type=bind", + "source=${env:HOME}${env:USERPROFILE}/.ssh,target=/home/vscode/.ssh,type=bind", + "source=${env:HOME}${env:USERPROFILE}/.gnupg,target=/home/vscode/.gnupg,type=bind", + "source=${env:HOME}${env:USERPROFILE}/.npmrc,target=/home/vscode/.npmrc,type=bind" + ], + "runArgs": [ + "--network=host" + ], + "remoteEnv": { + "LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}" + }, + "postAttachCommand": "git-secrets --register-aws; git-secrets --add-provider -- cat /usr/share/secrets-scanner/nhsd-rules-deny.txt", + "features": {}, + "customizations": { + "vscode": { + "extensions": [ + "AmazonWebServices.aws-toolkit-vscode", + "redhat.vscode-yaml", + "ms-python.python", + "ms-python.flake8", + "eamodio.gitlens", + "github.vscode-pull-request-github", + "orta.vscode-jest", + "42crunch.vscode-openapi", + "mermade.openapi-lint", + "christian-kohler.npm-intellisense", + "dbaeumer.vscode-eslint", + "lfm.vscode-makefile-term", + "GrapeCity.gc-excelviewer", + "redhat.vscode-xml", + "streetsidesoftware.code-spell-checker", + "timonwong.shellcheck", + "mkhl.direnv", + "github.vscode-github-actions", + "Gruntfuggly.todo-tree", + "ms-vscode.makefile-tools" + ], + "settings": { + "python.defaultInterpreterPath": "/workspaces/eps-prescription-tracker-ui/.venv/bin/python", + "python.analysis.autoSearchPaths": true, + "python.analysis.extraPaths": [], + "python.testing.unittestEnabled": false, + "python.testing.pytestEnabled": true, + "pylint.enabled": false, + "python.linting.flake8Enabled": true, + "python.linting.enabled": true, + "editor.formatOnPaste": false, + "editor.formatOnType": false, + "editor.formatOnSave": true, + "editor.formatOnSaveMode": "file", + "cSpell.words": [ + "fhir", + "Formik", + "pino", + "serialisation" ], - "settings": { - "python.defaultInterpreterPath": "/workspaces/eps-prescription-tracker-ui/.venv/bin/python", - "python.analysis.autoSearchPaths": true, - "python.analysis.extraPaths": [], - "python.testing.unittestEnabled": false, - "python.testing.pytestEnabled": true, - "pylint.enabled": false, - "python.linting.flake8Enabled": true, - "python.linting.enabled": true, // required to format on save - "editor.formatOnPaste": false, // required - "editor.formatOnType": false, // required - "editor.formatOnSave": true, // optional - "editor.formatOnSaveMode": "file", - "cSpell.words": ["fhir", "Formik", "pino", "serialisation"], - "editor.defaultFormatter": "dbaeumer.vscode-eslint" - - }, - "eslint.useFlatConfig": true, - "eslint.format.enable": true - } - }, - "postCreateCommand": "rm -f ~/.docker/config.json; git config --global --add safe.directory /workspaces/eps-prescription-tracker-ui; make install; direnv allow ." - // "features": {}, - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [], - // Use 'postCreateCommand' to run commands after the container is created. - // "postCreateCommand": "" - // Configure tool-specific properties. - // "customizations": {}, - // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. - // "remoteUser": "root" + "editor.defaultFormatter": "dbaeumer.vscode-eslint" + }, + "eslint.useFlatConfig": true, + "eslint.format.enable": true + } } - +} diff --git a/.github/scripts/call_mark_jira_released.sh b/.github/scripts/call_mark_jira_released.sh deleted file mode 100755 index 6bd62438c5..0000000000 --- a/.github/scripts/call_mark_jira_released.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -echo "calling mark jira released" - -cat < payload.json -{ - "releaseVersion": "Clinical-Tracker-$RELEASE_TAG" -} -EOF -cat payload.json - -function_arn=$(aws cloudformation list-exports --query "Exports[?Name=='release-notes:MarkJiraReleasedLambdaArn'].Value" --output text) -aws lambda invoke --function-name "${function_arn}" --cli-binary-format raw-in-base64-out --payload file://payload.json out.txt -cat out.txt diff --git a/.github/scripts/create_env_release_notes.sh b/.github/scripts/create_env_release_notes.sh deleted file mode 100755 index f892a23699..0000000000 --- a/.github/scripts/create_env_release_notes.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash - -cat < payload.json -{ - "currentTag": "$CURRENT_DEPLOYED_TAG", - "targetTag": "$DEV_TAG", - "repoName": "eps-prescription-tracker-ui", - "targetEnvironment": "$ENV", - "productName": "Clinical Tracker UI", - "releaseNotesPageId": "$PAGE_ID", - "releaseNotesPageTitle": "Current Clinical Tracker UI release notes - $ENV" -} -EOF -cat payload.json - -function_arn=$(aws cloudformation list-exports --query "Exports[?Name=='release-notes:CreateReleaseNotesLambdaArn'].Value" --output text) -aws lambda invoke --function-name "${function_arn}" --cli-binary-format raw-in-base64-out --payload file://payload.json out.txt -cat out.txt diff --git a/.github/scripts/create_int_rc_release_notes.sh b/.github/scripts/create_int_rc_release_notes.sh deleted file mode 100755 index 81cac7ba24..0000000000 --- a/.github/scripts/create_int_rc_release_notes.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash - -cat < payload.json -{ - "currentTag": "$CURRENT_DEPLOYED_TAG", - "targetTag": "$RELEASE_TAG", - "repoName": "eps-prescription-tracker-ui", - "targetEnvironment": "INT", - "productName": "Clinical Tracker UI", - "releaseNotesPageId": "$PAGE_ID", - "releaseNotesPageTitle": "Clinical-Tracker-UI-$RELEASE_TAG - Deployed to [INT] on $(date +'%d-%m-%y')", - "createReleaseCandidate": "true", - "releasePrefix": "Clinical-Tracker-UI-" -} -EOF -cat payload.json - -function_arn=$(aws cloudformation list-exports --query "Exports[?Name=='release-notes:CreateReleaseNotesLambdaArn'].Value" --output text) -aws lambda invoke --function-name "${function_arn}" --cli-binary-format raw-in-base64-out --payload file://payload.json out.txt -cat out.txt diff --git a/.github/scripts/get_current_dev_tag.sh b/.github/scripts/get_current_dev_tag.sh deleted file mode 100755 index 3e7f0e949b..0000000000 --- a/.github/scripts/get_current_dev_tag.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -dev_tag=$(aws cloudformation describe-stacks --stack-name cpt-ui-stateful-resources --query "Stacks[0].Tags[?Key=='version'].Value" --output text) - -echo "DEV_TAG=${dev_tag}" >> "$GITHUB_ENV" diff --git a/.github/scripts/get_target_deployed_tag.sh b/.github/scripts/get_target_deployed_tag.sh deleted file mode 100755 index 12b027bcd6..0000000000 --- a/.github/scripts/get_target_deployed_tag.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash - -current_deployed_tag=$(aws cloudformation describe-stacks --stack-name cpt-ui-stateful-resources --query "Stacks[0].Tags[?Key=='version'].Value" --output text) - -if [ -z "$current_deployed_tag" ] -then - current_deployed_tag=v1.0.0-beta -fi - -echo "CURRENT_DEPLOYED_TAG=${current_deployed_tag}" >> "$GITHUB_ENV" diff --git a/.github/workflows/cdk_package_code.yml b/.github/workflows/cdk_package_code.yml index a7d073cc43..69d4d8db45 100644 --- a/.github/workflows/cdk_package_code.yml +++ b/.github/workflows/cdk_package_code.yml @@ -9,47 +9,31 @@ on: COMMIT_ID: required: true type: string + pinned_image: + required: true + type: string jobs: package_code: runs-on: ubuntu-22.04 + container: + image: ${{ inputs.pinned_image }} + options: --user 1001:1001 --group-add 128 + defaults: + run: + shell: bash permissions: id-token: write contents: read packages: read steps: + - name: copy .tool-versions + run: | + cp /home/vscode/.tool-versions "$HOME/.tool-versions" - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd with: ref: ${{ env.BRANCH_NAME }} - - # using git commit sha for version of action to ensure we have stable version - - name: Get asdf version - id: asdf-version - run: echo "version=$(awk '!/^#/ && NF {print $1; exit}' .tool-versions.asdf)" >> "$GITHUB_OUTPUT" - - # using git commit sha for version of action to ensure we have stable version - - name: Install asdf - uses: asdf-vm/actions/setup@b7bcd026f18772e44fe1026d729e1611cc435d47 - with: - asdf_version: ${{ steps.asdf-version.outputs.version }} - - - name: Cache asdf - uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 - with: - path: | - ~/.asdf - key: ${{ runner.os }}-asdf-${{ hashFiles('**/.tool-versions') }}-${{ steps.asdf-version.outputs.version }} - restore-keys: | - ${{ runner.os }}-asdf-${{ hashFiles('**/.tool-versions') }}-${{ steps.asdf-version.outputs.version }} - - - name: Install asdf dependencies in .tool-versions - uses: asdf-vm/actions/install@b7bcd026f18772e44fe1026d729e1611cc435d47 - with: - asdf_version: ${{ steps.asdf-version.outputs.version }} - env: - PYTHON_CONFIGURE_OPTS: --enable-shared - - name: make install run: | make install @@ -58,7 +42,6 @@ jobs: - name: "Tar files" run: | tar -rf artifact.tar \ - .tool-versions \ packages \ node_modules \ package.json \ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b040dd16d6..2dfb2099a7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,29 +8,15 @@ env: BRANCH_NAME: ${{ github.event.ref.BRANCH_NAME }} jobs: - get_asdf_version: - runs-on: ubuntu-22.04 - outputs: - asdf_version: ${{ steps.asdf-version.outputs.version }} - tag_format: ${{ steps.load-config.outputs.TAG_FORMAT }} - steps: - - name: Checkout code - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - - - name: Get asdf version - id: asdf-version - run: echo "version=$(awk '!/^#/ && NF {print $1; exit}' .tool-versions.asdf)" >> "$GITHUB_OUTPUT" - - name: Load config value - id: load-config - run: | - TAG_FORMAT=$(yq '.TAG_FORMAT' .github/config/settings.yml) - echo "TAG_FORMAT=$TAG_FORMAT" >> "$GITHUB_OUTPUT" - + get_config_values: + uses: NHSDigital/eps-common-workflows/.github/workflows/get-repo-config.yml@383f3f9eaf3cb553ebcd74897bfed4d5e387629e + with: + verify_published_from_main_image: true quality_checks: - uses: NHSDigital/eps-common-workflows/.github/workflows/quality-checks.yml@383f3f9eaf3cb553ebcd74897bfed4d5e387629e - needs: [get_asdf_version] + uses: NHSDigital/eps-common-workflows/.github/workflows/quality-checks-devcontainer.yml@383f3f9eaf3cb553ebcd74897bfed4d5e387629e + needs: [get_config_values] with: - asdfVersion: ${{ needs.get_asdf_version.outputs.asdf_version }} + pinned_image: ${{ needs.get_config_values.outputs.pinned_image }} secrets: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} @@ -45,26 +31,31 @@ jobs: echo "commit_id=${{ github.sha }}" >> "$GITHUB_OUTPUT" tag_release: - needs: [quality_checks, get_commit_id, get_asdf_version] - uses: NHSDigital/eps-common-workflows/.github/workflows/tag-release.yml@383f3f9eaf3cb553ebcd74897bfed4d5e387629e + needs: [quality_checks, get_commit_id, get_config_values] + uses: NHSDigital/eps-common-workflows/.github/workflows/tag-release-devcontainer.yml@7a89b111ae752548e8e3f3fbaeb89bd6ecca0698 + permissions: + id-token: write + contents: write with: dry_run: true - asdfVersion: ${{ needs.get_asdf_version.outputs.asdf_version }} + pinned_image: ${{ needs.get_config_values.outputs.pinned_image }} branch_name: main - tag_format: ${{ needs.get_asdf_version.outputs.tag_format }} + tag_format: ${{ needs.get_config_values.outputs.tag_format }} secrets: inherit package_code: - needs: [tag_release, get_commit_id] + needs: [tag_release, get_commit_id, get_config_values] uses: ./.github/workflows/cdk_package_code.yml with: VERSION_NUMBER: ${{needs.tag_release.outputs.version_tag}} COMMIT_ID: ${{needs.get_commit_id.outputs.commit_id}} + pinned_image: ${{ needs.get_config_values.outputs.pinned_image }} release_dev: - needs: [tag_release, package_code, get_commit_id] + needs: [tag_release, package_code, get_commit_id, get_config_values] uses: ./.github/workflows/release_all_stacks.yml with: + pinned_image: ${{ needs.get_config_values.outputs.pinned_image }} SERVICE_NAME: cpt-ui TARGET_ENVIRONMENT: dev VERSION_NUMBER: ${{needs.tag_release.outputs.version_tag}} @@ -95,18 +86,15 @@ jobs: ROUTE53_EXPORT_NAME: EPS REACT_LOG_LEVEL: "debug" LOG_RETENTION_IN_DAYS: 30 - CREATE_INT_RELEASE_NOTES: true - CREATE_PROD_RELEASE_NOTES: true - MARK_JIRA_RELEASED: false - CREATE_INT_RC_RELEASE_NOTES: false IS_PULL_REQUEST: false FORWARD_CSOC_LOGS: false secrets: inherit release_qa: - needs: [tag_release, release_dev, package_code, get_commit_id] + needs: [tag_release, release_dev, package_code, get_commit_id, get_config_values] uses: ./.github/workflows/release_all_stacks.yml with: + pinned_image: ${{ needs.get_config_values.outputs.pinned_image }} SERVICE_NAME: cpt-ui TARGET_ENVIRONMENT: qa VERSION_NUMBER: ${{needs.tag_release.outputs.version_tag}} diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 6dc5907566..8a9b5505e7 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -8,30 +8,16 @@ env: BRANCH_NAME: ${{ github.event.pull_request.head.ref }} jobs: + get_config_values: + uses: NHSDigital/eps-common-workflows/.github/workflows/get-repo-config.yml@141907b215220e95e3ed3811d0fe8fa18675dbed + with: + verify_published_from_main_image: false dependabot-auto-approve-and-merge: needs: quality_checks uses: NHSDigital/eps-common-workflows/.github/workflows/dependabot-auto-approve-and-merge.yml@e208462679dedaded1e066c25c9830b9c0bf1930 secrets: AUTOMERGE_APP_ID: ${{ secrets.AUTOMERGE_APP_ID }} AUTOMERGE_PEM: ${{ secrets.AUTOMERGE_PEM }} - get_asdf_version: - runs-on: ubuntu-22.04 - outputs: - asdf_version: ${{ steps.asdf-version.outputs.version }} - tag_format: ${{ steps.load-config.outputs.TAG_FORMAT }} - steps: - - name: Checkout code - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - - - name: Get asdf version - id: asdf-version - run: echo "version=$(awk '!/^#/ && NF {print $1; exit}' .tool-versions.asdf)" >> "$GITHUB_OUTPUT" - - name: Load config value - id: load-config - run: | - TAG_FORMAT=$(yq '.TAG_FORMAT' .github/config/settings.yml) - echo "TAG_FORMAT=$TAG_FORMAT" >> "$GITHUB_OUTPUT" - get_commit_message: runs-on: ubuntu-22.04 outputs: @@ -49,10 +35,10 @@ jobs: quality_checks: # always run, but only block in the non-skip case - needs: [get_commit_message, get_asdf_version] - uses: NHSDigital/eps-common-workflows/.github/workflows/quality-checks.yml@383f3f9eaf3cb553ebcd74897bfed4d5e387629e + needs: [get_commit_message, get_config_values] + uses: NHSDigital/eps-common-workflows/.github/workflows/quality-checks-devcontainer.yml@383f3f9eaf3cb553ebcd74897bfed4d5e387629e with: - asdfVersion: ${{ needs.get_asdf_version.outputs.asdf_version }} + pinned_image: ${{ needs.get_config_values.outputs.pinned_image }} secrets: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} @@ -149,13 +135,16 @@ jobs: result-encoding: string tag_release: - needs: [get_asdf_version] - uses: NHSDigital/eps-common-workflows/.github/workflows/tag-release.yml@383f3f9eaf3cb553ebcd74897bfed4d5e387629e + needs: [get_config_values] + uses: NHSDigital/eps-common-workflows/.github/workflows/tag-release-devcontainer.yml@7a89b111ae752548e8e3f3fbaeb89bd6ecca0698 + permissions: + id-token: write + contents: write with: dry_run: true - asdfVersion: ${{ needs.get_asdf_version.outputs.asdf_version }} + pinned_image: ${{ needs.get_config_values.outputs.pinned_image }} branch_name: ${{ github.event.pull_request.head.ref }} - tag_format: ${{ needs.get_asdf_version.outputs.tag_format }} + tag_format: ${{ needs.get_config_values.outputs.tag_format }} secrets: inherit get_commit_id: @@ -169,7 +158,7 @@ jobs: echo "commit_id=${{ github.sha }}" >> "$GITHUB_OUTPUT" package_code: - needs: [get_issue_number, get_commit_id, quality_gate] + needs: [get_issue_number, get_commit_id, quality_gate, get_config_values] if: | always() && ! contains(needs.*.result, 'failure') && @@ -178,15 +167,17 @@ jobs: with: VERSION_NUMBER: PR-${{ needs.get_issue_number.outputs.issue_number }} COMMIT_ID: ${{ needs.get_commit_id.outputs.commit_id }} + pinned_image: ${{ needs.get_config_values.outputs.pinned_image }} release_code: - needs: [get_issue_number, package_code, get_commit_id] + needs: [get_issue_number, package_code, get_commit_id, get_config_values] if: | always() && ! contains(needs.*.result, 'failure') && ! contains(needs.*.result, 'cancelled') uses: ./.github/workflows/release_all_stacks.yml with: + pinned_image: ${{ needs.get_config_values.outputs.pinned_image }} SERVICE_NAME: cpt-ui-pr-${{needs.get_issue_number.outputs.issue_number}} TARGET_ENVIRONMENT: dev-pr VERSION_NUMBER: PR-${{ needs.get_issue_number.outputs.issue_number }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7b7e66f080..7cc203104b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -7,28 +7,15 @@ env: BRANCH_NAME: ${{ github.event.ref.BRANCH_NAME }} jobs: - get_asdf_version: - runs-on: ubuntu-22.04 - outputs: - asdf_version: ${{ steps.asdf-version.outputs.version }} - tag_format: ${{ steps.load-config.outputs.TAG_FORMAT }} - steps: - - name: Checkout code - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - - - name: Get asdf version - id: asdf-version - run: echo "version=$(awk '!/^#/ && NF {print $1; exit}' .tool-versions.asdf)" >> "$GITHUB_OUTPUT" - - name: Load config value - id: load-config - run: | - TAG_FORMAT=$(yq '.TAG_FORMAT' .github/config/settings.yml) - echo "TAG_FORMAT=$TAG_FORMAT" >> "$GITHUB_OUTPUT" + get_config_values: + uses: NHSDigital/eps-common-workflows/.github/workflows/get-repo-config.yml@383f3f9eaf3cb553ebcd74897bfed4d5e387629e + with: + verify_published_from_main_image: true quality_checks: - uses: NHSDigital/eps-common-workflows/.github/workflows/quality-checks.yml@383f3f9eaf3cb553ebcd74897bfed4d5e387629e - needs: [get_asdf_version] + uses: NHSDigital/eps-common-workflows/.github/workflows/quality-checks-devcontainer.yml@383f3f9eaf3cb553ebcd74897bfed4d5e387629e + needs: [get_config_values] with: - asdfVersion: ${{ needs.get_asdf_version.outputs.asdf_version }} + pinned_image: ${{ needs.get_config_values.outputs.pinned_image }} secrets: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} @@ -43,26 +30,34 @@ jobs: echo "commit_id=${{ github.sha }}" >> "$GITHUB_OUTPUT" tag_release: - needs: [quality_checks, get_commit_id, get_asdf_version] - uses: NHSDigital/eps-common-workflows/.github/workflows/tag-release.yml@383f3f9eaf3cb553ebcd74897bfed4d5e387629e + needs: [quality_checks, get_commit_id, get_config_values] + uses: NHSDigital/eps-common-workflows/.github/workflows/tag-release-devcontainer.yml@7a89b111ae752548e8e3f3fbaeb89bd6ecca0698 + permissions: + id-token: write + contents: write with: dry_run: false - asdfVersion: ${{ needs.get_asdf_version.outputs.asdf_version }} + pinned_image: ${{ needs.get_config_values.outputs.pinned_image }} branch_name: main - tag_format: ${{ needs.get_asdf_version.outputs.tag_format }} - secrets: inherit - + tag_format: ${{ needs.get_config_values.outputs.tag_format }} + update_jira: true + jira_release_prefix: "cpt-ui" + secrets: + EXECUTE_JIRA_LAMBDA_ROLE: ${{ secrets.DEV_CLOUD_FORMATION_EXECUTE_LAMBDA_ROLE }} + package_code: - needs: [tag_release, get_commit_id] + needs: [tag_release, get_commit_id, get_config_values] uses: ./.github/workflows/cdk_package_code.yml with: VERSION_NUMBER: ${{needs.tag_release.outputs.version_tag}} COMMIT_ID: ${{needs.get_commit_id.outputs.commit_id}} + pinned_image: ${{ needs.get_config_values.outputs.pinned_image }} release_dev: - needs: [tag_release, package_code, get_commit_id] + needs: [tag_release, package_code, get_commit_id, get_config_values] uses: ./.github/workflows/release_all_stacks.yml with: + pinned_image: ${{ needs.get_config_values.outputs.pinned_image }} SERVICE_NAME: cpt-ui TARGET_ENVIRONMENT: dev VERSION_NUMBER: ${{needs.tag_release.outputs.version_tag}} @@ -93,18 +88,15 @@ jobs: ROUTE53_EXPORT_NAME: EPS REACT_LOG_LEVEL: "debug" LOG_RETENTION_IN_DAYS: 30 - CREATE_INT_RELEASE_NOTES: true - CREATE_PROD_RELEASE_NOTES: true - MARK_JIRA_RELEASED: false - CREATE_INT_RC_RELEASE_NOTES: false IS_PULL_REQUEST: false FORWARD_CSOC_LOGS: false secrets: inherit release_ref: - needs: [tag_release, package_code, get_commit_id, release_dev] + needs: [tag_release, package_code, get_commit_id, release_dev, get_config_values] uses: ./.github/workflows/release_all_stacks.yml with: + pinned_image: ${{ needs.get_config_values.outputs.pinned_image }} SERVICE_NAME: cpt-ui TARGET_ENVIRONMENT: ref VERSION_NUMBER: ${{needs.tag_release.outputs.version_tag}} @@ -140,9 +132,10 @@ jobs: secrets: inherit release_qa: - needs: [tag_release, package_code, get_commit_id, release_dev] + needs: [tag_release, package_code, get_commit_id, release_dev, get_config_values] uses: ./.github/workflows/release_all_stacks.yml with: + pinned_image: ${{ needs.get_config_values.outputs.pinned_image }} SERVICE_NAME: cpt-ui TARGET_ENVIRONMENT: qa VERSION_NUMBER: ${{needs.tag_release.outputs.version_tag}} @@ -177,9 +170,10 @@ jobs: FORWARD_CSOC_LOGS: false secrets: inherit release_int: - needs: [tag_release, package_code, get_commit_id, release_qa] + needs: [tag_release, package_code, get_commit_id, release_qa, get_config_values] uses: ./.github/workflows/release_all_stacks.yml with: + pinned_image: ${{ needs.get_config_values.outputs.pinned_image }} SERVICE_NAME: cpt-ui TARGET_ENVIRONMENT: int VERSION_NUMBER: ${{needs.tag_release.outputs.version_tag}} @@ -206,17 +200,14 @@ jobs: ROUTE53_EXPORT_NAME: CPT REACT_LOG_LEVEL: "debug" # change this before pilot LOG_RETENTION_IN_DAYS: 30 - CREATE_INT_RELEASE_NOTES: true - CREATE_PROD_RELEASE_NOTES: true - MARK_JIRA_RELEASED: false - CREATE_INT_RC_RELEASE_NOTES: true IS_PULL_REQUEST: false FORWARD_CSOC_LOGS: false secrets: inherit release_prod: - needs: [tag_release, package_code, get_commit_id, release_int] + needs: [tag_release, package_code, get_commit_id, release_int, get_config_values] uses: ./.github/workflows/release_all_stacks.yml with: + pinned_image: ${{ needs.get_config_values.outputs.pinned_image }} SERVICE_NAME: cpt-ui TARGET_ENVIRONMENT: prod VERSION_NUMBER: ${{needs.tag_release.outputs.version_tag}} @@ -243,10 +234,6 @@ jobs: ROUTE53_EXPORT_NAME: CPT REACT_LOG_LEVEL: "debug" # change this before pilot LOG_RETENTION_IN_DAYS: 731 - CREATE_INT_RELEASE_NOTES: true - CREATE_PROD_RELEASE_NOTES: true - MARK_JIRA_RELEASED: false - CREATE_INT_RC_RELEASE_NOTES: false IS_PULL_REQUEST: false FORWARD_CSOC_LOGS: true secrets: inherit diff --git a/.github/workflows/release_all_stacks.yml b/.github/workflows/release_all_stacks.yml index 0e8b356266..1e3afa130b 100644 --- a/.github/workflows/release_all_stacks.yml +++ b/.github/workflows/release_all_stacks.yml @@ -75,32 +75,34 @@ on: LOG_RETENTION_IN_DAYS: type: string required: true - CREATE_INT_RELEASE_NOTES: - type: boolean - default: false - CREATE_PROD_RELEASE_NOTES: - type: boolean - default: false - MARK_JIRA_RELEASED: - type: boolean - default: false - CREATE_INT_RC_RELEASE_NOTES: - type: boolean - default: false IS_PULL_REQUEST: type: boolean required: true FORWARD_CSOC_LOGS: type: boolean required: true + pinned_image: + required: true + type: string jobs: release_all_code: runs-on: ubuntu-22.04 environment: ${{ inputs.TARGET_ENVIRONMENT }} + container: + image: ${{ inputs.pinned_image }} + options: --user 1001:1001 --group-add 128 + defaults: + run: + shell: bash permissions: id-token: write contents: write + env: + AWS_MAX_ATTEMPTS: 20 steps: + - name: copy .tool-versions + run: | + cp /home/vscode/.tool-versions "$HOME/.tool-versions" - name: Checkout local github actions uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd with: @@ -109,24 +111,6 @@ jobs: sparse-checkout: | .github - - name: create_int_rc_release_notes - uses: ./.github/actions/update_confluence_jira - if: ${{ inputs.CREATE_INT_RC_RELEASE_NOTES == true }} - with: - TARGET_ENVIRONMENT: int - RELEASE_TAG: ${{ inputs.VERSION_NUMBER }} - CONFLUENCE_PAGE_ID: "899319592" - CREATE_RC_RELEASE_NOTES: true - DEV_CLOUD_FORMATION_CHECK_VERSION_ROLE: ${{ secrets.DEV_CLOUD_FORMATION_CHECK_VERSION_ROLE }} - TARGET_CLOUD_FORMATION_CHECK_VERSION_ROLE: ${{ secrets.INT_CLOUD_FORMATION_CHECK_VERSION_ROLE }} - DEV_CLOUD_FORMATION_EXECUTE_LAMBDA_ROLE: ${{ secrets.DEV_CLOUD_FORMATION_EXECUTE_LAMBDA_ROLE }} - - name: Configure AWS Credentials - id: connect_aws_pull_image - uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 - with: - aws-region: eu-west-2 - role-to-assume: ${{ secrets.CDK_PULL_IMAGE_ROLE }} - role-session-name: prescription-clinical-tracker-ui-pull-image - name: build_artifact download uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c with: @@ -137,20 +121,6 @@ jobs: mkdir -p .build tar -xf artifact.tar -C .build - - name: Retrieve AWS Account ID - id: retrieve_aws_account_id - run: echo "ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)" >> "$GITHUB_ENV" - - - name: Login to Amazon ECR - id: login_ecr - run: | - aws ecr get-login-password --region eu-west-2 | docker login --username AWS --password-stdin ${{ env.ACCOUNT_ID }}.dkr.ecr.eu-west-2.amazonaws.com - - - name: Pull cdk-utils-build from Amazon ECR - run: | - docker pull "${{ env.ACCOUNT_ID }}.dkr.ecr.eu-west-2.amazonaws.com/cdk-utils-build-repo:latest" - docker tag "${{ env.ACCOUNT_ID }}.dkr.ecr.eu-west-2.amazonaws.com/cdk-utils-build-repo:latest" cdk-utils-build-repo:latest - - name: Configure AWS Credentials id: connect_aws_for_deployment uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 @@ -162,8 +132,6 @@ jobs: - name: check redeploy stateful stack id: check_redeploy_stateful_stack - env: - AWS_MAX_ATTEMPTS: 20 run: | CF_LONDON_EXPORTS=$(aws cloudformation list-exports --region eu-west-2 --output json) CLOUDFRONT_DISTRIBUTION_ID=$(echo "$CF_LONDON_EXPORTS" | \ @@ -251,41 +219,20 @@ jobs: CLOUDFRONT_ORIGIN_CUSTOM_HEADER: ${{secrets.CLOUDFRONT_ORIGIN_CUSTOM_HEADER }} IS_PULL_REQUEST: ${{inputs.IS_PULL_REQUEST}} FORWARD_CSOC_LOGS: ${{ inputs.FORWARD_CSOC_LOGS }} - AWS_MAX_ATTEMPTS: 20 - - - name: Show diff for stateful stack - run: | - docker run \ - -v "$(pwd)/.build":/home/cdkuser/workspace/ \ - -e AWS_ACCESS_KEY_ID=${{ steps.connect_aws_for_deployment.outputs.aws-access-key-id }} \ - -e AWS_SECRET_ACCESS_KEY=${{ steps.connect_aws_for_deployment.outputs.aws-secret-access-key }} \ - -e AWS_SESSION_TOKEN=${{ steps.connect_aws_for_deployment.outputs.aws-session-token }} \ - -e AWS_REGION="eu-west-2" \ - -e SHOW_DIFF="true" \ - -e DEPLOY_CODE="false" \ - -e CONFIG_FILE_NAME="stateful_resources.json" \ - -e CDK_APP_PATH="packages/cdk/bin/StatefulResourcesApp.ts" \ - cdk-utils-build-repo:latest - shell: bash - name: Deploy for stateful stack run: | - docker run \ - -v "$(pwd)/.build":/home/cdkuser/workspace/ \ - -e AWS_ACCESS_KEY_ID=${{ steps.connect_aws_for_deployment.outputs.aws-access-key-id }} \ - -e AWS_SECRET_ACCESS_KEY=${{ steps.connect_aws_for_deployment.outputs.aws-secret-access-key }} \ - -e AWS_SESSION_TOKEN=${{ steps.connect_aws_for_deployment.outputs.aws-session-token }} \ - -e AWS_REGION="eu-west-2" \ - -e SHOW_DIFF="false" \ - -e DEPLOY_CODE="true" \ - -e CONFIG_FILE_NAME="stateful_resources.json" \ - -e CDK_APP_PATH="packages/cdk/bin/StatefulResourcesApp.ts" \ - cdk-utils-build-repo:latest + cd .build + npx cdk deploy \ + --app "npx ts-node --prefer-ts-exts packages/cdk/bin/StatefulResourcesApp.ts" \ + --all \ + --require-approval=never \ + --ci true shell: bash + env: + CONFIG_FILE_NAME: stateful_resources.json - name: Set Environment Variables for website deployment id: setup_env_website_deployment - env: - AWS_MAX_ATTEMPTS: 20 run: | CF_LONDON_EXPORTS=$(aws cloudformation list-exports --region eu-west-2 --output json) CF_US_EXPORTS=$(aws cloudformation list-exports --region us-east-1 --output json) @@ -340,8 +287,6 @@ jobs: make react-build - name: deploy website - env: - AWS_MAX_ATTEMPTS: 20 run: | staticBucketName=$(aws cloudformation list-exports --query "Exports[?Name=='${{ inputs.SERVICE_NAME }}-stateful-resources:StaticContentBucket:Name'].Value" --output text) aws s3 cp ".build/packages/staticContent/404.html" "s3://${staticBucketName}/404.html" @@ -393,41 +338,20 @@ jobs: CLOUDFRONT_ORIGIN_CUSTOM_HEADER: ${{secrets.CLOUDFRONT_ORIGIN_CUSTOM_HEADER }} IS_PULL_REQUEST: ${{inputs.IS_PULL_REQUEST}} FORWARD_CSOC_LOGS: ${{ inputs.FORWARD_CSOC_LOGS }} - AWS_MAX_ATTEMPTS: 20 - - - name: Show diff for stateless stack - run: | - docker run \ - -v "$(pwd)/.build":/home/cdkuser/workspace/ \ - -e AWS_ACCESS_KEY_ID=${{ steps.connect_aws_for_deployment.outputs.aws-access-key-id }} \ - -e AWS_SECRET_ACCESS_KEY=${{ steps.connect_aws_for_deployment.outputs.aws-secret-access-key }} \ - -e AWS_SESSION_TOKEN=${{ steps.connect_aws_for_deployment.outputs.aws-session-token }} \ - -e AWS_REGION="eu-west-2" \ - -e SHOW_DIFF="true" \ - -e DEPLOY_CODE="false" \ - -e CONFIG_FILE_NAME="stateless_resources.json" \ - -e CDK_APP_PATH="packages/cdk/bin/StatelessResourcesApp.ts" \ - cdk-utils-build-repo:latest - shell: bash - name: Deploy code for stateless stack run: | - docker run \ - -v "$(pwd)/.build":/home/cdkuser/workspace/ \ - -e AWS_ACCESS_KEY_ID=${{ steps.connect_aws_for_deployment.outputs.aws-access-key-id }} \ - -e AWS_SECRET_ACCESS_KEY=${{ steps.connect_aws_for_deployment.outputs.aws-secret-access-key }} \ - -e AWS_SESSION_TOKEN=${{ steps.connect_aws_for_deployment.outputs.aws-session-token }} \ - -e AWS_REGION="eu-west-2" \ - -e SHOW_DIFF="false" \ - -e DEPLOY_CODE="true" \ - -e CONFIG_FILE_NAME="stateless_resources.json" \ - -e CDK_APP_PATH="packages/cdk/bin/StatelessResourcesApp.ts" \ - cdk-utils-build-repo:latest + cd .build + npx cdk deploy \ + --app "npx ts-node --prefer-ts-exts packages/cdk/bin/StatelessResourcesApp.ts" \ + --all \ + --require-approval=never \ + --ci true shell: bash + env: + CONFIG_FILE_NAME: stateless_resources.json - name: update cloudfront kvs id: update_cloudfront_kvs - env: - AWS_MAX_ATTEMPTS: 20 shell: bash run: | # shellcheck disable=SC2140 @@ -524,68 +448,19 @@ jobs: CLOUDFRONT_ORIGIN_CUSTOM_HEADER: ${{secrets.CLOUDFRONT_ORIGIN_CUSTOM_HEADER }} IS_PULL_REQUEST: ${{inputs.IS_PULL_REQUEST}} FORWARD_CSOC_LOGS: ${{ inputs.FORWARD_CSOC_LOGS }} - AWS_MAX_ATTEMPTS: 20 - - - name: Show diff for stateful stack redeployment - if: ${{ steps.check_redeploy_stateful_stack.outputs.REDEPLOY_STATEFUL_STACK == 'true' }} - run: | - docker run \ - -v "$(pwd)/.build":/home/cdkuser/workspace/ \ - -e AWS_ACCESS_KEY_ID=${{ steps.connect_aws_for_deployment.outputs.aws-access-key-id }} \ - -e AWS_SECRET_ACCESS_KEY=${{ steps.connect_aws_for_deployment.outputs.aws-secret-access-key }} \ - -e AWS_SESSION_TOKEN=${{ steps.connect_aws_for_deployment.outputs.aws-session-token }} \ - -e AWS_REGION="eu-west-2" \ - -e SHOW_DIFF="true" \ - -e DEPLOY_CODE="false" \ - -e CONFIG_FILE_NAME="stateful_resources.json" \ - -e CDK_APP_PATH="packages/cdk/bin/StatefulResourcesApp.ts" \ - cdk-utils-build-repo:latest - shell: bash - name: Deploy code for stateful stack redeployment if: ${{ steps.check_redeploy_stateful_stack.outputs.REDEPLOY_STATEFUL_STACK == 'true' }} run: | - docker run \ - -v "$(pwd)/.build":/home/cdkuser/workspace/ \ - -e AWS_ACCESS_KEY_ID=${{ steps.connect_aws_for_deployment.outputs.aws-access-key-id }} \ - -e AWS_SECRET_ACCESS_KEY=${{ steps.connect_aws_for_deployment.outputs.aws-secret-access-key }} \ - -e AWS_SESSION_TOKEN=${{ steps.connect_aws_for_deployment.outputs.aws-session-token }} \ - -e AWS_REGION="eu-west-2" \ - -e SHOW_DIFF="false" \ - -e DEPLOY_CODE="true" \ - -e CONFIG_FILE_NAME="stateful_resources.json" \ - -e CDK_APP_PATH="packages/cdk/bin/StatefulResourcesApp.ts" \ - cdk-utils-build-repo:latest + cd .build + npx cdk deploy \ + --app "npx ts-node --prefer-ts-exts packages/cdk/bin/StatefulResourcesApp.ts" \ + --all \ + --require-approval=never \ + --ci true shell: bash - - - name: create_int_release_notes - uses: ./.github/actions/update_confluence_jira - if: ${{ inputs.CREATE_INT_RELEASE_NOTES == true && always() && !failure() && !cancelled() }} - with: - TARGET_ENVIRONMENT: int - CONFLUENCE_PAGE_ID: "899319595" - CREATE_RC_RELEASE_NOTES: false - DEV_CLOUD_FORMATION_CHECK_VERSION_ROLE: ${{ secrets.DEV_CLOUD_FORMATION_CHECK_VERSION_ROLE }} - TARGET_CLOUD_FORMATION_CHECK_VERSION_ROLE: ${{ secrets.INT_CLOUD_FORMATION_CHECK_VERSION_ROLE }} - DEV_CLOUD_FORMATION_EXECUTE_LAMBDA_ROLE: ${{ secrets.DEV_CLOUD_FORMATION_EXECUTE_LAMBDA_ROLE }} - - - name: create_prod_release_notes - uses: ./.github/actions/update_confluence_jira - if: ${{ inputs.CREATE_PROD_RELEASE_NOTES == true && always() && !failure() && !cancelled() }} - with: - TARGET_ENVIRONMENT: prod - CONFLUENCE_PAGE_ID: "899319597" - CREATE_RC_RELEASE_NOTES: false - DEV_CLOUD_FORMATION_CHECK_VERSION_ROLE: ${{ secrets.DEV_CLOUD_FORMATION_CHECK_VERSION_ROLE }} - TARGET_CLOUD_FORMATION_CHECK_VERSION_ROLE: ${{ secrets.PROD_CLOUD_FORMATION_CHECK_VERSION_ROLE }} - DEV_CLOUD_FORMATION_EXECUTE_LAMBDA_ROLE: ${{ secrets.DEV_CLOUD_FORMATION_EXECUTE_LAMBDA_ROLE }} - - - name: mark_released_in_jira - uses: ./.github/actions/mark_jira_released - if: ${{ inputs.MARK_JIRA_RELEASED == true && always() && !failure() && !cancelled() }} - with: - RELEASE_TAG: ${{ inputs.VERSION_NUMBER }} - DEV_CLOUD_FORMATION_EXECUTE_LAMBDA_ROLE: ${{ secrets.DEV_CLOUD_FORMATION_EXECUTE_LAMBDA_ROLE }} + env: + CONFIG_FILE_NAME: stateful_resources.json update_github_pages: runs-on: ubuntu-22.04 @@ -625,5 +500,6 @@ jobs: with: ENVIRONMENT: ${{ inputs.TARGET_ENVIRONMENT }} VERSION_NUMBER: ${{ inputs.VERSION_NUMBER }} + pinned_image: ${{ inputs.pinned_image }} secrets: REGRESSION_TESTS_PEM: ${{ secrets.REGRESSION_TESTS_PEM }} diff --git a/.github/workflows/run_regression_tests.yml b/.github/workflows/run_regression_tests.yml index 7afc9756e5..336ff4cd25 100644 --- a/.github/workflows/run_regression_tests.yml +++ b/.github/workflows/run_regression_tests.yml @@ -11,7 +11,9 @@ on: type: string REGRESSION_TESTS_PEM: type: string - default: false + pinned_image: + type: string + required: true secrets: REGRESSION_TESTS_PEM: required: true @@ -19,11 +21,20 @@ on: jobs: run_regression_tests: runs-on: ubuntu-22.04 + container: + image: ${{ inputs.pinned_image }} + options: --user 1001:1001 --group-add 128 + defaults: + run: + shell: bash permissions: id-token: write contents: write steps: + - name: copy .tool-versions + run: | + cp /home/vscode/.tool-versions "$HOME/.tool-versions" - name: Checkout local github actions uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd with: @@ -38,33 +49,6 @@ jobs: private-key: ${{ secrets.REGRESSION_TESTS_PEM }} owner: "NHSDigital" repositories: "electronic-prescription-service-api-regression-tests" - - - name: Get asdf version - id: asdf-version - run: echo "version=$(awk '!/^#/ && NF {print $1; exit}' .tool-versions.asdf)" >> "$GITHUB_OUTPUT" - - # using git commit sha for version of action to ensure we have stable version - - name: Install asdf - uses: asdf-vm/actions/setup@b7bcd026f18772e44fe1026d729e1611cc435d47 - with: - asdf_version: ${{ steps.asdf-version.outputs.version }} - - - name: Cache asdf - uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 - with: - path: | - ~/.asdf - key: ${{ runner.os }}-asdf-${{ hashFiles('**/.tool-versions') }}-${{ steps.asdf-version.outputs.version }} - restore-keys: | - ${{ runner.os }}-asdf-${{ hashFiles('**/.tool-versions') }}-${{ steps.asdf-version.outputs.version }} - - - name: Install asdf dependencies in .tool-versions - uses: asdf-vm/actions/install@b7bcd026f18772e44fe1026d729e1611cc435d47 - with: - asdf_version: ${{ steps.asdf-version.outputs.version }} - env: - PYTHON_CONFIGURE_OPTS: --enable-shared - - name: Run Regression Testing working-directory: scripts env: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4d4eb95aba..d0dadd4845 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -201,7 +201,7 @@ repos: entry: bash args: - -c - - 'docker run -v "$LOCAL_WORKSPACE_FOLDER:/src" git-secrets --pre_commit_hook' + - 'git-secrets --pre_commit_hook' language: system fail_fast: true diff --git a/.tool-versions b/.tool-versions deleted file mode 100644 index d30d74554c..0000000000 --- a/.tool-versions +++ /dev/null @@ -1,7 +0,0 @@ -nodejs 24.12.0 -python 3.14.2 -poetry 2.2.1 -shellcheck 0.10.0 -direnv 2.32.2 -actionlint 1.7.3 -ruby 3.3.0 diff --git a/.tool-versions.asdf b/.tool-versions.asdf deleted file mode 100644 index 4921076f8e..0000000000 --- a/.tool-versions.asdf +++ /dev/null @@ -1,2 +0,0 @@ -# define the .asdf-version to use here -0.18.0 diff --git a/Makefile b/Makefile index 71b27b2589..c24df66311 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ guard-%: exit 1; \ fi -.PHONY: install build test publish release clean +.PHONY: install build test publish release clean lint compile cdk-synth cdk-deploy cdk-diff react-dev react-build react-start react-lint check-licenses cdk-synth-no-mock cdk-synth-mock cdk-synth-stateful-resources-no-mock cdk-synth-stateless-resources-no-mock cdk-synth-stateful-resources-mock cdk-synth-stateless-resources-mock install: install-node install-python install-hooks @@ -106,17 +106,6 @@ check-licenses-node: npm run check-licenses --workspace packages/testingSupport/clearActiveSessions npm run check-licenses --workspace packages/testingSupport/setLastActivityTime -check-licenses-python: - scripts/check_python_licenses.sh - -aws-configure: - aws configure sso --region eu-west-2 - -aws-login: - aws sso login --sso-session sso-session - -cfn-guard: - ./scripts/run_cfn_guard.sh react-dev: npm run dev --workspace packages/cpt-ui @@ -352,5 +341,5 @@ cdk-diff: guard-CDK_APP_NAME --context VERSION_NUMBER=$$VERSION_NUMBER \ --context COMMIT_ID=$$COMMIT_ID -build-deployment-container-image: - docker build -t "clinical-prescription-tracker-ui" -f docker/Dockerfile . +%: + @$(MAKE) -f /usr/local/share/eps/Mk/common.mk $@ diff --git a/poetry.lock b/poetry.lock index 0b81e44774..a94b2d7919 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.3.2 and should not be changed by hand. [[package]] name = "certifi" @@ -250,24 +250,6 @@ files = [ {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, ] -[[package]] -name = "pip-licenses" -version = "5.5.1" -description = "Dump the software license list of Python packages installed with pip." -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "pip_licenses-5.5.1-py3-none-any.whl", hash = "sha256:ed5e229a93760e529cfa7edaec6630b5a2cd3874c1bddb8019e5f18a723fdead"}, - {file = "pip_licenses-5.5.1.tar.gz", hash = "sha256:7df370e6e5024a3f7449abf8e4321ef868ba9a795698ad24ab6851f3e7fc65a7"}, -] - -[package.dependencies] -prettytable = ">=3.12.0" - -[package.extras] -dev = ["autopep8", "black", "docutils", "isort", "mypy", "pip-tools", "pypandoc", "pytest-cov", "pytest-pycodestyle", "pytest-runner", "tomli-w", "twine", "wheel"] - [[package]] name = "platformdirs" version = "4.5.1" @@ -320,24 +302,6 @@ nodeenv = ">=0.11.1" pyyaml = ">=5.1" virtualenv = ">=20.10.0" -[[package]] -name = "prettytable" -version = "3.17.0" -description = "A simple Python library for easily displaying tabular data in a visually appealing ASCII table format" -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "prettytable-3.17.0-py3-none-any.whl", hash = "sha256:aad69b294ddbe3e1f95ef8886a060ed1666a0b83018bbf56295f6f226c43d287"}, - {file = "prettytable-3.17.0.tar.gz", hash = "sha256:59f2590776527f3c9e8cf9fe7b66dd215837cca96a9c39567414cbc632e8ddb0"}, -] - -[package.dependencies] -wcwidth = "*" - -[package.extras] -tests = ["pytest", "pytest-cov", "pytest-lazy-fixtures"] - [[package]] name = "pygments" version = "2.19.2" @@ -519,19 +483,7 @@ platformdirs = ">=3.9.1,<5" docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8) ; platform_python_implementation == \"PyPy\" or platform_python_implementation == \"GraalVM\" or platform_python_implementation == \"CPython\" and sys_platform == \"win32\" and python_version >= \"3.13\"", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10) ; platform_python_implementation == \"CPython\""] -[[package]] -name = "wcwidth" -version = "0.2.14" -description = "Measures the displayed width of unicode strings in a terminal" -optional = false -python-versions = ">=3.6" -groups = ["dev"] -files = [ - {file = "wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1"}, - {file = "wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605"}, -] - [metadata] lock-version = "2.1" python-versions = "^3.14" -content-hash = "622d4bab08b2f3e8ef5e748bbfe0766fcb363e5083e0fa989bac804810e51126" +content-hash = "2993eac056e74e3024e3a729ffc69eb747701c755805ab54c94056ff04c2ba32" diff --git a/pyproject.toml b/pyproject.toml index af49ede0e4..13385f4c61 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,6 @@ requests = "^2.32.3" [tool.poetry.group.dev.dependencies] pre-commit = "^4.5.1" -pip-licenses = "^5.5.1" [build-system] requires = ["poetry>=0.12"] diff --git a/scripts/check_python_licenses.sh b/scripts/check_python_licenses.sh deleted file mode 100755 index 1a8148feb3..0000000000 --- a/scripts/check_python_licenses.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash -set -euo pipefail - -LICENSES=$(poetry run pip-licenses) -INCOMPATIBLE_LIBS=$(echo "$LICENSES" | grep 'GPL' || true) - -if [[ -z $INCOMPATIBLE_LIBS ]]; then - exit 0 -else - echo "The following libraries were found which are not compatible with this project's license:" - echo "$INCOMPATIBLE_LIBS" - exit 1 -fi diff --git a/scripts/run_cfn_guard.sh b/scripts/run_cfn_guard.sh deleted file mode 100755 index 77f6652e47..0000000000 --- a/scripts/run_cfn_guard.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash -set -eou pipefail - -rm -rf /tmp/ruleset -rm -rf cfn_guard_output - -wget -O /tmp/ruleset.zip https://github.com/aws-cloudformation/aws-guard-rules-registry/releases/download/1.0.2/ruleset-build-v1.0.2.zip >/dev/null 2>&1 -unzip /tmp/ruleset.zip -d /tmp/ruleset/ >/dev/null 2>&1 - -curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/aws-cloudformation/cloudformation-guard/main/install-guard.sh | sh >/dev/null 2>&1 - -mkdir -p cfn_guard_output - -declare -a rulesets=("ncsc" "ncsc-cafv3" "wa-Reliability-Pillar" "wa-Security-Pillar") -for ruleset in "${rulesets[@]}" - do - echo "Checking all templates in cdk.out folder with ruleest $ruleset" - - ~/.guard/bin/cfn-guard validate \ - --data cdk.out \ - --rules "/tmp/ruleset/output/$ruleset.guard" \ - --show-summary fail \ - > "cfn_guard_output/cdk.out_$ruleset.txt" - -done - -rm -rf /tmp/ruleset From ec9c2b5046e2d50abf3780dff3c5033f9387d856 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Mar 2026 09:54:47 +0000 Subject: [PATCH 02/18] Upgrade: [dependabot] - bump flatted from 3.3.3 to 3.4.2 (#1922) Bumps [flatted](https://github.com/WebReflection/flatted) from 3.3.3 to 3.4.2.
Commits
  • 3bf0909 3.4.2
  • 885ddcc fix CWE-1321
  • 0bdba70 added flatted-view to the benchmark
  • 2a02dce 3.4.1
  • fba4e8f Merge pull request #89 from WebReflection/python-fix
  • 5fe8648 added "when in Rome" also a test for PHP
  • 53517ad some minor improvement
  • b3e2a0c Fixing recursion issue in Python too
  • c4b46db Add SECURITY.md for security policy and reporting
  • f86d071 Create dependabot.yml for version updates
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=flatted&package-manager=npm_and_yarn&previous-version=3.3.3&new-version=3.4.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/NHSDigital/eps-prescription-tracker-ui/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 7086fa1262..2e7e55898c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10433,7 +10433,9 @@ } }, "node_modules/flatted": { - "version": "3.3.3", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true, "license": "ISC" }, From 79cd8dad3fcae07276b9ebc4070f5fdc14e91d87 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Fri, 20 Mar 2026 10:33:32 +0000 Subject: [PATCH 03/18] New: [AEA-6360] - Add new RUM log to role confirmation (#1920) ## Summary - Routine Change ### Details - Adds a new log to the confirm role button / single role auto-redirect, to log when a user as "completed" sign in --- .../src/components/EpsRoleSelectionPage.tsx | 9 ++++++++ .../cpt-ui/src/pages/YourSelectedRolePage.tsx | 21 ++++++++++++++++--- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/packages/cpt-ui/src/components/EpsRoleSelectionPage.tsx b/packages/cpt-ui/src/components/EpsRoleSelectionPage.tsx index 57a5ca3392..d75576ccfe 100644 --- a/packages/cpt-ui/src/components/EpsRoleSelectionPage.tsx +++ b/packages/cpt-ui/src/components/EpsRoleSelectionPage.tsx @@ -253,6 +253,15 @@ export default function RoleSelectionPage({ useEffect(() => { if (auth.hasSingleRoleAccess() && auth.isSignedIn) { + logger.debug("Role confirmed", { + sessionId: auth.sessionId, + pageName: location.pathname, + userId: auth.userDetails?.sub, + roleName: auth.selectedRole?.role_name, + roleId: auth.selectedRole?.role_id, + orgName: auth.selectedRole?.org_name, + orgCode: auth.selectedRole?.org_code + }, true) navigate(FRONTEND_PATHS.SEARCH_BY_PRESCRIPTION_ID) } }, [auth.hasSingleRoleAccess, auth.isSignedIn]) diff --git a/packages/cpt-ui/src/pages/YourSelectedRolePage.tsx b/packages/cpt-ui/src/pages/YourSelectedRolePage.tsx index 6748b5c24b..00f9796fea 100644 --- a/packages/cpt-ui/src/pages/YourSelectedRolePage.tsx +++ b/packages/cpt-ui/src/pages/YourSelectedRolePage.tsx @@ -6,16 +6,18 @@ import { Row, SummaryList } from "nhsuk-react-components" -import {Link} from "react-router-dom" +import {Link, useNavigate} from "react-router-dom" import {YOUR_SELECTED_ROLE_STRINGS} from "@/constants/ui-strings/YourSelectedRoleStrings" import {useAuth} from "@/context/AuthProvider" import {Button} from "@/components/ReactRouterButton" import {FRONTEND_PATHS} from "@/constants/environment" import {usePageTitle} from "@/hooks/usePageTitle" +import {logger} from "@/helpers/logger" export default function YourSelectedRolePage() { - const {selectedRole} = useAuth() + const {selectedRole, sessionId, userDetails} = useAuth() + const navigate = useNavigate() usePageTitle(YOUR_SELECTED_ROLE_STRINGS.pageTitle) const [roleName, setRoleName] = useState(YOUR_SELECTED_ROLE_STRINGS.noRoleName) @@ -36,6 +38,19 @@ export default function YourSelectedRolePage() { setOdsCode(selectedRole.org_code || YOUR_SELECTED_ROLE_STRINGS.noODSCode) }, [selectedRole]) + const onConfirmRole = () => { + logger.debug("Role confirmed", { + sessionId: sessionId, + pageName: location.pathname, + userId: userDetails?.sub, + roleName: selectedRole?.role_name, + roleId: selectedRole?.role_id, + orgName: selectedRole?.org_name, + orgCode: selectedRole?.org_code + }, true) + navigate(FRONTEND_PATHS.SEARCH_BY_PRESCRIPTION_ID) + } + const { heading, subheading, @@ -113,7 +128,7 @@ export default function YourSelectedRolePage() {