diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 07bc88c..0d56aaa 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,44 +1,14 @@ -FROM mcr.microsoft.com/devcontainers/base:ubuntu - -ARG ASDF_VERSION -COPY .tool-versions.asdf /tmp/.tool-versions.asdf - -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 \ - openjdk-8-jdk 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 - -# 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 actionlint; - -WORKDIR /workspaces/eps-spine-shared -ADD .tool-versions /workspaces/eps-spine-shared/.tool-versions -ADD .tool-versions /home/vscode/.tool-versions - -RUN asdf install python; \ - asdf install +ARG IMAGE_NAME=node_24_python_3_10 +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 \ + groupmod -g ${DOCKER_GID} docker; \ + fi && \ + usermod -aG docker vscode; \ + fi diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 059332f..0e20772 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,12 +1,15 @@ { - // 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 + "name": "eps-spine-shared", "build": { "dockerfile": "Dockerfile", "context": "..", - "args": {} + "args": { + "DOCKER_GID": "${env:DOCKER_GID:}", + "IMAGE_NAME": "node_24_python_3_10", + "IMAGE_VERSION": "v1.1.3", + "USER_UID": "${localEnv:USER_ID:}", + "USER_GID": "${localEnv:GROUP_ID:}" + } }, "mounts": [ "source=${env:HOME}${env:USERPROFILE}/.aws,target=/home/vscode/.aws,type=bind", @@ -14,12 +17,7 @@ "source=${env:HOME}${env:USERPROFILE}/.gnupg,target=/home/vscode/.gnupg,type=bind" ], "features": { - "ghcr.io/devcontainers/features/docker-outside-of-docker:1": { - "version": "latest", - "moby": "true", - "installDockerBuildx": "true" - } - }, + }, "customizations": { "vscode": { "extensions": [ @@ -41,11 +39,11 @@ "python.testing.unittestEnabled": false, "python.testing.pytestEnabled": true, "flake8.enabled": true, - "python.linting.enabled": true, // required to format on save + "python.linting.enabled": true, "editor.defaultFormatter": "dbaeumer.vscode-eslint", - "editor.formatOnPaste": false, // required - "editor.formatOnType": false, // required - "editor.formatOnSave": true, // optional + "editor.formatOnPaste": false, + "editor.formatOnType": false, + "editor.formatOnSave": true, "editor.formatOnSaveMode": "file", "editor.tabSize": 2, "eslint.useFlatConfig": true, @@ -54,5 +52,5 @@ } }, "remoteEnv": { "LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}" }, - "postCreateCommand": "rm -f ~/.docker/config.json; git config --global --add safe.directory /workspaces/eps-spine-shared; source ~/.bashrc; make reinstall-poetry; make install; docker build -t git-secrets -f https://raw.githubusercontent.com/NHSDigital/eps-common-workflows/3cba6a3733673bafc95526503478674332c26007/dockerfiles/nhsd-git-secrets.dockerfile ." + "postAttachCommand": "git-secrets --register-aws; git-secrets --add-provider -- cat /usr/share/secrets-scanner/nhsd-rules-deny.txt" } diff --git a/.github/actions/get_asdf_version/action.yaml b/.github/actions/get_asdf_version/action.yaml deleted file mode 100644 index 24b971e..0000000 --- a/.github/actions/get_asdf_version/action.yaml +++ /dev/null @@ -1,17 +0,0 @@ -name: Get asdf version -description: Get asdf version from .tool-versions.asdf file - -outputs: - version: - value: ${{ steps.get_asdf_version.outputs.version }} - description: Version defined in .tool-versions.asdf - -runs: - using: composite - steps: - - name: Get asdf version - id: get_asdf_version - shell: bash - run: | - echo "version=$(awk '!/^#/ && NF {print $1; exit}' .tool-versions.asdf)" - echo "version=$(awk '!/^#/ && NF {print $1; exit}' .tool-versions.asdf)" >> "$GITHUB_OUTPUT" diff --git a/.github/actions/install_dependencies/action.yaml b/.github/actions/install_dependencies/action.yaml deleted file mode 100644 index 11f15f4..0000000 --- a/.github/actions/install_dependencies/action.yaml +++ /dev/null @@ -1,43 +0,0 @@ -name: Install dependencies -description: Install dependencies specified in .tool-versions file using asdf - -inputs: - asdf_version: - description: The asdf version to install - required: true - -runs: - using: composite - steps: - - name: Install asdf - uses: asdf-vm/actions/setup@1902764435ca0dd2f3388eea723a4f92a4eb8302 - with: - asdf_version: ${{ inputs.asdf_version }} - - - name: Cache asdf - uses: actions/cache@v4 - with: - path: | - ~/.asdf - key: ${{ runner.os }}-asdf-${{ hashFiles('**/.tool-versions') }} - - - name: Install asdf dependencies in .tool-versions - uses: asdf-vm/actions/install@1902764435ca0dd2f3388eea723a4f92a4eb8302 - with: - asdf_version: ${{ inputs.asdf_version }} - env: - PYTHON_CONFIGURE_OPTS: --enable-shared - - - name: Reinstall poetry on top of desired python version - shell: bash - run: make reinstall-poetry - - - name: Cache python venv - uses: actions/cache@v4 - with: - path: .venv - key: ${{ runner.os }}-venv-${{ hashFiles('poetry.lock') }} - - - name: Setup python venv - shell: bash - run: make install diff --git a/.github/config/settings.yml b/.github/config/settings.yml new file mode 100644 index 0000000..05dbcda --- /dev/null +++ b/.github/config/settings.yml @@ -0,0 +1 @@ +TAG_FORMAT: "v${version}" diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 24212fe..0bffe61 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -6,25 +6,16 @@ on: - main jobs: - get_asdf_version: - name: Get asdf Version - runs-on: ubuntu-22.04 - outputs: - version: ${{ steps.get_asdf_version.outputs.version }} - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - name: Checkout source code - - - name: Get asdf version - id: get_asdf_version - uses: ./.github/actions/get_asdf_version + get_config_values: + uses: NHSDigital/eps-common-workflows/.github/workflows/get-repo-config.yml@cd3cf9fa582d391ce9c50b10c43155eb48ca65e3 + with: + verify_published_from_main_image: true quality_checks: name: Quality Checks - needs: get_asdf_version - uses: NHSDigital/eps-common-workflows/.github/workflows/quality-checks.yml@3166a790ef94af847ffcafc6b9fbadbf4c56f6d0 + needs: get_config_values + uses: NHSDigital/eps-common-workflows/.github/workflows/quality-checks-devcontainer.yml@cd3cf9fa582d391ce9c50b10c43155eb48ca65e3 with: - asdfVersion: ${{ needs.get_asdf_version.outputs.version }} - reinstall_poetry: true + pinned_image: ${{ needs.get_config_values.outputs.pinned_image }} secrets: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/.github/workflows/pull_request.yaml b/.github/workflows/pull_request.yaml index 213f48e..1f1fa50 100644 --- a/.github/workflows/pull_request.yaml +++ b/.github/workflows/pull_request.yaml @@ -9,22 +9,14 @@ on: jobs: pr_title_format_check: name: PR Title Format Check - uses: NHSDigital/eps-common-workflows/.github/workflows/pr_title_check.yml@3166a790ef94af847ffcafc6b9fbadbf4c56f6d0 + uses: NHSDigital/eps-common-workflows/.github/workflows/pr_title_check.yml@cd3cf9fa582d391ce9c50b10c43155eb48ca65e3 permissions: pull-requests: write + get_config_values: + uses: NHSDigital/eps-common-workflows/.github/workflows/get-repo-config.yml@cd3cf9fa582d391ce9c50b10c43155eb48ca65e3 + with: + verify_published_from_main_image: false - get_asdf_version: - name: Get asdf Version - runs-on: ubuntu-22.04 - outputs: - version: ${{ steps.get_asdf_version.outputs.version }} - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - name: Checkout source code - - - name: Get asdf version - id: get_asdf_version - uses: ./.github/actions/get_asdf_version get_pypi_token: name: Get PyPI Token for Trusted Publishing @@ -43,20 +35,19 @@ jobs: quality_checks: name: Quality Checks - needs: get_asdf_version - uses: NHSDigital/eps-common-workflows/.github/workflows/quality-checks.yml@3166a790ef94af847ffcafc6b9fbadbf4c56f6d0 + needs: get_config_values + uses: NHSDigital/eps-common-workflows/.github/workflows/quality-checks-devcontainer.yml@cd3cf9fa582d391ce9c50b10c43155eb48ca65e3 with: - asdfVersion: ${{ needs.get_asdf_version.outputs.version }} - reinstall_poetry: true + pinned_image: ${{ needs.get_config_values.outputs.pinned_image }} secrets: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} tag_release: name: Tag Release (Dry Run) - needs: [get_asdf_version, get_pypi_token] - uses: NHSDigital/eps-common-workflows/.github/workflows/tag-release.yml@3166a790ef94af847ffcafc6b9fbadbf4c56f6d0 + needs: [get_config_values, get_pypi_token] + uses: NHSDigital/eps-common-workflows/.github/workflows/tag-release-devcontainer.yml@cd3cf9fa582d391ce9c50b10c43155eb48ca65e3 with: - asdfVersion: ${{ needs.get_asdf_version.outputs.version }} + pinned_image: ${{ needs.get_config_values.outputs.pinned_image }} branch_name: ${{ github.event.pull_request.head.ref }} dry_run: true pypi_publish: true @@ -69,7 +60,7 @@ jobs: dependabot_auto_approve_and_merge: name: Dependabot Auto Approve and Merge needs: quality_checks - uses: NHSDigital/eps-common-workflows/.github/workflows/dependabot-auto-approve-and-merge.yml@3166a790ef94af847ffcafc6b9fbadbf4c56f6d0 + uses: NHSDigital/eps-common-workflows/.github/workflows/dependabot-auto-approve-and-merge.yml@cd3cf9fa582d391ce9c50b10c43155eb48ca65e3 permissions: contents: write pull-requests: write diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 44db61f..fc5d44e 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -4,19 +4,6 @@ on: workflow_dispatch: jobs: - get_asdf_version: - name: Get asdf Version - runs-on: ubuntu-22.04 - outputs: - version: ${{ steps.get-asdf-version.outputs.version }} - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - name: Checkout source code - - - name: Get asdf version - id: get-asdf-version - uses: ./.github/actions/get_asdf_version - get_pypi_token: name: Get PyPI Token for Trusted Publishing runs-on: ubuntu-22.04 @@ -31,41 +18,49 @@ jobs: - name: Get PyPI token id: get_pypi_token uses: ./.github/actions/get_pypi_token - + get_config_values: + uses: NHSDigital/eps-common-workflows/.github/workflows/get-repo-config.yml@cd3cf9fa582d391ce9c50b10c43155eb48ca65e3 + with: + verify_published_from_main_image: false quality_checks: name: Quality Checks - needs: get_asdf_version - uses: NHSDigital/eps-common-workflows/.github/workflows/quality-checks.yml@3166a790ef94af847ffcafc6b9fbadbf4c56f6d0 + needs: get_config_values + uses: NHSDigital/eps-common-workflows/.github/workflows/quality-checks-devcontainer.yml@cd3cf9fa582d391ce9c50b10c43155eb48ca65e3 with: - asdfVersion: ${{ needs.get_asdf_version.outputs.version }} - reinstall_poetry: true + pinned_image: ${{ needs.get_config_values.outputs.pinned_image }} secrets: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} get_next_version: name: Get Next Version Number for Poetry - uses: NHSDigital/eps-common-workflows/.github/workflows/tag-release.yml@3166a790ef94af847ffcafc6b9fbadbf4c56f6d0 - needs: [get_asdf_version, quality_checks] + uses: NHSDigital/eps-common-workflows/.github/workflows/tag-release-devcontainer.yml@cd3cf9fa582d391ce9c50b10c43155eb48ca65e3 + needs: [get_config_values, quality_checks] with: - asdfVersion: ${{ needs.get_asdf_version.outputs.version }} + pinned_image: ${{ needs.get_config_values.outputs.pinned_image }} branch_name: main dry_run: true build: name: Build Package and Upload as Artifact runs-on: ubuntu-22.04 - needs: [get_asdf_version, get_next_version] + container: + image: ${{ needs.get_config_values.outputs.pinned_image }} + options: --user 1001:1001 --group-add 128 + defaults: + run: + shell: bash + needs: [get_config_values, get_next_version] outputs: artifact_id: ${{ steps.upload-artifact.outputs.artifact-id }} steps: + - name: copy .tool-versions + run: | + cp /home/vscode/.tool-versions "$HOME/.tool-versions" - name: Git checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - - - name: Install dependencies - uses: ./.github/actions/install_dependencies - with: - asdf_version: ${{ needs.get_asdf_version.outputs.version }} - + uses: actions/checkout@v6 + - name: make install + run: | + make install - name: Build package run: | poetry version "$NEXT_VERSION" @@ -85,10 +80,10 @@ jobs: tag_release: name: Tag Release - uses: NHSDigital/eps-common-workflows/.github/workflows/tag-release.yml@3166a790ef94af847ffcafc6b9fbadbf4c56f6d0 - needs: [build, get_asdf_version, get_pypi_token] + uses: NHSDigital/eps-common-workflows/.github/workflows/tag-release-devcontainer.yml@cd3cf9fa582d391ce9c50b10c43155eb48ca65e3 + needs: [build, get_config_values, get_pypi_token] with: - asdfVersion: ${{ needs.get_asdf_version.outputs.version }} + pinned_image: ${{ needs.get_config_values.outputs.pinned_image }} branch_name: main extra_artifact_name: eps_spine_shared.zip extra_artifact_id: ${{ needs.build.outputs.artifact_id }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f3ff750..8d9db6a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,7 +24,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 - id: python-pre-commit diff --git a/.tool-versions b/.tool-versions deleted file mode 100644 index 193cb42..0000000 --- a/.tool-versions +++ /dev/null @@ -1,4 +0,0 @@ -actionlint 1.6.26 -poetry 2.1.3 -python 3.10.12 -shellcheck 0.9.0 diff --git a/.tool-versions.asdf b/.tool-versions.asdf deleted file mode 100644 index 4921076..0000000 --- a/.tool-versions.asdf +++ /dev/null @@ -1,2 +0,0 @@ -# define the .asdf-version to use here -0.18.0 diff --git a/.trivyignore b/.trivyignore deleted file mode 100644 index 344e1cd..0000000 --- a/.trivyignore +++ /dev/null @@ -1,8 +0,0 @@ -# urllib3 - can't upgrade due to spine version restraints -CVE-2025-66418 -CVE-2025-66471 -CVE-2026-21441 -CVE-2025-50181 - -# cryptography (moto dependency) - will eventually update via dependabot -CVE-2026-26007 diff --git a/.trivyignore.yaml b/.trivyignore.yaml new file mode 100644 index 0000000..7d70c48 --- /dev/null +++ b/.trivyignore.yaml @@ -0,0 +1,12 @@ +vulnerabilities: + - id: CVE-2025-66418 + statement: urllib3 - can't upgrade due to spine version restraints + - id: CVE-2025-66471 + statement: urllib3 - can't upgrade due to spine version restraints + - id: CVE-2026-21441 + statement: urllib3 - can't upgrade due to spine version restraints + - id: CVE-2025-50181 + statement: urllib3 - can't upgrade due to spine version restraints + - id: CVE-2026-26007 + statement: cryptography (moto dependency) - will eventually update via dependabot + expired_at: 2027-01-01 diff --git a/Makefile b/Makefile index 4412d2d..4720c38 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,11 @@ SHELL:=/usr/bin/env bash -O globstar .SHELLFLAGS = -ec -.PHONY: build check-licenses clean deep-clean format install lint python-pre-commit reinstall-poetry test +.PHONY: build clean deep-clean format install lint python-pre-commit reinstall-poetry test build: poetry build -check-licenses: - scripts/check_python_licenses.sh - clean: rm -rf dist rm -rf htmlcov @@ -40,3 +37,6 @@ reinstall-poetry: test: build poetry run python -m coverage run --data-file=.coverage/coverage -m pytest tests && \ poetry run python -m coverage xml --data-file=.coverage/coverage -o .coverage/info.xml + +%: + @$(MAKE) -f /usr/local/share/eps/Mk/common.mk $@ diff --git a/scripts/check_python_licenses.sh b/scripts/check_python_licenses.sh deleted file mode 100755 index 1a8148f..0000000 --- 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/trivy.yaml b/trivy.yaml new file mode 100644 index 0000000..eb24337 --- /dev/null +++ b/trivy.yaml @@ -0,0 +1 @@ +ignorefile: ".trivyignore.yaml"