diff --git a/infrastructure/terraform/bin/terraform.sh b/infrastructure/terraform/bin/terraform.sh index 659b535c2..3a8bcf43c 100755 --- a/infrastructure/terraform/bin/terraform.sh +++ b/infrastructure/terraform/bin/terraform.sh @@ -391,8 +391,8 @@ rm -rf ${component_path}/.terraform; # Run global pre.sh if [ -f "pre.sh" ]; then - source pre.sh "${region}" "${environment}" "${action}" \ - || error_and_die "Global pre script execution failed with exit code ${?}"; + PROJECT="${project}" AWS_REGION="${region}" COMPONENT="${component}" AWS_ACCOUNT_ID="${aws_account_id}" ENVIRONMENT="${environment}" ACTION="${action}" GITHUB_TOKEN="${GITHUB_TOKEN}" \ + source pre.sh || error_and_die "Global pre script execution failed with exit code ${?}"; fi; # Make sure we're running in the component directory @@ -427,8 +427,8 @@ fi; # Run pre.sh if [ -f "pre.sh" ]; then - source pre.sh "${region}" "${environment}" "${action}" \ - || error_and_die "Component pre script execution failed with exit code ${?}"; + PROJECT="${project}" AWS_REGION="${region}" COMPONENT="${component}" AWS_ACCOUNT_ID="${aws_account_id}" ENVIRONMENT="${environment}" ACTION="${action}" GITHUB_TOKEN="${GITHUB_TOKEN}" \ + source pre.sh || error_and_die "Component pre script execution failed with exit code ${?}"; fi; # Pull down secret TFVAR file from S3 diff --git a/infrastructure/terraform/components/app/pre.sh b/infrastructure/terraform/components/app/pre.sh old mode 100755 new mode 100644 index e7ce6cd62..b88cc1905 --- a/infrastructure/terraform/components/app/pre.sh +++ b/infrastructure/terraform/components/app/pre.sh @@ -1,8 +1,35 @@ +#!/bin/bash + +# This script is run before Terraform executable commands. +# It ensures all Node.js dependencies are installed, generates any required dependencies, +# and builds all Lambda functions in the workspace before Terraform provisions infrastructure. # pre.sh runs in the same shell as terraform.sh, not in a subshell -# any variables set or changed, any change of directory will persist once this script exits and returns control to terraform.sh -REGION=$1 -ENVIRONMENT=$2 -ACTION=$3 + +: "${PROJECT:?PROJECT is required}" +: "${AWS_REGION:?AWS_REGION is required}" +: "${COMPONENT:?COMPONENT is required}" +: "${ENVIRONMENT:?ENVIRONMENT is required}" +: "${AWS_ACCOUNT_ID:?AWS_ACCOUNT_ID is required}" +: "${ACTION:?ACTION is required}" + +echo "Running app pre.sh" +echo "ENVIRONMENT=$ENVIRONMENT" +echo "ACTION=$ACTION" +echo "PROJECT=$PROJECT" +echo "COMPONENT=$COMPONENT" +echo "AWS_REGION=$AWS_REGION" +echo "AWS_ACCOUNT_ID=$AWS_ACCOUNT_ID" + +# Calculate container image prefix from PROJECT, ENVIRONMENT, COMPONENT +CONTAINER_IMAGE_PREFIX="${PROJECT}-${ENVIRONMENT}-${COMPONENT}" +echo "CONTAINER_IMAGE_PREFIX: ${CONTAINER_IMAGE_PREFIX}" + +# Translate ACTION to PUBLISH_CONTAINER_IMAGE (build) +if [ "${ACTION}" = "plan" ]; then + PUBLISH_CONTAINER_IMAGE="false" +else + PUBLISH_CONTAINER_IMAGE="true" +fi # Helper function for error handling run_or_fail() { @@ -13,28 +40,36 @@ run_or_fail() { fi } -echo "Running app pre.sh" -echo "REGION=$REGION" -echo "ENVIRONMENT=$ENVIRONMENT" -echo "ACTION=$ACTION" +# Switch to repo root +pushd "$(git rev-parse --show-toplevel)" || exit 1 +# Calculate git-based version suffix +SHORT_SHA="$(git rev-parse --short HEAD)" GIT_TAG="$(git describe --tags --exact-match 2>/dev/null || true)" + if [ -n "${GIT_TAG}" ]; then RELEASE_VERSION="${GIT_TAG#v}" - export TF_VAR_container_image_tag_suffix="release-${RELEASE_VERSION}-$(git rev-parse --short HEAD)" - echo "On tag: $GIT_TAG, image tag suffixes will be: release-${RELEASE_VERSION}-$(git rev-parse --short HEAD)" + CONTAINER_IMAGE_SUFFIX="release-${RELEASE_VERSION}-${SHORT_SHA}" + echo "On tag: $GIT_TAG, image suffix: ${CONTAINER_IMAGE_SUFFIX}" else - export TF_VAR_container_image_tag_suffix="sha-$(git rev-parse --short HEAD)" - echo "Not on a tag, image tag suffix will be: sha-$(git rev-parse --short HEAD)" + CONTAINER_IMAGE_SUFFIX="sha-${SHORT_SHA}" + echo "Not on a tag, image suffix: ${CONTAINER_IMAGE_SUFFIX}" fi -# change to monorepo root -cd $(git rev-parse --show-toplevel) +# Export for Terraform +export TF_VAR_container_image_tag_suffix="${CONTAINER_IMAGE_SUFFIX}" run_or_fail npm ci run_or_fail npm run generate-dependencies --workspaces --if-present run_or_fail npm run lambda-build --workspaces --if-present +run_or_fail env \ + CONTAINER_IMAGE_PREFIX="${CONTAINER_IMAGE_PREFIX}" \ + CONTAINER_IMAGE_SUFFIX="${CONTAINER_IMAGE_SUFFIX}" \ + AWS_ACCOUNT_ID="${AWS_ACCOUNT_ID}" \ + AWS_REGION="${AWS_REGION}" \ + GITHUB_TOKEN="${GITHUB_TOKEN}" \ + PUBLISH_CONTAINER_IMAGE="${PUBLISH_CONTAINER_IMAGE}" \ + npm run build:container --workspaces --if-present run_or_fail lambdas/layers/pdfjs/build.sh -# revert back to original directory -cd - +popd || exit 1 # Return to working directory diff --git a/infrastructure/terraform/components/sbx/pre.sh b/infrastructure/terraform/components/sbx/pre.sh old mode 100755 new mode 100644 index 1661385d9..0bbf4fda2 --- a/infrastructure/terraform/components/sbx/pre.sh +++ b/infrastructure/terraform/components/sbx/pre.sh @@ -1,8 +1,35 @@ +#!/bin/bash + +# This script is run before Terraform executable commands. +# It ensures all Node.js dependencies are installed, generates any required dependencies, +# and builds all Lambda functions in the workspace before Terraform provisions infrastructure. # pre.sh runs in the same shell as terraform.sh, not in a subshell -# any variables set or changed, and change of directory will persist once this script exits and returns control to terraform.sh -REGION=$1 -ENVIRONMENT=$2 -ACTION=$3 + +: "${PROJECT:?PROJECT is required}" +: "${AWS_REGION:?AWS_REGION is required}" +: "${COMPONENT:?COMPONENT is required}" +: "${ENVIRONMENT:?ENVIRONMENT is required}" +: "${AWS_ACCOUNT_ID:?AWS_ACCOUNT_ID is required}" +: "${ACTION:?ACTION is required}" + +echo "Running sbx pre.sh" +echo "ENVIRONMENT=$ENVIRONMENT" +echo "ACTION=$ACTION" +echo "PROJECT=$PROJECT" +echo "COMPONENT=$COMPONENT" +echo "AWS_REGION=$AWS_REGION" +echo "AWS_ACCOUNT_ID=$AWS_ACCOUNT_ID" + +# Calculate container image prefix from PROJECT, ENVIRONMENT, COMPONENT +CONTAINER_IMAGE_PREFIX="${PROJECT}-${ENVIRONMENT}-${COMPONENT}" +echo "CONTAINER_IMAGE_PREFIX: ${CONTAINER_IMAGE_PREFIX}" + +# Translate ACTION to PUBLISH_CONTAINER_IMAGE (build) +if [ "${ACTION}" = "plan" ]; then + PUBLISH_CONTAINER_IMAGE="false" +else + PUBLISH_CONTAINER_IMAGE="true" +fi # Helper function for error handling run_or_fail() { @@ -13,23 +40,24 @@ run_or_fail() { fi } -echo "Running sandbox pre.sh" -echo "REGION=$REGION" -echo "ENVIRONMENT=$ENVIRONMENT" -echo "ACTION=$ACTION" +# Switch to repo root +pushd "$(git rev-parse --show-toplevel)" || exit 1 +# Calculate git-based version suffix +SHORT_SHA="$(git rev-parse --short HEAD)" GIT_TAG="$(git describe --tags --exact-match 2>/dev/null || true)" + if [ -n "${GIT_TAG}" ]; then RELEASE_VERSION="${GIT_TAG#v}" - export TF_VAR_container_image_tag_suffix="release-${RELEASE_VERSION}-$(git rev-parse --short HEAD)" - echo "On tag: $GIT_TAG, image tag suffixes will be: release-${RELEASE_VERSION}-$(git rev-parse --short HEAD)" + CONTAINER_IMAGE_SUFFIX="release-${RELEASE_VERSION}-${SHORT_SHA}" + echo "On tag: $GIT_TAG, image suffix: ${CONTAINER_IMAGE_SUFFIX}" else - export TF_VAR_container_image_tag_suffix="sha-$(git rev-parse --short HEAD)" - echo "Not on a tag, image tag suffix will be: sha-$(git rev-parse --short HEAD)" + CONTAINER_IMAGE_SUFFIX="sha-${SHORT_SHA}" + echo "Not on a tag, image suffix: ${CONTAINER_IMAGE_SUFFIX}" fi -# change to monorepo root -cd $(git rev-parse --show-toplevel) +# Export for Terraform +export TF_VAR_container_image_tag_suffix="${CONTAINER_IMAGE_SUFFIX}" case "${ACTION}" in apply) @@ -44,6 +72,13 @@ case "${ACTION}" in run_or_fail npm run generate-dependencies --workspaces --if-present run_or_fail npm run lambda-build --workspaces --if-present + run_or_fail env \ + CONTAINER_IMAGE_PREFIX="${CONTAINER_IMAGE_PREFIX}" \ + CONTAINER_IMAGE_SUFFIX="${CONTAINER_IMAGE_SUFFIX}" \ + AWS_ACCOUNT_ID="${AWS_ACCOUNT_ID}" \ + AWS_REGION="${AWS_REGION}" \ + PUBLISH_CONTAINER_IMAGE="${PUBLISH_CONTAINER_IMAGE}" \ + npm run build:container --workspaces --if-present run_or_fail lambdas/layers/pdfjs/build.sh ;; plan) @@ -54,5 +89,4 @@ case "${ACTION}" in ;; esac -# revert back to original directory -cd - +popd || exit 1 # Return to working directory diff --git a/lambdas/letter-preview-renderer/docker/lambda/Dockerfile b/lambdas/letter-preview-renderer/docker/Dockerfile similarity index 100% rename from lambdas/letter-preview-renderer/docker/lambda/Dockerfile rename to lambdas/letter-preview-renderer/docker/Dockerfile diff --git a/lambdas/letter-preview-renderer/package.json b/lambdas/letter-preview-renderer/package.json index 9b7165019..ecd17bded 100644 --- a/lambdas/letter-preview-renderer/package.json +++ b/lambdas/letter-preview-renderer/package.json @@ -30,7 +30,7 @@ "name": "nhs-notify-templates-letter-preview-renderer", "private": true, "scripts": { - "lambda-build": "../../scripts/lambda-container-build/docker.sh --base-image ghcr.io/nhsdigital/nhs-notify/libreoffice-amet-node-22:latest", + "build:container": "cd ../.. && make docker-build-and-push base_image=ghcr.io/nhsdigital/nhs-notify/libreoffice-amet-node-22:latest dir=lambdas/letter-preview-renderer", "lint": "eslint .", "lint:fix": "eslint . --fix", "test:unit": "jest", diff --git a/package-lock.json b/package-lock.json index 41c037ffa..2a092dda7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7719,18 +7719,18 @@ } }, "node_modules/@aws-sdk/credential-provider-login": { - "version": "3.972.18", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.18.tgz", - "integrity": "sha512-kINzc5BBxdYBkPZ0/i1AMPMOk5b5QaFNbYMElVw5QTX13AKj6jcxnv/YNl9oW9mg+Y08ti19hh01HhyEAxsSJQ==", + "version": "3.972.21", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.21.tgz", + "integrity": "sha512-ENU+YCiuQocQjfIf9bPxZ+ZY0wIBkl3SMH22optBQwy8UFpSfonHynXzGT27xQxer4cYTNOpwDqbfo57BusbpQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.973.19", - "@aws-sdk/nested-clients": "^3.996.8", - "@aws-sdk/types": "^3.973.5", - "@smithy/property-provider": "^4.2.11", - "@smithy/protocol-http": "^5.3.11", - "@smithy/shared-ini-file-loader": "^4.4.6", - "@smithy/types": "^4.13.0", + "@aws-sdk/core": "^3.973.21", + "@aws-sdk/nested-clients": "^3.996.11", + "@aws-sdk/types": "^3.973.6", + "@smithy/property-provider": "^4.2.12", + "@smithy/protocol-http": "^5.3.12", + "@smithy/shared-ini-file-loader": "^4.4.7", + "@smithy/types": "^4.13.1", "tslib": "^2.6.2" }, "engines": { @@ -7738,22 +7738,22 @@ } }, "node_modules/@aws-sdk/credential-provider-login/node_modules/@aws-sdk/core": { - "version": "3.973.19", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.973.19.tgz", - "integrity": "sha512-56KePyOcZnKTWCd89oJS1G6j3HZ9Kc+bh/8+EbvtaCCXdP6T7O7NzCiPuHRhFLWnzXIaXX3CxAz0nI5My9spHQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.973.5", - "@aws-sdk/xml-builder": "^3.972.10", - "@smithy/core": "^3.23.9", - "@smithy/node-config-provider": "^4.3.11", - "@smithy/property-provider": "^4.2.11", - "@smithy/protocol-http": "^5.3.11", - "@smithy/signature-v4": "^5.3.11", - "@smithy/smithy-client": "^4.12.3", - "@smithy/types": "^4.13.0", + "version": "3.973.21", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.973.21.tgz", + "integrity": "sha512-OTUcDX9Yfz/FLKbHjiMaP9D4Hs44lYJzN7zBcrK2nDmBt0Wr8D6nYt12QoBkZsW0nVMFsTIGaZCrsU9zCcIMXQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.6", + "@aws-sdk/xml-builder": "^3.972.12", + "@smithy/core": "^3.23.12", + "@smithy/node-config-provider": "^4.3.12", + "@smithy/property-provider": "^4.2.12", + "@smithy/protocol-http": "^5.3.12", + "@smithy/signature-v4": "^5.3.12", + "@smithy/smithy-client": "^4.12.6", + "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", - "@smithy/util-middleware": "^4.2.11", + "@smithy/util-middleware": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" }, @@ -7762,14 +7762,14 @@ } }, "node_modules/@aws-sdk/credential-provider-login/node_modules/@aws-sdk/middleware-host-header": { - "version": "3.972.7", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.972.7.tgz", - "integrity": "sha512-aHQZgztBFEpDU1BB00VWCIIm85JjGjQW1OG9+98BdmaOpguJvzmXBGbnAiYcciCd+IS4e9BEq664lhzGnWJHgQ==", + "version": "3.972.8", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.972.8.tgz", + "integrity": "sha512-wAr2REfKsqoKQ+OkNqvOShnBoh+nkPurDKW7uAeVSu6kUECnWlSJiPvnoqxGlfousEY/v9LfS9sNc46hjSYDIQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.5", - "@smithy/protocol-http": "^5.3.11", - "@smithy/types": "^4.13.0", + "@aws-sdk/types": "^3.973.6", + "@smithy/protocol-http": "^5.3.12", + "@smithy/types": "^4.13.1", "tslib": "^2.6.2" }, "engines": { @@ -7777,13 +7777,13 @@ } }, "node_modules/@aws-sdk/credential-provider-login/node_modules/@aws-sdk/middleware-logger": { - "version": "3.972.7", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.972.7.tgz", - "integrity": "sha512-LXhiWlWb26txCU1vcI9PneESSeRp/RYY/McuM4SpdrimQR5NgwaPb4VJCadVeuGWgh6QmqZ6rAKSoL1ob16W6w==", + "version": "3.972.8", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.972.8.tgz", + "integrity": "sha512-CWl5UCM57WUFaFi5kB7IBY1UmOeLvNZAZ2/OZ5l20ldiJ3TiIz1pC65gYj8X0BCPWkeR1E32mpsCk1L1I4n+lA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.5", - "@smithy/types": "^4.13.0", + "@aws-sdk/types": "^3.973.6", + "@smithy/types": "^4.13.1", "tslib": "^2.6.2" }, "engines": { @@ -7791,15 +7791,15 @@ } }, "node_modules/@aws-sdk/credential-provider-login/node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.972.7", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.972.7.tgz", - "integrity": "sha512-l2VQdcBcYLzIzykCHtXlbpiVCZ94/xniLIkAj0jpnpjY4xlgZx7f56Ypn+uV1y3gG0tNVytJqo3K9bfMFee7SQ==", + "version": "3.972.8", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.972.8.tgz", + "integrity": "sha512-BnnvYs2ZEpdlmZ2PNlV2ZyQ8j8AEkMTjN79y/YA475ER1ByFYrkVR85qmhni8oeTaJcDqbx364wDpitDAA/wCA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.5", + "@aws-sdk/types": "^3.973.6", "@aws/lambda-invoke-store": "^0.2.2", - "@smithy/protocol-http": "^5.3.11", - "@smithy/types": "^4.13.0", + "@smithy/protocol-http": "^5.3.12", + "@smithy/types": "^4.13.1", "tslib": "^2.6.2" }, "engines": { @@ -7807,18 +7807,18 @@ } }, "node_modules/@aws-sdk/credential-provider-login/node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.972.20", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.972.20.tgz", - "integrity": "sha512-3kNTLtpUdeahxtnJRnj/oIdLAUdzTfr9N40KtxNhtdrq+Q1RPMdCJINRXq37m4t5+r3H70wgC3opW46OzFcZYA==", + "version": "3.972.22", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.972.22.tgz", + "integrity": "sha512-pZPNGWZVQvgUIO/P9PXZNz7ciq9mLYb/wQEurg3phKTa3DiBIunIRcgA0eBNwmog6S3oy0KR1bv4EJ4ld9A5sQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.973.19", - "@aws-sdk/types": "^3.973.5", - "@aws-sdk/util-endpoints": "^3.996.4", - "@smithy/core": "^3.23.9", - "@smithy/protocol-http": "^5.3.11", - "@smithy/types": "^4.13.0", - "@smithy/util-retry": "^4.2.11", + "@aws-sdk/core": "^3.973.21", + "@aws-sdk/types": "^3.973.6", + "@aws-sdk/util-endpoints": "^3.996.5", + "@smithy/core": "^3.23.12", + "@smithy/protocol-http": "^5.3.12", + "@smithy/types": "^4.13.1", + "@smithy/util-retry": "^4.2.12", "tslib": "^2.6.2" }, "engines": { @@ -7826,47 +7826,47 @@ } }, "node_modules/@aws-sdk/credential-provider-login/node_modules/@aws-sdk/nested-clients": { - "version": "3.996.8", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.996.8.tgz", - "integrity": "sha512-6HlLm8ciMW8VzfB80kfIx16PBA9lOa9Dl+dmCBi78JDhvGlx3I7Rorwi5PpVRkL31RprXnYna3yBf6UKkD/PqA==", + "version": "3.996.11", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.996.11.tgz", + "integrity": "sha512-i7SwoSR4JB/79JoGDUACnFUQOZwXGLWNX35lIb1Pq72nUGlVV+RFZp+BLa8S+mog2pbXU9+6Kc5YwGiMi5bKhQ==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "^3.973.19", - "@aws-sdk/middleware-host-header": "^3.972.7", - "@aws-sdk/middleware-logger": "^3.972.7", - "@aws-sdk/middleware-recursion-detection": "^3.972.7", - "@aws-sdk/middleware-user-agent": "^3.972.20", - "@aws-sdk/region-config-resolver": "^3.972.7", - "@aws-sdk/types": "^3.973.5", - "@aws-sdk/util-endpoints": "^3.996.4", - "@aws-sdk/util-user-agent-browser": "^3.972.7", - "@aws-sdk/util-user-agent-node": "^3.973.5", - "@smithy/config-resolver": "^4.4.10", - "@smithy/core": "^3.23.9", - "@smithy/fetch-http-handler": "^5.3.13", - "@smithy/hash-node": "^4.2.11", - "@smithy/invalid-dependency": "^4.2.11", - "@smithy/middleware-content-length": "^4.2.11", - "@smithy/middleware-endpoint": "^4.4.23", - "@smithy/middleware-retry": "^4.4.40", - "@smithy/middleware-serde": "^4.2.12", - "@smithy/middleware-stack": "^4.2.11", - "@smithy/node-config-provider": "^4.3.11", - "@smithy/node-http-handler": "^4.4.14", - "@smithy/protocol-http": "^5.3.11", - "@smithy/smithy-client": "^4.12.3", - "@smithy/types": "^4.13.0", - "@smithy/url-parser": "^4.2.11", + "@aws-sdk/core": "^3.973.21", + "@aws-sdk/middleware-host-header": "^3.972.8", + "@aws-sdk/middleware-logger": "^3.972.8", + "@aws-sdk/middleware-recursion-detection": "^3.972.8", + "@aws-sdk/middleware-user-agent": "^3.972.22", + "@aws-sdk/region-config-resolver": "^3.972.8", + "@aws-sdk/types": "^3.973.6", + "@aws-sdk/util-endpoints": "^3.996.5", + "@aws-sdk/util-user-agent-browser": "^3.972.8", + "@aws-sdk/util-user-agent-node": "^3.973.8", + "@smithy/config-resolver": "^4.4.11", + "@smithy/core": "^3.23.12", + "@smithy/fetch-http-handler": "^5.3.15", + "@smithy/hash-node": "^4.2.12", + "@smithy/invalid-dependency": "^4.2.12", + "@smithy/middleware-content-length": "^4.2.12", + "@smithy/middleware-endpoint": "^4.4.26", + "@smithy/middleware-retry": "^4.4.43", + "@smithy/middleware-serde": "^4.2.15", + "@smithy/middleware-stack": "^4.2.12", + "@smithy/node-config-provider": "^4.3.12", + "@smithy/node-http-handler": "^4.5.0", + "@smithy/protocol-http": "^5.3.12", + "@smithy/smithy-client": "^4.12.6", + "@smithy/types": "^4.13.1", + "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", - "@smithy/util-defaults-mode-browser": "^4.3.39", - "@smithy/util-defaults-mode-node": "^4.2.42", - "@smithy/util-endpoints": "^3.3.2", - "@smithy/util-middleware": "^4.2.11", - "@smithy/util-retry": "^4.2.11", + "@smithy/util-defaults-mode-browser": "^4.3.42", + "@smithy/util-defaults-mode-node": "^4.2.45", + "@smithy/util-endpoints": "^3.3.3", + "@smithy/util-middleware": "^4.2.12", + "@smithy/util-retry": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" }, @@ -7875,15 +7875,15 @@ } }, "node_modules/@aws-sdk/credential-provider-login/node_modules/@aws-sdk/region-config-resolver": { - "version": "3.972.7", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.972.7.tgz", - "integrity": "sha512-/Ev/6AI8bvt4HAAptzSjThGUMjcWaX3GX8oERkB0F0F9x2dLSBdgFDiyrRz3i0u0ZFZFQ1b28is4QhyqXTUsVA==", + "version": "3.972.8", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.972.8.tgz", + "integrity": "sha512-1eD4uhTDeambO/PNIDVG19A6+v4NdD7xzwLHDutHsUqz0B+i661MwQB2eYO4/crcCvCiQG4SRm1k81k54FEIvw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.5", - "@smithy/config-resolver": "^4.4.10", - "@smithy/node-config-provider": "^4.3.11", - "@smithy/types": "^4.13.0", + "@aws-sdk/types": "^3.973.6", + "@smithy/config-resolver": "^4.4.11", + "@smithy/node-config-provider": "^4.3.12", + "@smithy/types": "^4.13.1", "tslib": "^2.6.2" }, "engines": { @@ -7891,12 +7891,12 @@ } }, "node_modules/@aws-sdk/credential-provider-login/node_modules/@aws-sdk/types": { - "version": "3.973.5", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.5.tgz", - "integrity": "sha512-hl7BGwDCWsjH8NkZfx+HgS7H2LyM2lTMAI7ba9c8O0KqdBLTdNJivsHpqjg9rNlAlPyREb6DeDRXUl0s8uFdmQ==", + "version": "3.973.6", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.6.tgz", + "integrity": "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.0", + "@smithy/types": "^4.13.1", "tslib": "^2.6.2" }, "engines": { @@ -7904,15 +7904,15 @@ } }, "node_modules/@aws-sdk/credential-provider-login/node_modules/@aws-sdk/util-endpoints": { - "version": "3.996.4", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.996.4.tgz", - "integrity": "sha512-Hek90FBmd4joCFj+Vc98KLJh73Zqj3s2W56gjAcTkrNLMDI5nIFkG9YpfcJiVI1YlE2Ne1uOQNe+IgQ/Vz2XRA==", + "version": "3.996.5", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.996.5.tgz", + "integrity": "sha512-Uh93L5sXFNbyR5sEPMzUU8tJ++Ku97EY4udmC01nB8Zu+xfBPwpIwJ6F7snqQeq8h2pf+8SGN5/NoytfKgYPIw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.5", - "@smithy/types": "^4.13.0", - "@smithy/url-parser": "^4.2.11", - "@smithy/util-endpoints": "^3.3.2", + "@aws-sdk/types": "^3.973.6", + "@smithy/types": "^4.13.1", + "@smithy/url-parser": "^4.2.12", + "@smithy/util-endpoints": "^3.3.3", "tslib": "^2.6.2" }, "engines": { @@ -7920,27 +7920,28 @@ } }, "node_modules/@aws-sdk/credential-provider-login/node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.972.7", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.972.7.tgz", - "integrity": "sha512-7SJVuvhKhMF/BkNS1n0QAJYgvEwYbK2QLKBrzDiwQGiTRU6Yf1f3nehTzm/l21xdAOtWSfp2uWSddPnP2ZtsVw==", + "version": "3.972.8", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.972.8.tgz", + "integrity": "sha512-B3KGXJviV2u6Cdw2SDY2aDhoJkVfY/Q/Trwk2CMSkikE1Oi6gRzxhvhIfiRpHfmIsAhV4EA54TVEX8K6CbHbkA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.5", - "@smithy/types": "^4.13.0", + "@aws-sdk/types": "^3.973.6", + "@smithy/types": "^4.13.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "node_modules/@aws-sdk/credential-provider-login/node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.973.5", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.973.5.tgz", - "integrity": "sha512-Dyy38O4GeMk7UQ48RupfHif//gqnOPbq/zlvRssc11E2mClT+aUfc3VS2yD8oLtzqO3RsqQ9I3gOBB4/+HjPOw==", + "version": "3.973.8", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.973.8.tgz", + "integrity": "sha512-Kvb96TafGPLYo4Z2GRCzQTne77epXgiZEo0DDXwavzkWmgDV/1XD1tMA766gzRcHHFUraWsE+4T8DKtPTZUxgQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/middleware-user-agent": "^3.972.20", - "@aws-sdk/types": "^3.973.5", - "@smithy/node-config-provider": "^4.3.11", - "@smithy/types": "^4.13.0", + "@aws-sdk/middleware-user-agent": "^3.972.22", + "@aws-sdk/types": "^3.973.6", + "@smithy/node-config-provider": "^4.3.12", + "@smithy/types": "^4.13.1", + "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "engines": { @@ -7956,13 +7957,13 @@ } }, "node_modules/@aws-sdk/credential-provider-login/node_modules/@aws-sdk/xml-builder": { - "version": "3.972.10", - "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.10.tgz", - "integrity": "sha512-OnejAIVD+CxzyAUrVic7lG+3QRltyja9LoNqCE/1YVs8ichoTbJlVSaZ9iSMcnHLyzrSNtvaOGjSDRP+d/ouFA==", + "version": "3.972.13", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.13.tgz", + "integrity": "sha512-I/+BMxM4WE/6xL0tyV7tAUDOAXmyw/va1oGr/eSly43HmLUcD1G+v96vEKAA8VoLcZ03ZQo/PWzjmN9zQErqPQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.0", - "fast-xml-parser": "5.4.1", + "@smithy/types": "^4.13.1", + "fast-xml-parser": "5.5.6", "tslib": "^2.6.2" }, "engines": { @@ -7970,9 +7971,9 @@ } }, "node_modules/@aws-sdk/credential-provider-login/node_modules/@aws/lambda-invoke-store": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.3.tgz", - "integrity": "sha512-oLvsaPMTBejkkmHhjf09xTgk71mOqyr/409NKhRIL08If7AhVfUsJhVsx386uJaqNd42v9kWamQ9lFbkoC2dYw==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.4.tgz", + "integrity": "sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ==", "license": "Apache-2.0", "engines": { "node": ">=18.0.0" @@ -12820,12 +12821,12 @@ "license": "(Unlicense OR Apache-2.0)" }, "node_modules/@smithy/abort-controller": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.2.11.tgz", - "integrity": "sha512-Hj4WoYWMJnSpM6/kchsm4bUNTL9XiSyhvoMb2KIq4VJzyDt7JpGHUZHkVNPZVC7YE1tf8tPeVauxpFBKGW4/KQ==", + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.2.12.tgz", + "integrity": "sha512-xolrFw6b+2iYGl6EcOL7IJY71vvyZ0DJ3mcKtpykqPe2uscwtzDZJa1uVQXyP7w9Dd+kGwYnPbMsJrGISKiY/Q==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.0", + "@smithy/types": "^4.13.1", "tslib": "^2.6.2" }, "engines": { @@ -12858,16 +12859,16 @@ } }, "node_modules/@smithy/config-resolver": { - "version": "4.4.10", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.10.tgz", - "integrity": "sha512-IRTkd6ps0ru+lTWnfnsbXzW80A8Od8p3pYiZnW98K2Hb20rqfsX7VTlfUwhrcOeSSy68Gn9WBofwPuw3e5CCsg==", + "version": "4.4.11", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.11.tgz", + "integrity": "sha512-YxFiiG4YDAtX7WMN7RuhHZLeTmRRAOyCbr+zB8e3AQzHPnUhS8zXjB1+cniPVQI3xbWsQPM0X2aaIkO/ME0ymw==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.3.11", - "@smithy/types": "^4.13.0", + "@smithy/node-config-provider": "^4.3.12", + "@smithy/types": "^4.13.1", "@smithy/util-config-provider": "^4.2.2", - "@smithy/util-endpoints": "^3.3.2", - "@smithy/util-middleware": "^4.2.11", + "@smithy/util-endpoints": "^3.3.3", + "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" }, "engines": { @@ -12875,18 +12876,18 @@ } }, "node_modules/@smithy/core": { - "version": "3.23.9", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.23.9.tgz", - "integrity": "sha512-1Vcut4LEL9HZsdpI0vFiRYIsaoPwZLjAxnVQDUMQK8beMS+EYPLDQCXtbzfxmM5GzSgjfe2Q9M7WaXwIMQllyQ==", + "version": "3.23.12", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.23.12.tgz", + "integrity": "sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w==", "license": "Apache-2.0", "dependencies": { - "@smithy/middleware-serde": "^4.2.12", - "@smithy/protocol-http": "^5.3.11", - "@smithy/types": "^4.13.0", + "@smithy/protocol-http": "^5.3.12", + "@smithy/types": "^4.13.1", + "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", - "@smithy/util-middleware": "^4.2.11", - "@smithy/util-stream": "^4.5.17", + "@smithy/util-middleware": "^4.2.12", + "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" @@ -12896,15 +12897,15 @@ } }, "node_modules/@smithy/credential-provider-imds": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.11.tgz", - "integrity": "sha512-lBXrS6ku0kTj3xLmsJW0WwqWbGQ6ueooYyp/1L9lkyT0M02C+DWwYwc5aTyXFbRaK38ojALxNixg+LxKSHZc0g==", + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.12.tgz", + "integrity": "sha512-cr2lR792vNZcYMriSIj+Um3x9KWrjcu98kn234xA6reOAFMmbRpQMOv8KPgEmLLtx3eldU6c5wALKFqNOhugmg==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.3.11", - "@smithy/property-provider": "^4.2.11", - "@smithy/types": "^4.13.0", - "@smithy/url-parser": "^4.2.11", + "@smithy/node-config-provider": "^4.3.12", + "@smithy/property-provider": "^4.2.12", + "@smithy/types": "^4.13.1", + "@smithy/url-parser": "^4.2.12", "tslib": "^2.6.2" }, "engines": { @@ -12982,14 +12983,14 @@ } }, "node_modules/@smithy/fetch-http-handler": { - "version": "5.3.13", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.13.tgz", - "integrity": "sha512-U2Hcfl2s3XaYjikN9cT4mPu8ybDbImV3baXR0PkVlC0TTx808bRP3FaPGAzPtB8OByI+JqJ1kyS+7GEgae7+qQ==", + "version": "5.3.15", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.15.tgz", + "integrity": "sha512-T4jFU5N/yiIfrtrsb9uOQn7RdELdM/7HbyLNr6uO/mpkj1ctiVs7CihVr51w4LyQlXWDpXFn4BElf1WmQvZu/A==", "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^5.3.11", - "@smithy/querystring-builder": "^4.2.11", - "@smithy/types": "^4.13.0", + "@smithy/protocol-http": "^5.3.12", + "@smithy/querystring-builder": "^4.2.12", + "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "tslib": "^2.6.2" }, @@ -13013,12 +13014,12 @@ } }, "node_modules/@smithy/hash-node": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.11.tgz", - "integrity": "sha512-T+p1pNynRkydpdL015ruIoyPSRw9e/SQOWmSAMmmprfswMrd5Ow5igOWNVlvyVFZlxXqGmyH3NQwfwy8r5Jx0A==", + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.12.tgz", + "integrity": "sha512-QhBYbGrbxTkZ43QoTPrK72DoYviDeg6YKDrHTMJbbC+A0sml3kSjzFtXP7BtbyJnXojLfTQldGdUR0RGD8dA3w==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.0", + "@smithy/types": "^4.13.1", "@smithy/util-buffer-from": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" @@ -13042,12 +13043,12 @@ } }, "node_modules/@smithy/invalid-dependency": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.11.tgz", - "integrity": "sha512-cGNMrgykRmddrNhYy1yBdrp5GwIgEkniS7k9O1VLB38yxQtlvrxpZtUVvo6T4cKpeZsriukBuuxfJcdZQc/f/g==", + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.12.tgz", + "integrity": "sha512-/4F1zb7Z8LOu1PalTdESFHR0RbPwHd3FcaG1sI3UEIriQTWakysgJr65lc1jj6QY5ye7aFsisajotH6UhWfm/g==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.0", + "@smithy/types": "^4.13.1", "tslib": "^2.6.2" }, "engines": { @@ -13081,13 +13082,13 @@ } }, "node_modules/@smithy/middleware-content-length": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.11.tgz", - "integrity": "sha512-UvIfKYAKhCzr4p6jFevPlKhQwyQwlJ6IeKLDhmV1PlYfcW3RL4ROjNEDtSik4NYMi9kDkH7eSwyTP3vNJ/u/Dw==", + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.12.tgz", + "integrity": "sha512-YE58Yz+cvFInWI/wOTrB+DbvUVz/pLn5mC5MvOV4fdRUc6qGwygyngcucRQjAhiCEbmfLOXX0gntSIcgMvAjmA==", "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^5.3.11", - "@smithy/types": "^4.13.0", + "@smithy/protocol-http": "^5.3.12", + "@smithy/types": "^4.13.1", "tslib": "^2.6.2" }, "engines": { @@ -13095,18 +13096,18 @@ } }, "node_modules/@smithy/middleware-endpoint": { - "version": "4.4.23", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.23.tgz", - "integrity": "sha512-UEFIejZy54T1EJn2aWJ45voB7RP2T+IRzUqocIdM6GFFa5ClZncakYJfcYnoXt3UsQrZZ9ZRauGm77l9UCbBLw==", + "version": "4.4.26", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.26.tgz", + "integrity": "sha512-8Qfikvd2GVKSm8S6IbjfwFlRY9VlMrj0Dp4vTwAuhqbX7NhJKE5DQc2bnfJIcY0B+2YKMDBWfvexbSZeejDgeg==", "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^3.23.9", - "@smithy/middleware-serde": "^4.2.12", - "@smithy/node-config-provider": "^4.3.11", - "@smithy/shared-ini-file-loader": "^4.4.6", - "@smithy/types": "^4.13.0", - "@smithy/url-parser": "^4.2.11", - "@smithy/util-middleware": "^4.2.11", + "@smithy/core": "^3.23.12", + "@smithy/middleware-serde": "^4.2.15", + "@smithy/node-config-provider": "^4.3.12", + "@smithy/shared-ini-file-loader": "^4.4.7", + "@smithy/types": "^4.13.1", + "@smithy/url-parser": "^4.2.12", + "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" }, "engines": { @@ -13114,18 +13115,18 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "4.4.40", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.40.tgz", - "integrity": "sha512-YhEMakG1Ae57FajERdHNZ4ShOPIY7DsgV+ZoAxo/5BT0KIe+f6DDU2rtIymNNFIj22NJfeeI6LWIifrwM0f+rA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/node-config-provider": "^4.3.11", - "@smithy/protocol-http": "^5.3.11", - "@smithy/service-error-classification": "^4.2.11", - "@smithy/smithy-client": "^4.12.3", - "@smithy/types": "^4.13.0", - "@smithy/util-middleware": "^4.2.11", - "@smithy/util-retry": "^4.2.11", + "version": "4.4.43", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.43.tgz", + "integrity": "sha512-ZwsifBdyuNHrFGmbc7bAfP2b54+kt9J2rhFd18ilQGAB+GDiP4SrawqyExbB7v455QVR7Psyhb2kjULvBPIhvA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.3.12", + "@smithy/protocol-http": "^5.3.12", + "@smithy/service-error-classification": "^4.2.12", + "@smithy/smithy-client": "^4.12.6", + "@smithy/types": "^4.13.1", + "@smithy/util-middleware": "^4.2.12", + "@smithy/util-retry": "^4.2.12", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" }, @@ -13134,13 +13135,14 @@ } }, "node_modules/@smithy/middleware-serde": { - "version": "4.2.12", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.12.tgz", - "integrity": "sha512-W9g1bOLui7Xn5FABRVS0o3rXL0gfN37d/8I/W7i0N7oxjx9QecUmXEMSUMADTODwdtka9cN43t5BI2CodLJpng==", + "version": "4.2.15", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.15.tgz", + "integrity": "sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg==", "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^5.3.11", - "@smithy/types": "^4.13.0", + "@smithy/core": "^3.23.12", + "@smithy/protocol-http": "^5.3.12", + "@smithy/types": "^4.13.1", "tslib": "^2.6.2" }, "engines": { @@ -13148,12 +13150,12 @@ } }, "node_modules/@smithy/middleware-stack": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.11.tgz", - "integrity": "sha512-s+eenEPW6RgliDk2IhjD2hWOxIx1NKrOHxEwNUaUXxYBxIyCcDfNULZ2Mu15E3kwcJWBedTET/kEASPV1A1Akg==", + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.12.tgz", + "integrity": "sha512-kruC5gRHwsCOuyCd4ouQxYjgRAym2uDlCvQ5acuMtRrcdfg7mFBg6blaxcJ09STpt3ziEkis6bhg1uwrWU7txw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.0", + "@smithy/types": "^4.13.1", "tslib": "^2.6.2" }, "engines": { @@ -13161,14 +13163,14 @@ } }, "node_modules/@smithy/node-config-provider": { - "version": "4.3.11", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.11.tgz", - "integrity": "sha512-xD17eE7kaLgBBGf5CZQ58hh2YmwK1Z0O8YhffwB/De2jsL0U3JklmhVYJ9Uf37OtUDLF2gsW40Xwwag9U869Gg==", + "version": "4.3.12", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.12.tgz", + "integrity": "sha512-tr2oKX2xMcO+rBOjobSwVAkV05SIfUKz8iI53rzxEmgW3GOOPOv0UioSDk+J8OpRQnpnhsO3Af6IEBabQBVmiw==", "license": "Apache-2.0", "dependencies": { - "@smithy/property-provider": "^4.2.11", - "@smithy/shared-ini-file-loader": "^4.4.6", - "@smithy/types": "^4.13.0", + "@smithy/property-provider": "^4.2.12", + "@smithy/shared-ini-file-loader": "^4.4.7", + "@smithy/types": "^4.13.1", "tslib": "^2.6.2" }, "engines": { @@ -13176,15 +13178,15 @@ } }, "node_modules/@smithy/node-http-handler": { - "version": "4.4.14", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.4.14.tgz", - "integrity": "sha512-DamSqaU8nuk0xTJDrYnRzZndHwwRnyj/n/+RqGGCcBKB4qrQem0mSDiWdupaNWdwxzyMU91qxDmHOCazfhtO3A==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.5.0.tgz", + "integrity": "sha512-Rnq9vQWiR1+/I6NZZMNzJHV6pZYyEHt2ZnuV3MG8z2NNenC4i/8Kzttz7CjZiHSmsN5frhXhg17z3Zqjjhmz1A==", "license": "Apache-2.0", "dependencies": { - "@smithy/abort-controller": "^4.2.11", - "@smithy/protocol-http": "^5.3.11", - "@smithy/querystring-builder": "^4.2.11", - "@smithy/types": "^4.13.0", + "@smithy/abort-controller": "^4.2.12", + "@smithy/protocol-http": "^5.3.12", + "@smithy/querystring-builder": "^4.2.12", + "@smithy/types": "^4.13.1", "tslib": "^2.6.2" }, "engines": { @@ -13192,12 +13194,12 @@ } }, "node_modules/@smithy/property-provider": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.11.tgz", - "integrity": "sha512-14T1V64o6/ndyrnl1ze1ZhyLzIeYNN47oF/QU6P5m82AEtyOkMJTb0gO1dPubYjyyKuPD6OSVMPDKe+zioOnCg==", + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.12.tgz", + "integrity": "sha512-jqve46eYU1v7pZ5BM+fmkbq3DerkSluPr5EhvOcHxygxzD05ByDRppRwRPPpFrsFo5yDtCYLKu+kreHKVrvc7A==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.0", + "@smithy/types": "^4.13.1", "tslib": "^2.6.2" }, "engines": { @@ -13205,12 +13207,12 @@ } }, "node_modules/@smithy/protocol-http": { - "version": "5.3.11", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.11.tgz", - "integrity": "sha512-hI+barOVDJBkNt4y0L2mu3Ugc0w7+BpJ2CZuLwXtSltGAAwCb3IvnalGlbDV/UCS6a9ZuT3+exd1WxNdLb5IlQ==", + "version": "5.3.12", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.12.tgz", + "integrity": "sha512-fit0GZK9I1xoRlR4jXmbLhoN0OdEpa96ul8M65XdmXnxXkuMxM0Y8HDT0Fh0Xb4I85MBvBClOzgSrV1X2s1Hxw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.0", + "@smithy/types": "^4.13.1", "tslib": "^2.6.2" }, "engines": { @@ -13218,12 +13220,12 @@ } }, "node_modules/@smithy/querystring-builder": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.11.tgz", - "integrity": "sha512-7spdikrYiljpket6u0up2Ck2mxhy7dZ0+TDd+S53Dg2DHd6wg+YNJrTCHiLdgZmEXZKI7LJZcwL3721ZRDFiqA==", + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.12.tgz", + "integrity": "sha512-6wTZjGABQufekycfDGMEB84BgtdOE/rCVTov+EDXQ8NHKTUNIp/j27IliwP7tjIU9LR+sSzyGBOXjeEtVgzCHg==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.0", + "@smithy/types": "^4.13.1", "@smithy/util-uri-escape": "^4.2.2", "tslib": "^2.6.2" }, @@ -13232,12 +13234,12 @@ } }, "node_modules/@smithy/querystring-parser": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.11.tgz", - "integrity": "sha512-nE3IRNjDltvGcoThD2abTozI1dkSy8aX+a2N1Rs55en5UsdyyIXgGEmevUL3okZFoJC77JgRGe99xYohhsjivQ==", + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.12.tgz", + "integrity": "sha512-P2OdvrgiAKpkPNKlKUtWbNZKB1XjPxM086NeVhK+W+wI46pIKdWBe5QyXvhUm3MEcyS/rkLvY8rZzyUdmyDZBw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.0", + "@smithy/types": "^4.13.1", "tslib": "^2.6.2" }, "engines": { @@ -13245,24 +13247,24 @@ } }, "node_modules/@smithy/service-error-classification": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.2.11.tgz", - "integrity": "sha512-HkMFJZJUhzU3HvND1+Yw/kYWXp4RPDLBWLcK1n+Vqw8xn4y2YiBhdww8IxhkQjP/QlZun5bwm3vcHc8AqIU3zw==", + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.2.12.tgz", + "integrity": "sha512-LlP29oSQN0Tw0b6D0Xo6BIikBswuIiGYbRACy5ujw/JgWSzTdYj46U83ssf6Ux0GyNJVivs2uReU8pt7Eu9okQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.0" + "@smithy/types": "^4.13.1" }, "engines": { "node": ">=18.0.0" } }, "node_modules/@smithy/shared-ini-file-loader": { - "version": "4.4.6", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.6.tgz", - "integrity": "sha512-IB/M5I8G0EeXZTHsAxpx51tMQ5R719F3aq+fjEB6VtNcCHDc0ajFDIGDZw+FW9GxtEkgTduiPpjveJdA/CX7sw==", + "version": "4.4.7", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.7.tgz", + "integrity": "sha512-HrOKWsUb+otTeo1HxVWeEb99t5ER1XrBi/xka2Wv6NVmTbuCUC1dvlrksdvxFtODLBjsC+PHK+fuy2x/7Ynyiw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.0", + "@smithy/types": "^4.13.1", "tslib": "^2.6.2" }, "engines": { @@ -13270,16 +13272,16 @@ } }, "node_modules/@smithy/signature-v4": { - "version": "5.3.11", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.11.tgz", - "integrity": "sha512-V1L6N9aKOBAN4wEHLyqjLBnAz13mtILU0SeDrjOaIZEeN6IFa6DxwRt1NNpOdmSpQUfkBj0qeD3m6P77uzMhgQ==", + "version": "5.3.12", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.12.tgz", + "integrity": "sha512-B/FBwO3MVOL00DaRSXfXfa/TRXRheagt/q5A2NM13u7q+sHS59EOVGQNfG7DkmVtdQm5m3vOosoKAXSqn/OEgw==", "license": "Apache-2.0", "dependencies": { "@smithy/is-array-buffer": "^4.2.2", - "@smithy/protocol-http": "^5.3.11", - "@smithy/types": "^4.13.0", + "@smithy/protocol-http": "^5.3.12", + "@smithy/types": "^4.13.1", "@smithy/util-hex-encoding": "^4.2.2", - "@smithy/util-middleware": "^4.2.11", + "@smithy/util-middleware": "^4.2.12", "@smithy/util-uri-escape": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" @@ -13289,17 +13291,17 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "4.12.3", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.12.3.tgz", - "integrity": "sha512-7k4UxjSpHmPN2AxVhvIazRSzFQjWnud3sOsXcFStzagww17j1cFQYqTSiQ8xuYK3vKLR1Ni8FzuT3VlKr3xCNw==", + "version": "4.12.6", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.12.6.tgz", + "integrity": "sha512-aib3f0jiMsJ6+cvDnXipBsGDL7ztknYSVqJs1FdN9P+u9tr/VzOR7iygSh6EUOdaBeMCMSh3N0VdyYsG4o91DQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^3.23.9", - "@smithy/middleware-endpoint": "^4.4.23", - "@smithy/middleware-stack": "^4.2.11", - "@smithy/protocol-http": "^5.3.11", - "@smithy/types": "^4.13.0", - "@smithy/util-stream": "^4.5.17", + "@smithy/core": "^3.23.12", + "@smithy/middleware-endpoint": "^4.4.26", + "@smithy/middleware-stack": "^4.2.12", + "@smithy/protocol-http": "^5.3.12", + "@smithy/types": "^4.13.1", + "@smithy/util-stream": "^4.5.20", "tslib": "^2.6.2" }, "engines": { @@ -13307,9 +13309,9 @@ } }, "node_modules/@smithy/types": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.13.0.tgz", - "integrity": "sha512-COuLsZILbbQsdrwKQpkkpyep7lCsByxwj7m0Mg5v66/ZTyenlfBc40/QFQ5chO0YN/PNEH1Bi3fGtfXPnYNeDw==", + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.13.1.tgz", + "integrity": "sha512-787F3yzE2UiJIQ+wYW1CVg2odHjmaWLGksnKQHUrK/lYZSEcy1msuLVvxaR/sI2/aDe9U+TBuLsXnr3vod1g0g==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -13319,13 +13321,13 @@ } }, "node_modules/@smithy/url-parser": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.11.tgz", - "integrity": "sha512-oTAGGHo8ZYc5VZsBREzuf5lf2pAurJQsccMusVZ85wDkX66ojEc/XauiGjzCj50A61ObFTPe6d7Pyt6UBYaing==", + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.12.tgz", + "integrity": "sha512-wOPKPEpso+doCZGIlr+e1lVI6+9VAKfL4kZWFgzVgGWY2hZxshNKod4l2LXS3PRC9otH/JRSjtEHqQ/7eLciRA==", "license": "Apache-2.0", "dependencies": { - "@smithy/querystring-parser": "^4.2.11", - "@smithy/types": "^4.13.0", + "@smithy/querystring-parser": "^4.2.12", + "@smithy/types": "^4.13.1", "tslib": "^2.6.2" }, "engines": { @@ -13396,14 +13398,14 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "4.3.39", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.39.tgz", - "integrity": "sha512-ui7/Ho/+VHqS7Km2wBw4/Ab4RktoiSshgcgpJzC4keFPs6tLJS4IQwbeahxQS3E/w98uq6E1mirCH/id9xIXeQ==", + "version": "4.3.42", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.42.tgz", + "integrity": "sha512-0vjwmcvkWAUtikXnWIUOyV6IFHTEeQUYh3JUZcDgcszF+hD/StAsQ3rCZNZEPHgI9kVNcbnyc8P2CBHnwgmcwg==", "license": "Apache-2.0", "dependencies": { - "@smithy/property-provider": "^4.2.11", - "@smithy/smithy-client": "^4.12.3", - "@smithy/types": "^4.13.0", + "@smithy/property-provider": "^4.2.12", + "@smithy/smithy-client": "^4.12.6", + "@smithy/types": "^4.13.1", "tslib": "^2.6.2" }, "engines": { @@ -13411,17 +13413,17 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "4.2.42", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.42.tgz", - "integrity": "sha512-QDA84CWNe8Akpj15ofLO+1N3Rfg8qa2K5uX0y6HnOp4AnRYRgWrKx/xzbYNbVF9ZsyJUYOfcoaN3y93wA/QJ2A==", + "version": "4.2.45", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.45.tgz", + "integrity": "sha512-q5dOqqfTgUcLe38TAGiFn9srToKj2YCHJ34QGOLzM+xYLLA+qRZv7N+33kl1MERVusue36ZHnlNaNEvY/PzSrw==", "license": "Apache-2.0", "dependencies": { - "@smithy/config-resolver": "^4.4.10", - "@smithy/credential-provider-imds": "^4.2.11", - "@smithy/node-config-provider": "^4.3.11", - "@smithy/property-provider": "^4.2.11", - "@smithy/smithy-client": "^4.12.3", - "@smithy/types": "^4.13.0", + "@smithy/config-resolver": "^4.4.11", + "@smithy/credential-provider-imds": "^4.2.12", + "@smithy/node-config-provider": "^4.3.12", + "@smithy/property-provider": "^4.2.12", + "@smithy/smithy-client": "^4.12.6", + "@smithy/types": "^4.13.1", "tslib": "^2.6.2" }, "engines": { @@ -13429,13 +13431,13 @@ } }, "node_modules/@smithy/util-endpoints": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.3.2.tgz", - "integrity": "sha512-+4HFLpE5u29AbFlTdlKIT7jfOzZ8PDYZKTb3e+AgLz986OYwqTourQ5H+jg79/66DB69Un1+qKecLnkZdAsYcA==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.3.3.tgz", + "integrity": "sha512-VACQVe50j0HZPjpwWcjyT51KUQ4AnsvEaQ2lKHOSL4mNLD0G9BjEniQ+yCt1qqfKfiAHRAts26ud7hBjamrwig==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.3.11", - "@smithy/types": "^4.13.0", + "@smithy/node-config-provider": "^4.3.12", + "@smithy/types": "^4.13.1", "tslib": "^2.6.2" }, "engines": { @@ -13455,12 +13457,12 @@ } }, "node_modules/@smithy/util-middleware": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.11.tgz", - "integrity": "sha512-r3dtF9F+TpSZUxpOVVtPfk09Rlo4lT6ORBqEvX3IBT6SkQAdDSVKR5GcfmZbtl7WKhKnmb3wbDTQ6ibR2XHClw==", + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.12.tgz", + "integrity": "sha512-Er805uFUOvgc0l8nv0e0su0VFISoxhJ/AwOn3gL2NWNY2LUEldP5WtVcRYSQBcjg0y9NfG8JYrCJaYDpupBHJQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.0", + "@smithy/types": "^4.13.1", "tslib": "^2.6.2" }, "engines": { @@ -13468,13 +13470,13 @@ } }, "node_modules/@smithy/util-retry": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.2.11.tgz", - "integrity": "sha512-XSZULmL5x6aCTTii59wJqKsY1l3eMIAomRAccW7Tzh9r8s7T/7rdo03oektuH5jeYRlJMPcNP92EuRDvk9aXbw==", + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.2.12.tgz", + "integrity": "sha512-1zopLDUEOwumjcHdJ1mwBHddubYF8GMQvstVCLC54Y46rqoHwlIU+8ZzUeaBcD+WCJHyDGSeZ2ml9YSe9aqcoQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/service-error-classification": "^4.2.11", - "@smithy/types": "^4.13.0", + "@smithy/service-error-classification": "^4.2.12", + "@smithy/types": "^4.13.1", "tslib": "^2.6.2" }, "engines": { @@ -13482,14 +13484,14 @@ } }, "node_modules/@smithy/util-stream": { - "version": "4.5.17", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.17.tgz", - "integrity": "sha512-793BYZ4h2JAQkNHcEnyFxDTcZbm9bVybD0UV/LEWmZ5bkTms7JqjfrLMi2Qy0E5WFcCzLwCAPgcvcvxoeALbAQ==", + "version": "4.5.20", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.20.tgz", + "integrity": "sha512-4yXLm5n/B5SRBR2p8cZ90Sbv4zL4NKsgxdzCzp/83cXw2KxLEumt5p+GAVyRNZgQOSrzXn9ARpO0lUe8XSlSDw==", "license": "Apache-2.0", "dependencies": { - "@smithy/fetch-http-handler": "^5.3.13", - "@smithy/node-http-handler": "^4.4.14", - "@smithy/types": "^4.13.0", + "@smithy/fetch-http-handler": "^5.3.15", + "@smithy/node-http-handler": "^4.5.0", + "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-buffer-from": "^4.2.2", "@smithy/util-hex-encoding": "^4.2.2", @@ -18755,9 +18757,9 @@ } }, "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.1.tgz", + "integrity": "sha512-IxfVbRFVlV8V/yRaGzk0UVIcsKKHMSfYw66T/u4nTwlWteQePsxe//LjudR1AMX4tZW3WFCh3Zqa/sjlqpbURQ==", "license": "ISC" }, "node_modules/fn.name": { diff --git a/package.json b/package.json index d92f56c06..df1b30227 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "name": "nhs-notify-web-template-management", "overrides": { "fast-xml-parser": "^5.3.6", + "flatted": "^3.4.0", "immutable": "^5.1.5", "nhsuk-react-components": { "nhsuk-frontend": "^10.3.1" diff --git a/scripts/docker/docker.lib.sh b/scripts/docker/docker.lib.sh index 187871050..cf756be58 100644 --- a/scripts/docker/docker.lib.sh +++ b/scripts/docker/docker.lib.sh @@ -301,3 +301,149 @@ function _get-git-branch-name() { echo "$branch_name" } + +# ============================================================================== +# NHS Notify Project-Specific Functions - Container Support + +# Get git-based version suffix for containers. +# Returns either "release--" for tagged commits +# or "sha-" for untagged commits. +function docker-get-git-version-suffix() { + + local short_sha=$(git rev-parse --short HEAD) + local git_tag=$(git describe --tags --exact-match 2>/dev/null || true) + + if [ -n "$git_tag" ]; then + local release_version="${git_tag#v}" + echo "release-${release_version}-${short_sha}" + else + echo "sha-${short_sha}" + fi +} + +# Authenticate Docker with AWS ECR. +# Arguments (provided as environment variables): +# AWS_ACCOUNT_ID=[AWS account ID] +# AWS_REGION=[AWS region, e.g., eu-west-2] +function docker-ecr-login() { + + if [ -z "${AWS_ACCOUNT_ID:-}" ]; then + echo "Error: AWS_ACCOUNT_ID environment variable is required" >&2 + return 1 + fi + + if [ -z "${AWS_REGION:-}" ]; then + echo "Error: AWS_REGION environment variable is required" >&2 + return 1 + fi + + echo "Authenticating Docker with ECR..." + aws ecr get-login-password --region "${AWS_REGION}" | \ + docker login --username AWS --password-stdin \ + "${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com" +} + +# Authenticate Docker with GitHub Container Registry. +# Arguments (provided as environment variables): +# GITHUB_TOKEN=[GitHub personal access token with packages:read/write scope] +function docker-ghcr-login() { + + local ghcr_username="${GITHUB_ACTOR:-}" + + if [ -z "${GITHUB_TOKEN:-}" ]; then + echo "Error: GITHUB_TOKEN environment variable is required" >&2 + return 1 + fi + + if [ -z "${ghcr_username}" ]; then + ghcr_username="$(git config user.name 2>/dev/null || true)" + fi + + if [ -z "${ghcr_username}" ]; then + echo "Error: unable to determine GHCR username. Set GITHUB_ACTOR or configure git user.name" >&2 + return 1 + fi + + echo "Authenticating Docker with GitHub Container Registry..." + echo "${GITHUB_TOKEN}" | docker login ghcr.io --username "${ghcr_username}" --password-stdin +} + +# Build container image. +# Arguments (provided as environment variables): +# BASE_IMAGE=[base Docker image, e.g., node:22-alpine] +# dir=[path to container directory, default is '.'] +# DOCKER_IMAGE=[full ECR image URI with tag] +# Prerequisites: +# - Container directory must have build.sh script +# - Container directory must have docker/lambda/Dockerfile +function docker-build-container() { + + local dir=${dir:-$PWD} + + if [ -z "${BASE_IMAGE:-}" ]; then + echo "Error: BASE_IMAGE environment variable is required" >&2 + return 1 + fi + + if [ ! -f "${dir}/build.sh" ]; then + echo "Error: build.sh not found in ${dir}" >&2 + return 1 + fi + + if [ ! -f "${dir}/docker/Dockerfile" ]; then + echo "Error: docker/Dockerfile not found in ${dir}" >&2 + return 1 + fi + + # Run the container build script first + echo "Running build.sh in ${dir}..." + current_dir=$(pwd) + cd "$dir" + chmod +x ./build.sh + ./build.sh + + # Build the Docker image + echo "Building container image..." + docker buildx build \ + -f docker/Dockerfile \ + --platform=linux/amd64 \ + --provenance=false \ + --sbom=false \ + --build-arg BASE_IMAGE="${BASE_IMAGE}" \ + -t "${DOCKER_IMAGE}" \ + --load \ + . + + cd "$current_dir" +} + +# Push container image to ECR. +# Arguments (provided as environment variables): +# DOCKER_IMAGE=[full ECR image URI with tag] +# PUBLISH_CONTAINER_IMAGE=[true to push, false to skip, default is true] +function docker-push-container() { + + if [ "${PUBLISH_CONTAINER_IMAGE:-true}" = "true" ]; then + echo "Pushing to ECR..." + echo "Pushing ${DOCKER_IMAGE}..." + docker push "${DOCKER_IMAGE}" + echo "Push complete." + else + echo "PUBLISH_CONTAINER_IMAGE is false. Skipping push." + echo "Built image is available locally as: ${DOCKER_IMAGE}" + fi +} + +# Calculate and print Docker image name for NHS Notify containers. +# Arguments (provided as environment variables): +# CONTAINER_IMAGE_PREFIX, AWS_ACCOUNT_ID, AWS_REGION (required) +# CONTAINER_IMAGE_SUFFIX, ECR_REPO, CONTAINER_NAME, dir (optional) +function docker-calculate-image-name() { + local dir=${dir:-$PWD} + local container_name="${CONTAINER_NAME:-$(basename "$dir")}" + local ecr_repo="${ECR_REPO:-nhs-notify-main-acct}" + local image_suffix="${CONTAINER_IMAGE_SUFFIX:-$(docker-get-git-version-suffix)}" + local image_tag="${CONTAINER_IMAGE_PREFIX}-${container_name}" + local ecr_repo_uri="${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${ecr_repo}" + echo "${ecr_repo_uri}:${image_tag}-${image_suffix}" +} diff --git a/scripts/docker/docker.mk b/scripts/docker/docker.mk index a31ad9dba..1421de4a4 100644 --- a/scripts/docker/docker.mk +++ b/scripts/docker/docker.mk @@ -1,30 +1,54 @@ # This file is for you! Edit it to implement your own Docker make targets. # ============================================================================== -# Custom implementation - implementation of a make target should not exceed 5 lines of effective code. -# In most cases there should be no need to modify the existing make targets. +# NHS Notify Container Support (ECR with container name prefix) -docker-build: # Build Docker image - optional: docker_dir|dir=[path to the Dockerfile to use, default is '.'] @Development - make _docker cmd="build" \ - dir=$(or ${docker_dir}, ${dir}) - file=$(or ${docker_dir}, ${dir})/Dockerfile.effective - scripts/docker/dockerfile-linter.sh +docker-build: # Build container image - required: DOCKER_IMAGE, base_image=[base image]; optional: dir=[container directory] @Development + source scripts/docker/docker.lib.sh; \ + dir=$(or ${dir}, .); \ + BASE_IMAGE="${base_image}" \ + DOCKER_IMAGE="$${DOCKER_IMAGE}" \ + dir="$${dir}" \ + docker-build-container -docker-push: # Push Docker image - optional: docker_dir|dir=[path to the image directory where the Dockerfile is located, default is '.'] @Development - make _docker cmd="push" \ - dir=$(or ${docker_dir}, ${dir}) +docker-push: # Push container image to registry - required: DOCKER_IMAGE @Development + source scripts/docker/docker.lib.sh; \ + DOCKER_IMAGE="$${DOCKER_IMAGE}" \ + docker-push-container -clean:: # Remove Docker resources (docker) - optional: docker_dir|dir=[path to the image directory where the Dockerfile is located, default is '.'] @Operations - make _docker cmd="clean" \ - dir=$(or ${docker_dir}, ${dir}) +docker-build-and-push: # Build and push container in one workflow - required: base_image=[base image]; optional: dir=[container directory], ecr_repo=[ECR repo name], container_name=[container name] @Development + @dir=$(or ${dir}, .); \ + export DOCKER_IMAGE=$$(source scripts/docker/docker.lib.sh && \ + CONTAINER_IMAGE_PREFIX="$${CONTAINER_IMAGE_PREFIX}" \ + CONTAINER_IMAGE_SUFFIX="$${CONTAINER_IMAGE_SUFFIX:-}" \ + AWS_ACCOUNT_ID="$${AWS_ACCOUNT_ID}" \ + AWS_REGION="$${AWS_REGION}" \ + ECR_REPO="$${ECR_REPO:-${ecr_repo}}" \ + GITHUB_TOKEN="$${GITHUB_TOKEN:-}" \ + CONTAINER_NAME="$${CONTAINER_NAME:-${container_name}}" \ + dir="$${dir}" \ + docker-calculate-image-name); \ + echo "Building and pushing: $${DOCKER_IMAGE}"; \ + ${MAKE} docker-ghcr-login; \ + ${MAKE} docker-ecr-login; \ + ${MAKE} docker-build base_image=${base_image} dir="$${dir}" DOCKER_IMAGE="$${DOCKER_IMAGE}"; \ + ${MAKE} docker-push DOCKER_IMAGE="$${DOCKER_IMAGE}" -_docker: # Docker command wrapper - mandatory: cmd=[command to execute]; optional: dir=[path to the image directory where the Dockerfile is located, relative to the project's top-level directory, default is '.'] - # 'DOCKER_IMAGE' and 'DOCKER_TITLE' are passed to the functions as environment variables - DOCKER_IMAGE=$(or ${DOCKER_IMAGE}, $(or ${docker_image}, $(or ${IMAGE}, $(or ${image}, ghcr.io/org/repo)))) - DOCKER_TITLE=$(or "${DOCKER_TITLE}", $(or "${docker_title}", $(or "${TITLE}", $(or "${title}", "Service Docker image")))) - source scripts/docker/docker.lib.sh - dir=$(realpath ${dir}) - docker-${cmd} # 'dir' is accessible by the function as environment variable +docker-ecr-login: # Authenticate Docker with AWS ECR - required: AWS_ACCOUNT_ID, AWS_REGION @Development + source scripts/docker/docker.lib.sh; \ + AWS_ACCOUNT_ID="$${AWS_ACCOUNT_ID}" \ + AWS_REGION="$${AWS_REGION}" \ + docker-ecr-login + +docker-ghcr-login: # Authenticate Docker with GitHub Container Registry - required: GITHUB_TOKEN @Development + source scripts/docker/docker.lib.sh; \ + GITHUB_TOKEN="$${GITHUB_TOKEN:-}" \ + docker-ghcr-login + +clean:: # Remove container image and resources - required: DOCKER_IMAGE @Development + source scripts/docker/docker.lib.sh; \ + DOCKER_IMAGE="$${DOCKER_IMAGE:-}" \ + docker-clean # ============================================================================== # Quality checks - please DO NOT edit this section! @@ -34,50 +58,13 @@ docker-shellscript-lint: # Lint all Docker module shell scripts @Quality file=$${file} scripts/shellscript-linter.sh done -# ============================================================================== -# Module tests and examples - please DO NOT edit this section! - -docker-test-suite-run: # Run Docker test suite @ExamplesAndTests - scripts/docker/tests/docker.test.sh - -docker-example-build: # Build Docker example @ExamplesAndTests - source scripts/docker/docker.lib.sh - cd scripts/docker/examples/python - DOCKER_IMAGE=repository-template/docker-example-python - DOCKER_TITLE="Repository Template Docker Python Example" - TOOL_VERSIONS="$(shell git rev-parse --show-toplevel)/scripts/docker/examples/python/.tool-versions.example" - docker-build - -docker-example-lint: # Lint Docker example @ExamplesAndTests - dockerfile=scripts/docker/examples/python/Dockerfile - file=$${dockerfile} scripts/docker/dockerfile-linter.sh - -docker-example-run: # Run Docker example @ExamplesAndTests - source scripts/docker/docker.lib.sh - cd scripts/docker/examples/python - DOCKER_IMAGE=repository-template/docker-example-python - args=" \ - -it \ - --publish 8000:8000 \ - " - docker-run - -docker-example-clean: # Remove Docker example resources @ExamplesAndTests - source scripts/docker/docker.lib.sh - cd scripts/docker/examples/python - DOCKER_IMAGE=repository-template/docker-example-python - docker-clean - # ============================================================================== ${VERBOSE}.SILENT: \ - _docker \ clean \ docker-build \ - docker-example-build \ - docker-example-clean \ - docker-example-lint \ - docker-example-run \ + docker-build-and-push \ + docker-ecr-login \ + docker-ghcr-login \ docker-push \ docker-shellscript-lint \ - docker-test-suite-run \ diff --git a/scripts/docker/tests/.gitignore b/scripts/docker/tests/.gitignore deleted file mode 100644 index c50e8c0a8..000000000 --- a/scripts/docker/tests/.gitignore +++ /dev/null @@ -1 +0,0 @@ -Dockerfile.effective diff --git a/scripts/docker/tests/.tool-versions.test b/scripts/docker/tests/.tool-versions.test deleted file mode 100644 index 920931162..000000000 --- a/scripts/docker/tests/.tool-versions.test +++ /dev/null @@ -1,2 +0,0 @@ -# python, SEE: https://hub.docker.com/_/python/tags -# docker/python 3.11.4-alpine3.18@sha256:0135ae6442d1269379860b361760ad2cf6ab7c403d21935a8015b48d5bf78a86 diff --git a/scripts/docker/tests/Dockerfile b/scripts/docker/tests/Dockerfile deleted file mode 100644 index b5ea56060..000000000 --- a/scripts/docker/tests/Dockerfile +++ /dev/null @@ -1,3 +0,0 @@ -# `*:latest` will be replaced with a corresponding version stored in the '.tool-versions' file -# hadolint ignore=DL3007 -FROM python:latest diff --git a/scripts/docker/tests/VERSION b/scripts/docker/tests/VERSION deleted file mode 100644 index fb366351e..000000000 --- a/scripts/docker/tests/VERSION +++ /dev/null @@ -1,3 +0,0 @@ -${yyyy}${mm}${dd}-${hash} -$yyyy.$mm.$dd-$hash -somme-name-yyyyeah diff --git a/scripts/docker/tests/docker.test.sh b/scripts/docker/tests/docker.test.sh deleted file mode 100755 index 8f487b8f9..000000000 --- a/scripts/docker/tests/docker.test.sh +++ /dev/null @@ -1,162 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC1091,SC2034,SC2317 - -# WARNING: Please DO NOT edit this file! It is maintained in the Repository Template (https://github.com/nhs-england-tools/repository-template). Raise a PR instead. - -set -euo pipefail - -# Test suite for Docker functions. -# -# Usage: -# $ ./docker.test.sh -# -# Arguments (provided as environment variables): -# VERBOSE=true # Show all the executed commands, default is 'false' - -# ============================================================================== - -function main() { - - cd "$(git rev-parse --show-toplevel)" - source ./scripts/docker/docker.lib.sh - cd ./scripts/docker/tests - - DOCKER_IMAGE=repository-template/docker-test - DOCKER_TITLE="Repository Template Docker Test" - - test-docker-suite-setup - tests=( \ - test-docker-build \ - test-docker-image-from-signature \ - test-docker-version-file \ - test-docker-test \ - test-docker-run \ - test-docker-clean \ - test-docker-get-image-version-and-pull \ - ) - local status=0 - for test in "${tests[@]}"; do - { - echo -n "$test" - # shellcheck disable=SC2015 - $test && echo " PASS" || { echo " FAIL"; ((status++)); } - } - done - echo "Total: ${#tests[@]}, Passed: $(( ${#tests[@]} - status )), Failed: $status" - test-docker-suite-teardown - [ $status -gt 0 ] && return 1 || return 0 -} - -# ============================================================================== - -function test-docker-suite-setup() { - - : -} - -function test-docker-suite-teardown() { - - : -} - -# ============================================================================== - -function test-docker-build() { - - # Arrange - export BUILD_DATETIME="2023-09-04T15:46:34+0000" - # Act - docker-build > /dev/null 2>&1 - # Assert - docker image inspect "${DOCKER_IMAGE}:$(_get-effective-version)" > /dev/null 2>&1 && return 0 || return 1 -} - -function test-docker-image-from-signature() { - - # Arrange - TOOL_VERSIONS="$(git rev-parse --show-toplevel)/scripts/docker/tests/.tool-versions.test" - cp Dockerfile Dockerfile.effective - # Act - _replace-image-latest-by-specific-version - # Assert - grep -q "FROM python:.*-alpine.*@sha256:.*" Dockerfile.effective && return 0 || return 1 -} - -function test-docker-version-file() { - - # Arrange - export BUILD_DATETIME="2023-09-04T15:46:34+0000" - # Act - version-create-effective-file - # Assert - # shellcheck disable=SC2002 - ( - cat .version | grep -q "20230904-" && - cat .version | grep -q "2023.09.04-" && - cat .version | grep -q "somme-name-yyyyeah" - ) && return 0 || return 1 -} - -function test-docker-test() { - - # Arrange - cmd="python --version" - check="Python" - # Act - output=$(docker-check-test) - # Assert - echo "$output" | grep -q "PASS" -} - -function test-docker-run() { - - # Arrange - cmd="python --version" - # Act - output=$(docker-run) - # Assert - echo "$output" | grep -Eq "Python [0-9]+\.[0-9]+\.[0-9]+" -} - -function test-docker-clean() { - - # Arrange - version="$(_get-effective-version)" - # Act - docker-clean - # Assert - docker image inspect "${DOCKER_IMAGE}:${version}" > /dev/null 2>&1 && return 1 || return 0 -} - -function test-docker-get-image-version-and-pull() { - - # Arrange - name="ghcr.io/nhs-england-tools/github-runner-image" - match_version=".*-rt.*" - # Act - docker-get-image-version-and-pull > /dev/null 2>&1 - # Assert - docker images \ - --filter=reference="$name" \ - --format "{{.Tag}}" \ - | grep -vq "" -} - -# ============================================================================== - -function is-arg-true() { - - if [[ "$1" =~ ^(true|yes|y|on|1|TRUE|YES|Y|ON)$ ]]; then - return 0 - else - return 1 - fi -} - -# ============================================================================== - -is-arg-true "${VERBOSE:-false}" && set -x - -main "$@" - -exit 0