diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index f519b68..3903c81 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,53 +1,14 @@ -FROM mcr.microsoft.com/devcontainers/base:ubuntu - -# provide DOCKER_GID via build args if you need to force group id to match host -ARG DOCKER_GID +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 \ - groupmod -g ${DOCKER_GID} docker; \ - fi && \ - usermod -aG docker vscode; \ + if ! getent group docker; then \ + groupadd -g ${DOCKER_GID} docker; \ + else \ + groupmod -g ${DOCKER_GID} docker; \ + fi && \ + usermod -aG docker vscode; \ fi - -# Anticipate and resolve potential permission issues with apt -RUN mkdir -p /tmp && chmod 1777 /tmp - -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 - -USER vscode - -# Install ASDF -RUN git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.11.3 && \ - echo '. $HOME/.asdf/asdf.sh' >> ~/.bashrc && \ - echo '. $HOME/.asdf/completions/asdf.bash' >> ~/.bashrc - -ENV PATH="$PATH:/home/vscode/.asdf/bin/:/workspaces/eps-prescription-tracker-ui/node_modules/.bin:/workspaces/eps-common-workflows/.venv/bin" - -# Install ASDF plugins# -RUN asdf plugin add nodejs https://github.com/asdf-vm/asdf-nodejs.git && \ - asdf plugin add actionlint && \ - asdf plugin add shellcheck https://github.com/luizm/asdf-shellcheck.git && \ - asdf plugin add poetry https://github.com/asdf-community/asdf-poetry.git && \ - asdf plugin add python - -WORKDIR /workspaces/eps-common-workflows - -ADD .tool-versions /workspaces/eps-common-workflows/.tool-versions -ADD .tool-versions /home/vscode/.tool-versions - -RUN asdf install python && \ - asdf install && \ - asdf reshim nodejs diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 9510367..601f388 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,15 +1,18 @@ -// 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-common-workflows", "build": { "dockerfile": "Dockerfile", "context": "..", "args": { - "DOCKER_GID": "${env:DOCKER_GID:}" - } + "DOCKER_GID": "${env:DOCKER_GID:}", + "IMAGE_NAME": "node_24_python_3_14", + "IMAGE_VERSION": "pr-23-d823049", + "USER_UID": "${localEnv:USER_ID:}", + "USER_GID": "${localEnv:GROUP_ID:}" + }, + "updateRemoteUserUID": false }, + "postAttachCommand": "git-secrets --register-aws; git-secrets --add-provider -- cat /usr/share/secrets-scanner/nhsd-rules-deny.txt", "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", @@ -20,15 +23,7 @@ "remoteEnv": { "LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}" }, - "postAttachCommand": "make install && docker build -f /workspaces/eps-common-workflows/dockerfiles/nhsd-git-secrets.dockerfile -t git-secrets . && pre-commit install --install-hooks -f", - "features": { - "ghcr.io/devcontainers/features/github-cli:1": {}, - "ghcr.io/devcontainers/features/docker-outside-of-docker:1": { - "version": "latest", - "moby": "true", - "installDockerBuildx": "true" - } - }, + "features": {}, "customizations": { "vscode": { "extensions": [ diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index f606e1f..29e7093 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -16,36 +16,45 @@ jobs: AUTOMERGE_PEM: ${{ secrets.AUTOMERGE_PEM }} pr_title_format_check: uses: ./.github/workflows/pr_title_check.yml - get_asdf_version: + get_config_values: runs-on: ubuntu-22.04 outputs: - asdf_version: ${{ steps.asdf-version.outputs.version }} tag_format: ${{ steps.load-config.outputs.TAG_FORMAT }} + devcontainer_version: ${{ steps.load-config.outputs.DEVCONTAINER_VERSION }} + devcontainer_image: ${{ steps.load-config.outputs.DEVCONTAINER_IMAGE }} 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" + DEVCONTAINER_IMAGE=$(jq -r '.build.args.IMAGE_NAME' .devcontainer/devcontainer.json) + DEVCONTAINER_VERSION=$(jq -r '.build.args.IMAGE_VERSION' .devcontainer/devcontainer.json) + { + echo "TAG_FORMAT=$TAG_FORMAT" + echo "DEVCONTAINER_IMAGE=$DEVCONTAINER_IMAGE" + echo "DEVCONTAINER_VERSION=$DEVCONTAINER_VERSION" + } >> "$GITHUB_OUTPUT" quality_checks: - uses: ./.github/workflows/quality-checks.yml - needs: [get_asdf_version] + uses: ./.github/workflows/quality-checks-devcontainer.yml + needs: [get_config_values] with: - asdfVersion: ${{ needs.get_asdf_version.outputs.asdf_version }} + runtime_docker_image: "${{ needs.get_config_values.outputs.devcontainer_image }}:githubactions-${{ needs.get_config_values.outputs.devcontainer_version }}" secrets: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} tag_release: - needs: [quality_checks, get_asdf_version] - uses: ./.github/workflows/tag-release.yml + needs: [quality_checks, get_config_values] + uses: ./.github/workflows/tag-release-devcontainer.yml + permissions: + contents: read + packages: read + attestations: read with: dry_run: true - asdfVersion: ${{ needs.get_asdf_version.outputs.asdf_version }} + runtime_docker_image: "${{ needs.get_config_values.outputs.devcontainer_image }}:githubactions-${{ needs.get_config_values.outputs.devcontainer_version }}" 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 }} + use_published_from_main_image: false secrets: inherit diff --git a/.github/workflows/quality-checks-devcontainer.yml b/.github/workflows/quality-checks-devcontainer.yml new file mode 100644 index 0000000..6393155 --- /dev/null +++ b/.github/workflows/quality-checks-devcontainer.yml @@ -0,0 +1,448 @@ +name: Quality Checks + +on: + workflow_call: + secrets: + SONAR_TOKEN: + required: false + inputs: + run_sonar: + type: boolean + description: Toggle to run sonar code analyis on this repository. + default: true + required: false + run_docker_scan: + type: boolean + description: Toggle to run docker vulnerability scan on this repository. + default: false + required: false + docker_images: + type: string + description: comma separated list of docker image references to scan when docker scanning is enabled. + default: "" + required: false + runtime_docker_image: + type: string + required: true + +jobs: + verify_attestation: + uses: ./.github/workflows/verify_attestation.yml + with: + runtime_docker_image: "${{ inputs.runtime_docker_image }}" + use_published_from_main_image: false + quality_checks: + runs-on: ubuntu-22.04 + needs: verify_attestation + container: + image: ${{ needs.verify_attestation.outputs.pinned_image }} + options: --user 1001:1001 --group-add 128 + defaults: + run: + shell: bash + steps: + - &init_tool_versions + name: copy .tool-versions + run: | + cp /home/vscode/.tool-versions "$HOME/.tool-versions" + + - &checkout + name: Checkout code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + ref: ${{ env.BRANCH_NAME }} + fetch-depth: 0 + + - &setup_npmrc + name: Setting up .npmrc + env: + NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + echo "//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}" >> ~/.npmrc + echo "@nhsdigital:registry=https://npm.pkg.github.com" >> ~/.npmrc + + - &cache_npm + name: Cache npm dependencies + uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb + with: + path: ./node_modules + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + + - name: make install + run: | + make install + - name: Run secrets scan + run: | + make secret-scan + - name: Run actionlint + run: | + make actionlint + + - name: Check language tools used and setup trivy config + id: check_languages + run: | + if [ -f "pyproject.toml" ] && grep -q '\[tool.poetry\]' "pyproject.toml"; then + echo "****************" + echo "Detected a poetry project" + echo "****************" + echo "uses_poetry=true" >> "$GITHUB_OUTPUT" + else + echo "****************" + echo "Project does not use poetry" + echo "****************" + echo "uses_poetry=false" >> "$GITHUB_OUTPUT" + fi + if [ -f pom.xml ]; then + echo "****************" + echo "Detected a Java project" + echo "****************" + echo "uses_java=true" >> "$GITHUB_OUTPUT" + else + echo "****************" + echo "Project does not use Java" + echo "****************" + echo "uses_java=false" >> "$GITHUB_OUTPUT" + fi + if [ -f package-lock.json ]; then + echo "****************" + echo "Detected a Node.js project" + echo "****************" + echo "uses_node=true" >> "$GITHUB_OUTPUT" + else + echo "****************" + echo "Project does not use Node.js" + echo "****************" + echo "uses_node=false" >> "$GITHUB_OUTPUT" + fi + if [ -f src/go.sum ]; then + echo "****************" + echo "Detected a Go project" + echo "****************" + echo "uses_go=true" >> "$GITHUB_OUTPUT" + else + echo "****************" + echo "Project does not use Go" + echo "****************" + echo "uses_go=false" >> "$GITHUB_OUTPUT" + fi + - name: Check licenses + run: | + make trivy-license-check + + - name: Show license scan output + if: always() + run: | + if [ -f license_scan.txt ]; then + cat .trivy_out/license_scan.txt + fi + - name: Run code lint + run: | + make lint + + - name: Run ShellCheck + run: | + make shellcheck + + - name: Run unit tests + run: | + make test + - name: make generate sbom + run: | + make trivy-generate-sbom + - name: Upload sbom + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f + with: + name: sbom.cdx.json + path: .trivy_out/sbom.cdx.json + + - name: Check python vulnerabilities + if: ${{ steps.check_languages.outputs.uses_poetry == 'true' }} + run: | + make trivy-scan-python + + - name: Check node vulnerabilities + if: ${{ steps.check_languages.outputs.uses_node == 'true' }} + run: | + make trivy-scan-node + - name: Check go vulnerabilities + if: ${{ steps.check_languages.outputs.uses_go == 'true' }} + run: | + make trivy-scan-go + - name: Check java vulnerabilities + if: ${{ steps.check_languages.outputs.uses_java == 'true' }} + run: | + make trivy-scan-java + - name: Show vulnerability output + if: always() + run: | + if [ -f .trivy_out/dependency_results_python.txt ]; then + cat .trivy_out/dependency_results_python.txt + fi + if [ -f .trivy_out/dependency_results_node.txt ]; then + cat .trivy_out/dependency_results_node.txt + fi + if [ -f .trivy_out/dependency_results_java.txt ]; then + cat .trivy_out/dependency_results_java.txt + fi + if [ -f .trivy_out/dependency_results_go.txt ]; then + cat .trivy_out/dependency_results_go.txt + fi + - name: "check is SONAR_TOKEN exists" + env: + super_secret: ${{ secrets.SONAR_TOKEN }} + if: ${{ env.super_secret != '' && inputs.run_sonar == true }} + run: echo "SONAR_TOKEN_EXISTS=true" >> "$GITHUB_ENV" + + - name: Run SonarQube analysis + if: ${{ steps.check_languages.outputs.uses_java == 'true' && env.SONAR_TOKEN_EXISTS == 'true' }} + run: | + # issues with sonar scanner and sslcontext-kickstart 9.1.0, forcing re-download + rm -rf ~/.m2/repository/io/github/hakky54/sslcontext-kickstart/9.1.0 + mvn dependency:get -U -Dartifact=io.github.hakky54:sslcontext-kickstart:9.1.0 + # run sonar scan + mvn sonar:sonar -Dsonar.token="$SONAR_TOKEN" + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + + - name: SonarCloud Scan + uses: SonarSource/sonarqube-scan-action@a31c9398be7ace6bbfaf30c0bd5d415f843d45e9 + if: ${{ steps.check_languages.outputs.uses_java == 'false' && env.SONAR_TOKEN_EXISTS == 'true' }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + + get_docker_images_to_scan: + runs-on: ubuntu-22.04 + needs: verify_attestation + container: + image: ${{ needs.verify_attestation.outputs.pinned_image }} + options: --user 1001:1001 --group-add 128 + defaults: + run: + shell: bash + outputs: + docker_images: ${{ steps.normalized_docker_images.outputs.images }} + steps: + - *init_tool_versions + - *checkout + - name: Determine docker images to scan + id: normalized_docker_images + env: + DOCKER_IMAGES: ${{ inputs.docker_images }} + run: | + if [ "${{ inputs.run_docker_scan }}" != "true" ]; then + echo "Docker scanning disabled; emitting empty image list." + echo 'images=[]' >> "$GITHUB_OUTPUT" + exit 0 + fi + + INPUT="${DOCKER_IMAGES}" + + if [ -z "$INPUT" ]; then + INPUT="[]" + fi + + normalize_to_json_array() { + local raw="$1" + + # If the input already looks like JSON, return as-is + if echo "$raw" | grep -q '^[[:space:]]*\['; then + echo "$raw" + return + fi + + local json="[" + local first=true + IFS=',' read -ra ITEMS <<< "$raw" + for item in "${ITEMS[@]}"; do + # Trim whitespace around each image reference + item=$(echo "$item" | xargs) + if [ -z "$item" ]; then + continue + fi + if [ "$first" = true ]; then + first=false + else + json+=", " + fi + json+="\"$item\"" + done + json+="]" + echo "$json" + } + + NORMALIZED=$(normalize_to_json_array "$INPUT") + + if [ "$NORMALIZED" = "[]" ]; then + echo "No docker images provided" + exit 1 + fi + + echo "Using provided docker images: $NORMALIZED" + echo "images=$NORMALIZED" >> "$GITHUB_OUTPUT" + + docker_vulnerability_scan: + runs-on: ubuntu-22.04 + needs: [get_docker_images_to_scan, verify_attestation] + container: + image: ${{ needs.verify_attestation.outputs.pinned_image }} + options: --user 1001:1001 --group-add 128 + defaults: + run: + shell: bash + if: ${{ inputs.run_docker_scan == true }} + strategy: + matrix: + docker_image: ${{ fromJson(needs.get_docker_images_to_scan.outputs.docker_images) }} + steps: + - *init_tool_versions + - *checkout + - *setup_npmrc + - *cache_npm + + - name: make install + run: | + make install + + - name: Build docker images + run: | + make docker-build + env: + DOCKER_IMAGE: ${{ matrix.docker_image }} + + - name: Check docker vulnerabilities + run: | + make trivy-scan-docker + env: + DOCKER_IMAGE: ${{ matrix.docker_image }} + + - name: Show docker vulnerability output + if: always() + run: | + echo "Scan output for ${{ matrix.docker_image }}" + if [ -f .trivy_out/dependency_results_docker.txt ]; then + cat .trivy_out/dependency_results_docker.txt + fi + + IaC-validation: + runs-on: ubuntu-22.04 + needs: verify_attestation + container: + image: ${{ needs.verify_attestation.outputs.pinned_image }} + options: --user 1001:1001 --group-add 128 + defaults: + run: + shell: bash + steps: + - *init_tool_versions + - *checkout + - *setup_npmrc + - *cache_npm + + - name: Check for SAM templates + id: check_sam_templates + run: | + if [ -d "SAMtemplates" ]; then + echo "****************" + echo "Project has SAM templates" + echo "****************" + echo "sam_exists=true" >> "$GITHUB_OUTPUT" + else + echo "****************" + echo "Project does not have SAM templates" + echo "****************" + echo "sam_exists=false" >> "$GITHUB_OUTPUT" + fi + + - name: Check for cloudformation templates + id: check_cf_templates + run: | + if [ -d "cloudformation" ]; then + echo "****************" + echo "Project has cloudformation templates" + echo "****************" + echo "cf_exists=true" >> "$GITHUB_OUTPUT" + else + echo "****************" + echo "Project does not have cloudformation templates" + echo "****************" + echo "cf_exists=false" >> "$GITHUB_OUTPUT" + fi + + - name: Check for cdk + id: check_cdk + run: | + if [ -d "packages/cdk" ]; then + echo "****************" + echo "Project has cdk" + echo "****************" + echo "cdk_exists=true" >> "$GITHUB_OUTPUT" + else + echo "****************" + echo "Project does not have cdk" + echo "****************" + echo "cdk_exists=false" >> "$GITHUB_OUTPUT" + fi + + - name: Run cfn-lint + if: steps.check_sam_templates.outputs.sam_exists == 'true' || steps.check_cf_templates.outputs.cf_exists == 'true' + run: | + make cfn-lint + + - name: make install NodeJS + if: steps.check_cdk.outputs.cdk_exists == 'true' + run: | + make install-node compile + + - name: Run cdk-synth + if: steps.check_cdk.outputs.cdk_exists == 'true' + run: | + make cdk-synth + + - name: Run cfn-guard script for sam templates + run: | + make cfn-guard-sam-templates + + - name: Run cfn-guard script for cloudformation templates + if: steps.check_cf_templates.outputs.cf_exists == 'true' + run: | + make cfn-guard-cloudformation + - name: Run cfn-guard script for cdk templates + if: steps.check_cdk.outputs.cdk_exists == 'true' + run: | + make cfn-guard-cdk + + - name: Download terraform plans + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 + with: + pattern: "*_terraform_plan" + path: terraform_plans/ + merge-multiple: true + + - name: Check terraform plans exist + id: check_terraform_plans + run: | + if [ ! -d terraform_plans ]; then + echo "Terraform plans not present." + echo "terraform_plans_exist=false" >> "$GITHUB_OUTPUT" + else + echo "Terraform plans present:" + ls -l terraform_plans/ + echo "terraform_plans_exist=true" >> "$GITHUB_OUTPUT" + fi + + - name: Run cfn-guard script for terraform plans + if: steps.check_terraform_plans.outputs.terraform_plans_exist == 'true' + run: | + make cfn-guard-terraform + + - name: Show cfn-guard output + if: failure() + run: find .cfn_guard_out -type f -print0 | xargs -0 cat + + - name: Upload cfn_guard_output + if: failure() + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f + with: + name: cfn_guard_output + path: .cfn_guard_out diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c4cc00a..ba9104a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,36 +8,41 @@ env: BRANCH_NAME: ${{ github.event.ref.BRANCH_NAME }} jobs: - get_asdf_version: + get_config_values: runs-on: ubuntu-22.04 outputs: - asdf_version: ${{ steps.asdf-version.outputs.version }} tag_format: ${{ steps.load-config.outputs.TAG_FORMAT }} + devcontainer_version: ${{ steps.load-config.outputs.DEVCONTAINER_VERSION }} + devcontainer_image: ${{ steps.load-config.outputs.DEVCONTAINER_IMAGE }} 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" + DEVCONTAINER_IMAGE=$(jq -r '.build.args.IMAGE_NAME' .devcontainer/devcontainer.json) + DEVCONTAINER_VERSION=$(jq -r '.build.args.IMAGE_VERSION' .devcontainer/devcontainer.json) + { + echo "TAG_FORMAT=$TAG_FORMAT" + echo "DEVCONTAINER_IMAGE=$DEVCONTAINER_IMAGE" + echo "DEVCONTAINER_VERSION=$DEVCONTAINER_VERSION" + } >> "$GITHUB_OUTPUT" quality_checks: - needs: [get_asdf_version] - uses: ./.github/workflows/quality-checks.yml + needs: [get_config_values] + uses: ./.github/workflows/quality-checks-devcontainer.yml with: - asdfVersion: ${{ needs.get_asdf_version.outputs.asdf_version }} + runtime_docker_image: "${{ needs.get_config_values.outputs.devcontainer_image }}:githubactions-${{ needs.get_config_values.outputs.devcontainer_version }}" secrets: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} tag_release: - needs: [quality_checks, get_asdf_version] - uses: ./.github/workflows/tag-release.yml + needs: [quality_checks, get_config_values] + uses: ./.github/workflows/tag-release-devcontainer.yml with: dry_run: false - asdfVersion: ${{ needs.get_asdf_version.outputs.asdf_version }} + runtime_docker_image: "${{ needs.get_config_values.outputs.devcontainer_image }}:githubactions-${{ needs.get_config_values.outputs.devcontainer_version }}" branch_name: main - tag_format: ${{ needs.get_asdf_version.outputs.tag_format }} + tag_format: ${{ needs.get_config_values.outputs.tag_format }} + use_published_from_main_image: true secrets: inherit diff --git a/.github/workflows/tag-release-devcontainer.yml b/.github/workflows/tag-release-devcontainer.yml new file mode 100644 index 0000000..33cd12d --- /dev/null +++ b/.github/workflows/tag-release-devcontainer.yml @@ -0,0 +1,287 @@ +name: Tag Release + +on: + workflow_call: + inputs: + dry_run: + description: "Whether to run in dry-run mode (true) or create actual tags (false)" + required: true + type: boolean + branch_name: + description: "The branch name to base the release on" + required: true + type: string + runtime_docker_image: + type: string + required: true + publish_packages: + description: "comma separated list of package folders to publish to an npm registry" + required: false + type: string + default: "" + tag_format: + description: "The tag format to use for the release tags" + required: false + type: string + default: "v${version}" + main_branch: + description: "The main branch name for releases" + required: false + type: string + default: "main" + extra_artifact_name: + description: "An extra artifact to include in the release" + required: false + type: string + extra_artifact_id: + description: "An id for the extra artifact" + required: false + type: string + extra_artifact_run_id: + description: "An run id for the extra artifact" + required: false + type: string + extra_artifact_repository: + description: "An repository for the extra artifact" + required: false + type: string + use_published_from_main_image: + required: true + type: boolean + outputs: + version_tag: + value: ${{ jobs.tag_release.outputs.version_tag }} + change_set_version: + description: "The change set version for deployments" + value: ${{ jobs.tag_release.outputs.change_set_version }} + next_version_tag: + description: "The next version tag that will be created" + value: ${{ jobs.tag_release.outputs.next_version_tag }} + secrets: + NPM_TOKEN: + required: false + description: "NPM token to publish packages" +jobs: + verify_attestation: + uses: ./.github/workflows/verify_attestation.yml + with: + runtime_docker_image: "${{ inputs.runtime_docker_image }}" + use_published_from_main_image: ${{ inputs.use_published_from_main_image }} + tag_release: + runs-on: ubuntu-22.04 + needs: verify_attestation + container: + image: ${{ needs.verify_attestation.outputs.pinned_image }} + options: --user 1001:1001 --group-add 128 + defaults: + run: + shell: bash + outputs: + version_tag: ${{steps.output_version_tag.outputs.VERSION_TAG}} + change_set_version: ${{ steps.output_change_set_version.outputs.CHANGE_SET_VERSION }} + next_version_tag: ${{ steps.output_version_tag.outputs.NEXT_VERSION_TAG }} + steps: + - name: copy .tool-versions + run: | + cp /home/vscode/.tool-versions "$HOME/.tool-versions" + - name: Clone calling repo + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + repository: ${{ github.repository }} + ref: ${{ github.sha }} + + - name: Checkout semantic-release workflow + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + repository: NHSDigital/eps-common-workflows + sparse-checkout-cone-mode: false + path: common_workflow_config + sparse-checkout: | + package.json + package-lock.json + release.config.cjs + releaseNotesTemplates/commit.hbs + - name: Install semantic release dependencies globally + run: | + cd common_workflow_config + dependencies="$(jq -r '.devDependencies | to_entries | map("\(.key)@\(.value)") | join(" ")' package.json)" + echo "Installing: $dependencies" + + # shellcheck disable=SC2086 + npm install --global $dependencies + echo "Copying semantic-release config and templates for use in the workflow" + cp release.config.cjs ../ + mkdir -p ../releaseNotesTemplates + cp releaseNotesTemplates/commit.hbs ../releaseNotesTemplates/ + echo "Current dir is ${PWD}" + - name: Setup Git branch for semantic-release + run: | + # When running from a PR, GitHub checks out a merge commit + # We need to ensure we're on the actual branch for semantic-release + git checkout -B "${BRANCH_NAME}" + git branch --show-current + env: + BRANCH_NAME: ${{ inputs.branch_name }} + + - name: Install Dependencies and Build Package + if: inputs.publish_packages != '' + run: | + make install + make build + + - name: Download extra artifact + if: ${{ inputs.extra_artifact_name != '' }} + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 + with: + artifact-ids: ${{ inputs.extra_artifact_id }} + github-token: ${{ secrets.GITHUB_TOKEN }} + repository: ${{ inputs.extra_artifact_repository }} + run-id: ${{ inputs.extra_artifact_run_id }} + + - name: Set VERSION_TAG based on dry_run flag + id: output_version_tag + run: | + if [ "${{ inputs.dry_run }}" = "true" ]; then + # Determine semantic-release command based on branch + if [ "${BRANCH_NAME}" = "${MAIN_BRANCH}" ]; then + echo "on ${MAIN_BRANCH} branch" + npx semantic-release --dry-run --tag-format "${TAG_FORMAT}" > semantic-release-output.log + exit_code=1 + else + # For non-main branches, override the branches configuration + echo "overriding branches for semantic-release to ${BRANCH_NAME}" + + # we need to set GITHUB_REF and GITHUB_EVENT_NAME for semantic-release to work correctly + # but need to ensure that actionlint does not complain about unused variables + + # shellcheck disable=SC2034 + GITHUB_REF=refs/heads/${BRANCH_NAME} + # shellcheck disable=SC2034 + GITHUB_EVENT_NAME=push + echo "running semantic-release" + npx semantic-release --dry-run --branches "${BRANCH_NAME}" --branch "${BRANCH_NAME}" --tag-format "${TAG_FORMAT}" > semantic-release-output.log + echo "finish semantic-release with exit code $?" + exit_code=0 + fi + # Dry run mode: use short git SHA and get next version for summary + VERSION_TAG=$(git rev-parse --short HEAD) + echo "Getting next_version" + NEXT_VERSION=$(grep -i 'The next release version is' semantic-release-output.log | sed -E 's/.* ([[:digit:].]+)$/\1/' || true) + NEXT_VERSION=${NEXT_VERSION:-UNKNOWN} + echo "got next version" + # disabling shellcheck as replace does not work + # shellcheck disable=SC2001 + NEW_VERSION_TAG=$(echo "$TAG_FORMAT" | sed "s/\${version}/$NEXT_VERSION/") + echo "## VERSION TAG : ${VERSION_TAG}" >> "$GITHUB_STEP_SUMMARY" + echo "## NEXT TAG WILL BE : ${NEW_VERSION_TAG}" >> "$GITHUB_STEP_SUMMARY" + if [ "${NEXT_VERSION}" == "UNKNOWN" ] + then + echo "Could not get next tag. Here is the log from semantic-release" + cat semantic-release-output.log + exit ${exit_code} + fi + else + # Production mode: get next version and create actual tag + npx semantic-release --dry-run --tag-format "${TAG_FORMAT}" > semantic-release-output.log + NEXT_VERSION=$(grep -i 'The next release version is' semantic-release-output.log | sed -E 's/.* ([[:digit:].]+)$/\1/') + # disabling shellcheck as replace does not work + # shellcheck disable=SC2001 + VERSION_TAG=$(echo "$TAG_FORMAT" | sed "s/\${version}/$NEXT_VERSION/") + echo "## VERSION TAG : ${VERSION_TAG}" >> "$GITHUB_STEP_SUMMARY" + fi + echo "VERSION_TAG=${VERSION_TAG}" >> "$GITHUB_OUTPUT" + echo "VERSION_TAG=${VERSION_TAG}" >> "$GITHUB_ENV" + echo "NEXT_VERSION_TAG=${NEW_VERSION_TAG}" >> "$GITHUB_OUTPUT" + env: + GITHUB_TOKEN: ${{ github.token }} + BRANCH_NAME: ${{ inputs.branch_name }} + PUBLISH_PACKAGES: ${{ inputs.publish_packages }} + TAG_FORMAT: ${{ inputs.tag_format }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + MAIN_BRANCH: ${{ inputs.main_branch }} + EXTRA_ASSET: ${{ inputs.extra_artifact_name }} + + - name: Create semantic release tag + if: ${{ !inputs.dry_run }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + PUBLISH_PACKAGES: ${{ inputs.publish_packages }} + TAG_FORMAT: ${{ inputs.tag_format }} + MAIN_BRANCH: ${{ inputs.main_branch }} + EXTRA_ASSET: ${{ inputs.extra_artifact_name }} + run: | + npx semantic-release --tag-format "${TAG_FORMAT}" + + - name: Get release for editing + if: ${{ !inputs.dry_run }} + id: get_release + # version 1.2.4 + uses: cardinalby/git-get-release-action@5172c3a026600b1d459b117738c605fabc9e4e44 + env: + GITHUB_TOKEN: ${{ github.token }} + with: + tag: ${{ steps.output_version_tag.outputs.VERSION_TAG }} + + - name: Edit Release + if: ${{ !inputs.dry_run }} + # version 1.2.0 + uses: irongut/EditRelease@ccf529ad26dddf9996e7dd0f24ca5da4ea507cc2 + with: + token: ${{ secrets.GITHUB_TOKEN }} + id: ${{ steps.get_release.outputs.id }} + body: | + ## Info + [Release workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) - Workflow ID: ${{ github.run_id }} + + It was initialized by [${{ github.event.sender.login }}](${{ github.event.sender.html_url }}) + + - name: Checkout gh-pages branch + if: ${{ !inputs.dry_run }} + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + repository: ${{ github.repository }} + ref: gh-pages + path: gh-pages + + - name: Publish release notes to gh-pages + if: ${{ !inputs.dry_run }} + working-directory: gh-pages + env: + RELEASE_ID: ${{ steps.get_release.outputs.id }} + VERSION_TAG: ${{ steps.output_version_tag.outputs.VERSION_TAG }} + GH_REPO: ${{ github.repository }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -euo pipefail + notes_dir="release_notes" + mkdir -p "$notes_dir" + note_file="$notes_dir/${VERSION_TAG}.md" + + gh api "/repos/${GH_REPO}/releases/${RELEASE_ID}" | jq -r '.body // ""' > "$note_file" + + if [ ! -s "$note_file" ]; then + echo "Release notes are empty; skipping gh-pages update." + exit 0 + fi + + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + + git add -f "$note_file" + if git diff --cached --quiet; then + echo "No changes detected in release notes; skipping commit." + exit 0 + fi + + git commit -m "docs: add release notes for ${VERSION_TAG}" + parallel --retries 10 --delay 3 ::: "git pull --rebase && git push" + + - name: Output Change Set Version + id: output_change_set_version + shell: bash + run: | + TIMESTAMP=$(date +%s) + VERSION=$(echo ${{ steps.output_version_tag.outputs.VERSION_TAG }} | tr . -) + echo CHANGE_SET_VERSION="$VERSION-$TIMESTAMP" >> "$GITHUB_OUTPUT" diff --git a/.github/workflows/verify_attestation.yml b/.github/workflows/verify_attestation.yml new file mode 100644 index 0000000..55a3ab3 --- /dev/null +++ b/.github/workflows/verify_attestation.yml @@ -0,0 +1,111 @@ +name: Verify image digest and attestation +"on": + workflow_call: + inputs: + runtime_docker_image: + required: true + type: string + description: Image reference as name:tag (for example node_24_python_3_12:v1.2.3) or fully qualified image ref + registry: + required: false + type: string + default: ghcr.io + namespace: + required: false + type: string + default: nhsdigital/eps-devcontainers + owner: + required: false + type: string + default: NHSDigital + use_published_from_main_image: + required: false + type: boolean + default: true + predicate_type: + required: false + type: string + default: https://slsa.dev/provenance/v1 + outputs: + pinned_image: + description: Fully-qualified digest-pinned image reference + value: ${{ jobs.verify_attestation.outputs.pinned_image }} + resolved_digest: + description: Resolved digest for the supplied image reference + value: ${{ jobs.verify_attestation.outputs.resolved_digest }} + +jobs: + verify_attestation: + runs-on: ubuntu-22.04 + permissions: + contents: read + packages: read + attestations: read + outputs: + pinned_image: ${{ steps.resolve.outputs.pinned_image }} + resolved_digest: ${{ steps.resolve.outputs.resolved_digest }} + steps: + - name: Login to github container registry + if: startsWith(inputs.registry, 'ghcr.io') + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Resolve digest + id: resolve + shell: bash + env: + RUNTIME_DOCKER_IMAGE: ${{ inputs.runtime_docker_image }} + REGISTRY: ${{ inputs.registry }} + NAMESPACE: ${{ inputs.namespace }} + run: | + set -euo pipefail + + if [[ "$RUNTIME_DOCKER_IMAGE" == *"/"* ]]; then + IMAGE_REF="$RUNTIME_DOCKER_IMAGE" + else + IMAGE_REF="${REGISTRY}/${NAMESPACE}/${RUNTIME_DOCKER_IMAGE}" + fi + + if [[ "$IMAGE_REF" == *@sha256:* ]]; then + IMAGE_BASE="${IMAGE_REF%@*}" + RESOLVED_DIGEST="${IMAGE_REF#*@}" + else + RESOLVED_DIGEST="$(docker buildx imagetools inspect "$IMAGE_REF" | awk '/^Digest:/ {print $2; exit}')" + IMAGE_BASE="${IMAGE_REF%:*}" + fi + + if [[ -z "$RESOLVED_DIGEST" ]]; then + echo "Could not resolve digest for image: $IMAGE_REF" >&2 + exit 1 + fi + + PINNED_IMAGE="${IMAGE_BASE}@${RESOLVED_DIGEST}" + echo "resolved_digest=${RESOLVED_DIGEST}" >> "$GITHUB_OUTPUT" + echo "pinned_image=${PINNED_IMAGE}" >> "$GITHUB_OUTPUT" + echo "Resolved image reference: ${IMAGE_REF}" + echo "Resolved digest: ${RESOLVED_DIGEST}" + echo "Resolved image reference: ${PINNED_IMAGE}" + + - name: Verify attestation + shell: bash + env: + GH_TOKEN: ${{ github.token }} + OWNER: ${{ inputs.owner }} + USE_PUBLISHED_FROM_MAIN_IMAGE: ${{ inputs.use_published_from_main_image }} + PREDICATE_TYPE: ${{ inputs.predicate_type }} + PINNED_IMAGE: ${{ steps.resolve.outputs.pinned_image }} + run: | + set -euo pipefail + + args=("oci://${PINNED_IMAGE}" "--owner" "$OWNER" "--predicate-type" "$PREDICATE_TYPE") + + if [[ "$USE_PUBLISHED_FROM_MAIN_IMAGE" == "true" ]]; then + args+=("--source-ref" "refs/heads/main") + fi + + + GH_FORCE_TTY=120 gh attestation verify "${args[@]}" 2>&1 + echo "Verified attestation for ${PINNED_IMAGE}" diff --git a/.gitignore b/.gitignore index 5642dae..0ed3cb4 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ .DS_Store release_notes .venv -.asdf \ No newline at end of file +.asdf +.trivy_out diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index db94a2e..f319077 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -23,7 +23,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: lint-githubactions name: Lint github actions diff --git a/.tool-versions b/.tool-versions deleted file mode 100644 index 8605e6e..0000000 --- a/.tool-versions +++ /dev/null @@ -1,5 +0,0 @@ -nodejs 24.12.0 -actionlint 1.7.10 -shellcheck 0.11.0 -python 3.14.2 -poetry 2.2.1 diff --git a/.tool-versions.asdf b/.tool-versions.asdf deleted file mode 100644 index aa85979..0000000 --- a/.tool-versions.asdf +++ /dev/null @@ -1,2 +0,0 @@ -# define the .asdf-version to use here -0.18.0 \ No newline at end of file diff --git a/.trivyignore.yaml b/.trivyignore.yaml index b578dd9..2809a32 100644 --- a/.trivyignore.yaml +++ b/.trivyignore.yaml @@ -10,6 +10,12 @@ vulnerabilities: - id: CVE-2026-25547 statement: isaacs/brace-expansion vulnerability accepted as risk - dependency of semantic-release expired_at: 2026-03-01 - - id: CVE-2026-0775 + - id: CVE-2026-0775 statement: npm vulnerability accepted as risk - dependency of semantic-release expired_at: 2026-03-01 + - id: CVE-2026-26960 + statement: tar vulnerability accepted as risk - dependency of semantic-release + expired_at: 2026-03-01 + - id: CVE-2026-26996 + statement: minimatch vulnerability accepted as risk - dependency of semantic-release + expired_at: 2026-04-01 diff --git a/Makefile b/Makefile index aae27f8..e466290 100644 --- a/Makefile +++ b/Makefile @@ -14,12 +14,8 @@ install-hooks: install-python deep-clean: find . -name 'node_modules' -type d -prune -exec rm -rf '{}' + -check-licenses: check-licenses-python - -check-licenses-python: - scripts/check_python_licenses.sh - lint: lint-githubactions lint-githubaction-scripts + echo "Linting complete" lint-githubactions: actionlint @@ -32,3 +28,6 @@ test: build: echo "Not implemented" + +%: + @$(MAKE) -f /usr/local/share/eps/Mk/common.mk $@ diff --git a/README.md b/README.md index 590766a..3aa7ea2 100644 --- a/README.md +++ b/README.md @@ -157,6 +157,43 @@ jobs: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} ``` +## quality checks - dev container version +This workflow runs common quality checks using a prebuilt devcontainer (https://github.com/NHSDigital/eps-devcontainers). +To use this, you must have overridden any common makefile targets described in https://github.com/NHSDigital/eps-devcontainers?tab=readme-ov-file#common-makefile-targets +#### Inputs + +- `run_sonar`: Whether to run sonar checks or not. +- `run_docker_scan`: whether to run a scan of docker images +- `docker_images`: csv list of docker images to scan. These must match images produced by make docker-build +- `runtime_docker_image`: the docker image to run everything on. This should just be the image name and tag pushed to https://github.com/NHSDigital/eps-devcontainers +#### Secret Inputs +- `SONAR_TOKEN`: Token used to authenticate to sonar + +#### Outputs + +None + +#### Example + +To use this workflow in your repository, call it from another workflow file: + +```yaml +name: Release + +on: + workflow_dispatch: + +jobs: + quality_checks: + uses: NHSDigital/eps-common-workflows/.github/workflows/quality-checks.yml@f5c8313a10855d0cc911db6a9cd666494c00045a + needs: [get_config_values] + with: + runtime_docker_image: "${{ needs.get_config_values.outputs.devcontainer_image }}:githubactions-${{ needs.get_config_values.outputs.devcontainer_version }}" + run_docker_scan: true + docker_images: fhir-facade,validator + secrets: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} +``` ## tag release @@ -197,6 +234,49 @@ jobs: publish_package: false ``` +## tag release - devcontainer version +This workflow uses the semantic-release npm package to generate a new version tag, changelog, and github release for a repo. +*The devcontainer MUST have node installed* +#### Inputs + +- `dry_run`: Whether to run in dry_run mode (do not create tags) or not +- `branch_name`: The branch name to base the release on +- `runtime_docker_image`: the docker image to run everything on. This should just be the image name and tag pushed to https://github.com/NHSDigital/eps-devcontainers +- `publish_packages`: comma separated list of package folders to publish to an npm registry +- `tagFormat`: Default `v\\${version}`. A template for the version tag. +- `main_branch`: The branch to use for publishing. Defaults to main +- `extra_artifact_name`: optional param to include an extra artifact in the release +- `extra_artifact_id`: optional param of the extra artifact id to include in the release +- `extra_artifact_run_id`: optional param of the run id to download the extra artifact id to include in the release +- `extra_artifact_repository` optional param to indicate which repo the run to download the artifact was from + +#### Outputs + +- `version_tag`: The version tag created by semantic-release. +- `change_set_version`: A timestamped string that con be used for creating changesets. + +#### Example + +To use this workflow in your repository, call it from another workflow file: + +```yaml +name: Release + +on: + workflow_dispatch: + +jobs: + tag_release: + uses: NHSDigital/eps-common-workflows/.github/workflows/tag-release-devcontainer.yml@f5c8313a10855d0cc911db6a9cd666494c00045a + needs: [get_config_values] + with: + tagFormat: "v\\${version}-beta" + dry_run: true + runtime_docker_image: "${{ needs.get_config_values.outputs.devcontainer_image }}:githubactions-${{ needs.get_config_values.outputs.devcontainer_version }}" + branch_name: main + publish_package: false +``` + ## Secret scanning docker diff --git a/package-lock.json b/package-lock.json index 0733795..f5a605f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,6 @@ "@semantic-release/github": "^12.0.5", "@semantic-release/release-notes-generator": "^14.1.0", "conventional-changelog-eslint": "^6.0.0", - "license-checker": "^25.0.1", "semantic-release": "^25.0.3" } }, @@ -132,6 +131,7 @@ "integrity": "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@octokit/auth-token": "^6.0.0", "@octokit/graphql": "^9.0.3", @@ -634,13 +634,6 @@ "dev": true, "license": "MIT" }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true, - "license": "ISC" - }, "node_modules/agent-base": { "version": "7.1.4", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", @@ -728,16 +721,6 @@ "dev": true, "license": "MIT" }, - "node_modules/array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/array-ify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", @@ -745,20 +728,6 @@ "dev": true, "license": "MIT" }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "dev": true, - "license": "MIT" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, "node_modules/before-after-hook": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz", @@ -773,17 +742,6 @@ "dev": true, "license": "MIT" }, - "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "node_modules/braces": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", @@ -1112,13 +1070,6 @@ "dot-prop": "^5.1.0" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, "node_modules/config-chain": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", @@ -1326,17 +1277,6 @@ } } }, - "node_modules/debuglog": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", - "integrity": "sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, "node_modules/deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -1347,17 +1287,6 @@ "node": ">=4.0.0" } }, - "node_modules/dezalgo": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", - "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", - "dev": true, - "license": "ISC", - "dependencies": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -1736,23 +1665,6 @@ "node": ">=14.14" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/function-timeout": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/function-timeout/-/function-timeout-1.0.2.tgz", @@ -1817,28 +1729,6 @@ "traverse": "0.6.8" } }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -1878,19 +1768,6 @@ "node": ">=4" } }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/highlight.js": { "version": "10.7.3", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", @@ -1914,13 +1791,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true, - "license": "ISC" - }, "node_modules/http-proxy-agent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", @@ -2034,18 +1904,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -2084,22 +1942,6 @@ "dev": true, "license": "MIT" }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -2257,48 +2099,6 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/license-checker": { - "version": "25.0.1", - "resolved": "https://registry.npmjs.org/license-checker/-/license-checker-25.0.1.tgz", - "integrity": "sha512-mET5AIwl7MR2IAKYYoVBBpV0OnkKQ1xGj2IMMeEFIs42QAkEVjRtFZGWmQ28WeU7MP779iAgOaOy93Mn44mn6g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "chalk": "^2.4.1", - "debug": "^3.1.0", - "mkdirp": "^0.5.1", - "nopt": "^4.0.1", - "read-installed": "~4.0.3", - "semver": "^5.5.0", - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0", - "spdx-satisfies": "^4.0.0", - "treeify": "^1.1.0" - }, - "bin": { - "license-checker": "bin/license-checker" - } - }, - "node_modules/license-checker/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/license-checker/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -2430,6 +2230,7 @@ "integrity": "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==", "dev": true, "license": "MIT", + "peer": true, "bin": { "marked": "bin/marked.js" }, @@ -2535,19 +2336,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", @@ -2558,19 +2346,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -2620,43 +2395,6 @@ "node": ">=18" } }, - "node_modules/nopt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", - "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", - "dev": true, - "license": "ISC", - "dependencies": { - "abbrev": "1", - "osenv": "^0.1.4" - }, - "bin": { - "nopt": "bin/nopt.js" - } - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, "node_modules/normalize-url": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.1.0.tgz", @@ -2827,13 +2565,6 @@ "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/npm-normalize-package-bin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", - "dev": true, - "license": "ISC" - }, "node_modules/npm-run-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", @@ -4690,6 +4421,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -4832,16 +4564,6 @@ "node": ">=0.10.0" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, "node_modules/onetime": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", @@ -4858,38 +4580,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "deprecated": "This package is no longer supported.", - "dev": true, - "license": "ISC", - "dependencies": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, "node_modules/p-each-series": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-3.0.0.tgz", @@ -5098,16 +4788,6 @@ "node": ">=4" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -5118,13 +4798,6 @@ "node": ">=8" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -5225,49 +4898,6 @@ "rc": "cli.js" } }, - "node_modules/read-installed": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz", - "integrity": "sha512-O03wg/IYuV/VtnK2h/KXEt9VIbMUFbk3ERG0Iu4FhLZw0EP0T9znqrYDGn6ncbEsXUFaUjiVAWXHzxwt3lhRPQ==", - "deprecated": "This package is no longer supported.", - "dev": true, - "license": "ISC", - "dependencies": { - "debuglog": "^1.0.1", - "read-package-json": "^2.0.0", - "readdir-scoped-modules": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "slide": "~1.1.3", - "util-extend": "^1.0.1" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.2" - } - }, - "node_modules/read-installed/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/read-package-json": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.2.tgz", - "integrity": "sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==", - "deprecated": "This package is no longer supported. Please use @npmcli/package-json instead.", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.1", - "json-parse-even-better-errors": "^2.3.0", - "normalize-package-data": "^2.0.0", - "npm-normalize-package-bin": "^1.0.0" - } - }, "node_modules/read-package-up": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-11.0.0.tgz", @@ -5350,20 +4980,6 @@ "util-deprecate": "~1.0.1" } }, - "node_modules/readdir-scoped-modules": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", - "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", - "deprecated": "This functionality has been moved to @npmcli/fs", - "dev": true, - "license": "ISC", - "dependencies": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "graceful-fs": "^4.1.2", - "once": "^1.3.0" - } - }, "node_modules/registry-auth-token": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.1.0.tgz", @@ -5387,27 +5003,6 @@ "node": ">=0.10.0" } }, - "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -5431,6 +5026,7 @@ "integrity": "sha512-WRgl5GcypwramYX4HV+eQGzUbD7UUbljVmS+5G1uMwX/wLgYuJAxGeerXJDMO2xshng4+FXqCgyB5QfClV6WjA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@semantic-release/commit-analyzer": "^13.0.1", "@semantic-release/error": "^4.0.0", @@ -5758,16 +5354,6 @@ "node": ">=8" } }, - "node_modules/slide": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", - "integrity": "sha512-NwrtjCg+lZoqhFU8fOwl4ay2ei8PaqCBOUV3/ektPY9trO1yQ1oXEfmHAhKArUVUr/hOHvy5f6AdP17dCM0zMw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "*" - } - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -5785,18 +5371,6 @@ "dev": true, "license": "MIT" }, - "node_modules/spdx-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/spdx-compare/-/spdx-compare-1.0.0.tgz", - "integrity": "sha512-C1mDZOX0hnu0ep9dfmuoi03+eOdDoz2yvK79RxbcrVEG1NO1Ph35yW102DHWKN4pk80nwCgeMmSY5L25VE4D9A==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-find-index": "^1.0.2", - "spdx-expression-parse": "^3.0.0", - "spdx-ranges": "^2.0.0" - } - }, "node_modules/spdx-correct": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", @@ -5833,25 +5407,6 @@ "dev": true, "license": "CC0-1.0" }, - "node_modules/spdx-ranges": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/spdx-ranges/-/spdx-ranges-2.1.1.tgz", - "integrity": "sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA==", - "dev": true, - "license": "(MIT AND CC-BY-3.0)" - }, - "node_modules/spdx-satisfies": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/spdx-satisfies/-/spdx-satisfies-4.0.1.tgz", - "integrity": "sha512-WVzZ/cXAzoNmjCWiEluEA3BjHp5tiUmmhn9MK+X0tBbR9sOqtC6UQwmgCNrAIZvNlMuBUYAaHYfb2oqlF9SwKA==", - "dev": true, - "license": "MIT", - "dependencies": { - "spdx-compare": "^1.0.0", - "spdx-expression-parse": "^3.0.0", - "spdx-ranges": "^2.0.0" - } - }, "node_modules/split2": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/split2/-/split2-1.0.0.tgz", @@ -6025,19 +5580,6 @@ "node": ">=8" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/tagged-tag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", @@ -6197,6 +5739,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -6230,16 +5773,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/treeify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.1.0.tgz", - "integrity": "sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, "node_modules/tunnel": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", @@ -6360,13 +5893,6 @@ "dev": true, "license": "MIT" }, - "node_modules/util-extend": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", - "integrity": "sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA==", - "dev": true, - "license": "MIT" - }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -6462,13 +5988,6 @@ "dev": true, "license": "MIT" }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" - }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/package.json b/package.json index 862b5db..ea9de84 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,6 @@ "@semantic-release/github": "^12.0.5", "@semantic-release/release-notes-generator": "^14.1.0", "conventional-changelog-eslint": "^6.0.0", - "license-checker": "^25.0.1", "semantic-release": "^25.0.3" } -} \ No newline at end of file +} diff --git a/scripts/check_python_licenses.sh b/scripts/check_python_licenses.sh deleted file mode 100755 index ea3de41..0000000 --- a/scripts/check_python_licenses.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -set -euo pipefail - -# known packages with dual licensing -IGNORE_PACKAGES=("PyGithub" "chardet" "text-unidecode") -LICENSES=$(poetry run pip-licenses --ignore-packages "${IGNORE_PACKAGES[@]}") -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