diff --git a/database/create-schema.sql b/database/create-schema.sql new file mode 100644 index 00000000..7294205e --- /dev/null +++ b/database/create-schema.sql @@ -0,0 +1,70 @@ +-- ================================================================= +-- Create a new schema for a specific environment +-- +-- This script provisions a new schema within the same Aurora PostgreSQL +-- database, enabling multiple environments (dev, staging, prod, etc.) +-- to share a single database instance for cost optimization. +-- +-- Usage: +-- psql -v schema_name='dev_hometest' -f create-schema.sql +-- +-- Or manually set the variable before running: +-- \set schema_name 'dev_hometest' +-- \i create-schema.sql +-- +-- The schema_name variable must be set before execution. +-- ================================================================= + +-- noqa: disable=all +-- (psql :variable syntax is not parseable by sqlfluff) + +-- Create the schema +CREATE SCHEMA IF NOT EXISTS :schema_name; + +-- Make the migration user own the schema +ALTER SCHEMA :schema_name OWNER TO app_migrator; + +-- Grant schema-level privileges to app_migrator +GRANT CREATE, USAGE ON SCHEMA :schema_name TO app_migrator; + +-- Grant DML privileges on existing objects +GRANT SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER +ON ALL TABLES IN SCHEMA :schema_name TO app_migrator; + +GRANT USAGE, SELECT, UPDATE +ON ALL SEQUENCES IN SCHEMA :schema_name TO app_migrator; + +-- Auto-grant privileges on future tables/sequences for app_migrator +ALTER DEFAULT PRIVILEGES IN SCHEMA :schema_name +GRANT SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER +ON TABLES TO app_migrator; + +ALTER DEFAULT PRIVILEGES IN SCHEMA :schema_name +GRANT USAGE, SELECT, UPDATE +ON SEQUENCES TO app_migrator; + +-- Grant schema privileges to app_user +GRANT USAGE ON SCHEMA :schema_name TO app_user; + +GRANT SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER +ON ALL TABLES IN SCHEMA :schema_name TO app_user; + +GRANT USAGE, SELECT, UPDATE +ON ALL SEQUENCES IN SCHEMA :schema_name TO app_user; + +-- Auto-grant privileges on future tables/sequences for app_user +ALTER DEFAULT PRIVILEGES IN SCHEMA :schema_name +GRANT SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER +ON TABLES TO app_user; + +ALTER DEFAULT PRIVILEGES IN SCHEMA :schema_name +GRANT USAGE, SELECT, UPDATE +ON SEQUENCES TO app_user; + +-- Grant admin access +GRANT CREATE, USAGE ON SCHEMA :schema_name TO admin; + +-- noqa: enable=all + +-- Ensure pgcrypto extension is available (database-level, idempotent) +CREATE EXTENSION IF NOT EXISTS pgcrypto; diff --git a/database/db-migrate-schema.sh b/database/db-migrate-schema.sh new file mode 100755 index 00000000..ba609e39 --- /dev/null +++ b/database/db-migrate-schema.sh @@ -0,0 +1,57 @@ +#!/bin/bash +set -e + +# ================================================================= +# Schema-aware database migration script +# +# Provisions a new schema and runs goose migrations against it. +# This enables multiple environments to share a single Aurora +# PostgreSQL database using separate schemas. +# +# Usage: +# ./db-migrate-schema.sh [db_host] [db_name] +# +# Examples: +# ./db-migrate-schema.sh dev_hometest +# ./db-migrate-schema.sh staging_hometest aurora-cluster.xyz.eu-west-2.rds.amazonaws.com mydb +# ./db-migrate-schema.sh hometest # default schema (backwards compatible) +# +# Environment variables (override defaults): +# ADMIN_USER, ADMIN_PASSWORD, MIGRATOR_USER, MIGRATOR_PASSWORD +# ================================================================= + +SCHEMA_NAME="${1:?Usage: $0 [db_host] [db_name]}" +DB_HOST="${2:-postgres-db}" +LOCAL_DB="${3:-local_hometest_db}" + +ADMIN_USER="${ADMIN_USER:-admin}" +ADMIN_PASSWORD="${ADMIN_PASSWORD:-admin}" +MIGRATOR_USER="${MIGRATOR_USER:-app_migrator}" +MIGRATOR_PASSWORD="${MIGRATOR_PASSWORD:-STRONG_PASSWORD_MIGRATOR}" +SQL_DIR="${SQL_DIR:-/docker-entrypoint-initdb.d}" +PSQL_OPTIONS="-v ON_ERROR_STOP=1" +DB_URL="postgresql://${MIGRATOR_USER}:${MIGRATOR_PASSWORD}@${DB_HOST}:5432/${LOCAL_DB}?search_path=${SCHEMA_NAME}" + +export PGHOST="$DB_HOST" + +echo "Starting database migration for schema: ${SCHEMA_NAME}..." + +# Step 1: Create schema and grant permissions (as admin) +export PGPASSWORD="$ADMIN_PASSWORD" +export PGUSER="$ADMIN_USER" + +echo "Step 1: Creating schema '${SCHEMA_NAME}' and granting permissions..." +psql $PSQL_OPTIONS -d "$LOCAL_DB" -v schema_name="${SCHEMA_NAME}" -f "$SQL_DIR/create-schema.sql" + +# Step 2: Run goose migrations (as migrator, with search_path set to target schema) +export PGPASSWORD="$MIGRATOR_PASSWORD" +export PGUSER="$MIGRATOR_USER" + +echo "Step 2: Running goose migrations against schema '${SCHEMA_NAME}'..." +goose -dir "$SQL_DIR/migrations" postgres "$DB_URL" up + +# Step 3: Load seed data (as migrator, with search_path) +echo "Step 3: Loading seed data into schema '${SCHEMA_NAME}'..." +psql $PSQL_OPTIONS -d "$LOCAL_DB" -c "SET search_path TO ${SCHEMA_NAME};" -f "$SQL_DIR/03-seed-hometest-data.sql" + +echo "Migration complete for schema: ${SCHEMA_NAME}" diff --git a/lambdas/package-lock.json b/lambdas/package-lock.json index 861678ef..1fc20e25 100644 --- a/lambdas/package-lock.json +++ b/lambdas/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@aws-sdk/client-secrets-manager": "^3.996.0", "@aws-sdk/client-sqs": "^3.996.0", + "@aws-sdk/rds-signer": "^3.1000.0", "@middy/core": "^7.1.1", "@middy/http-cors": "^7.1.1", "@middy/http-error-handler": "^7.1.1", @@ -173,6 +174,72 @@ "node": ">=14.0.0" } }, + "node_modules/@aws-sdk/client-cognito-identity": { + "version": "3.1000.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.1000.0.tgz", + "integrity": "sha512-7PtY49oxAo0rzkXZ1ulumtRL4QYi30Q5AMJtqJhYCHc1VZr0I2f0LHxiwovzquqUPzmTArgY6LjcPB7bkB/54w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "^3.973.15", + "@aws-sdk/credential-provider-node": "^3.972.14", + "@aws-sdk/middleware-host-header": "^3.972.6", + "@aws-sdk/middleware-logger": "^3.972.6", + "@aws-sdk/middleware-recursion-detection": "^3.972.6", + "@aws-sdk/middleware-user-agent": "^3.972.15", + "@aws-sdk/region-config-resolver": "^3.972.6", + "@aws-sdk/types": "^3.973.4", + "@aws-sdk/util-endpoints": "^3.996.3", + "@aws-sdk/util-user-agent-browser": "^3.972.6", + "@aws-sdk/util-user-agent-node": "^3.973.0", + "@smithy/config-resolver": "^4.4.9", + "@smithy/core": "^3.23.6", + "@smithy/fetch-http-handler": "^5.3.11", + "@smithy/hash-node": "^4.2.10", + "@smithy/invalid-dependency": "^4.2.10", + "@smithy/middleware-content-length": "^4.2.10", + "@smithy/middleware-endpoint": "^4.4.20", + "@smithy/middleware-retry": "^4.4.37", + "@smithy/middleware-serde": "^4.2.11", + "@smithy/middleware-stack": "^4.2.10", + "@smithy/node-config-provider": "^4.3.10", + "@smithy/node-http-handler": "^4.4.12", + "@smithy/protocol-http": "^5.3.10", + "@smithy/smithy-client": "^4.12.0", + "@smithy/types": "^4.13.0", + "@smithy/url-parser": "^4.2.10", + "@smithy/util-base64": "^4.3.1", + "@smithy/util-body-length-browser": "^4.2.1", + "@smithy/util-body-length-node": "^4.2.2", + "@smithy/util-defaults-mode-browser": "^4.3.36", + "@smithy/util-defaults-mode-node": "^4.2.39", + "@smithy/util-endpoints": "^3.3.1", + "@smithy/util-middleware": "^4.2.10", + "@smithy/util-retry": "^4.2.10", + "@smithy/util-utf8": "^4.2.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/util-endpoints": { + "version": "3.996.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.996.3.tgz", + "integrity": "sha512-yWIQSNiCjykLL+ezN5A+DfBb1gfXTytBxm57e64lYmwxDHNmInYHRJYYRAGWG1o77vKEiWaw4ui28e3yb1k5aQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.4", + "@smithy/types": "^4.13.0", + "@smithy/url-parser": "^4.2.10", + "@smithy/util-endpoints": "^3.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/@aws-sdk/client-secrets-manager": { "version": "3.996.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-secrets-manager/-/client-secrets-manager-3.996.0.tgz", @@ -275,73 +342,40 @@ "node": ">=20.0.0" } }, - "node_modules/@aws-sdk/client-sso": { - "version": "3.996.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.996.0.tgz", - "integrity": "sha512-QzlZozTam0modnGanLjXBHbHC53mMxH/4XmoA9f6ZjPYaGlCcHPYLcslO6w2w68v+F3qN0kxVldUAcL/edtBBA==", + "node_modules/@aws-sdk/core": { + "version": "3.973.15", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.973.15.tgz", + "integrity": "sha512-AlC0oQ1/mdJ8vCIqu524j5RB7M8i8E24bbkZmya1CuiQxkY7SdIZAyw7NDNMGaNINQFq/8oGRMX0HeOfCVsl/A==", "license": "Apache-2.0", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "^3.973.12", - "@aws-sdk/middleware-host-header": "^3.972.3", - "@aws-sdk/middleware-logger": "^3.972.3", - "@aws-sdk/middleware-recursion-detection": "^3.972.3", - "@aws-sdk/middleware-user-agent": "^3.972.12", - "@aws-sdk/region-config-resolver": "^3.972.3", - "@aws-sdk/types": "^3.973.1", - "@aws-sdk/util-endpoints": "3.996.0", - "@aws-sdk/util-user-agent-browser": "^3.972.3", - "@aws-sdk/util-user-agent-node": "^3.972.11", - "@smithy/config-resolver": "^4.4.6", - "@smithy/core": "^3.23.2", - "@smithy/fetch-http-handler": "^5.3.9", - "@smithy/hash-node": "^4.2.8", - "@smithy/invalid-dependency": "^4.2.8", - "@smithy/middleware-content-length": "^4.2.8", - "@smithy/middleware-endpoint": "^4.4.16", - "@smithy/middleware-retry": "^4.4.33", - "@smithy/middleware-serde": "^4.2.9", - "@smithy/middleware-stack": "^4.2.8", - "@smithy/node-config-provider": "^4.3.8", - "@smithy/node-http-handler": "^4.4.10", - "@smithy/protocol-http": "^5.3.8", - "@smithy/smithy-client": "^4.11.5", - "@smithy/types": "^4.12.0", - "@smithy/url-parser": "^4.2.8", - "@smithy/util-base64": "^4.3.0", - "@smithy/util-body-length-browser": "^4.2.0", - "@smithy/util-body-length-node": "^4.2.1", - "@smithy/util-defaults-mode-browser": "^4.3.32", - "@smithy/util-defaults-mode-node": "^4.2.35", - "@smithy/util-endpoints": "^3.2.8", - "@smithy/util-middleware": "^4.2.8", - "@smithy/util-retry": "^4.2.8", - "@smithy/util-utf8": "^4.2.0", + "@aws-sdk/types": "^3.973.4", + "@aws-sdk/xml-builder": "^3.972.8", + "@smithy/core": "^3.23.6", + "@smithy/node-config-provider": "^4.3.10", + "@smithy/property-provider": "^4.2.10", + "@smithy/protocol-http": "^5.3.10", + "@smithy/signature-v4": "^5.3.10", + "@smithy/smithy-client": "^4.12.0", + "@smithy/types": "^4.13.0", + "@smithy/util-base64": "^4.3.1", + "@smithy/util-middleware": "^4.2.10", + "@smithy/util-utf8": "^4.2.1", "tslib": "^2.6.2" }, "engines": { "node": ">=20.0.0" } }, - "node_modules/@aws-sdk/core": { - "version": "3.973.12", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.973.12.tgz", - "integrity": "sha512-hFiezao0lCEddPhSQEF6vCu+TepUN3edKxWYbswMoH87XpUvHJmFVX5+zttj4qi33saGiuOaJciswWcN6YSA9g==", + "node_modules/@aws-sdk/credential-provider-cognito-identity": { + "version": "3.972.6", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.972.6.tgz", + "integrity": "sha512-RJqEZYFoXkBTVCwSJuYFd311qc/Q/cBJ8BH08+ggX/rUTWw47TUEyZlxzyTlKfP7DoXG4Khu/TX+pzU6godEGQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.1", - "@aws-sdk/xml-builder": "^3.972.5", - "@smithy/core": "^3.23.2", - "@smithy/node-config-provider": "^4.3.8", - "@smithy/property-provider": "^4.2.8", - "@smithy/protocol-http": "^5.3.8", - "@smithy/signature-v4": "^5.3.8", - "@smithy/smithy-client": "^4.11.5", - "@smithy/types": "^4.12.0", - "@smithy/util-base64": "^4.3.0", - "@smithy/util-middleware": "^4.2.8", - "@smithy/util-utf8": "^4.2.0", + "@aws-sdk/nested-clients": "^3.996.3", + "@aws-sdk/types": "^3.973.4", + "@smithy/property-provider": "^4.2.10", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -349,15 +383,15 @@ } }, "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.972.10", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.10.tgz", - "integrity": "sha512-YTWjM78Wiqix0Jv/anbq7+COFOFIBBMLZ+JsLKGwbTZNJ2DG4JNBnLVJAWylPOHwurMws9157pqzU8ODrpBOow==", + "version": "3.972.13", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.13.tgz", + "integrity": "sha512-6ljXKIQ22WFKyIs1jbORIkGanySBHaPPTOI4OxACP5WXgbcR0nDYfqNJfXEGwCK7IzHdNbCSFsNKKs0qCexR8Q==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.973.12", - "@aws-sdk/types": "^3.973.1", - "@smithy/property-provider": "^4.2.8", - "@smithy/types": "^4.12.0", + "@aws-sdk/core": "^3.973.15", + "@aws-sdk/types": "^3.973.4", + "@smithy/property-provider": "^4.2.10", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -365,20 +399,20 @@ } }, "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.972.12", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.12.tgz", - "integrity": "sha512-adDRE3iFrgJJ7XhRHkb6RdFDMrA5x64WAWxygI3F6wND+3v5qQ4Uks12vsnEZgduU/+JQBgFB6L4vfwUS+rpBQ==", + "version": "3.972.15", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.15.tgz", + "integrity": "sha512-dJuSTreu/T8f24SHDNTjd7eQ4rabr0TzPh2UTCwYexQtzG3nTDKm1e5eIdhiroTMDkPEJeY+WPkA6F9wod/20A==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.973.12", - "@aws-sdk/types": "^3.973.1", - "@smithy/fetch-http-handler": "^5.3.9", - "@smithy/node-http-handler": "^4.4.10", - "@smithy/property-provider": "^4.2.8", - "@smithy/protocol-http": "^5.3.8", - "@smithy/smithy-client": "^4.11.5", - "@smithy/types": "^4.12.0", - "@smithy/util-stream": "^4.5.12", + "@aws-sdk/core": "^3.973.15", + "@aws-sdk/types": "^3.973.4", + "@smithy/fetch-http-handler": "^5.3.11", + "@smithy/node-http-handler": "^4.4.12", + "@smithy/property-provider": "^4.2.10", + "@smithy/protocol-http": "^5.3.10", + "@smithy/smithy-client": "^4.12.0", + "@smithy/types": "^4.13.0", + "@smithy/util-stream": "^4.5.15", "tslib": "^2.6.2" }, "engines": { @@ -386,24 +420,24 @@ } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.972.10", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.10.tgz", - "integrity": "sha512-uAXUMfnQJxJ25qeiX4e3Z36NTm1XT7woajV8BXx2yAUDD4jF6kubqnLEcqtiPzHANxmhta2SXm5PbDwSdhThBw==", + "version": "3.972.13", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.13.tgz", + "integrity": "sha512-JKSoGb7XeabZLBJptpqoZIFbROUIS65NuQnEHGOpuT9GuuZwag2qciKANiDLFiYk4u8nSrJC9JIOnWKVvPVjeA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.973.12", - "@aws-sdk/credential-provider-env": "^3.972.10", - "@aws-sdk/credential-provider-http": "^3.972.12", - "@aws-sdk/credential-provider-login": "^3.972.10", - "@aws-sdk/credential-provider-process": "^3.972.10", - "@aws-sdk/credential-provider-sso": "^3.972.10", - "@aws-sdk/credential-provider-web-identity": "^3.972.10", - "@aws-sdk/nested-clients": "3.996.0", - "@aws-sdk/types": "^3.973.1", - "@smithy/credential-provider-imds": "^4.2.8", - "@smithy/property-provider": "^4.2.8", - "@smithy/shared-ini-file-loader": "^4.4.3", - "@smithy/types": "^4.12.0", + "@aws-sdk/core": "^3.973.15", + "@aws-sdk/credential-provider-env": "^3.972.13", + "@aws-sdk/credential-provider-http": "^3.972.15", + "@aws-sdk/credential-provider-login": "^3.972.13", + "@aws-sdk/credential-provider-process": "^3.972.13", + "@aws-sdk/credential-provider-sso": "^3.972.13", + "@aws-sdk/credential-provider-web-identity": "^3.972.13", + "@aws-sdk/nested-clients": "^3.996.3", + "@aws-sdk/types": "^3.973.4", + "@smithy/credential-provider-imds": "^4.2.10", + "@smithy/property-provider": "^4.2.10", + "@smithy/shared-ini-file-loader": "^4.4.5", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -411,18 +445,18 @@ } }, "node_modules/@aws-sdk/credential-provider-login": { - "version": "3.972.10", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.10.tgz", - "integrity": "sha512-7Me+/EkY3kQC1nehBjb9ryc558N+a8R4Dg3rSV3zpiB7iQtvXh4gU3rV14h/dIbn2/VkK9sh55YdXamSjfdb/Q==", + "version": "3.972.13", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.13.tgz", + "integrity": "sha512-RtYcrxdnJHKY8MFQGLltCURcjuMjnaQpAxPE6+/QEdDHHItMKZgabRe/KScX737F9vJMQsmJy9EmMOkCnoC1JQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.973.12", - "@aws-sdk/nested-clients": "3.996.0", - "@aws-sdk/types": "^3.973.1", - "@smithy/property-provider": "^4.2.8", - "@smithy/protocol-http": "^5.3.8", - "@smithy/shared-ini-file-loader": "^4.4.3", - "@smithy/types": "^4.12.0", + "@aws-sdk/core": "^3.973.15", + "@aws-sdk/nested-clients": "^3.996.3", + "@aws-sdk/types": "^3.973.4", + "@smithy/property-provider": "^4.2.10", + "@smithy/protocol-http": "^5.3.10", + "@smithy/shared-ini-file-loader": "^4.4.5", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -430,22 +464,22 @@ } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.972.11", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.11.tgz", - "integrity": "sha512-maPmjL7nOT93a1QdSDzdF/qLbI+jit3oslKp7g+pTbASewkSYax7FwboETdKRxufPfCdrsRzMW2pIJ+QA8e+Bg==", + "version": "3.972.14", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.14.tgz", + "integrity": "sha512-WqoC2aliIjQM/L3oFf6j+op/enT2i9Cc4UTxxMEKrJNECkq4/PlKE5BOjSYFcq6G9mz65EFbXJh7zOU4CvjSKQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/credential-provider-env": "^3.972.10", - "@aws-sdk/credential-provider-http": "^3.972.12", - "@aws-sdk/credential-provider-ini": "^3.972.10", - "@aws-sdk/credential-provider-process": "^3.972.10", - "@aws-sdk/credential-provider-sso": "^3.972.10", - "@aws-sdk/credential-provider-web-identity": "^3.972.10", - "@aws-sdk/types": "^3.973.1", - "@smithy/credential-provider-imds": "^4.2.8", - "@smithy/property-provider": "^4.2.8", - "@smithy/shared-ini-file-loader": "^4.4.3", - "@smithy/types": "^4.12.0", + "@aws-sdk/credential-provider-env": "^3.972.13", + "@aws-sdk/credential-provider-http": "^3.972.15", + "@aws-sdk/credential-provider-ini": "^3.972.13", + "@aws-sdk/credential-provider-process": "^3.972.13", + "@aws-sdk/credential-provider-sso": "^3.972.13", + "@aws-sdk/credential-provider-web-identity": "^3.972.13", + "@aws-sdk/types": "^3.973.4", + "@smithy/credential-provider-imds": "^4.2.10", + "@smithy/property-provider": "^4.2.10", + "@smithy/shared-ini-file-loader": "^4.4.5", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -453,16 +487,16 @@ } }, "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.972.10", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.10.tgz", - "integrity": "sha512-tk/XxFhk37rKviArOIYbJ8crXiN3Mzn7Tb147jH51JTweNgUOwmqN+s027uqc3d8UeAyUcPUH8Bmfj86SzOhBQ==", + "version": "3.972.13", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.13.tgz", + "integrity": "sha512-rsRG0LQA4VR+jnDyuqtXi2CePYSmfm5GNL9KxiW8DSe25YwJSr06W8TdUfONAC+rjsTI+aIH2rBGG5FjMeANrw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.973.12", - "@aws-sdk/types": "^3.973.1", - "@smithy/property-provider": "^4.2.8", - "@smithy/shared-ini-file-loader": "^4.4.3", - "@smithy/types": "^4.12.0", + "@aws-sdk/core": "^3.973.15", + "@aws-sdk/types": "^3.973.4", + "@smithy/property-provider": "^4.2.10", + "@smithy/shared-ini-file-loader": "^4.4.5", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -470,18 +504,18 @@ } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.972.10", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.10.tgz", - "integrity": "sha512-tIz/O0yV1s77/FjMTWvvzU2vsztap2POlbetheOyRXq+E3PQtLOzCYopasXP+aeO1oerw3PFd9eycLbiwpgZZA==", + "version": "3.972.13", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.13.tgz", + "integrity": "sha512-fr0UU1wx8kNHDhTQBXioc/YviSW8iXuAxHvnH7eQUtn8F8o/FU3uu6EUMvAQgyvn7Ne5QFnC0Cj0BFlwCk+RFw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/client-sso": "3.996.0", - "@aws-sdk/core": "^3.973.12", - "@aws-sdk/token-providers": "3.996.0", - "@aws-sdk/types": "^3.973.1", - "@smithy/property-provider": "^4.2.8", - "@smithy/shared-ini-file-loader": "^4.4.3", - "@smithy/types": "^4.12.0", + "@aws-sdk/core": "^3.973.15", + "@aws-sdk/nested-clients": "^3.996.3", + "@aws-sdk/token-providers": "3.999.0", + "@aws-sdk/types": "^3.973.4", + "@smithy/property-provider": "^4.2.10", + "@smithy/shared-ini-file-loader": "^4.4.5", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -489,17 +523,48 @@ } }, "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.972.10", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.10.tgz", - "integrity": "sha512-HFlIVx8mm+Au7hkO7Hq/ZkPomjTt26iRj8uWZqEE1cJWMZ2NKvieNiT1ngzWt60Bc2uD51LqQUqiwr5JDgS4iQ==", + "version": "3.972.13", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.13.tgz", + "integrity": "sha512-a6iFMh1pgUH0TdcouBppLJUfPM7Yd3R9S1xFodPtCRoLqCz2RQFA3qjA8x4112PVYXEd4/pHX2eihapq39w0rA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.973.12", - "@aws-sdk/nested-clients": "3.996.0", - "@aws-sdk/types": "^3.973.1", - "@smithy/property-provider": "^4.2.8", - "@smithy/shared-ini-file-loader": "^4.4.3", - "@smithy/types": "^4.12.0", + "@aws-sdk/core": "^3.973.15", + "@aws-sdk/nested-clients": "^3.996.3", + "@aws-sdk/types": "^3.973.4", + "@smithy/property-provider": "^4.2.10", + "@smithy/shared-ini-file-loader": "^4.4.5", + "@smithy/types": "^4.13.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-providers": { + "version": "3.1000.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.1000.0.tgz", + "integrity": "sha512-J0pBgTZ2b3UCnj+NQTPtWYjrEUne2aGwq1Xuuw8P2cIMpPBYJc39e59oYoRGpNseUXqcjkh0nLtWqZREEeMvkg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-cognito-identity": "3.1000.0", + "@aws-sdk/core": "^3.973.15", + "@aws-sdk/credential-provider-cognito-identity": "^3.972.6", + "@aws-sdk/credential-provider-env": "^3.972.13", + "@aws-sdk/credential-provider-http": "^3.972.15", + "@aws-sdk/credential-provider-ini": "^3.972.13", + "@aws-sdk/credential-provider-login": "^3.972.13", + "@aws-sdk/credential-provider-node": "^3.972.14", + "@aws-sdk/credential-provider-process": "^3.972.13", + "@aws-sdk/credential-provider-sso": "^3.972.13", + "@aws-sdk/credential-provider-web-identity": "^3.972.13", + "@aws-sdk/nested-clients": "^3.996.3", + "@aws-sdk/types": "^3.973.4", + "@smithy/config-resolver": "^4.4.9", + "@smithy/core": "^3.23.6", + "@smithy/credential-provider-imds": "^4.2.10", + "@smithy/node-config-provider": "^4.3.10", + "@smithy/property-provider": "^4.2.10", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -507,14 +572,14 @@ } }, "node_modules/@aws-sdk/middleware-host-header": { - "version": "3.972.3", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.972.3.tgz", - "integrity": "sha512-aknPTb2M+G3s+0qLCx4Li/qGZH8IIYjugHMv15JTYMe6mgZO8VBpYgeGYsNMGCqCZOcWzuf900jFBG5bopfzmA==", + "version": "3.972.6", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.972.6.tgz", + "integrity": "sha512-5XHwjPH1lHB+1q4bfC7T8Z5zZrZXfaLcjSMwTd1HPSPrCmPFMbg3UQ5vgNWcVj0xoX4HWqTGkSf2byrjlnRg5w==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.1", - "@smithy/protocol-http": "^5.3.8", - "@smithy/types": "^4.12.0", + "@aws-sdk/types": "^3.973.4", + "@smithy/protocol-http": "^5.3.10", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -522,13 +587,13 @@ } }, "node_modules/@aws-sdk/middleware-logger": { - "version": "3.972.3", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.972.3.tgz", - "integrity": "sha512-Ftg09xNNRqaz9QNzlfdQWfpqMCJbsQdnZVJP55jfhbKi1+FTWxGuvfPoBhDHIovqWKjqbuiew3HuhxbJ0+OjgA==", + "version": "3.972.6", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.972.6.tgz", + "integrity": "sha512-iFnaMFMQdljAPrvsCVKYltPt2j40LQqukAbXvW7v0aL5I+1GO7bZ/W8m12WxW3gwyK5p5u1WlHg8TSAizC5cZw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.1", - "@smithy/types": "^4.12.0", + "@aws-sdk/types": "^3.973.4", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -536,15 +601,15 @@ } }, "node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.972.3", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.972.3.tgz", - "integrity": "sha512-PY57QhzNuXHnwbJgbWYTrqIDHYSeOlhfYERTAuc16LKZpTZRJUjzBFokp9hF7u1fuGeE3D70ERXzdbMBOqQz7Q==", + "version": "3.972.6", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.972.6.tgz", + "integrity": "sha512-dY4v3of5EEMvik6+UDwQ96KfUFDk8m1oZDdkSc5lwi4o7rFrjnv0A+yTV+gu230iybQZnKgDLg/rt2P3H+Vscw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.1", + "@aws-sdk/types": "^3.973.4", "@aws/lambda-invoke-store": "^0.2.2", - "@smithy/protocol-http": "^5.3.8", - "@smithy/types": "^4.12.0", + "@smithy/protocol-http": "^5.3.10", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -569,17 +634,33 @@ } }, "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.972.12", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.972.12.tgz", - "integrity": "sha512-iv9toQZloEJp+dIuOr+1XWGmBMLU9c2qqNtgscfnEBZnUq3qKdBJHmLTKoq3mkLlV+41GrCWn8LrOunc6OlP6g==", + "version": "3.972.15", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.972.15.tgz", + "integrity": "sha512-ABlFVcIMmuRAwBT+8q5abAxOr7WmaINirDJBnqGY5b5jSDo00UMlg/G4a0xoAgwm6oAECeJcwkvDlxDwKf58fQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.973.12", - "@aws-sdk/types": "^3.973.1", - "@aws-sdk/util-endpoints": "3.996.0", - "@smithy/core": "^3.23.2", - "@smithy/protocol-http": "^5.3.8", - "@smithy/types": "^4.12.0", + "@aws-sdk/core": "^3.973.15", + "@aws-sdk/types": "^3.973.4", + "@aws-sdk/util-endpoints": "^3.996.3", + "@smithy/core": "^3.23.6", + "@smithy/protocol-http": "^5.3.10", + "@smithy/types": "^4.13.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent/node_modules/@aws-sdk/util-endpoints": { + "version": "3.996.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.996.3.tgz", + "integrity": "sha512-yWIQSNiCjykLL+ezN5A+DfBb1gfXTytBxm57e64lYmwxDHNmInYHRJYYRAGWG1o77vKEiWaw4ui28e3yb1k5aQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.4", + "@smithy/types": "^4.13.0", + "@smithy/url-parser": "^4.2.10", + "@smithy/util-endpoints": "^3.3.1", "tslib": "^2.6.2" }, "engines": { @@ -587,48 +668,87 @@ } }, "node_modules/@aws-sdk/nested-clients": { - "version": "3.996.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.996.0.tgz", - "integrity": "sha512-edZwYLgRI0rZlH9Hru9+JvTsR1OAxuCRGEtJohkZneIJ5JIYzvFoMR1gaASjl1aPKRhjkCv8SSAb7hes5a1GGA==", + "version": "3.996.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.996.3.tgz", + "integrity": "sha512-AU5TY1V29xqwg/MxmA2odwysTez+ccFAhmfRJk+QZT5HNv90UTA9qKd1J9THlsQkvmH7HWTEV1lDNxkQO5PzNw==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "^3.973.12", - "@aws-sdk/middleware-host-header": "^3.972.3", - "@aws-sdk/middleware-logger": "^3.972.3", - "@aws-sdk/middleware-recursion-detection": "^3.972.3", - "@aws-sdk/middleware-user-agent": "^3.972.12", - "@aws-sdk/region-config-resolver": "^3.972.3", - "@aws-sdk/types": "^3.973.1", - "@aws-sdk/util-endpoints": "3.996.0", - "@aws-sdk/util-user-agent-browser": "^3.972.3", - "@aws-sdk/util-user-agent-node": "^3.972.11", - "@smithy/config-resolver": "^4.4.6", - "@smithy/core": "^3.23.2", - "@smithy/fetch-http-handler": "^5.3.9", - "@smithy/hash-node": "^4.2.8", - "@smithy/invalid-dependency": "^4.2.8", - "@smithy/middleware-content-length": "^4.2.8", - "@smithy/middleware-endpoint": "^4.4.16", - "@smithy/middleware-retry": "^4.4.33", - "@smithy/middleware-serde": "^4.2.9", - "@smithy/middleware-stack": "^4.2.8", - "@smithy/node-config-provider": "^4.3.8", - "@smithy/node-http-handler": "^4.4.10", - "@smithy/protocol-http": "^5.3.8", - "@smithy/smithy-client": "^4.11.5", - "@smithy/types": "^4.12.0", - "@smithy/url-parser": "^4.2.8", - "@smithy/util-base64": "^4.3.0", - "@smithy/util-body-length-browser": "^4.2.0", - "@smithy/util-body-length-node": "^4.2.1", - "@smithy/util-defaults-mode-browser": "^4.3.32", - "@smithy/util-defaults-mode-node": "^4.2.35", - "@smithy/util-endpoints": "^3.2.8", - "@smithy/util-middleware": "^4.2.8", - "@smithy/util-retry": "^4.2.8", - "@smithy/util-utf8": "^4.2.0", + "@aws-sdk/core": "^3.973.15", + "@aws-sdk/middleware-host-header": "^3.972.6", + "@aws-sdk/middleware-logger": "^3.972.6", + "@aws-sdk/middleware-recursion-detection": "^3.972.6", + "@aws-sdk/middleware-user-agent": "^3.972.15", + "@aws-sdk/region-config-resolver": "^3.972.6", + "@aws-sdk/types": "^3.973.4", + "@aws-sdk/util-endpoints": "^3.996.3", + "@aws-sdk/util-user-agent-browser": "^3.972.6", + "@aws-sdk/util-user-agent-node": "^3.973.0", + "@smithy/config-resolver": "^4.4.9", + "@smithy/core": "^3.23.6", + "@smithy/fetch-http-handler": "^5.3.11", + "@smithy/hash-node": "^4.2.10", + "@smithy/invalid-dependency": "^4.2.10", + "@smithy/middleware-content-length": "^4.2.10", + "@smithy/middleware-endpoint": "^4.4.20", + "@smithy/middleware-retry": "^4.4.37", + "@smithy/middleware-serde": "^4.2.11", + "@smithy/middleware-stack": "^4.2.10", + "@smithy/node-config-provider": "^4.3.10", + "@smithy/node-http-handler": "^4.4.12", + "@smithy/protocol-http": "^5.3.10", + "@smithy/smithy-client": "^4.12.0", + "@smithy/types": "^4.13.0", + "@smithy/url-parser": "^4.2.10", + "@smithy/util-base64": "^4.3.1", + "@smithy/util-body-length-browser": "^4.2.1", + "@smithy/util-body-length-node": "^4.2.2", + "@smithy/util-defaults-mode-browser": "^4.3.36", + "@smithy/util-defaults-mode-node": "^4.2.39", + "@smithy/util-endpoints": "^3.3.1", + "@smithy/util-middleware": "^4.2.10", + "@smithy/util-retry": "^4.2.10", + "@smithy/util-utf8": "^4.2.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/util-endpoints": { + "version": "3.996.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.996.3.tgz", + "integrity": "sha512-yWIQSNiCjykLL+ezN5A+DfBb1gfXTytBxm57e64lYmwxDHNmInYHRJYYRAGWG1o77vKEiWaw4ui28e3yb1k5aQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.4", + "@smithy/types": "^4.13.0", + "@smithy/url-parser": "^4.2.10", + "@smithy/util-endpoints": "^3.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/rds-signer": { + "version": "3.1000.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/rds-signer/-/rds-signer-3.1000.0.tgz", + "integrity": "sha512-kD80cbJxsuw+fb/aFmyBXWye/cXY+GyNBGKwMk0hJHoPOL/EPmUAaM/g6eTRy31/6pxtb+YWP8aSCnFIbX11zw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/credential-providers": "3.1000.0", + "@aws-sdk/util-format-url": "^3.972.6", + "@smithy/config-resolver": "^4.4.9", + "@smithy/hash-node": "^4.2.10", + "@smithy/invalid-dependency": "^4.2.10", + "@smithy/node-config-provider": "^4.3.10", + "@smithy/protocol-http": "^5.3.10", + "@smithy/signature-v4": "^5.3.10", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -636,15 +756,15 @@ } }, "node_modules/@aws-sdk/region-config-resolver": { - "version": "3.972.3", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.972.3.tgz", - "integrity": "sha512-v4J8qYAWfOMcZ4MJUyatntOicTzEMaU7j3OpkRCGGFSL2NgXQ5VbxauIyORA+pxdKZ0qQG2tCQjQjZDlXEC3Ow==", + "version": "3.972.6", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.972.6.tgz", + "integrity": "sha512-Aa5PusHLXAqLTX1UKDvI3pHQJtIsF7Q+3turCHqfz/1F61/zDMWfbTC8evjhrrYVAtz9Vsv3SJ/waSUeu7B6gw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.1", - "@smithy/config-resolver": "^4.4.6", - "@smithy/node-config-provider": "^4.3.8", - "@smithy/types": "^4.12.0", + "@aws-sdk/types": "^3.973.4", + "@smithy/config-resolver": "^4.4.9", + "@smithy/node-config-provider": "^4.3.10", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -652,17 +772,17 @@ } }, "node_modules/@aws-sdk/token-providers": { - "version": "3.996.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.996.0.tgz", - "integrity": "sha512-jzBmlG97hYPdHjFs7G11fBgVArcwUrZX+SbGeQMph7teEWLDqIruKV+N0uzxFJF2GJJJ0UnMaKhv3PcXMltySg==", + "version": "3.999.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.999.0.tgz", + "integrity": "sha512-cx0hHUlgXULfykx4rdu/ciNAJaa3AL5xz3rieCz7NKJ68MJwlj3664Y8WR5MGgxfyYJBdamnkjNSx5Kekuc0cg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.973.12", - "@aws-sdk/nested-clients": "3.996.0", - "@aws-sdk/types": "^3.973.1", - "@smithy/property-provider": "^4.2.8", - "@smithy/shared-ini-file-loader": "^4.4.3", - "@smithy/types": "^4.12.0", + "@aws-sdk/core": "^3.973.15", + "@aws-sdk/nested-clients": "^3.996.3", + "@aws-sdk/types": "^3.973.4", + "@smithy/property-provider": "^4.2.10", + "@smithy/shared-ini-file-loader": "^4.4.5", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -670,12 +790,12 @@ } }, "node_modules/@aws-sdk/types": { - "version": "3.973.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.1.tgz", - "integrity": "sha512-DwHBiMNOB468JiX6+i34c+THsKHErYUdNQ3HexeXZvVn4zouLjgaS4FejiGSi2HyBuzuyHg7SuOPmjSvoU9NRg==", + "version": "3.973.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.4.tgz", + "integrity": "sha512-RW60aH26Bsc016Y9B98hC0Plx6fK5P2v/iQYwMzrSjiDh1qRMUCP6KrXHYEHe3uFvKiOC93Z9zk4BJsUi6Tj1Q==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.12.0", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -698,6 +818,21 @@ "node": ">=20.0.0" } }, + "node_modules/@aws-sdk/util-format-url": { + "version": "3.972.6", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-format-url/-/util-format-url-3.972.6.tgz", + "integrity": "sha512-0YNVNgFyziCejXJx0rzxPiD2rkxTWco4c9wiMF6n37Tb9aQvIF8+t7GyEyIFCwQHZ0VMQaAl+nCZHOYz5I5EKw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.4", + "@smithy/querystring-builder": "^4.2.10", + "@smithy/types": "^4.13.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/@aws-sdk/util-locate-window": { "version": "3.965.4", "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.965.4.tgz", @@ -711,27 +846,27 @@ } }, "node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.972.3", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.972.3.tgz", - "integrity": "sha512-JurOwkRUcXD/5MTDBcqdyQ9eVedtAsZgw5rBwktsPTN7QtPiS2Ld1jkJepNgYoCufz1Wcut9iup7GJDoIHp8Fw==", + "version": "3.972.6", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.972.6.tgz", + "integrity": "sha512-Fwr/llD6GOrFgQnKaI2glhohdGuBDfHfora6iG9qsBBBR8xv1SdCSwbtf5CWlUdCw5X7g76G/9Hf0Inh0EmoxA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.1", - "@smithy/types": "^4.12.0", + "@aws-sdk/types": "^3.973.4", + "@smithy/types": "^4.13.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.972.11", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.972.11.tgz", - "integrity": "sha512-pQr35pSZANfUb0mJ9H87pziJQ39jW1D7xFRwh36eWfrEclbKoIqrzpOIVz49o1Jq9ZQzOtjS7rQVvt7V4w5awA==", + "version": "3.973.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.973.0.tgz", + "integrity": "sha512-A9J2G4Nf236e9GpaC1JnA8wRn6u6GjnOXiTwBLA6NUJhlBTIGfrTy+K1IazmF8y+4OFdW3O5TZlhyspJMqiqjA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/middleware-user-agent": "^3.972.12", - "@aws-sdk/types": "^3.973.1", - "@smithy/node-config-provider": "^4.3.8", - "@smithy/types": "^4.12.0", + "@aws-sdk/middleware-user-agent": "^3.972.15", + "@aws-sdk/types": "^3.973.4", + "@smithy/node-config-provider": "^4.3.10", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -747,12 +882,12 @@ } }, "node_modules/@aws-sdk/xml-builder": { - "version": "3.972.5", - "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.5.tgz", - "integrity": "sha512-mCae5Ys6Qm1LDu0qdGwx2UQ63ONUe+FHw908fJzLDqFKTDBK4LDZUqKWm4OkTCNFq19bftjsBSESIGLD/s3/rA==", + "version": "3.972.8", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.8.tgz", + "integrity": "sha512-Ql8elcUdYCha83Ol7NznBsgN5GVZnv3vUd86fEc6waU6oUdY0T1O9NODkEEOS/Uaogr87avDrUC6DSeM4oXjZg==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.12.0", + "@smithy/types": "^4.13.0", "fast-xml-parser": "5.3.6", "tslib": "^2.6.2" }, @@ -3987,12 +4122,12 @@ } }, "node_modules/@smithy/abort-controller": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.2.9.tgz", - "integrity": "sha512-6YGSygFmck1vMjzSxbjEPKMm1xWUr2+w+F8kWVc8rqKQYd1C5zZftvxGii4ti4Mh5ulIXZtAUoXS88Hhu6fkjQ==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.2.10.tgz", + "integrity": "sha512-qocxM/X4XGATqQtUkbE9SPUB6wekBi+FyJOMbPj0AhvyvFGYEmOlz6VB22iMePCQsFmMIvFSeViDvA7mZJG47g==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.12.1", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -4000,16 +4135,16 @@ } }, "node_modules/@smithy/config-resolver": { - "version": "4.4.7", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.7.tgz", - "integrity": "sha512-RISbtc12JKdFRYadt2kW12Cp6XCSU00uFaBZPZqInNVSrRdJFPY/S6nd6/sV7+ySTgGPiKrERtnimEFI6sSweQ==", + "version": "4.4.9", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.9.tgz", + "integrity": "sha512-ejQvXqlcU30h7liR9fXtj7PIAau1t/sFbJpgWPfiYDs7zd16jpH0IsSXKcba2jF6ChTXvIjACs27kNMc5xxE2Q==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.3.9", - "@smithy/types": "^4.12.1", + "@smithy/node-config-provider": "^4.3.10", + "@smithy/types": "^4.13.0", "@smithy/util-config-provider": "^4.2.1", - "@smithy/util-endpoints": "^3.2.9", - "@smithy/util-middleware": "^4.2.9", + "@smithy/util-endpoints": "^3.3.1", + "@smithy/util-middleware": "^4.2.10", "tslib": "^2.6.2" }, "engines": { @@ -4017,18 +4152,18 @@ } }, "node_modules/@smithy/core": { - "version": "3.23.4", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.23.4.tgz", - "integrity": "sha512-IH7G3hWxUhd2Z6HtvjZ1EiyDBCRYRr2sngOB9KUWf96XQ8JP2O5ascUH6TouW5YCIMFaVnKADEscM/vUfI3TvA==", + "version": "3.23.6", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.23.6.tgz", + "integrity": "sha512-4xE+0L2NrsFKpEVFlFELkIHQddBvMbQ41LRIP74dGCXnY1zQ9DgksrBcRBDJT+iOzGy4VEJIeU3hkUK5mn06kg==", "license": "Apache-2.0", "dependencies": { - "@smithy/middleware-serde": "^4.2.10", - "@smithy/protocol-http": "^5.3.9", - "@smithy/types": "^4.12.1", + "@smithy/middleware-serde": "^4.2.11", + "@smithy/protocol-http": "^5.3.10", + "@smithy/types": "^4.13.0", "@smithy/util-base64": "^4.3.1", "@smithy/util-body-length-browser": "^4.2.1", - "@smithy/util-middleware": "^4.2.9", - "@smithy/util-stream": "^4.5.14", + "@smithy/util-middleware": "^4.2.10", + "@smithy/util-stream": "^4.5.15", "@smithy/util-utf8": "^4.2.1", "@smithy/uuid": "^1.1.1", "tslib": "^2.6.2" @@ -4038,15 +4173,15 @@ } }, "node_modules/@smithy/credential-provider-imds": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.9.tgz", - "integrity": "sha512-Jf723a38EGAzWHxJHzb9DtBq7lrvdJlkCAPWQdN/oiznovx5yWXCFCVspzDe8JU6b+k9hJXYB5duFZpb+3mB6Q==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.10.tgz", + "integrity": "sha512-3bsMLJJLTZGZqVGGeBVFfLzuRulVsGTj12BzRKODTHqUABpIr0jMN1vN3+u6r2OfyhAQ2pXaMZWX/swBK5I6PQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.3.9", - "@smithy/property-provider": "^4.2.9", - "@smithy/types": "^4.12.1", - "@smithy/url-parser": "^4.2.9", + "@smithy/node-config-provider": "^4.3.10", + "@smithy/property-provider": "^4.2.10", + "@smithy/types": "^4.13.0", + "@smithy/url-parser": "^4.2.10", "tslib": "^2.6.2" }, "engines": { @@ -4054,14 +4189,14 @@ } }, "node_modules/@smithy/fetch-http-handler": { - "version": "5.3.10", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.10.tgz", - "integrity": "sha512-qF4EcrEtEf2P6f2kGGuSVe1lan26cn7PsWJBC3vZJ6D16Fm5FSN06udOMVoW6hjzQM3W7VDFwtyUG2szQY50dA==", + "version": "5.3.11", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.11.tgz", + "integrity": "sha512-wbTRjOxdFuyEg0CpumjZO0hkUl+fetJFqxNROepuLIoijQh51aMBmzFLfoQdwRjxsuuS2jizzIUTjPWgd8pd7g==", "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^5.3.9", - "@smithy/querystring-builder": "^4.2.9", - "@smithy/types": "^4.12.1", + "@smithy/protocol-http": "^5.3.10", + "@smithy/querystring-builder": "^4.2.10", + "@smithy/types": "^4.13.0", "@smithy/util-base64": "^4.3.1", "tslib": "^2.6.2" }, @@ -4070,12 +4205,12 @@ } }, "node_modules/@smithy/hash-node": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.9.tgz", - "integrity": "sha512-/iSYAwSIA/SAeLga2YEpPLLOmw3n86RW4/bkhxtY1DSTR9z5HGjbYTzPaBKv2m8a4nK1rqZWchhl41qTaqMLbg==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.10.tgz", + "integrity": "sha512-1VzIOI5CcsvMDvP3iv1vG/RfLJVVVc67dCRyLSB2Hn9SWCZrDO3zvcIzj3BfEtqRW5kcMg5KAeVf1K3dR6nD3w==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.12.1", + "@smithy/types": "^4.13.0", "@smithy/util-buffer-from": "^4.2.1", "@smithy/util-utf8": "^4.2.1", "tslib": "^2.6.2" @@ -4085,12 +4220,12 @@ } }, "node_modules/@smithy/invalid-dependency": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.9.tgz", - "integrity": "sha512-J+0rlwWZKgOYugVgRE5VlVz/UFV+6cIpZkmfWBq1ld1x3htKDdHOutYhZTURIvSVztWn0T3aghCdEzGdXXsSMw==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.10.tgz", + "integrity": "sha512-vy9KPNSFUU0ajFYk0sDZIYiUlAWGEAhRfehIr5ZkdFrRFTAuXEPUd41USuqHU6vvLX4r6Q9X7MKBco5+Il0Org==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.12.1", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -4124,13 +4259,13 @@ } }, "node_modules/@smithy/middleware-content-length": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.9.tgz", - "integrity": "sha512-9ViCZhFkmLUDyIPeBAsW7h5/Tcix806gWqd/BBqwW6KB8mhgZTTqjRMsyTTmMo2zpF+KckpYQsSiiFrIGHRaFw==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.10.tgz", + "integrity": "sha512-TQZ9kX5c6XbjhaEBpvhSvMEZ0klBs1CFtOdPFwATZSbC9UeQfKHPLPN9Y+I6wZGMOavlYTOlHEPDrt42PMSH9w==", "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^5.3.9", - "@smithy/types": "^4.12.1", + "@smithy/protocol-http": "^5.3.10", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -4138,18 +4273,18 @@ } }, "node_modules/@smithy/middleware-endpoint": { - "version": "4.4.18", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.18.tgz", - "integrity": "sha512-4OS3TP3IWZysT8KlSG/UwfKdelJmuQ2CqVNfrkjm2Rsm146/DuSTfXiD1ulgWpp9L6lJmPYfWTp7/m4b4dQSdQ==", + "version": "4.4.20", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.20.tgz", + "integrity": "sha512-9W6Np4ceBP3XCYAGLoMCmn8t2RRVzuD1ndWPLBbv7H9CrwM9Bprf6Up6BM9ZA/3alodg0b7Kf6ftBK9R1N04vw==", "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^3.23.4", - "@smithy/middleware-serde": "^4.2.10", - "@smithy/node-config-provider": "^4.3.9", - "@smithy/shared-ini-file-loader": "^4.4.4", - "@smithy/types": "^4.12.1", - "@smithy/url-parser": "^4.2.9", - "@smithy/util-middleware": "^4.2.9", + "@smithy/core": "^3.23.6", + "@smithy/middleware-serde": "^4.2.11", + "@smithy/node-config-provider": "^4.3.10", + "@smithy/shared-ini-file-loader": "^4.4.5", + "@smithy/types": "^4.13.0", + "@smithy/url-parser": "^4.2.10", + "@smithy/util-middleware": "^4.2.10", "tslib": "^2.6.2" }, "engines": { @@ -4157,18 +4292,18 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "4.4.35", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.35.tgz", - "integrity": "sha512-sz+Th9ofKypOtaboPTcyZtIfCs2LNb84bzxEhPffCElyMorVYDBdeGzxYqSLC6gWaZUqpPSbj5F6TIxYUlSCfQ==", + "version": "4.4.37", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.37.tgz", + "integrity": "sha512-/1psZZllBBSQ7+qo5+hhLz7AEPGLx3Z0+e3ramMBEuPK2PfvLK4SrncDB9VegX5mBn+oP/UTDrM6IHrFjvX1ZA==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.3.9", - "@smithy/protocol-http": "^5.3.9", - "@smithy/service-error-classification": "^4.2.9", - "@smithy/smithy-client": "^4.11.7", - "@smithy/types": "^4.12.1", - "@smithy/util-middleware": "^4.2.9", - "@smithy/util-retry": "^4.2.9", + "@smithy/node-config-provider": "^4.3.10", + "@smithy/protocol-http": "^5.3.10", + "@smithy/service-error-classification": "^4.2.10", + "@smithy/smithy-client": "^4.12.0", + "@smithy/types": "^4.13.0", + "@smithy/util-middleware": "^4.2.10", + "@smithy/util-retry": "^4.2.10", "@smithy/uuid": "^1.1.1", "tslib": "^2.6.2" }, @@ -4177,13 +4312,13 @@ } }, "node_modules/@smithy/middleware-serde": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.10.tgz", - "integrity": "sha512-BQsdoi7ma4siJAzD0S6MedNPhiMcTdTLUqEUjrHeT1TJppBKWnwqySg34Oh/uGRhJeBd1sAH2t5tghBvcyD6tw==", + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.11.tgz", + "integrity": "sha512-STQdONGPwbbC7cusL60s7vOa6He6A9w2jWhoapL0mgVjmR19pr26slV+yoSP76SIssMTX/95e5nOZ6UQv6jolg==", "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^5.3.9", - "@smithy/types": "^4.12.1", + "@smithy/protocol-http": "^5.3.10", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -4191,12 +4326,12 @@ } }, "node_modules/@smithy/middleware-stack": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.9.tgz", - "integrity": "sha512-pid7ksBr7nm0X/3paIlGo9Fh3UK1pQ5yH0007tBmdkVvv+AsBZAOzC2dmLhlzDWKkSB+ZCiiyDArjAW3klkbMg==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.10.tgz", + "integrity": "sha512-pmts/WovNcE/tlyHa8z/groPeOtqtEpp61q3W0nW1nDJuMq/x+hWa/OVQBtgU0tBqupeXq0VBOLA4UZwE8I0YA==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.12.1", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -4204,14 +4339,14 @@ } }, "node_modules/@smithy/node-config-provider": { - "version": "4.3.9", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.9.tgz", - "integrity": "sha512-EjdDTVGnnyJ9y8jXIfkF45UUZs21/Pp8xaMTZySLoC0xI3EhY7jq4co3LQnhh/bB6VVamd9ELpYJWLDw2ANhZA==", + "version": "4.3.10", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.10.tgz", + "integrity": "sha512-UALRbJtVX34AdP2VECKVlnNgidLHA2A7YgcJzwSBg1hzmnO/bZBHl/LDQQyYifzUwp1UOODnl9JJ3KNawpUJ9w==", "license": "Apache-2.0", "dependencies": { - "@smithy/property-provider": "^4.2.9", - "@smithy/shared-ini-file-loader": "^4.4.4", - "@smithy/types": "^4.12.1", + "@smithy/property-provider": "^4.2.10", + "@smithy/shared-ini-file-loader": "^4.4.5", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -4219,15 +4354,15 @@ } }, "node_modules/@smithy/node-http-handler": { - "version": "4.4.11", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.4.11.tgz", - "integrity": "sha512-kQNJFwzYA9y+Fj3h9t1ToXYOJBobwUVEc6/WX45urJXyErgG0WOsres8Se8BAiFCMe8P06OkzRgakv7bQ5S+6Q==", + "version": "4.4.12", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.4.12.tgz", + "integrity": "sha512-zo1+WKJkR9x7ZtMeMDAAsq2PufwiLDmkhcjpWPRRkmeIuOm6nq1qjFICSZbnjBvD09ei8KMo26BWxsu2BUU+5w==", "license": "Apache-2.0", "dependencies": { - "@smithy/abort-controller": "^4.2.9", - "@smithy/protocol-http": "^5.3.9", - "@smithy/querystring-builder": "^4.2.9", - "@smithy/types": "^4.12.1", + "@smithy/abort-controller": "^4.2.10", + "@smithy/protocol-http": "^5.3.10", + "@smithy/querystring-builder": "^4.2.10", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -4235,12 +4370,12 @@ } }, "node_modules/@smithy/property-provider": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.9.tgz", - "integrity": "sha512-ibHwLxq4KlbfueoNxMNrZkG+O7V/5XKrewhDGYn0p9DYKCsdsofuWHKdX3QW4zHlAUfLStqdCUSDi/q/9WSjwA==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.10.tgz", + "integrity": "sha512-5jm60P0CU7tom0eNrZ7YrkgBaoLFXzmqB0wVS+4uK8PPGmosSrLNf6rRd50UBvukztawZ7zyA8TxlrKpF5z9jw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.12.1", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -4248,12 +4383,12 @@ } }, "node_modules/@smithy/protocol-http": { - "version": "5.3.9", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.9.tgz", - "integrity": "sha512-PRy4yZqsKI3Eab8TLc16Dj2NzC4dnw/8E95+++Jc+wwlkjBpAq3tNLqkLHMmSvDfxKQ+X5PmmCYt+rM/GcMKPA==", + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.10.tgz", + "integrity": "sha512-2NzVWpYY0tRdfeCJLsgrR89KE3NTWT2wGulhNUxYlRmtRmPwLQwKzhrfVaiNlA9ZpJvbW7cjTVChYKgnkqXj1A==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.12.1", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -4261,12 +4396,12 @@ } }, "node_modules/@smithy/querystring-builder": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.9.tgz", - "integrity": "sha512-/AIDaq0+ehv+QfeyAjCUFShwHIt+FA1IodsV/2AZE5h4PUZcQYv5sjmy9V67UWfsBoTjOPKUFYSRfGoNW9T2UQ==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.10.tgz", + "integrity": "sha512-HeN7kEvuzO2DmAzLukE9UryiUvejD3tMp9a1D1NJETerIfKobBUCLfviP6QEk500166eD2IATaXM59qgUI+YDA==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.12.1", + "@smithy/types": "^4.13.0", "@smithy/util-uri-escape": "^4.2.1", "tslib": "^2.6.2" }, @@ -4275,12 +4410,12 @@ } }, "node_modules/@smithy/querystring-parser": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.9.tgz", - "integrity": "sha512-kZ9AHhrYTea3UoklXudEnyA4duy9KAWERC28+ft8y8HIhR3yGsjv1PFTgzMpB+5L4tQKXNTwFbVJMeRK20vpHQ==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.10.tgz", + "integrity": "sha512-4Mh18J26+ao1oX5wXJfWlTT+Q1OpDR8ssiC9PDOuEgVBGloqg18Fw7h5Ct8DyT9NBYwJgtJ2nLjKKFU6RP1G1Q==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.12.1", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -4288,24 +4423,24 @@ } }, "node_modules/@smithy/service-error-classification": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.2.9.tgz", - "integrity": "sha512-DYYd4xrm9Ozik+ZT4f5ZqSXdzscVHF/tFCzqieIFcLrjRDxWSgRtvtXOohJGoniLfPcBcy5ltR3tp2Lw4/d9ag==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.2.10.tgz", + "integrity": "sha512-0R/+/Il5y8nB/By90o8hy/bWVYptbIfvoTYad0igYQO5RefhNCDmNzqxaMx7K1t/QWo0d6UynqpqN5cCQt1MCg==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.12.1" + "@smithy/types": "^4.13.0" }, "engines": { "node": ">=18.0.0" } }, "node_modules/@smithy/shared-ini-file-loader": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.4.tgz", - "integrity": "sha512-tA5Cm11BHQCk/67y6VPIWydLh/pMY90jqOEWIr/2VAzTOoDwGpwp0C/AuHBc3/xWSOA5m5PXLN+lIOrsnTm/PQ==", + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.5.tgz", + "integrity": "sha512-pHgASxl50rrtOztgQCPmOXFjRW+mCd7ALr/3uXNzRrRoGV5G2+78GOsQ3HlQuBVHCh9o6xqMNvlIKZjWn4Euug==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.12.1", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -4313,16 +4448,16 @@ } }, "node_modules/@smithy/signature-v4": { - "version": "5.3.9", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.9.tgz", - "integrity": "sha512-QZKreDINuWf6KIcUUuurjBJiPPSRpMyU3sFPKk6urNAYcKkXhe6Ma+9MBX9e87yDnZfa/cqNMxobkdi9bpJt1A==", + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.10.tgz", + "integrity": "sha512-Wab3wW8468WqTKIxI+aZe3JYO52/RYT/8sDOdzkUhjnLakLe9qoQqIcfih/qxcF4qWEFoWBszY0mj5uxffaVXA==", "license": "Apache-2.0", "dependencies": { "@smithy/is-array-buffer": "^4.2.1", - "@smithy/protocol-http": "^5.3.9", - "@smithy/types": "^4.12.1", + "@smithy/protocol-http": "^5.3.10", + "@smithy/types": "^4.13.0", "@smithy/util-hex-encoding": "^4.2.1", - "@smithy/util-middleware": "^4.2.9", + "@smithy/util-middleware": "^4.2.10", "@smithy/util-uri-escape": "^4.2.1", "@smithy/util-utf8": "^4.2.1", "tslib": "^2.6.2" @@ -4332,17 +4467,17 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "4.11.7", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.11.7.tgz", - "integrity": "sha512-gQP2J3qB/Wmc26gdmB8gA6zq2o2spG5sEU3o7TaTATBJEk29sYGWdEFoGEy91BczSpifTo0DQhVYjZXBEVcrpA==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.12.0.tgz", + "integrity": "sha512-R8bQ9K3lCcXyZmBnQqUZJF4ChZmtWT5NLi6x5kgWx5D+/j0KorXcA0YcFg/X5TOgnTCy1tbKc6z2g2y4amFupQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^3.23.4", - "@smithy/middleware-endpoint": "^4.4.18", - "@smithy/middleware-stack": "^4.2.9", - "@smithy/protocol-http": "^5.3.9", - "@smithy/types": "^4.12.1", - "@smithy/util-stream": "^4.5.14", + "@smithy/core": "^3.23.6", + "@smithy/middleware-endpoint": "^4.4.20", + "@smithy/middleware-stack": "^4.2.10", + "@smithy/protocol-http": "^5.3.10", + "@smithy/types": "^4.13.0", + "@smithy/util-stream": "^4.5.15", "tslib": "^2.6.2" }, "engines": { @@ -4350,9 +4485,9 @@ } }, "node_modules/@smithy/types": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.12.1.tgz", - "integrity": "sha512-ow30Ze/DD02KH2p0eMyIF2+qJzGyNb0kFrnTRtPpuOkQ4hrgvLdaU4YC6r/K8aOrCML4FH0Cmm0aI4503L1Hwg==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.13.0.tgz", + "integrity": "sha512-COuLsZILbbQsdrwKQpkkpyep7lCsByxwj7m0Mg5v66/ZTyenlfBc40/QFQ5chO0YN/PNEH1Bi3fGtfXPnYNeDw==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -4362,13 +4497,13 @@ } }, "node_modules/@smithy/url-parser": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.9.tgz", - "integrity": "sha512-gYs8FrnwKoIvL+GyPz6VvweCkrXqHeD+KnOAxB+NFy6mLr4l75lFrn3dZ413DG0K2TvFtN7L43x7r8hyyohYdg==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.10.tgz", + "integrity": "sha512-uypjF7fCDsRk26u3qHmFI/ePL7bxxB9vKkE+2WKEciHhz+4QtbzWiHRVNRJwU3cKhrYDYQE3b0MRFtqfLYdA4A==", "license": "Apache-2.0", "dependencies": { - "@smithy/querystring-parser": "^4.2.9", - "@smithy/types": "^4.12.1", + "@smithy/querystring-parser": "^4.2.10", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -4439,14 +4574,14 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "4.3.34", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.34.tgz", - "integrity": "sha512-m75CH7xaVG8ErlnfXsIBLrgVrApejrvUpohr41CMdeWNcEu/Ouvj9fbNA7oW9Qpr0Awf+BmDRrYx72hEKgY+FQ==", + "version": "4.3.36", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.36.tgz", + "integrity": "sha512-R0smq7EHQXRVMxkAxtH5akJ/FvgAmNF6bUy/GwY/N20T4GrwjT633NFm0VuRpC+8Bbv8R9A0DoJ9OiZL/M3xew==", "license": "Apache-2.0", "dependencies": { - "@smithy/property-provider": "^4.2.9", - "@smithy/smithy-client": "^4.11.7", - "@smithy/types": "^4.12.1", + "@smithy/property-provider": "^4.2.10", + "@smithy/smithy-client": "^4.12.0", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -4454,17 +4589,17 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "4.2.37", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.37.tgz", - "integrity": "sha512-1LcAt0PV1dletxiGwcw2IJ8vLNhfkir02NTi1i/CFCY2ObtM5wDDjn/8V2dbPrbyoh6OTFH+uayI1rSVRBMT3A==", + "version": "4.2.39", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.39.tgz", + "integrity": "sha512-otWuoDm35btJV1L8MyHrPl462B07QCdMTktKc7/yM+Psv6KbED/ziXiHnmr7yPHUjfIwE9S8Max0LO24Mo3ZVg==", "license": "Apache-2.0", "dependencies": { - "@smithy/config-resolver": "^4.4.7", - "@smithy/credential-provider-imds": "^4.2.9", - "@smithy/node-config-provider": "^4.3.9", - "@smithy/property-provider": "^4.2.9", - "@smithy/smithy-client": "^4.11.7", - "@smithy/types": "^4.12.1", + "@smithy/config-resolver": "^4.4.9", + "@smithy/credential-provider-imds": "^4.2.10", + "@smithy/node-config-provider": "^4.3.10", + "@smithy/property-provider": "^4.2.10", + "@smithy/smithy-client": "^4.12.0", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -4472,13 +4607,13 @@ } }, "node_modules/@smithy/util-endpoints": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.2.9.tgz", - "integrity": "sha512-9FTqTzKxCFelCKdtHb22BTbrLgw7tTI+D6r/Ci/njI0tzqWLQctS0uEDTzraCR5K6IJItfFp1QmESlBytSpRhQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.3.1.tgz", + "integrity": "sha512-xyctc4klmjmieQiF9I1wssBWleRV0RhJ2DpO8+8yzi2LO1Z+4IWOZNGZGNj4+hq9kdo+nyfrRLmQTzc16Op2Vg==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.3.9", - "@smithy/types": "^4.12.1", + "@smithy/node-config-provider": "^4.3.10", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -4498,12 +4633,12 @@ } }, "node_modules/@smithy/util-middleware": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.9.tgz", - "integrity": "sha512-pfnZneJ1S9X3TRmg2l3pG11Pvx2BW9O3NFhUN30llrK/yUKu8WbqMTx4/CzED+qKBYw0//ntUT00hvmaG+nLgA==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.10.tgz", + "integrity": "sha512-LxaQIWLp4y0r72eA8mwPNQ9va4h5KeLM0I3M/HV9klmFaY2kN766wf5vsTzmaOpNNb7GgXAd9a25P3h8T49PSA==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.12.1", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -4511,13 +4646,13 @@ } }, "node_modules/@smithy/util-retry": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.2.9.tgz", - "integrity": "sha512-79hfhL/oxP40SCXJGfjfE9pjbUVfHhXZFpCWXTHqXSluzaVy7jwWs9Ui7lLbfDBSp+7i+BIwgeVIRerbIRWN6g==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.2.10.tgz", + "integrity": "sha512-HrBzistfpyE5uqTwiyLsFHscgnwB0kgv8vySp7q5kZ0Eltn/tjosaSGGDj/jJ9ys7pWzIP/icE2d+7vMKXLv7A==", "license": "Apache-2.0", "dependencies": { - "@smithy/service-error-classification": "^4.2.9", - "@smithy/types": "^4.12.1", + "@smithy/service-error-classification": "^4.2.10", + "@smithy/types": "^4.13.0", "tslib": "^2.6.2" }, "engines": { @@ -4525,14 +4660,14 @@ } }, "node_modules/@smithy/util-stream": { - "version": "4.5.14", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.14.tgz", - "integrity": "sha512-IOBEiJTOltSx6MAfwkx/GSVM8/UCJxdtw13haP5OEL543lb1DN6TAypsxv+qcj4l/rKcpapbS6zK9MQGBOhoaA==", + "version": "4.5.15", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.15.tgz", + "integrity": "sha512-OlOKnaqnkU9X+6wEkd7mN+WB7orPbCVDauXOj22Q7VtiTkvy7ZdSsOg4QiNAZMgI4OkvNf+/VLUC3VXkxuWJZw==", "license": "Apache-2.0", "dependencies": { - "@smithy/fetch-http-handler": "^5.3.10", - "@smithy/node-http-handler": "^4.4.11", - "@smithy/types": "^4.12.1", + "@smithy/fetch-http-handler": "^5.3.11", + "@smithy/node-http-handler": "^4.4.12", + "@smithy/types": "^4.13.0", "@smithy/util-base64": "^4.3.1", "@smithy/util-buffer-from": "^4.2.1", "@smithy/util-hex-encoding": "^4.2.1", @@ -10392,9 +10527,9 @@ } }, "node_modules/strnum": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.2.tgz", - "integrity": "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.0.tgz", + "integrity": "sha512-Y7Bj8XyJxnPAORMZj/xltsfo55uOiyHcU2tnAVzHUnSJR/KsEX+9RoDeXEnsXtl/CX4fAcrt64gZ13aGaWPeBg==", "funding": [ { "type": "github", diff --git a/lambdas/package.json b/lambdas/package.json index df521522..829f2770 100644 --- a/lambdas/package.json +++ b/lambdas/package.json @@ -21,6 +21,7 @@ "dependencies": { "@aws-sdk/client-secrets-manager": "^3.996.0", "@aws-sdk/client-sqs": "^3.996.0", + "@aws-sdk/rds-signer": "^3.1000.0", "@middy/core": "^7.1.1", "@middy/http-cors": "^7.1.1", "@middy/http-error-handler": "^7.1.1", diff --git a/lambdas/scripts/build.ts b/lambdas/scripts/build.ts index 21dc9635..a109887f 100644 --- a/lambdas/scripts/build.ts +++ b/lambdas/scripts/build.ts @@ -55,12 +55,25 @@ async function buildLambda(lambdaName: string): Promise { platform: 'node', target: 'node24', format: 'cjs', +<<<<<<< Updated upstream external: ['aws-sdk', '@aws-sdk/*'], +======= + // The Lambda nodejs24.x runtime provides @aws-sdk/client-* and @aws-sdk/lib-* + // packages. @aws-sdk/rds-signer is NOT in the runtime and must be bundled, + // along with its transitive deps (@smithy/*, @aws-sdk/credential-providers). + external: [ + 'aws-sdk', + '@aws-sdk/client-*', + '@aws-sdk/lib-*', + ], +>>>>>>> Stashed changes packages: 'bundle', - minify: false, - sourcemap: false, + treeShaking: true, + minify: isProduction, + legalComments: 'none', + sourcemap: !isProduction, logLevel: 'info', - metafile: true + metafile: true, }); writeFileSync(join(outDir, 'meta.json'), JSON.stringify(result.metafile, null, 2)); @@ -89,9 +102,7 @@ async function main(): Promise { try { const lambdas: string[] = options.specificLambda ? [options.specificLambda] : getLambdas(); - for (const lambdaName of lambdas) { - await buildLambda(lambdaName); - } + await Promise.all(lambdas.map(buildLambda)); console.log('Build complete!'); } catch (error) { diff --git a/lambdas/src/get-results-lambda/init.ts b/lambdas/src/get-results-lambda/init.ts index 0c1ba8a5..7b3ebee8 100644 --- a/lambdas/src/get-results-lambda/init.ts +++ b/lambdas/src/get-results-lambda/init.ts @@ -1,10 +1,10 @@ import { AwsSecretsClient } from "../lib/secrets/secrets-manager-client"; import { FetchHttpClient } from "../lib/http/http-client"; import { PostgresDbClient } from "../lib/db/db-client"; +import { postgresConfigFromEnv } from "../lib/db/db-config"; import { SupplierService } from "../lib/db/supplier-db"; import { SupplierTestResultsService } from "../lib/supplier/supplier-test-results-service"; import { TestResultDbClient } from "../lib/db/test-result-db-client"; -import { postgresConfigFromEnv } from "../lib/db/db-config"; export interface Environment { testResultDbClient: TestResultDbClient; diff --git a/lambdas/src/lib/db/db-config.test.ts b/lambdas/src/lib/db/db-config.test.ts index c99240c7..869d4159 100644 --- a/lambdas/src/lib/db/db-config.test.ts +++ b/lambdas/src/lib/db/db-config.test.ts @@ -1,4 +1,4 @@ -import { postgresConfig, postgresConfigFromEnv } from "./db-config"; +import { postgresConfig, postgresIamConfig, postgresConfigFromEnv } from "./db-config"; import { EU_WEST_2_BUNDLE } from "../../certs/eu-west-2-bundle"; describe("db-config", () => { @@ -10,6 +10,8 @@ describe("db-config", () => { const ENV_DB_SCHEMA = "DB_SCHEMA"; const ENV_DB_SECRET_NAME = "DB_SECRET_NAME"; const ENV_DB_SSL = "DB_SSL"; + const ENV_USE_IAM_AUTH = "USE_IAM_AUTH"; + const ENV_DB_REGION = "DB_REGION"; // Common test values const TEST_USERNAME = "test"; @@ -259,4 +261,175 @@ describe("db-config", () => { }); }); }); + + describe("IAM authentication", () => { + const mockIamAuthClient = { + getAuthToken: jest.fn(), + }; + + it("should build config with IAM auth token as password", async () => { + const expectedToken = "iam-auth-token-abc123"; + mockIamAuthClient.getAuthToken.mockResolvedValue(expectedToken); + + const config = postgresIamConfig({ + username: TEST_USERNAME, + address: TEST_ADDRESS, + port: TEST_PORT, + database: TEST_DATABASE, + schema: TEST_SCHEMA_PUBLIC, + region: "eu-west-2", + sslEnabled: true, + iamAuthClient: mockIamAuthClient, + }); + + expect(config.user).toEqual(TEST_USERNAME); + expect(config.host).toEqual(TEST_ADDRESS); + expect(config.port).toEqual(5432); + expect(config.database).toEqual(TEST_DATABASE); + expect(config.options).toEqual(`-c search_path=${TEST_SCHEMA_PUBLIC}`); + + // IAM auth always enables SSL + expect(config.ssl).toEqual({ + rejectUnauthorized: true, + ca: EU_WEST_2_BUNDLE, + }); + + // Password should be an async function that returns the IAM token + expect(typeof config.password).toBe("function"); + const resolvedPassword = await (config.password as () => Promise)(); + expect(resolvedPassword).toEqual(expectedToken); + expect(mockIamAuthClient.getAuthToken).toHaveBeenCalled(); + }); + + it("should enforce SSL even when sslEnabled is false", () => { + mockIamAuthClient.getAuthToken.mockResolvedValue("token"); + + const config = postgresIamConfig({ + username: TEST_USERNAME, + address: TEST_ADDRESS, + port: TEST_PORT, + database: TEST_DATABASE, + region: "eu-west-2", + sslEnabled: false, + iamAuthClient: mockIamAuthClient, + }); + + // SSL must always be enabled for IAM auth + expect(config.ssl).toEqual({ + rejectUnauthorized: true, + ca: EU_WEST_2_BUNDLE, + }); + }); + + it("should set search_path when schema is provided", async () => { + mockIamAuthClient.getAuthToken.mockResolvedValue("token"); + + const config = postgresIamConfig({ + username: TEST_USERNAME, + address: TEST_ADDRESS, + port: TEST_PORT, + database: TEST_DATABASE, + schema: "my_schema", + region: "eu-west-2", + sslEnabled: true, + iamAuthClient: mockIamAuthClient, + }); + + expect(config.options).toEqual("-c search_path=my_schema"); + }); + + it("should not set search_path when schema is undefined", async () => { + mockIamAuthClient.getAuthToken.mockResolvedValue("token"); + + const config = postgresIamConfig({ + username: TEST_USERNAME, + address: TEST_ADDRESS, + port: TEST_PORT, + database: TEST_DATABASE, + schema: undefined, + region: "eu-west-2", + sslEnabled: true, + iamAuthClient: mockIamAuthClient, + }); + + expect(config.options).toBeUndefined(); + }); + }); + + describe("postgresConfigFromEnv with IAM auth", () => { + let originalEnv: NodeJS.ProcessEnv; + beforeEach(() => { + originalEnv = { ...process.env }; + Object.assign(process.env, { + ...mockEnvVariables, + [ENV_USE_IAM_AUTH]: "true", + [ENV_DB_REGION]: "eu-west-2", + }); + }); + + afterEach(() => { + process.env = originalEnv; + }); + + it("should use IAM auth when USE_IAM_AUTH is true", () => { + // DB_SECRET_NAME should NOT be required when using IAM auth + delete process.env[ENV_DB_SECRET_NAME]; + + const config = postgresConfigFromEnv(secretsClient); + + expect(config.user).toEqual("test-username"); + expect(config.host).toEqual("test-address"); + expect(config.port).toEqual(5432); + expect(config.database).toEqual("test-database"); + expect(config.options).toEqual("-c search_path=test-schema"); + // IAM auth always enforces SSL + expect(config.ssl).toEqual({ + rejectUnauthorized: true, + ca: EU_WEST_2_BUNDLE, + }); + expect(typeof config.password).toBe("function"); + }); + + it("should not require DB_SECRET_NAME when using IAM auth", () => { + delete process.env[ENV_DB_SECRET_NAME]; + + expect(() => postgresConfigFromEnv(secretsClient)).not.toThrow(); + }); + + it("should use DB_REGION env var for the region", () => { + process.env[ENV_DB_REGION] = "us-east-1"; + + const config = postgresConfigFromEnv(secretsClient); + + // Config should be created successfully with the specified region + expect(config.user).toEqual("test-username"); + }); + + it("should fall back to AWS_REGION when DB_REGION is not set", () => { + delete process.env[ENV_DB_REGION]; + process.env.AWS_REGION = "ap-southeast-1"; + + const config = postgresConfigFromEnv(secretsClient); + + expect(config.user).toEqual("test-username"); + }); + + it("should use Secrets Manager when USE_IAM_AUTH is false", () => { + process.env[ENV_USE_IAM_AUTH] = "false"; + + const config = postgresConfigFromEnv(secretsClient); + + expect(config.user).toEqual("test-username"); + expect(typeof config.password).toBe("function"); + }); + + it("should use Secrets Manager when USE_IAM_AUTH is not set", () => { + delete process.env[ENV_USE_IAM_AUTH]; + + const config = postgresConfigFromEnv(secretsClient); + + expect(config.user).toEqual("test-username"); + expect(typeof config.password).toBe("function"); + }); + }); }); diff --git a/lambdas/src/lib/db/db-config.ts b/lambdas/src/lib/db/db-config.ts index 84be0d31..cd99a0d6 100644 --- a/lambdas/src/lib/db/db-config.ts +++ b/lambdas/src/lib/db/db-config.ts @@ -6,6 +6,8 @@ import { import { EU_WEST_2_BUNDLE } from "../../certs/eu-west-2-bundle"; import type { SecretsClient } from "../secrets/secrets-manager-client"; +import type { RdsIamAuthClient } from "./rds-iam-auth"; +import { AwsRdsIamAuthClient } from "./rds-iam-auth"; export interface PostgresConfigOptions { username: string; @@ -18,6 +20,18 @@ export interface PostgresConfigOptions { sslEnabled: boolean; } +export interface PostgresIamConfigOptions { + username: string; + address: string; + port: string; + database: string; + schema?: string; + region: string; + sslEnabled: boolean; + /** Optional: inject a custom IAM auth client (useful for testing) */ + iamAuthClient?: RdsIamAuthClient; +} + function buildSslConfig(sslEnabled: boolean): false | { rejectUnauthorized: boolean; ca: string } { if (!sslEnabled) { return false; @@ -30,11 +44,11 @@ function buildSslConfig(sslEnabled: boolean): false | { rejectUnauthorized: bool }; } -export function postgresConfig(options: PostgresConfigOptions): ClientConfig { - const configOptions = options.schema - ? `-c search_path=${options.schema}` - : undefined; +function buildSearchPathOptions(schema?: string): string | undefined { + return schema ? `-c search_path=${schema}` : undefined; +} +export function postgresConfig(options: PostgresConfigOptions): ClientConfig { return { user: options.username, host: options.address, @@ -48,26 +62,90 @@ export function postgresConfig(options: PostgresConfigOptions): ClientConfig { // Trim whitespace and remove surrounding quotes return password.trim().replaceAll(/(^["']|["']$)/g, ""); }, - options: configOptions, + options: buildSearchPathOptions(options.schema), ssl: buildSslConfig(options.sslEnabled), }; } +/** + * Build a Postgres client config using RDS IAM authentication. + * The password is a short-lived IAM auth token (valid for 15 minutes) + * generated on each new connection. + * + * Requirements: + * - The Lambda's execution role must have the rds-db:connect IAM permission + * - SSL must be enabled (RDS IAM auth requires encrypted connections) + */ +export function postgresIamConfig(options: PostgresIamConfigOptions): ClientConfig { + const portNumber = Number.parseInt(options.port, 10); + + const iamAuthClient = options.iamAuthClient ?? new AwsRdsIamAuthClient({ + hostname: options.address, + port: portNumber, + username: options.username, + region: options.region, + }); + + return { + user: options.username, + host: options.address, + port: portNumber, + database: options.database, + password: async () => iamAuthClient.getAuthToken(), + options: buildSearchPathOptions(options.schema), + // IAM auth requires SSL; enforce it regardless of the sslEnabled flag + ssl: buildSslConfig(true), + }; +} + +/** + * Build Postgres client config from environment variables. + * + * Supports two authentication modes controlled by the USE_IAM_AUTH env var: + * - USE_IAM_AUTH=true → RDS IAM authentication (no Secrets Manager needed for DB password) + * - USE_IAM_AUTH=false → Secrets Manager password (default, backwards-compatible) + * + * When using IAM auth, the DB_SECRET_NAME env var is not required. + * The DB_REGION env var (or AWS_REGION / AWS_DEFAULT_REGION) determines the AWS region. + */ export function postgresConfigFromEnv( secretsClient: SecretsClient, ): ClientConfig { const sslEnabled = retrieveOptionalEnvVariable("DB_SSL", "true") === "true"; + const useIamAuth = retrieveOptionalEnvVariable("USE_IAM_AUTH", "false") === "true"; - const config: PostgresConfigOptions = { - username: retrieveMandatoryEnvVariable("DB_USERNAME"), - address: retrieveMandatoryEnvVariable("DB_ADDRESS"), - port: retrieveMandatoryEnvVariable("DB_PORT"), - database: retrieveMandatoryEnvVariable("DB_NAME"), - schema: retrieveOptionalEnvVariable("DB_SCHEMA"), + const username = retrieveMandatoryEnvVariable("DB_USERNAME"); + const address = retrieveMandatoryEnvVariable("DB_ADDRESS"); + const port = retrieveMandatoryEnvVariable("DB_PORT"); + const database = retrieveMandatoryEnvVariable("DB_NAME"); + const schema = retrieveOptionalEnvVariable("DB_SCHEMA"); + + if (useIamAuth) { + const region = + retrieveOptionalEnvVariable("DB_REGION") || + process.env.AWS_REGION || + process.env.AWS_DEFAULT_REGION || + "eu-west-2"; + + return postgresIamConfig({ + username, + address, + port, + database, + schema, + region, + sslEnabled, + }); + } + + return postgresConfig({ + username, + address, + port, + database, + schema, passwordSecretName: retrieveMandatoryEnvVariable("DB_SECRET_NAME"), secretsClient, sslEnabled, - }; - - return postgresConfig(config); + }); } diff --git a/lambdas/src/lib/db/rds-iam-auth.ts b/lambdas/src/lib/db/rds-iam-auth.ts new file mode 100644 index 00000000..4a52511f --- /dev/null +++ b/lambdas/src/lib/db/rds-iam-auth.ts @@ -0,0 +1,30 @@ +import { Signer } from "@aws-sdk/rds-signer"; + +/** + * Interface for generating RDS IAM authentication tokens. + * Tokens are short-lived (15 minutes) and used as the DB password. + */ +export interface RdsIamAuthClient { + getAuthToken(): Promise; +} + +/** + * Generates RDS IAM auth tokens using the Lambda's execution role credentials. + * The Lambda's execution role must have the rds-db:connect IAM permission. + */ +export class AwsRdsIamAuthClient implements RdsIamAuthClient { + private readonly signer: Signer; + + constructor(options: { + hostname: string; + port: number; + username: string; + region: string; + }) { + this.signer = new Signer(options); + } + + async getAuthToken(): Promise { + return this.signer.getAuthToken(); + } +} diff --git a/lambdas/src/lib/db/test-result-db-client.ts b/lambdas/src/lib/db/test-result-db-client.ts index 0a5b4735..215f25f5 100644 --- a/lambdas/src/lib/db/test-result-db-client.ts +++ b/lambdas/src/lib/db/test-result-db-client.ts @@ -23,7 +23,7 @@ export class TestResultDbClient { o.supplier_id AS supplier_id FROM test_order o INNER JOIN patient_mapping p ON p.patient_uid = o.patient_uid - INNER JOIN result_status rs ON rs.order_uid = o.order_uid + INNER JOIN result_status rs ON o.order_uid = o.order_uid WHERE ( SELECT os.status_code = 'COMPLETE' diff --git a/tests/configuration/.env.local b/tests/configuration/.env.local index 0b94c088..8f99f771 100644 --- a/tests/configuration/.env.local +++ b/tests/configuration/.env.local @@ -1,6 +1,10 @@ # Development Environment Configuration UI_BASE_URL=http://localhost:3000 -API_BASE_URL=http://localhost:4566/_aws/execute-api/sul0xn9vqy/local +<<<<<<< Updated upstream +API_BASE_URL=http://localhost:4566/_aws/execute-api/qnb74xisbw/local +======= +API_BASE_URL=http://localhost:4566/_aws/execute-api/8udhtoyjp0/local +>>>>>>> Stashed changes HEADLESS=true TIMEOUT=30000 SLOW_MO=0 diff --git a/tests/configuration/EnvironmentVariables.ts b/tests/configuration/EnvironmentVariables.ts index 8c8e1571..e85ea5c8 100644 --- a/tests/configuration/EnvironmentVariables.ts +++ b/tests/configuration/EnvironmentVariables.ts @@ -13,6 +13,7 @@ export enum EnvironmentVariables { DB_NAME = 'DB_NAME', DB_USER = 'DB_USER', DB_PASSWORD = 'DB_PASSWORD', + DB_SCHEMA = 'DB_SCHEMA', } export const availableEnvironments = ['local', 'dev'] as const; diff --git a/tests/db/BaseDbClient.ts b/tests/db/BaseDbClient.ts index b0138e65..5c7c8a02 100644 --- a/tests/db/BaseDbClient.ts +++ b/tests/db/BaseDbClient.ts @@ -5,12 +5,14 @@ export class BaseDbClient { client: Client; constructor() { + const schema = process.env[EnvironmentVariables.DB_SCHEMA] ?? 'hometest'; this.client = new Client({ host: process.env[EnvironmentVariables.DB_HOST] ?? 'localhost', port: parseInt(process.env[EnvironmentVariables.DB_PORT] ?? '5432', 10), database: process.env[EnvironmentVariables.DB_NAME] ?? 'local_hometest_db', user: process.env[EnvironmentVariables.DB_USER] ?? 'admin', password: process.env[EnvironmentVariables.DB_PASSWORD] ?? 'admin', + options: `-c search_path=${schema}`, }); } diff --git a/tests/db/TestResultDbClient.ts b/tests/db/TestResultDbClient.ts index 9a20a2a5..bc3247ed 100644 --- a/tests/db/TestResultDbClient.ts +++ b/tests/db/TestResultDbClient.ts @@ -6,7 +6,7 @@ export class TestResultDbClient extends BaseDbClient { async insertStatusResult(order_uid: UUID, status: ResultStatus, correlation_id: UUID): Promise { const rows = ` - INSERT INTO hometest.result_status (order_uid, status, correlation_id) + INSERT INTO result_status (order_uid, status, correlation_id) VALUES ($1, $2, $3) `; await this.query(rows, [order_uid, status, correlation_id]); @@ -14,7 +14,7 @@ export class TestResultDbClient extends BaseDbClient { async deleteResultStatusByUid(orderUid: string): Promise { await this.query(` - DELETE FROM hometest.result_status + DELETE FROM result_status WHERE order_uid = $1 `, [orderUid]); } diff --git a/tests/package-lock.json b/tests/package-lock.json index afd2eccb..371e7fce 100644 --- a/tests/package-lock.json +++ b/tests/package-lock.json @@ -322,6 +322,7 @@ "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.56.1", "@typescript-eslint/types": "8.56.1", @@ -513,6 +514,7 @@ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -552,6 +554,7 @@ "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.1.tgz", "integrity": "sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A==", "license": "MPL-2.0", + "peer": true, "engines": { "node": ">=4" } @@ -666,6 +669,7 @@ "integrity": "sha512-uYixubwmqJZH+KLVYIVKY1JQt7tysXhtj21WSvjcSmU5SVNzMus1bgLe+pAt816yQ8opKfheVVoPLqvVMGejYw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", @@ -1168,6 +1172,7 @@ "resolved": "https://registry.npmjs.org/pg/-/pg-8.18.0.tgz", "integrity": "sha512-xqrUDL1b9MbkydY/s+VZ6v+xiMUmOUk7SS9d/1kpyQxoJ6U9AO1oIJyUWVZojbfe5Cc/oluutcgFG4L9RDP1iQ==", "license": "MIT", + "peer": true, "dependencies": { "pg-connection-string": "^2.11.0", "pg-pool": "^3.11.0", @@ -1258,6 +1263,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -1289,6 +1295,7 @@ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.2.tgz", "integrity": "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==", "license": "Apache-2.0", + "peer": true, "bin": { "playwright-core": "cli.js" }, @@ -1449,6 +1456,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/ui/package-lock.json b/ui/package-lock.json index 4c1de970..67f8342f 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -111,6 +111,7 @@ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -698,6 +699,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -721,6 +723,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" } @@ -2521,6 +2524,7 @@ "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -2807,6 +2811,7 @@ "integrity": "sha512-fPxQqz4VTgPI/IQ+lj9r0h+fDR66bzoeMGHp8ASee+32OSGIkeASsoZuJixsQoVef1QJbeubcPBxKk22QVoWdw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -2817,6 +2822,7 @@ "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -2827,6 +2833,7 @@ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "dev": true, "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -2907,6 +2914,7 @@ "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.56.1", "@typescript-eslint/types": "8.56.1", @@ -3387,6 +3395,7 @@ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3801,6 +3810,7 @@ "integrity": "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/types": "^7.26.0" } @@ -3917,6 +3927,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -4821,6 +4832,7 @@ "integrity": "sha512-uYixubwmqJZH+KLVYIVKY1JQt7tysXhtj21WSvjcSmU5SVNzMus1bgLe+pAt816yQ8opKfheVVoPLqvVMGejYw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", @@ -4967,6 +4979,7 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -7688,6 +7701,7 @@ "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "cssstyle": "^4.2.1", "data-urls": "^5.0.0", @@ -8463,6 +8477,7 @@ "resolved": "https://registry.npmjs.org/nhsuk-frontend/-/nhsuk-frontend-9.6.4.tgz", "integrity": "sha512-y0fi91jhgS1whD7jhNXKbpJ2Lmje/h5qBZ0aXmBbZdNo56805u7SsPJYxq7Uw6ffT86zQzQIxEwPwrjgSm5Whg==", "license": "MIT", + "peer": true, "workspaces": [ "." ], @@ -9121,6 +9136,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -9130,6 +9146,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -10238,6 +10255,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -10330,6 +10348,7 @@ "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -10530,6 +10549,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -11143,6 +11163,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" }