From 89461ccfced624daa20a0dca46b1a6b2463b256b Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Tue, 18 Mar 2025 14:00:34 +0000 Subject: [PATCH 01/54] CCM-8897_jwks-key-rotation --- lambdas/jwks-key-rotation/.eslintrc.json | 34 +++++++++++++++ lambdas/jwks-key-rotation/jest.config.ts | 53 ++++++++++++++++++++++++ lambdas/jwks-key-rotation/package.json | 20 +++++++++ lambdas/jwks-key-rotation/src/handler.ts | 0 lambdas/jwks-key-rotation/tsconfig.json | 6 +++ 5 files changed, 113 insertions(+) create mode 100644 lambdas/jwks-key-rotation/.eslintrc.json create mode 100644 lambdas/jwks-key-rotation/jest.config.ts create mode 100644 lambdas/jwks-key-rotation/package.json create mode 100644 lambdas/jwks-key-rotation/src/handler.ts create mode 100644 lambdas/jwks-key-rotation/tsconfig.json diff --git a/lambdas/jwks-key-rotation/.eslintrc.json b/lambdas/jwks-key-rotation/.eslintrc.json new file mode 100644 index 00000000..4218c6ab --- /dev/null +++ b/lambdas/jwks-key-rotation/.eslintrc.json @@ -0,0 +1,34 @@ +{ + "extends": [ + "airbnb", + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:jest/recommended", + "plugin:jsx-a11y/recommended", + "plugin:prettier/recommended", + "plugin:security/recommended-legacy", + "plugin:sonarjs/recommended-legacy", + "plugin:unicorn/recommended" + ], + "plugins": [ + "@typescript-eslint", + "html", + "import", + "jest", + "jsx-a11y", + "prettier", + "security", + "sonarjs", + "unicorn" + ], + "rules": { + "import/extensions": "off", + "import/prefer-default-export": "off", + "@next/next/no-html-link-for-pages": "off" + }, + "settings": { + "import/resolver": { + "typescript": {} // this loads /tsconfig.json to eslint + } + } +} diff --git a/lambdas/jwks-key-rotation/jest.config.ts b/lambdas/jwks-key-rotation/jest.config.ts new file mode 100644 index 00000000..246436d9 --- /dev/null +++ b/lambdas/jwks-key-rotation/jest.config.ts @@ -0,0 +1,53 @@ +/** + * For a detailed explanation regarding each configuration property, visit: + * https://jestjs.io/docs/configuration + */ + +import type { Config } from 'jest'; + +const config: Config = { + preset: 'ts-jest', + + // Automatically clear mock calls, instances, contexts and results before every test + clearMocks: true, + + // Indicates whether the coverage information should be collected while executing the test + collectCoverage: true, + + // The directory where Jest should output its coverage files + coverageDirectory: './.reports/unit/coverage', + + // Indicates which provider should be used to instrument code for coverage + coverageProvider: 'v8', + + coverageThreshold: { + global: { + branches: 100, + functions: 100, + lines: 100, + statements: -10, + }, + }, + + collectCoverageFrom: ['src/**/*.ts*'], + + // Use this configuration option to add custom reporters to Jest + reporters: [ + 'default', + [ + '../../node_modules/jest-html-reporter', + { + pageTitle: 'Test Report', + outputPath: './.reports/unit/test-report.html', + includeFailureMsg: true, + }, + ], + ], + + // The test environment that will be used for testing + testEnvironment: 'node', + + testPathIgnorePatterns: ['/node_modules/', '/tests/'], +}; + +export default config; diff --git a/lambdas/jwks-key-rotation/package.json b/lambdas/jwks-key-rotation/package.json new file mode 100644 index 00000000..0d676027 --- /dev/null +++ b/lambdas/jwks-key-rotation/package.json @@ -0,0 +1,20 @@ +{ + "name": "jwks-key-rotation", + "main": "handler.ts", + "scripts": { + "lint": "eslint .", + "test:unit": "jest" + }, + "description": "Runs periodically to generate a new public-private key pair and update the published public keys", + "devDependencies": { + "@tsconfig/node20": "^20.1.4", + "@types/aws-lambda": "^8.10.147", + "jest": "^29.7.0", + "jest-html-reporter": "^3.10.2", + "jest-mock-extended": "^4.0.0-beta1", + "jsonwebtoken": "^9.0.2" + }, + "dependencies": { + "winston": "^3.14.2" + } +} diff --git a/lambdas/jwks-key-rotation/src/handler.ts b/lambdas/jwks-key-rotation/src/handler.ts new file mode 100644 index 00000000..e69de29b diff --git a/lambdas/jwks-key-rotation/tsconfig.json b/lambdas/jwks-key-rotation/tsconfig.json new file mode 100644 index 00000000..e1ea40cd --- /dev/null +++ b/lambdas/jwks-key-rotation/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "@tsconfig/node20/tsconfig.json", + "include": [ + "**/*.ts" + ], +} From c03f0eae0f6a8cbe7cd7fcce05435d4ceb66a888 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Wed, 2 Apr 2025 15:53:49 +0100 Subject: [PATCH 02/54] CCM-8897: jwks key rotation WIP --- .../app/module_public_signing_keys.tf | 16 +++--- .../sandbox/module_public_signing_keys.tf | 1 + .../modules/public-signing-keys/locals.tf | 3 +- .../module_lambda_jwks_key_rotation.tf | 52 +++++++++++++++++++ .../modules/public-signing-keys/variables.tf | 17 ++++++ lambdas/jwks-key-rotation/src/handler.ts | 10 ++++ lambdas/jwks-key-rotation/src/utils/logger.ts | 15 ++++++ package-lock.json | 3 ++ 8 files changed, 109 insertions(+), 8 deletions(-) create mode 100644 infrastructure/terraform/modules/public-signing-keys/module_lambda_jwks_key_rotation.tf create mode 100644 lambdas/jwks-key-rotation/src/utils/logger.ts diff --git a/infrastructure/terraform/components/app/module_public_signing_keys.tf b/infrastructure/terraform/components/app/module_public_signing_keys.tf index b70fb30f..4e4043d2 100644 --- a/infrastructure/terraform/components/app/module_public_signing_keys.tf +++ b/infrastructure/terraform/components/app/module_public_signing_keys.tf @@ -1,15 +1,17 @@ module "public_signing_keys" { - source = "../../modules/public-signing-keys" + source = "../../modules/public-signing-keys" providers = { - aws = aws + aws = aws aws.us-east-1 = aws.us-east-1 } - aws_account_id = var.aws_account_id - component = var.component - environment = var.environment - project = var.project - region = var.region + aws_account_id = var.aws_account_id + component = var.component + environment = var.environment + project = var.project + region = var.region + group = var.group + log_retention_in_days = var.log_retention_in_days dns_zone_id = local.acct.dns_zone["id"] s3_access_logs_bucket_id = local.acct.s3_buckets["access_logs"]["id"] diff --git a/infrastructure/terraform/components/sandbox/module_public_signing_keys.tf b/infrastructure/terraform/components/sandbox/module_public_signing_keys.tf index 5806130e..925a2176 100644 --- a/infrastructure/terraform/components/sandbox/module_public_signing_keys.tf +++ b/infrastructure/terraform/components/sandbox/module_public_signing_keys.tf @@ -10,6 +10,7 @@ module "public_signing_keys" { environment = var.environment project = var.project region = var.region + group = var.group dns_zone_id = local.acct.dns_zone["id"] s3_access_logs_bucket_id = local.acct.s3_buckets["access_logs"]["id"] diff --git a/infrastructure/terraform/modules/public-signing-keys/locals.tf b/infrastructure/terraform/modules/public-signing-keys/locals.tf index 6c62c654..3b577afc 100644 --- a/infrastructure/terraform/modules/public-signing-keys/locals.tf +++ b/infrastructure/terraform/modules/public-signing-keys/locals.tf @@ -1,3 +1,4 @@ locals { - root_domain_name = "jwks.${var.environment}.${data.aws_route53_zone.main.name}" # e.g. jwks.[main|dev|abxy0].foo.[dev|nonprod|prod].nhsnotify.national.nhs.uk + root_domain_name = "jwks.${var.environment}.${data.aws_route53_zone.main.name}" # e.g. jwks.[main|dev|abxy0].foo.[dev|nonprod|prod].nhsnotify.national.nhs.uk + aws_lambda_functions_dir_path = "../../../../lambdas" } diff --git a/infrastructure/terraform/modules/public-signing-keys/module_lambda_jwks_key_rotation.tf b/infrastructure/terraform/modules/public-signing-keys/module_lambda_jwks_key_rotation.tf new file mode 100644 index 00000000..e18b8404 --- /dev/null +++ b/infrastructure/terraform/modules/public-signing-keys/module_lambda_jwks_key_rotation.tf @@ -0,0 +1,52 @@ +module "lambda_jwks_key_rotation" { + source = "git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/lambda?ref=v1.0.9" + + providers = { + aws = aws + } + + function_name = "jwks-key-rotation" + description = "A function for rotating CIS2 JWKS signing keys" + + aws_account_id = var.aws_account_id + component = var.component + environment = var.environment + project = var.project + region = "eu-west-2" + group = var.group + + log_retention_in_days = var.log_retention_in_days + kms_key_arn = module.kms.key_arn + + iam_policy_document = { + body = data.aws_iam_policy_document.lambda_jwks_key_rotation.json + } + + function_s3_bucket = local.acct.s3_buckets["lambda_function_artefacts"]["id"] + function_code_base_path = local.aws_lambda_functions_dir_path + function_code_dir = "jwks-key-rotation/src" + function_include_common = true + function_module_name = "handler" + runtime = "nodejs20.x" + memory = 128 + timeout = 5 + log_level = var.log_level + schedule = "rate(10 minutes)" + force_lambda_code_deploy = true +} + +data "aws_iam_policy_document" "lambda_jwks_key_rotation" { + statement { + sid = "KMSPermissions" + effect = "Allow" + + actions = [ + "kms:Decrypt", + "kms:GenerateDataKey", + ] + + resources = [ + module.kms.key_arn, + ] + } +} diff --git a/infrastructure/terraform/modules/public-signing-keys/variables.tf b/infrastructure/terraform/modules/public-signing-keys/variables.tf index 616b6e6c..03eff767 100644 --- a/infrastructure/terraform/modules/public-signing-keys/variables.tf +++ b/infrastructure/terraform/modules/public-signing-keys/variables.tf @@ -81,3 +81,20 @@ variable "protect_public_key_bucket" { description = "Prevent bucket deletion if objects remain in the bucket. Prevents accidental deletion of the bucket." default = true } + +variable "log_level" { + type = string + description = "Lambda log level" + default = "INFO" +} + +variable "group" { + type = string + description = "The group variables are being inherited from (often synonmous with account short-name)" +} + +variable "log_retention_in_days" { + type = number + description = "The retention period in days for the Cloudwatch Logs events to be retained, default of 0 is indefinite" + default = 0 +} diff --git a/lambdas/jwks-key-rotation/src/handler.ts b/lambdas/jwks-key-rotation/src/handler.ts index e69de29b..3865b801 100644 --- a/lambdas/jwks-key-rotation/src/handler.ts +++ b/lambdas/jwks-key-rotation/src/handler.ts @@ -0,0 +1,10 @@ +import type { ScheduledHandler } from 'aws-lambda'; +import { logger } from './utils/logger'; + + +export const handler: ScheduledHandler = async (event) => { + logger.info({ + description: 'Running jwks-key-rotation', + event, + }); +}; diff --git a/lambdas/jwks-key-rotation/src/utils/logger.ts b/lambdas/jwks-key-rotation/src/utils/logger.ts new file mode 100644 index 00000000..1d144664 --- /dev/null +++ b/lambdas/jwks-key-rotation/src/utils/logger.ts @@ -0,0 +1,15 @@ +import winston from 'winston'; + +const { combine, timestamp, json, errors } = winston.format; + +const logger = winston.createLogger({ + level: 'info', + format: combine(errors({ stack: true }), timestamp(), json()), + transports: [ + new winston.transports.Stream({ + stream: process.stdout, + }), + ], +}); + +export { logger }; diff --git a/package-lock.json b/package-lock.json index 52ac3746..efa9238b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15249,6 +15249,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -22090,6 +22091,7 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -24051,6 +24053,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" From 0a8fb85196d6170346ef6bfb7f75159b4a0bfc1d Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Wed, 2 Apr 2025 16:08:19 +0100 Subject: [PATCH 03/54] CCM-8897: create acct level shared sandbox KMS key --- .../components/acct/module_sandbox_kms.tf | 17 +++++++++++++++++ .../terraform/components/acct/variables.tf | 6 ++++++ 2 files changed, 23 insertions(+) create mode 100644 infrastructure/terraform/components/acct/module_sandbox_kms.tf diff --git a/infrastructure/terraform/components/acct/module_sandbox_kms.tf b/infrastructure/terraform/components/acct/module_sandbox_kms.tf new file mode 100644 index 00000000..2e1cb843 --- /dev/null +++ b/infrastructure/terraform/components/acct/module_sandbox_kms.tf @@ -0,0 +1,17 @@ +module "kms_sandbox" { + source = "git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/kms?ref=v1.0.8" + + count = var.support_sandbox_environments ? 1 : 0 + + aws_account_id = var.aws_account_id + component = var.component + environment = var.environment + project = var.project + region = var.region + + name = "sandbox" + deletion_window = var.kms_deletion_window + alias = "alias/${local.csi}-sandbox" + iam_delegation = true +} + diff --git a/infrastructure/terraform/components/acct/variables.tf b/infrastructure/terraform/components/acct/variables.tf index 06743ccc..65b27b3e 100644 --- a/infrastructure/terraform/components/acct/variables.tf +++ b/infrastructure/terraform/components/acct/variables.tf @@ -75,3 +75,9 @@ variable "observability_account_id" { type = string description = "The Observability Account ID that needs access" } + +variable "support_sandbox_environments" { + type = bool + description = "Does this account support dev sandbox environments?" + default = false +} From 1a810807bd25877898ca5209324741d32c4a37b4 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Thu, 3 Apr 2025 08:11:33 +0100 Subject: [PATCH 04/54] CCM-8897: create acct level shared sandbox KMS key --- infrastructure/terraform/components/acct/variables.tf | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/infrastructure/terraform/components/acct/variables.tf b/infrastructure/terraform/components/acct/variables.tf index 65b27b3e..d293e70f 100644 --- a/infrastructure/terraform/components/acct/variables.tf +++ b/infrastructure/terraform/components/acct/variables.tf @@ -81,3 +81,9 @@ variable "support_sandbox_environments" { description = "Does this account support dev sandbox environments?" default = false } + +variable "kms_deletion_window" { + type = string + description = "When a kms key is deleted, how long should it wait in the pending deletion state?" + default = "30" +} From d4855a4e66776cbebe3630ad2536c99e40cdef89 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Thu, 3 Apr 2025 13:28:18 +0100 Subject: [PATCH 05/54] CCM-8897: jwks key rotation WIP --- .../terraform/components/app/module_public_signing_keys.tf | 1 + .../terraform/components/sandbox/data_acct_kms_key.tf | 3 +++ .../components/sandbox/module_public_signing_keys.tf | 1 + .../public-signing-keys/module_lambda_jwks_key_rotation.tf | 2 +- .../terraform/modules/public-signing-keys/variables.tf | 5 +++++ 5 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 infrastructure/terraform/components/sandbox/data_acct_kms_key.tf diff --git a/infrastructure/terraform/components/app/module_public_signing_keys.tf b/infrastructure/terraform/components/app/module_public_signing_keys.tf index 4e4043d2..2d9f8e02 100644 --- a/infrastructure/terraform/components/app/module_public_signing_keys.tf +++ b/infrastructure/terraform/components/app/module_public_signing_keys.tf @@ -12,6 +12,7 @@ module "public_signing_keys" { region = var.region group = var.group log_retention_in_days = var.log_retention_in_days + kms_key_arn = module.kms.key_arn dns_zone_id = local.acct.dns_zone["id"] s3_access_logs_bucket_id = local.acct.s3_buckets["access_logs"]["id"] diff --git a/infrastructure/terraform/components/sandbox/data_acct_kms_key.tf b/infrastructure/terraform/components/sandbox/data_acct_kms_key.tf new file mode 100644 index 00000000..53cd9a75 --- /dev/null +++ b/infrastructure/terraform/components/sandbox/data_acct_kms_key.tf @@ -0,0 +1,3 @@ +data "aws_kms_key" "sandbox" { + key_id = "alias/${var.project}-main-acct-sandbox" +} diff --git a/infrastructure/terraform/components/sandbox/module_public_signing_keys.tf b/infrastructure/terraform/components/sandbox/module_public_signing_keys.tf index 925a2176..bea37b46 100644 --- a/infrastructure/terraform/components/sandbox/module_public_signing_keys.tf +++ b/infrastructure/terraform/components/sandbox/module_public_signing_keys.tf @@ -11,6 +11,7 @@ module "public_signing_keys" { project = var.project region = var.region group = var.group + kms_key_arn = data.aws_kms_key.sandbox.arn dns_zone_id = local.acct.dns_zone["id"] s3_access_logs_bucket_id = local.acct.s3_buckets["access_logs"]["id"] diff --git a/infrastructure/terraform/modules/public-signing-keys/module_lambda_jwks_key_rotation.tf b/infrastructure/terraform/modules/public-signing-keys/module_lambda_jwks_key_rotation.tf index e18b8404..1911e445 100644 --- a/infrastructure/terraform/modules/public-signing-keys/module_lambda_jwks_key_rotation.tf +++ b/infrastructure/terraform/modules/public-signing-keys/module_lambda_jwks_key_rotation.tf @@ -16,7 +16,7 @@ module "lambda_jwks_key_rotation" { group = var.group log_retention_in_days = var.log_retention_in_days - kms_key_arn = module.kms.key_arn + kms_key_arn = var.kms_key_arn iam_policy_document = { body = data.aws_iam_policy_document.lambda_jwks_key_rotation.json diff --git a/infrastructure/terraform/modules/public-signing-keys/variables.tf b/infrastructure/terraform/modules/public-signing-keys/variables.tf index 03eff767..a41a3803 100644 --- a/infrastructure/terraform/modules/public-signing-keys/variables.tf +++ b/infrastructure/terraform/modules/public-signing-keys/variables.tf @@ -98,3 +98,8 @@ variable "log_retention_in_days" { description = "The retention period in days for the Cloudwatch Logs events to be retained, default of 0 is indefinite" default = 0 } + +variable "kms_key_arn" { + type = string + description = "KMS Key ARN" +} From 6bd3767ba182457da333a1911061eaebf2c64505 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Fri, 4 Apr 2025 06:37:15 +0100 Subject: [PATCH 06/54] CCM-8897: add to acct outputs --- infrastructure/terraform/components/acct/outputs.tf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/infrastructure/terraform/components/acct/outputs.tf b/infrastructure/terraform/components/acct/outputs.tf index b8f6f581..9c0f42f6 100644 --- a/infrastructure/terraform/components/acct/outputs.tf +++ b/infrastructure/terraform/components/acct/outputs.tf @@ -29,3 +29,7 @@ output "s3_buckets" { } } } + +output "kms_sandbox_arn" { + value = var.support_sandbox_environments ? module.kms_sandbox[0].arn : null +} From d1fd25da21d0103a03776f323b4d7b8661e85d05 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Fri, 4 Apr 2025 08:38:43 +0100 Subject: [PATCH 07/54] CCM-8897: add to acct outputs --- infrastructure/terraform/components/acct/outputs.tf | 2 +- .../terraform/components/sandbox/data_acct_kms_key.tf | 3 --- .../terraform/components/sandbox/module_public_signing_keys.tf | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) delete mode 100644 infrastructure/terraform/components/sandbox/data_acct_kms_key.tf diff --git a/infrastructure/terraform/components/acct/outputs.tf b/infrastructure/terraform/components/acct/outputs.tf index 9c0f42f6..191c81e2 100644 --- a/infrastructure/terraform/components/acct/outputs.tf +++ b/infrastructure/terraform/components/acct/outputs.tf @@ -31,5 +31,5 @@ output "s3_buckets" { } output "kms_sandbox_arn" { - value = var.support_sandbox_environments ? module.kms_sandbox[0].arn : null + value = var.support_sandbox_environments ? module.kms_sandbox[0].key_arn : null } diff --git a/infrastructure/terraform/components/sandbox/data_acct_kms_key.tf b/infrastructure/terraform/components/sandbox/data_acct_kms_key.tf deleted file mode 100644 index 53cd9a75..00000000 --- a/infrastructure/terraform/components/sandbox/data_acct_kms_key.tf +++ /dev/null @@ -1,3 +0,0 @@ -data "aws_kms_key" "sandbox" { - key_id = "alias/${var.project}-main-acct-sandbox" -} diff --git a/infrastructure/terraform/components/sandbox/module_public_signing_keys.tf b/infrastructure/terraform/components/sandbox/module_public_signing_keys.tf index bea37b46..ec0361fb 100644 --- a/infrastructure/terraform/components/sandbox/module_public_signing_keys.tf +++ b/infrastructure/terraform/components/sandbox/module_public_signing_keys.tf @@ -11,7 +11,7 @@ module "public_signing_keys" { project = var.project region = var.region group = var.group - kms_key_arn = data.aws_kms_key.sandbox.arn + kms_key_arn = local.acct.kms_sandbox_arn dns_zone_id = local.acct.dns_zone["id"] s3_access_logs_bucket_id = local.acct.s3_buckets["access_logs"]["id"] From 4c3c41f47115b8ec8c18ea52446416bcfb395eda Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Mon, 7 Apr 2025 09:00:13 +0100 Subject: [PATCH 08/54] CCM-8897: jwks key rotation WIP --- .../components/acct/module_sandbox_kms.tf | 39 +++++++++++++++++++ .../app/module_public_signing_keys.tf | 1 + .../sandbox/module_public_signing_keys.tf | 6 ++- .../module_lambda_jwks_key_rotation.tf | 4 +- .../modules/public-signing-keys/variables.tf | 5 +++ 5 files changed, 51 insertions(+), 4 deletions(-) diff --git a/infrastructure/terraform/components/acct/module_sandbox_kms.tf b/infrastructure/terraform/components/acct/module_sandbox_kms.tf index 2e1cb843..2c6078b6 100644 --- a/infrastructure/terraform/components/acct/module_sandbox_kms.tf +++ b/infrastructure/terraform/components/acct/module_sandbox_kms.tf @@ -12,6 +12,45 @@ module "kms_sandbox" { name = "sandbox" deletion_window = var.kms_deletion_window alias = "alias/${local.csi}-sandbox" + key_policy_documents = [data.aws_iam_policy_document.kms_sandbox.json] iam_delegation = true } +data "aws_iam_policy_document" "kms_sandbox" { + # '*' resource scope is permitted in access policies as as the resource is itself + # https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-services.html + + statement { + sid = "AllowCloudWatchEncrypt" + effect = "Allow" + + principals { + type = "Service" + + identifiers = [ + "logs.${var.region}.amazonaws.com" + ] + } + + actions = [ + "kms:Encrypt*", + "kms:Decrypt*", + "kms:ReEncrypt*", + "kms:GenerateDataKey*", + "kms:Describe*" + ] + + resources = [ + "*", + ] + + condition { + test = "ArnLike" + variable = "kms:EncryptionContext:aws:logs:arn" + + values = [ + "arn:aws:logs:${var.region}:${var.aws_account_id}:log-group:*", + ] + } + } +} diff --git a/infrastructure/terraform/components/app/module_public_signing_keys.tf b/infrastructure/terraform/components/app/module_public_signing_keys.tf index 2d9f8e02..dfe1f14f 100644 --- a/infrastructure/terraform/components/app/module_public_signing_keys.tf +++ b/infrastructure/terraform/components/app/module_public_signing_keys.tf @@ -16,4 +16,5 @@ module "public_signing_keys" { dns_zone_id = local.acct.dns_zone["id"] s3_access_logs_bucket_id = local.acct.s3_buckets["access_logs"]["id"] + function_s3_bucket = local.acct.s3_buckets["lambda_function_artefacts"]["id"] } diff --git a/infrastructure/terraform/components/sandbox/module_public_signing_keys.tf b/infrastructure/terraform/components/sandbox/module_public_signing_keys.tf index ec0361fb..d0be9f29 100644 --- a/infrastructure/terraform/components/sandbox/module_public_signing_keys.tf +++ b/infrastructure/terraform/components/sandbox/module_public_signing_keys.tf @@ -13,8 +13,10 @@ module "public_signing_keys" { group = var.group kms_key_arn = local.acct.kms_sandbox_arn - dns_zone_id = local.acct.dns_zone["id"] - s3_access_logs_bucket_id = local.acct.s3_buckets["access_logs"]["id"] + dns_zone_id = local.acct.dns_zone["id"] + s3_access_logs_bucket_id = local.acct.s3_buckets["access_logs"]["id"] + function_s3_bucket = local.acct.s3_buckets["lambda_function_artefacts"]["id"] + deploy_cdn = false protect_public_key_bucket = false } diff --git a/infrastructure/terraform/modules/public-signing-keys/module_lambda_jwks_key_rotation.tf b/infrastructure/terraform/modules/public-signing-keys/module_lambda_jwks_key_rotation.tf index 1911e445..439fbb99 100644 --- a/infrastructure/terraform/modules/public-signing-keys/module_lambda_jwks_key_rotation.tf +++ b/infrastructure/terraform/modules/public-signing-keys/module_lambda_jwks_key_rotation.tf @@ -22,7 +22,7 @@ module "lambda_jwks_key_rotation" { body = data.aws_iam_policy_document.lambda_jwks_key_rotation.json } - function_s3_bucket = local.acct.s3_buckets["lambda_function_artefacts"]["id"] + function_s3_bucket = var.function_s3_bucket function_code_base_path = local.aws_lambda_functions_dir_path function_code_dir = "jwks-key-rotation/src" function_include_common = true @@ -46,7 +46,7 @@ data "aws_iam_policy_document" "lambda_jwks_key_rotation" { ] resources = [ - module.kms.key_arn, + var.kms_key_arn, ] } } diff --git a/infrastructure/terraform/modules/public-signing-keys/variables.tf b/infrastructure/terraform/modules/public-signing-keys/variables.tf index a41a3803..fbd1ed88 100644 --- a/infrastructure/terraform/modules/public-signing-keys/variables.tf +++ b/infrastructure/terraform/modules/public-signing-keys/variables.tf @@ -103,3 +103,8 @@ variable "kms_key_arn" { type = string description = "KMS Key ARN" } + +variable "function_s3_bucket" { + type = string + description = "The bucket to upload Lambda packages to" +} From e387c429ebcef0cc82e8c18f332914a3e40796fe Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Tue, 15 Apr 2025 12:48:46 +0100 Subject: [PATCH 09/54] CCM-8897: jwks key rotation WIP --- .../app/module_public_signing_keys.tf | 1 + .../terraform/components/app/pre.sh | 1 + .../sandbox/module_public_signing_keys.tf | 1 + .../terraform/components/sandbox/pre.sh | 7 +- .../modules/public-signing-keys/locals.tf | 6 +- .../module_lambda_jwks_key_rotation.tf | 48 +- .../public-signing-keys/ssm_key_directory.tf | 10 + .../ssm_parameter_asymmetric_key_policy.tf | 57 + lambdas/jwks-key-rotation/package.json | 17 +- lambdas/jwks-key-rotation/src/handler.ts | 119 +- .../jwks-key-rotation/src/utils/aws-utils.ts | 19 + .../src/utils/key-directory-repository.ts | 43 + .../jwks-key-rotation/src/utils/key-util.ts | 51 + .../jwks-key-rotation/src/utils/kms-util.ts | 39 + .../jwks-key-rotation/src/utils/ssm-util.ts | 25 + package-lock.json | 1676 ++++++++++++++--- package.json | 2 + scripts/config/sonar-scanner.properties | 4 +- 18 files changed, 1846 insertions(+), 280 deletions(-) create mode 100644 infrastructure/terraform/modules/public-signing-keys/ssm_key_directory.tf create mode 100644 infrastructure/terraform/modules/public-signing-keys/ssm_parameter_asymmetric_key_policy.tf create mode 100644 lambdas/jwks-key-rotation/src/utils/aws-utils.ts create mode 100644 lambdas/jwks-key-rotation/src/utils/key-directory-repository.ts create mode 100644 lambdas/jwks-key-rotation/src/utils/key-util.ts create mode 100644 lambdas/jwks-key-rotation/src/utils/kms-util.ts create mode 100644 lambdas/jwks-key-rotation/src/utils/ssm-util.ts diff --git a/infrastructure/terraform/components/app/module_public_signing_keys.tf b/infrastructure/terraform/components/app/module_public_signing_keys.tf index dfe1f14f..37c5d777 100644 --- a/infrastructure/terraform/components/app/module_public_signing_keys.tf +++ b/infrastructure/terraform/components/app/module_public_signing_keys.tf @@ -13,6 +13,7 @@ module "public_signing_keys" { group = var.group log_retention_in_days = var.log_retention_in_days kms_key_arn = module.kms.key_arn + default_tags = local.default_tags dns_zone_id = local.acct.dns_zone["id"] s3_access_logs_bucket_id = local.acct.s3_buckets["access_logs"]["id"] diff --git a/infrastructure/terraform/components/app/pre.sh b/infrastructure/terraform/components/app/pre.sh index 385cb3aa..76f2b9d9 100644 --- a/infrastructure/terraform/components/app/pre.sh +++ b/infrastructure/terraform/components/app/pre.sh @@ -1 +1,2 @@ npm ci +(cd ../../../.. && npm run build-lambda) diff --git a/infrastructure/terraform/components/sandbox/module_public_signing_keys.tf b/infrastructure/terraform/components/sandbox/module_public_signing_keys.tf index d0be9f29..5acdbaee 100644 --- a/infrastructure/terraform/components/sandbox/module_public_signing_keys.tf +++ b/infrastructure/terraform/components/sandbox/module_public_signing_keys.tf @@ -12,6 +12,7 @@ module "public_signing_keys" { region = var.region group = var.group kms_key_arn = local.acct.kms_sandbox_arn + default_tags = local.default_tags dns_zone_id = local.acct.dns_zone["id"] s3_access_logs_bucket_id = local.acct.s3_buckets["access_logs"]["id"] diff --git a/infrastructure/terraform/components/sandbox/pre.sh b/infrastructure/terraform/components/sandbox/pre.sh index 385cb3aa..c3449226 100644 --- a/infrastructure/terraform/components/sandbox/pre.sh +++ b/infrastructure/terraform/components/sandbox/pre.sh @@ -1 +1,6 @@ -npm ci +if [ "$SUPPRESS_SANDBOX_CI" != "true" ] + then + npm ci +fi + +(cd ../../../.. && npm run build-lambda) diff --git a/infrastructure/terraform/modules/public-signing-keys/locals.tf b/infrastructure/terraform/modules/public-signing-keys/locals.tf index 3b577afc..248a27a8 100644 --- a/infrastructure/terraform/modules/public-signing-keys/locals.tf +++ b/infrastructure/terraform/modules/public-signing-keys/locals.tf @@ -1,4 +1,6 @@ locals { - root_domain_name = "jwks.${var.environment}.${data.aws_route53_zone.main.name}" # e.g. jwks.[main|dev|abxy0].foo.[dev|nonprod|prod].nhsnotify.national.nhs.uk - aws_lambda_functions_dir_path = "../../../../lambdas" + root_domain_name = "jwks.${var.environment}.${data.aws_route53_zone.main.name}" # e.g. jwks.[main|dev|abxy0].foo.[dev|nonprod|prod].nhsnotify.national.nhs.uk + lambdas_source_code_dir = "/../../../../lambdas" + ssm_asymmetric_key_policy_name = "/${local.csi}/asymmetric_key_policy" + ssm_key_directory_name = "/${local.csi}/key_directory" } diff --git a/infrastructure/terraform/modules/public-signing-keys/module_lambda_jwks_key_rotation.tf b/infrastructure/terraform/modules/public-signing-keys/module_lambda_jwks_key_rotation.tf index 439fbb99..48dab4ad 100644 --- a/infrastructure/terraform/modules/public-signing-keys/module_lambda_jwks_key_rotation.tf +++ b/infrastructure/terraform/modules/public-signing-keys/module_lambda_jwks_key_rotation.tf @@ -23,16 +23,24 @@ module "lambda_jwks_key_rotation" { } function_s3_bucket = var.function_s3_bucket - function_code_base_path = local.aws_lambda_functions_dir_path - function_code_dir = "jwks-key-rotation/src" + function_code_base_path = local.lambdas_source_code_dir + function_code_dir = "jwks-key-rotation/dist" function_include_common = true function_module_name = "handler" runtime = "nodejs20.x" memory = 128 timeout = 5 log_level = var.log_level - schedule = "rate(10 minutes)" + schedule = "rate(28 days)" force_lambda_code_deploy = true + + lambda_env_vars = { + "SSM_KEY_DIRECTORY_NAME" = local.ssm_key_directory_name, + "SSM_ASYMMETRIC_KEY_POLICY" = local.ssm_asymmetric_key_policy_name, + "KEY_TAGS" = join(",", formatlist("%s=%s", keys(var.default_tags), values(var.default_tags))), + "REGION" = var.region, + "ACCOUNT_ID" = var.aws_account_id + } } data "aws_iam_policy_document" "lambda_jwks_key_rotation" { @@ -41,12 +49,40 @@ data "aws_iam_policy_document" "lambda_jwks_key_rotation" { effect = "Allow" actions = [ - "kms:Decrypt", - "kms:GenerateDataKey", + "kms:Create*", + "kms:DescribeKey", + "kms:Get*", + "kms:List*", + "kms:Put*", + "kms:ScheduleKeyDeletion", + "kms:TagResource" + ] + + resources = [ + "*" + ] + } + + statement { + sid = "AllowSSMParametersRead" + effect = "Allow" + actions = [ + "ssm:GetParameter" ] + resources = [ + "arn:aws:ssm:${var.region}:${var.aws_account_id}:parameter${local.ssm_asymmetric_key_policy_name}", + "arn:aws:ssm:${var.region}:${var.aws_account_id}:parameter${local.ssm_key_directory_name}" + ] + } + statement { + sid = "AllowSSMParametersWrite" + effect = "Allow" + actions = [ + "ssm:PutParameter" + ] resources = [ - var.kms_key_arn, + "arn:aws:ssm:${var.region}:${var.aws_account_id}:parameter${local.ssm_key_directory_name}" ] } } diff --git a/infrastructure/terraform/modules/public-signing-keys/ssm_key_directory.tf b/infrastructure/terraform/modules/public-signing-keys/ssm_key_directory.tf new file mode 100644 index 00000000..cb1bea94 --- /dev/null +++ b/infrastructure/terraform/modules/public-signing-keys/ssm_key_directory.tf @@ -0,0 +1,10 @@ +resource "aws_ssm_parameter" "key_directory" { + name = local.ssm_key_directory_name + description = "An array of KMS signing keys in rotation used for CIS2 authentication" + type = "String" + value = "[]" + + lifecycle { + ignore_changes = [value] + } +} \ No newline at end of file diff --git a/infrastructure/terraform/modules/public-signing-keys/ssm_parameter_asymmetric_key_policy.tf b/infrastructure/terraform/modules/public-signing-keys/ssm_parameter_asymmetric_key_policy.tf new file mode 100644 index 00000000..a664178c --- /dev/null +++ b/infrastructure/terraform/modules/public-signing-keys/ssm_parameter_asymmetric_key_policy.tf @@ -0,0 +1,57 @@ +resource "aws_ssm_parameter" "asymmetric_key_policy" { + name = local.ssm_asymmetric_key_policy_name + description = "The IAM policy applied to new asymmetric KMS keys used for CIS2 auth" + type = "String" + value = data.aws_iam_policy_document.asymmetric_key_policy.minified_json + + lifecycle { + ignore_changes = [value] + } +} + +data "aws_iam_policy_document" "asymmetric_key_policy" { + statement { + sid = "AllowRootFullAccess" + effect = "Allow" + + actions = [ + "kms:*", + ] + + resources = [ + "*" + ] + + principals { + type = "AWS" + identifiers = [ + "arn:aws:iam::${var.aws_account_id}:root" + ] + } + } + + statement { + sid = "AllowRotationLambdaAccess" + effect = "Allow" + + actions = [ + "kms:Create*", + "kms:DescribeKey", + "kms:Get*", + "kms:List*", + "kms:Put*", + "kms:ScheduleKeyDeletion" + ] + + resources = [ + "*" + ] + + principals { + type = "AWS" + identifiers = [ + module.lambda_jwks_key_rotation.iam_role_arn + ] + } + } +} diff --git a/lambdas/jwks-key-rotation/package.json b/lambdas/jwks-key-rotation/package.json index 0d676027..9a4e36f2 100644 --- a/lambdas/jwks-key-rotation/package.json +++ b/lambdas/jwks-key-rotation/package.json @@ -3,18 +3,27 @@ "main": "handler.ts", "scripts": { "lint": "eslint .", - "test:unit": "jest" + "test:unit": "jest", + "build-lambda": "rm -rf dist && npx esbuild --bundle --minify --sourcemap --target=es2020 --platform=node --entry-names=[name] --outdir=dist src/handler.ts" }, "description": "Runs periodically to generate a new public-private key pair and update the published public keys", "devDependencies": { - "@tsconfig/node20": "^20.1.4", + "@aws-sdk/types": "^3.775.0", + "@tsconfig/node20": "^20.1.5", "@types/aws-lambda": "^8.10.147", + "@types/node": "^22.14.0", "jest": "^29.7.0", "jest-html-reporter": "^3.10.2", "jest-mock-extended": "^4.0.0-beta1", - "jsonwebtoken": "^9.0.2" + "jsonwebtoken": "^9.0.2", + "node-jose": "^2.2.0", + "typescript": "^5.8.2" }, "dependencies": { - "winston": "^3.14.2" + "@aws-sdk/client-kms": "^3.782.0", + "@aws-sdk/client-ssm": "^3.782.0", + "@types/node-jose": "^1.1.13", + "winston": "^3.14.2", + "zod": "^3.24.2" } } diff --git a/lambdas/jwks-key-rotation/src/handler.ts b/lambdas/jwks-key-rotation/src/handler.ts index 3865b801..dcd90425 100644 --- a/lambdas/jwks-key-rotation/src/handler.ts +++ b/lambdas/jwks-key-rotation/src/handler.ts @@ -1,10 +1,121 @@ import type { ScheduledHandler } from 'aws-lambda'; import { logger } from './utils/logger'; +import { + getKeyDirectory, + SigningKeyDirectory, +} from './utils/key-directory-repository'; +import { createPublicKey } from 'node:crypto'; +import { JWK } from 'node-jose'; +import { generateKey, getPublicKey } from './utils/key-util'; +const algorithm = 'RS512'; -export const handler: ScheduledHandler = async (event) => { - logger.info({ - description: 'Running jwks-key-rotation', - event, +const keyLifetimeDays = Number.parseInt(process.env.KEY_LIFETIME_DAYS ?? '28'); +const keyLifetimeMillis = keyLifetimeDays * 24 * 60 * 60 * 1000; + +function formattedDate(offsetMillis = 0): string { + return new Date(Date.now() + offsetMillis).toISOString().split('T')[0]; +} + +function getKeysToDelete( + keyDirectory: SigningKeyDirectory +): SigningKeyDirectory { + if (keyDirectory.length <= 1) { + return []; + } + const cutOffDate = formattedDate(-keyLifetimeMillis); + return keyDirectory.filter( + (keyMetadata) => keyMetadata.createdDate <= cutOffDate + ); +} + +async function generateJwksFormat( + keyId: string, + publicKeyBytes: Uint8Array +): Promise { + const base64EncodedPublicKey = Buffer.from(publicKeyBytes).toString('base64'); + const pemFormat = `-----BEGIN PUBLIC KEY-----\n${base64EncodedPublicKey + .match(/(.{1,64})/g)!! + .join('\n')}\n-----END PUBLIC KEY-----`; + + const key = createPublicKey(pemFormat); + + const joseKey = await JWK.asKey( + key.export({ + type: 'spki', + format: 'pem', + }), + 'pem' + ); + + const publicKeyJwks = { + ...joseKey.toJSON(), + use: 'sig', + alg: algorithm, + kid: keyId, + }; + + return publicKeyJwks; +} + +export const handler: ScheduledHandler = async () => { + // Get the existing key directory + const keyDirectory = await getKeyDirectory(); + logger.info(keyDirectory); + + // Dertermine which keys we should remove + const keysToDelete = getKeysToDelete(keyDirectory); + const keyIdsToDelete = new Set( + keysToDelete.map((keyMetadata) => keyMetadata.kid) + ); + logger.info(keysToDelete); + + // Start creating new directory of remaining keys + let newKeyDirectory = keyDirectory.filter( + (keyMetadata) => !keyIdsToDelete.has(keyMetadata.kid) + ); + + // Create the new key + const keyId = await generateKey(); + newKeyDirectory.push({ + createdDate: formattedDate(), + kid: keyId, + }); + logger.info(keyId); + logger.info(newKeyDirectory); + + // Get the public keys + const publicKeys = await Promise.all( + newKeyDirectory.map((keyMetadata) => getPublicKey(keyMetadata.kid)) + ); + logger.info(publicKeys); + + // Make sure that the directory stays in sync with the KMS keys (i.e. remove any that may have been manually removed) + const validPublicKeyMap = publicKeys + .filter((publicKeyMetadata) => !!publicKeyMetadata.publicKey) + .reduce( + (acc, publicKeyMetadata) => { + acc[publicKeyMetadata.keyId] = publicKeyMetadata.publicKey!; + return acc; + }, + {} as Record + ); + + newKeyDirectory = newKeyDirectory.filter( + (keyMetadata) => !!validPublicKeyMap[keyMetadata.kid] + ); + + // Generate new public key file + const publicKeysArray = await newKeyDirectory.map((keyMetadata) => { + const publicKeyBytes = validPublicKeyMap[keyMetadata.kid]; + return generateJwksFormat(keyMetadata.kid, publicKeyBytes); }); + + logger.info('Generated public keys', { publicKeysArray }); + + // Write public key file to S3 + + // Update Key directory + + // Delete old keys }; diff --git a/lambdas/jwks-key-rotation/src/utils/aws-utils.ts b/lambdas/jwks-key-rotation/src/utils/aws-utils.ts new file mode 100644 index 00000000..e541303f --- /dev/null +++ b/lambdas/jwks-key-rotation/src/utils/aws-utils.ts @@ -0,0 +1,19 @@ +import { Tag } from '@aws-sdk/client-kms'; + +const tagsMatcher = /^(([^,^=]+=[^,^=]+),?)*$/; + +export function getKeyTags(): Array { + const keyTags: string = process.env.KEY_TAGS || ''; + if (!tagsMatcher.test(keyTags)) { + throw new Error(`Invalid tags ${keyTags}`); + } + + return keyTags + .split(',') + .filter((keyTag) => !!keyTag) + .map((keyTag) => keyTag.split('=')) + .map((keyTag) => ({ + TagKey: keyTag[0], + TagValue: keyTag[1], + })); +} diff --git a/lambdas/jwks-key-rotation/src/utils/key-directory-repository.ts b/lambdas/jwks-key-rotation/src/utils/key-directory-repository.ts new file mode 100644 index 00000000..414912f3 --- /dev/null +++ b/lambdas/jwks-key-rotation/src/utils/key-directory-repository.ts @@ -0,0 +1,43 @@ +import { z } from 'zod'; +import { logger } from './logger'; +import { getParameter } from './ssm-util'; + +const schemaFor = + () => + >(schema: S) => + schema; + +export type SigningKeyMetaData = { + kid: string; + createdDate: string; +}; + +export type SigningKeyDirectory = Array; + +const $SigningKeyMetaData = schemaFor()( + z.object({ + kid: z.string().nonempty(), + createdDate: z.string().date(), + }) +); + +const $SigningKeyDirectory = schemaFor()( + z.array($SigningKeyMetaData) +); + +export async function getKeyDirectory(): Promise { + const ssmResult = await getParameter(process.env.SSM_KEY_DIRECTORY_NAME); + + const keyDirectoryText = ssmResult.Parameter?.Value ?? '[]'; + const parseResult = $SigningKeyDirectory.safeParse( + JSON.parse(keyDirectoryText) + ); + if (!parseResult.success) { + logger.error('Failed to parse key directory', { + content: keyDirectoryText, + parseError: parseResult.error, + }); + throw new Error('Failed to parse key directory'); + } + return parseResult.data; +} diff --git a/lambdas/jwks-key-rotation/src/utils/key-util.ts b/lambdas/jwks-key-rotation/src/utils/key-util.ts new file mode 100644 index 00000000..0a4e2f58 --- /dev/null +++ b/lambdas/jwks-key-rotation/src/utils/key-util.ts @@ -0,0 +1,51 @@ +import { + CreateKeyCommand, + KeySpec, + KeyUsageType, + NotFoundException, +} from '@aws-sdk/client-kms'; +import { getKeyTags } from './aws-utils'; +import { createKmsKey, getKmsPublicKey } from './kms-util'; +import { getParameter } from './ssm-util'; +import { logger } from './logger'; + +async function getKeyPolicy(): Promise { + const ssmResult = await getParameter(process.env.SSM_ASYMMETRIC_KEY_POLICY); + if (!ssmResult.Parameter?.Value) { + throw new Error( + `Failed to retrieve key policy from ${process.env.SSM_ASYMMETRIC_KEY_POLICY}` + ); + } + return ssmResult.Parameter.Value; +} + +export async function generateKey(): Promise { + const keyPolicy = await getKeyPolicy(); + const keyTags = getKeyTags(); + + const keyId = await createKmsKey( + new CreateKeyCommand({ + Policy: keyPolicy, + Description: 'Used for JWKS auth for CIS2 login', + KeyUsage: KeyUsageType.SIGN_VERIFY, + KeySpec: KeySpec.RSA_4096, + Tags: keyTags, + }) + ); + + return keyId; +} + +export async function getPublicKey( + keyId: string +): Promise<{ keyId: string; publicKey?: Uint8Array }> { + const publicKey = await getKmsPublicKey(keyId).catch((err) => { + if (err instanceof NotFoundException) { + logger.warn(`Key not found: ${keyId}`); + return undefined; + } + throw err; + }); + + return { keyId, publicKey }; +} diff --git a/lambdas/jwks-key-rotation/src/utils/kms-util.ts b/lambdas/jwks-key-rotation/src/utils/kms-util.ts new file mode 100644 index 00000000..375abdae --- /dev/null +++ b/lambdas/jwks-key-rotation/src/utils/kms-util.ts @@ -0,0 +1,39 @@ +import { + CreateKeyCommand, + GetPublicKeyCommand, + KMSClient, +} from '@aws-sdk/client-kms'; +import { logger } from './logger'; + +const kmsClient = new KMSClient({ + region: process.env.REGION, + retryMode: 'standard', + maxAttempts: 10, +}); + +export async function createKmsKey(input: CreateKeyCommand): Promise { + const result = await kmsClient.send(input); + + if (!result.KeyMetadata?.KeyId) { + logger.error(result); + throw new Error('Failed to create key'); + } + return result.KeyMetadata?.KeyId; +} + +export async function getKmsPublicKey(keyId: string): Promise { + const keyArn = `arn:aws:kms:${process.env.REGION}:${process.env.ACCOUNT_ID}:key/${keyId}`; + logger.info(keyArn); + + const result = await kmsClient.send( + new GetPublicKeyCommand({ + KeyId: keyArn, + }) + ); + + if (!result.PublicKey) { + logger.warn(`PublicKey not found ${keyArn}`); + } + logger.info(result.PublicKey); + return result.PublicKey; +} diff --git a/lambdas/jwks-key-rotation/src/utils/ssm-util.ts b/lambdas/jwks-key-rotation/src/utils/ssm-util.ts new file mode 100644 index 00000000..5ba37faf --- /dev/null +++ b/lambdas/jwks-key-rotation/src/utils/ssm-util.ts @@ -0,0 +1,25 @@ +import { + GetParameterCommand, + GetParameterCommandOutput, + SSMClient, +} from '@aws-sdk/client-ssm'; + +const ssmClient = new SSMClient({ + region: process.env.REGION, + retryMode: 'standard', + maxAttempts: 10, +}); + +export async function getParameter( + name = '' +): Promise { + if (!name) { + throw new Error('Missing parameter name'); + } + + return ssmClient.send( + new GetParameterCommand({ + Name: name, + }) + ); +} diff --git a/package-lock.json b/package-lock.json index efa9238b..69f46984 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "workspaces": [ "frontend", "lambdas/cis2-api", + "lambdas/jwks-key-rotation", "tests/test-team", "utils/logger" ], @@ -111,6 +112,85 @@ "jsonwebtoken": "^9.0.2" } }, + "lambdas/jwks-key-rotation": { + "dependencies": { + "@aws-sdk/client-kms": "^3.782.0", + "@aws-sdk/client-ssm": "^3.782.0", + "@types/node-jose": "^1.1.13", + "winston": "^3.14.2", + "zod": "^3.24.2" + }, + "devDependencies": { + "@aws-sdk/types": "^3.775.0", + "@tsconfig/node20": "^20.1.5", + "@types/aws-lambda": "^8.10.147", + "@types/node": "^22.14.0", + "jest": "^29.7.0", + "jest-html-reporter": "^3.10.2", + "jest-mock-extended": "^4.0.0-beta1", + "jsonwebtoken": "^9.0.2", + "node-jose": "^2.2.0", + "typescript": "^5.8.2" + } + }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/types": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.775.0.tgz", + "integrity": "sha512-ZoGKwa4C9fC9Av6bdfqcW6Ix5ot05F/S4VxWR2nHuMv7hzfmAjTOcUiWT7UR4hM/U0whf84VhDtXN/DWAk52KA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@smithy/types": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@types/node": { + "version": "22.14.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.0.tgz", + "integrity": "sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/jest-mock-extended": { + "version": "4.0.0-beta1", + "resolved": "https://registry.npmjs.org/jest-mock-extended/-/jest-mock-extended-4.0.0-beta1.tgz", + "integrity": "sha512-MYcI0wQu3ceNhqKoqAJOdEfsVMamAFqDTjoLN5Y45PAG3iIm4WGnhOu0wpMjlWCexVPO71PMoNir9QrGXrnIlw==", + "dev": true, + "dependencies": { + "ts-essentials": "^10.0.2" + }, + "peerDependencies": { + "@jest/globals": "^28.0.0 || ^29.0.0", + "jest": "^24.0.0 || ^25.0.0 || ^26.0.0 || ^27.0.0 || ^28.0.0 || ^29.0.0", + "typescript": "^3.0.0 || ^4.0.0 || ^5.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@adobe/css-tools": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.2.tgz", @@ -3649,6 +3729,498 @@ "node": ">=16.0.0" } }, + "node_modules/@aws-sdk/client-kms": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-kms/-/client-kms-3.782.0.tgz", + "integrity": "sha512-HBqQ97Ca7xh0DYRp7hvIuS68av1ujeHKRj0uZ33CqokNfHVAFvxKr4Ow7xzuLDqMQejUfrsAMDFwer3erFCtHA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.775.0", + "@aws-sdk/credential-provider-node": "3.782.0", + "@aws-sdk/middleware-host-header": "3.775.0", + "@aws-sdk/middleware-logger": "3.775.0", + "@aws-sdk/middleware-recursion-detection": "3.775.0", + "@aws-sdk/middleware-user-agent": "3.782.0", + "@aws-sdk/region-config-resolver": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@aws-sdk/util-endpoints": "3.782.0", + "@aws-sdk/util-user-agent-browser": "3.775.0", + "@aws-sdk/util-user-agent-node": "3.782.0", + "@smithy/config-resolver": "^4.1.0", + "@smithy/core": "^3.2.0", + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/hash-node": "^4.0.2", + "@smithy/invalid-dependency": "^4.0.2", + "@smithy/middleware-content-length": "^4.0.2", + "@smithy/middleware-endpoint": "^4.1.0", + "@smithy/middleware-retry": "^4.1.0", + "@smithy/middleware-serde": "^4.0.3", + "@smithy/middleware-stack": "^4.0.2", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/protocol-http": "^5.1.0", + "@smithy/smithy-client": "^4.2.0", + "@smithy/types": "^4.2.0", + "@smithy/url-parser": "^4.0.2", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.8", + "@smithy/util-defaults-mode-node": "^4.0.8", + "@smithy/util-endpoints": "^3.0.2", + "@smithy/util-middleware": "^4.0.2", + "@smithy/util-retry": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-kms/node_modules/@aws-sdk/client-sso": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.782.0.tgz", + "integrity": "sha512-5GlJBejo8wqMpSSEKb45WE82YxI2k73YuebjLH/eWDNQeE6VI5Bh9lA1YQ7xNkLLH8hIsb0pSfKVuwh0VEzVrg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.775.0", + "@aws-sdk/middleware-host-header": "3.775.0", + "@aws-sdk/middleware-logger": "3.775.0", + "@aws-sdk/middleware-recursion-detection": "3.775.0", + "@aws-sdk/middleware-user-agent": "3.782.0", + "@aws-sdk/region-config-resolver": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@aws-sdk/util-endpoints": "3.782.0", + "@aws-sdk/util-user-agent-browser": "3.775.0", + "@aws-sdk/util-user-agent-node": "3.782.0", + "@smithy/config-resolver": "^4.1.0", + "@smithy/core": "^3.2.0", + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/hash-node": "^4.0.2", + "@smithy/invalid-dependency": "^4.0.2", + "@smithy/middleware-content-length": "^4.0.2", + "@smithy/middleware-endpoint": "^4.1.0", + "@smithy/middleware-retry": "^4.1.0", + "@smithy/middleware-serde": "^4.0.3", + "@smithy/middleware-stack": "^4.0.2", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/protocol-http": "^5.1.0", + "@smithy/smithy-client": "^4.2.0", + "@smithy/types": "^4.2.0", + "@smithy/url-parser": "^4.0.2", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.8", + "@smithy/util-defaults-mode-node": "^4.0.8", + "@smithy/util-endpoints": "^3.0.2", + "@smithy/util-middleware": "^4.0.2", + "@smithy/util-retry": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-kms/node_modules/@aws-sdk/core": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.775.0.tgz", + "integrity": "sha512-8vpW4WihVfz0DX+7WnnLGm3GuQER++b0IwQG35JlQMlgqnc44M//KbJPsIHA0aJUJVwJAEShgfr5dUbY8WUzaA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/core": "^3.2.0", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/property-provider": "^4.0.2", + "@smithy/protocol-http": "^5.1.0", + "@smithy/signature-v4": "^5.0.2", + "@smithy/smithy-client": "^4.2.0", + "@smithy/types": "^4.2.0", + "@smithy/util-middleware": "^4.0.2", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-kms/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.775.0.tgz", + "integrity": "sha512-6ESVxwCbGm7WZ17kY1fjmxQud43vzJFoLd4bmlR+idQSWdqlzGDYdcfzpjDKTcivdtNrVYmFvcH1JBUwCRAZhw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-kms/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.775.0.tgz", + "integrity": "sha512-PjDQeDH/J1S0yWV32wCj2k5liRo0ssXMseCBEkCsD3SqsU8o5cU82b0hMX4sAib/RkglCSZqGO0xMiN0/7ndww==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/property-provider": "^4.0.2", + "@smithy/protocol-http": "^5.1.0", + "@smithy/smithy-client": "^4.2.0", + "@smithy/types": "^4.2.0", + "@smithy/util-stream": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-kms/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.782.0.tgz", + "integrity": "sha512-wd4KdRy2YjLsE4Y7pz00470Iip06GlRHkG4dyLW7/hFMzEO2o7ixswCWp6J2VGZVAX64acknlv2Q0z02ebjmhw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.775.0", + "@aws-sdk/credential-provider-env": "3.775.0", + "@aws-sdk/credential-provider-http": "3.775.0", + "@aws-sdk/credential-provider-process": "3.775.0", + "@aws-sdk/credential-provider-sso": "3.782.0", + "@aws-sdk/credential-provider-web-identity": "3.782.0", + "@aws-sdk/nested-clients": "3.782.0", + "@aws-sdk/types": "3.775.0", + "@smithy/credential-provider-imds": "^4.0.2", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-kms/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.782.0.tgz", + "integrity": "sha512-HZiAF+TCEyKjju9dgysjiPIWgt/+VerGaeEp18mvKLNfgKz1d+/82A2USEpNKTze7v3cMFASx3CvL8yYyF7mJw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.775.0", + "@aws-sdk/credential-provider-http": "3.775.0", + "@aws-sdk/credential-provider-ini": "3.782.0", + "@aws-sdk/credential-provider-process": "3.775.0", + "@aws-sdk/credential-provider-sso": "3.782.0", + "@aws-sdk/credential-provider-web-identity": "3.782.0", + "@aws-sdk/types": "3.775.0", + "@smithy/credential-provider-imds": "^4.0.2", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-kms/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.775.0.tgz", + "integrity": "sha512-A6k68H9rQp+2+7P7SGO90Csw6nrUEm0Qfjpn9Etc4EboZhhCLs9b66umUsTsSBHus4FDIe5JQxfCUyt1wgNogg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-kms/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.782.0.tgz", + "integrity": "sha512-1y1ucxTtTIGDSNSNxriQY8msinilhe9gGvQpUDYW9gboyC7WQJPDw66imy258V6osdtdi+xoHzVCbCz3WhosMQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.782.0", + "@aws-sdk/core": "3.775.0", + "@aws-sdk/token-providers": "3.782.0", + "@aws-sdk/types": "3.775.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-kms/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.782.0.tgz", + "integrity": "sha512-xCna0opVPaueEbJoclj5C6OpDNi0Gynj+4d7tnuXGgQhTHPyAz8ZyClkVqpi5qvHTgxROdUEDxWqEO5jqRHZHQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.775.0", + "@aws-sdk/nested-clients": "3.782.0", + "@aws-sdk/types": "3.775.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-kms/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.775.0.tgz", + "integrity": "sha512-tkSegM0Z6WMXpLB8oPys/d+umYIocvO298mGvcMCncpRl77L9XkvSLJIFzaHes+o7djAgIduYw8wKIMStFss2w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-kms/node_modules/@aws-sdk/middleware-logger": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.775.0.tgz", + "integrity": "sha512-FaxO1xom4MAoUJsldmR92nT1G6uZxTdNYOFYtdHfd6N2wcNaTuxgjIvqzg5y7QIH9kn58XX/dzf1iTjgqUStZw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-kms/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.775.0.tgz", + "integrity": "sha512-GLCzC8D0A0YDG5u3F5U03Vb9j5tcOEFhr8oc6PDk0k0vm5VwtZOE6LvK7hcCSoAB4HXyOUM0sQuXrbaAh9OwXA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-kms/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.782.0.tgz", + "integrity": "sha512-i32H2R6IItX+bQ2p4+v2gGO2jA80jQoJO2m1xjU9rYWQW3+ErWy4I5YIuQHTBfb6hSdAHbaRfqPDgbv9J2rjEg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@aws-sdk/util-endpoints": "3.782.0", + "@smithy/core": "^3.2.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-kms/node_modules/@aws-sdk/nested-clients": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.782.0.tgz", + "integrity": "sha512-QOYC8q7luzHFXrP0xYAqBctoPkynjfV0r9dqntFu4/IWMTyC1vlo1UTxFAjIPyclYw92XJyEkVCVg9v/nQnsUA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.775.0", + "@aws-sdk/middleware-host-header": "3.775.0", + "@aws-sdk/middleware-logger": "3.775.0", + "@aws-sdk/middleware-recursion-detection": "3.775.0", + "@aws-sdk/middleware-user-agent": "3.782.0", + "@aws-sdk/region-config-resolver": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@aws-sdk/util-endpoints": "3.782.0", + "@aws-sdk/util-user-agent-browser": "3.775.0", + "@aws-sdk/util-user-agent-node": "3.782.0", + "@smithy/config-resolver": "^4.1.0", + "@smithy/core": "^3.2.0", + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/hash-node": "^4.0.2", + "@smithy/invalid-dependency": "^4.0.2", + "@smithy/middleware-content-length": "^4.0.2", + "@smithy/middleware-endpoint": "^4.1.0", + "@smithy/middleware-retry": "^4.1.0", + "@smithy/middleware-serde": "^4.0.3", + "@smithy/middleware-stack": "^4.0.2", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/protocol-http": "^5.1.0", + "@smithy/smithy-client": "^4.2.0", + "@smithy/types": "^4.2.0", + "@smithy/url-parser": "^4.0.2", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.8", + "@smithy/util-defaults-mode-node": "^4.0.8", + "@smithy/util-endpoints": "^3.0.2", + "@smithy/util-middleware": "^4.0.2", + "@smithy/util-retry": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-kms/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.775.0.tgz", + "integrity": "sha512-40iH3LJjrQS3LKUJAl7Wj0bln7RFPEvUYKFxtP8a+oKFDO0F65F52xZxIJbPn6sHkxWDAnZlGgdjZXM3p2g5wQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/types": "^4.2.0", + "@smithy/util-config-provider": "^4.0.0", + "@smithy/util-middleware": "^4.0.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-kms/node_modules/@aws-sdk/token-providers": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.782.0.tgz", + "integrity": "sha512-4tPuk/3+THPrzKaXW4jE2R67UyGwHLFizZ47pcjJWbhb78IIJAy94vbeqEQ+veS84KF5TXcU7g5jGTXC0D70Wg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/nested-clients": "3.782.0", + "@aws-sdk/types": "3.775.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-kms/node_modules/@aws-sdk/types": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.775.0.tgz", + "integrity": "sha512-ZoGKwa4C9fC9Av6bdfqcW6Ix5ot05F/S4VxWR2nHuMv7hzfmAjTOcUiWT7UR4hM/U0whf84VhDtXN/DWAk52KA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-kms/node_modules/@aws-sdk/util-endpoints": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.782.0.tgz", + "integrity": "sha512-/RJOAO7o7HI6lEa4ASbFFLHGU9iPK876BhsVfnl54MvApPVYWQ9sHO0anOUim2S5lQTwd/6ghuH3rFYSq/+rdw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/types": "^4.2.0", + "@smithy/util-endpoints": "^3.0.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-kms/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.775.0.tgz", + "integrity": "sha512-txw2wkiJmZKVdDbscK7VBK+u+TJnRtlUjRTLei+elZg2ADhpQxfVAQl436FUeIv6AhB/oRHW6/K/EAGXUSWi0A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/types": "^4.2.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-kms/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.782.0.tgz", + "integrity": "sha512-dMFkUBgh2Bxuw8fYZQoH/u3H4afQ12VSkzEi//qFiDTwbKYq+u+RYjc8GLDM6JSK1BShMu5AVR7HD4ap1TYUnA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.782.0", + "@aws-sdk/types": "3.775.0", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/client-kms/node_modules/@smithy/types": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-kms/node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@aws-sdk/client-personalize-events": { "version": "3.621.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-personalize-events/-/client-personalize-events-3.621.0.tgz", @@ -4761,6 +5333,501 @@ "node": ">=18.0.0" } }, + "node_modules/@aws-sdk/client-ssm": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-ssm/-/client-ssm-3.782.0.tgz", + "integrity": "sha512-Y3x5KOJ0HL50JMcRIvLILmkBUbnn335LpGM25gmPPhkDPR7cta3sclgZ8ioz16QDORlu0nClAF8ou2Arce+KaQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.775.0", + "@aws-sdk/credential-provider-node": "3.782.0", + "@aws-sdk/middleware-host-header": "3.775.0", + "@aws-sdk/middleware-logger": "3.775.0", + "@aws-sdk/middleware-recursion-detection": "3.775.0", + "@aws-sdk/middleware-user-agent": "3.782.0", + "@aws-sdk/region-config-resolver": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@aws-sdk/util-endpoints": "3.782.0", + "@aws-sdk/util-user-agent-browser": "3.775.0", + "@aws-sdk/util-user-agent-node": "3.782.0", + "@smithy/config-resolver": "^4.1.0", + "@smithy/core": "^3.2.0", + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/hash-node": "^4.0.2", + "@smithy/invalid-dependency": "^4.0.2", + "@smithy/middleware-content-length": "^4.0.2", + "@smithy/middleware-endpoint": "^4.1.0", + "@smithy/middleware-retry": "^4.1.0", + "@smithy/middleware-serde": "^4.0.3", + "@smithy/middleware-stack": "^4.0.2", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/protocol-http": "^5.1.0", + "@smithy/smithy-client": "^4.2.0", + "@smithy/types": "^4.2.0", + "@smithy/url-parser": "^4.0.2", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.8", + "@smithy/util-defaults-mode-node": "^4.0.8", + "@smithy/util-endpoints": "^3.0.2", + "@smithy/util-middleware": "^4.0.2", + "@smithy/util-retry": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", + "@smithy/util-waiter": "^4.0.3", + "@types/uuid": "^9.0.1", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/client-sso": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.782.0.tgz", + "integrity": "sha512-5GlJBejo8wqMpSSEKb45WE82YxI2k73YuebjLH/eWDNQeE6VI5Bh9lA1YQ7xNkLLH8hIsb0pSfKVuwh0VEzVrg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.775.0", + "@aws-sdk/middleware-host-header": "3.775.0", + "@aws-sdk/middleware-logger": "3.775.0", + "@aws-sdk/middleware-recursion-detection": "3.775.0", + "@aws-sdk/middleware-user-agent": "3.782.0", + "@aws-sdk/region-config-resolver": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@aws-sdk/util-endpoints": "3.782.0", + "@aws-sdk/util-user-agent-browser": "3.775.0", + "@aws-sdk/util-user-agent-node": "3.782.0", + "@smithy/config-resolver": "^4.1.0", + "@smithy/core": "^3.2.0", + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/hash-node": "^4.0.2", + "@smithy/invalid-dependency": "^4.0.2", + "@smithy/middleware-content-length": "^4.0.2", + "@smithy/middleware-endpoint": "^4.1.0", + "@smithy/middleware-retry": "^4.1.0", + "@smithy/middleware-serde": "^4.0.3", + "@smithy/middleware-stack": "^4.0.2", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/protocol-http": "^5.1.0", + "@smithy/smithy-client": "^4.2.0", + "@smithy/types": "^4.2.0", + "@smithy/url-parser": "^4.0.2", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.8", + "@smithy/util-defaults-mode-node": "^4.0.8", + "@smithy/util-endpoints": "^3.0.2", + "@smithy/util-middleware": "^4.0.2", + "@smithy/util-retry": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/core": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.775.0.tgz", + "integrity": "sha512-8vpW4WihVfz0DX+7WnnLGm3GuQER++b0IwQG35JlQMlgqnc44M//KbJPsIHA0aJUJVwJAEShgfr5dUbY8WUzaA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/core": "^3.2.0", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/property-provider": "^4.0.2", + "@smithy/protocol-http": "^5.1.0", + "@smithy/signature-v4": "^5.0.2", + "@smithy/smithy-client": "^4.2.0", + "@smithy/types": "^4.2.0", + "@smithy/util-middleware": "^4.0.2", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.775.0.tgz", + "integrity": "sha512-6ESVxwCbGm7WZ17kY1fjmxQud43vzJFoLd4bmlR+idQSWdqlzGDYdcfzpjDKTcivdtNrVYmFvcH1JBUwCRAZhw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.775.0.tgz", + "integrity": "sha512-PjDQeDH/J1S0yWV32wCj2k5liRo0ssXMseCBEkCsD3SqsU8o5cU82b0hMX4sAib/RkglCSZqGO0xMiN0/7ndww==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/property-provider": "^4.0.2", + "@smithy/protocol-http": "^5.1.0", + "@smithy/smithy-client": "^4.2.0", + "@smithy/types": "^4.2.0", + "@smithy/util-stream": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.782.0.tgz", + "integrity": "sha512-wd4KdRy2YjLsE4Y7pz00470Iip06GlRHkG4dyLW7/hFMzEO2o7ixswCWp6J2VGZVAX64acknlv2Q0z02ebjmhw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.775.0", + "@aws-sdk/credential-provider-env": "3.775.0", + "@aws-sdk/credential-provider-http": "3.775.0", + "@aws-sdk/credential-provider-process": "3.775.0", + "@aws-sdk/credential-provider-sso": "3.782.0", + "@aws-sdk/credential-provider-web-identity": "3.782.0", + "@aws-sdk/nested-clients": "3.782.0", + "@aws-sdk/types": "3.775.0", + "@smithy/credential-provider-imds": "^4.0.2", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.782.0.tgz", + "integrity": "sha512-HZiAF+TCEyKjju9dgysjiPIWgt/+VerGaeEp18mvKLNfgKz1d+/82A2USEpNKTze7v3cMFASx3CvL8yYyF7mJw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.775.0", + "@aws-sdk/credential-provider-http": "3.775.0", + "@aws-sdk/credential-provider-ini": "3.782.0", + "@aws-sdk/credential-provider-process": "3.775.0", + "@aws-sdk/credential-provider-sso": "3.782.0", + "@aws-sdk/credential-provider-web-identity": "3.782.0", + "@aws-sdk/types": "3.775.0", + "@smithy/credential-provider-imds": "^4.0.2", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.775.0.tgz", + "integrity": "sha512-A6k68H9rQp+2+7P7SGO90Csw6nrUEm0Qfjpn9Etc4EboZhhCLs9b66umUsTsSBHus4FDIe5JQxfCUyt1wgNogg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.782.0.tgz", + "integrity": "sha512-1y1ucxTtTIGDSNSNxriQY8msinilhe9gGvQpUDYW9gboyC7WQJPDw66imy258V6osdtdi+xoHzVCbCz3WhosMQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.782.0", + "@aws-sdk/core": "3.775.0", + "@aws-sdk/token-providers": "3.782.0", + "@aws-sdk/types": "3.775.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.782.0.tgz", + "integrity": "sha512-xCna0opVPaueEbJoclj5C6OpDNi0Gynj+4d7tnuXGgQhTHPyAz8ZyClkVqpi5qvHTgxROdUEDxWqEO5jqRHZHQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.775.0", + "@aws-sdk/nested-clients": "3.782.0", + "@aws-sdk/types": "3.775.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.775.0.tgz", + "integrity": "sha512-tkSegM0Z6WMXpLB8oPys/d+umYIocvO298mGvcMCncpRl77L9XkvSLJIFzaHes+o7djAgIduYw8wKIMStFss2w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/middleware-logger": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.775.0.tgz", + "integrity": "sha512-FaxO1xom4MAoUJsldmR92nT1G6uZxTdNYOFYtdHfd6N2wcNaTuxgjIvqzg5y7QIH9kn58XX/dzf1iTjgqUStZw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.775.0.tgz", + "integrity": "sha512-GLCzC8D0A0YDG5u3F5U03Vb9j5tcOEFhr8oc6PDk0k0vm5VwtZOE6LvK7hcCSoAB4HXyOUM0sQuXrbaAh9OwXA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.782.0.tgz", + "integrity": "sha512-i32H2R6IItX+bQ2p4+v2gGO2jA80jQoJO2m1xjU9rYWQW3+ErWy4I5YIuQHTBfb6hSdAHbaRfqPDgbv9J2rjEg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@aws-sdk/util-endpoints": "3.782.0", + "@smithy/core": "^3.2.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/nested-clients": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.782.0.tgz", + "integrity": "sha512-QOYC8q7luzHFXrP0xYAqBctoPkynjfV0r9dqntFu4/IWMTyC1vlo1UTxFAjIPyclYw92XJyEkVCVg9v/nQnsUA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.775.0", + "@aws-sdk/middleware-host-header": "3.775.0", + "@aws-sdk/middleware-logger": "3.775.0", + "@aws-sdk/middleware-recursion-detection": "3.775.0", + "@aws-sdk/middleware-user-agent": "3.782.0", + "@aws-sdk/region-config-resolver": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@aws-sdk/util-endpoints": "3.782.0", + "@aws-sdk/util-user-agent-browser": "3.775.0", + "@aws-sdk/util-user-agent-node": "3.782.0", + "@smithy/config-resolver": "^4.1.0", + "@smithy/core": "^3.2.0", + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/hash-node": "^4.0.2", + "@smithy/invalid-dependency": "^4.0.2", + "@smithy/middleware-content-length": "^4.0.2", + "@smithy/middleware-endpoint": "^4.1.0", + "@smithy/middleware-retry": "^4.1.0", + "@smithy/middleware-serde": "^4.0.3", + "@smithy/middleware-stack": "^4.0.2", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/protocol-http": "^5.1.0", + "@smithy/smithy-client": "^4.2.0", + "@smithy/types": "^4.2.0", + "@smithy/url-parser": "^4.0.2", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.8", + "@smithy/util-defaults-mode-node": "^4.0.8", + "@smithy/util-endpoints": "^3.0.2", + "@smithy/util-middleware": "^4.0.2", + "@smithy/util-retry": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.775.0.tgz", + "integrity": "sha512-40iH3LJjrQS3LKUJAl7Wj0bln7RFPEvUYKFxtP8a+oKFDO0F65F52xZxIJbPn6sHkxWDAnZlGgdjZXM3p2g5wQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/types": "^4.2.0", + "@smithy/util-config-provider": "^4.0.0", + "@smithy/util-middleware": "^4.0.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/token-providers": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.782.0.tgz", + "integrity": "sha512-4tPuk/3+THPrzKaXW4jE2R67UyGwHLFizZ47pcjJWbhb78IIJAy94vbeqEQ+veS84KF5TXcU7g5jGTXC0D70Wg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/nested-clients": "3.782.0", + "@aws-sdk/types": "3.775.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/types": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.775.0.tgz", + "integrity": "sha512-ZoGKwa4C9fC9Av6bdfqcW6Ix5ot05F/S4VxWR2nHuMv7hzfmAjTOcUiWT7UR4hM/U0whf84VhDtXN/DWAk52KA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/util-endpoints": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.782.0.tgz", + "integrity": "sha512-/RJOAO7o7HI6lEa4ASbFFLHGU9iPK876BhsVfnl54MvApPVYWQ9sHO0anOUim2S5lQTwd/6ghuH3rFYSq/+rdw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/types": "^4.2.0", + "@smithy/util-endpoints": "^3.0.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.775.0.tgz", + "integrity": "sha512-txw2wkiJmZKVdDbscK7VBK+u+TJnRtlUjRTLei+elZg2ADhpQxfVAQl436FUeIv6AhB/oRHW6/K/EAGXUSWi0A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/types": "^4.2.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.782.0.tgz", + "integrity": "sha512-dMFkUBgh2Bxuw8fYZQoH/u3H4afQ12VSkzEi//qFiDTwbKYq+u+RYjc8GLDM6JSK1BShMu5AVR7HD4ap1TYUnA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.782.0", + "@aws-sdk/types": "3.775.0", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/client-ssm/node_modules/@smithy/types": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ssm/node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@aws-sdk/client-sso": { "version": "3.772.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.772.0.tgz", @@ -11579,12 +12646,12 @@ } }, "node_modules/@smithy/abort-controller": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.1.tgz", - "integrity": "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.2.tgz", + "integrity": "sha512-Sl/78VDtgqKxN2+1qduaVE140XF+Xg+TafkncspwM4jFP/LHr76ZHmIY/y3V1M0mMLNk+Je6IGbzxy23RSToMw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.1.0", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -11592,9 +12659,9 @@ } }, "node_modules/@smithy/abort-controller/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -11629,15 +12696,15 @@ } }, "node_modules/@smithy/config-resolver": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.0.1.tgz", - "integrity": "sha512-Igfg8lKu3dRVkTSEm98QpZUvKEOa71jDX4vKRcvJVyRc3UgN3j7vFMf0s7xLQhYmKa8kyJGQgUJDOV5V3neVlQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.1.0.tgz", + "integrity": "sha512-8smPlwhga22pwl23fM5ew4T9vfLUCeFXlcqNOCD5M5h8VmNPNUE9j6bQSuRXpDSV11L/E/SwEBQuW8hr6+nS1A==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.0.1", - "@smithy/types": "^4.1.0", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/types": "^4.2.0", "@smithy/util-config-provider": "^4.0.0", - "@smithy/util-middleware": "^4.0.1", + "@smithy/util-middleware": "^4.0.2", "tslib": "^2.6.2" }, "engines": { @@ -11645,9 +12712,9 @@ } }, "node_modules/@smithy/config-resolver/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -11657,17 +12724,17 @@ } }, "node_modules/@smithy/core": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.1.5.tgz", - "integrity": "sha512-HLclGWPkCsekQgsyzxLhCQLa8THWXtB5PxyYN+2O6nkyLt550KQKTlbV2D1/j5dNIQapAZM1+qFnpBFxZQkgCA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.2.0.tgz", + "integrity": "sha512-k17bgQhVZ7YmUvA8at4af1TDpl0NDMBuBKJl8Yg0nrefwmValU+CnA5l/AriVdQNthU/33H3nK71HrLgqOPr1Q==", "license": "Apache-2.0", "dependencies": { - "@smithy/middleware-serde": "^4.0.2", - "@smithy/protocol-http": "^5.0.1", - "@smithy/types": "^4.1.0", + "@smithy/middleware-serde": "^4.0.3", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-middleware": "^4.0.1", - "@smithy/util-stream": "^4.1.2", + "@smithy/util-middleware": "^4.0.2", + "@smithy/util-stream": "^4.2.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, @@ -11676,9 +12743,9 @@ } }, "node_modules/@smithy/core/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -11701,15 +12768,15 @@ } }, "node_modules/@smithy/credential-provider-imds": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.0.1.tgz", - "integrity": "sha512-l/qdInaDq1Zpznpmev/+52QomsJNZ3JkTl5yrTl02V6NBgJOQ4LY0SFw/8zsMwj3tLe8vqiIuwF6nxaEwgf6mg==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.0.2.tgz", + "integrity": "sha512-32lVig6jCaWBHnY+OEQ6e6Vnt5vDHaLiydGrwYMW9tPqO688hPGTYRamYJ1EptxEC2rAwJrHWmPoKRBl4iTa8w==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.0.1", - "@smithy/property-provider": "^4.0.1", - "@smithy/types": "^4.1.0", - "@smithy/url-parser": "^4.0.1", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/property-provider": "^4.0.2", + "@smithy/types": "^4.2.0", + "@smithy/url-parser": "^4.0.2", "tslib": "^2.6.2" }, "engines": { @@ -11717,9 +12784,9 @@ } }, "node_modules/@smithy/credential-provider-imds/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -11871,14 +12938,14 @@ } }, "node_modules/@smithy/fetch-http-handler": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.1.tgz", - "integrity": "sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.2.tgz", + "integrity": "sha512-+9Dz8sakS9pe7f2cBocpJXdeVjMopUDLgZs1yWeu7h++WqSbjUYv/JAJwKwXw1HV6gq1jyWjxuyn24E2GhoEcQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^5.0.1", - "@smithy/querystring-builder": "^4.0.1", - "@smithy/types": "^4.1.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/querystring-builder": "^4.0.2", + "@smithy/types": "^4.2.0", "@smithy/util-base64": "^4.0.0", "tslib": "^2.6.2" }, @@ -11887,9 +12954,9 @@ } }, "node_modules/@smithy/fetch-http-handler/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -11926,12 +12993,12 @@ } }, "node_modules/@smithy/hash-node": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.0.1.tgz", - "integrity": "sha512-TJ6oZS+3r2Xu4emVse1YPB3Dq3d8RkZDKcPr71Nj/lJsdAP1c7oFzYqEn1IBc915TsgLl2xIJNuxCz+gLbLE0w==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.0.2.tgz", + "integrity": "sha512-VnTpYPnRUE7yVhWozFdlxcYknv9UN7CeOqSrMH+V877v4oqtVYuoqhIhtSjmGPvYrYnAkaM61sLMKHvxL138yg==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.1.0", + "@smithy/types": "^4.2.0", "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" @@ -11941,9 +13008,9 @@ } }, "node_modules/@smithy/hash-node/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -12005,12 +13072,12 @@ } }, "node_modules/@smithy/invalid-dependency": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.0.1.tgz", - "integrity": "sha512-gdudFPf4QRQ5pzj7HEnu6FhKRi61BfH/Gk5Yf6O0KiSbr1LlVhgjThcvjdu658VE6Nve8vaIWB8/fodmS1rBPQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.0.2.tgz", + "integrity": "sha512-GatB4+2DTpgWPday+mnUkoumP54u/MDM/5u44KF9hIu8jF0uafZtQLcdfIKkIcUNuF/fBojpLEHZS/56JqPeXQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.1.0", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -12018,9 +13085,9 @@ } }, "node_modules/@smithy/invalid-dependency/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -12081,13 +13148,13 @@ } }, "node_modules/@smithy/middleware-content-length": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.0.1.tgz", - "integrity": "sha512-OGXo7w5EkB5pPiac7KNzVtfCW2vKBTZNuCctn++TTSOMpe6RZO/n6WEC1AxJINn3+vWLKW49uad3lo/u0WJ9oQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.0.2.tgz", + "integrity": "sha512-hAfEXm1zU+ELvucxqQ7I8SszwQ4znWMbNv6PLMndN83JJN41EPuS93AIyh2N+gJ6x8QFhzSO6b7q2e6oClDI8A==", "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^5.0.1", - "@smithy/types": "^4.1.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -12095,9 +13162,9 @@ } }, "node_modules/@smithy/middleware-content-length/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -12107,18 +13174,18 @@ } }, "node_modules/@smithy/middleware-endpoint": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.0.6.tgz", - "integrity": "sha512-ftpmkTHIFqgaFugcjzLZv3kzPEFsBFSnq1JsIkr2mwFzCraZVhQk2gqN51OOeRxqhbPTkRFj39Qd2V91E/mQxg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.1.0.tgz", + "integrity": "sha512-xhLimgNCbCzsUppRTGXWkZywksuTThxaIB0HwbpsVLY5sceac4e1TZ/WKYqufQLaUy+gUSJGNdwD2jo3cXL0iA==", "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^3.1.5", - "@smithy/middleware-serde": "^4.0.2", - "@smithy/node-config-provider": "^4.0.1", - "@smithy/shared-ini-file-loader": "^4.0.1", - "@smithy/types": "^4.1.0", - "@smithy/url-parser": "^4.0.1", - "@smithy/util-middleware": "^4.0.1", + "@smithy/core": "^3.2.0", + "@smithy/middleware-serde": "^4.0.3", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", + "@smithy/url-parser": "^4.0.2", + "@smithy/util-middleware": "^4.0.2", "tslib": "^2.6.2" }, "engines": { @@ -12126,9 +13193,9 @@ } }, "node_modules/@smithy/middleware-endpoint/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -12138,18 +13205,18 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.0.7.tgz", - "integrity": "sha512-58j9XbUPLkqAcV1kHzVX/kAR16GT+j7DUZJqwzsxh1jtz7G82caZiGyyFgUvogVfNTg3TeAOIJepGc8TXF4AVQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.1.0.tgz", + "integrity": "sha512-2zAagd1s6hAaI/ap6SXi5T3dDwBOczOMCSkkYzktqN1+tzbk1GAsHNAdo/1uzxz3Ky02jvZQwbi/vmDA6z4Oyg==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.0.1", - "@smithy/protocol-http": "^5.0.1", - "@smithy/service-error-classification": "^4.0.1", - "@smithy/smithy-client": "^4.1.6", - "@smithy/types": "^4.1.0", - "@smithy/util-middleware": "^4.0.1", - "@smithy/util-retry": "^4.0.1", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/protocol-http": "^5.1.0", + "@smithy/service-error-classification": "^4.0.2", + "@smithy/smithy-client": "^4.2.0", + "@smithy/types": "^4.2.0", + "@smithy/util-middleware": "^4.0.2", + "@smithy/util-retry": "^4.0.2", "tslib": "^2.6.2", "uuid": "^9.0.1" }, @@ -12158,9 +13225,9 @@ } }, "node_modules/@smithy/middleware-retry/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -12170,12 +13237,12 @@ } }, "node_modules/@smithy/middleware-serde": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.2.tgz", - "integrity": "sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.3.tgz", + "integrity": "sha512-rfgDVrgLEVMmMn0BI8O+8OVr6vXzjV7HZj57l0QxslhzbvVfikZbVfBVthjLHqib4BW44QhcIgJpvebHlRaC9A==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.1.0", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -12183,9 +13250,9 @@ } }, "node_modules/@smithy/middleware-serde/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -12195,12 +13262,12 @@ } }, "node_modules/@smithy/middleware-stack": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.0.1.tgz", - "integrity": "sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.0.2.tgz", + "integrity": "sha512-eSPVcuJJGVYrFYu2hEq8g8WWdJav3sdrI4o2c6z/rjnYDd3xH9j9E7deZQCzFn4QvGPouLngH3dQ+QVTxv5bOQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.1.0", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -12208,9 +13275,9 @@ } }, "node_modules/@smithy/middleware-stack/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -12220,14 +13287,14 @@ } }, "node_modules/@smithy/node-config-provider": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.1.tgz", - "integrity": "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.2.tgz", + "integrity": "sha512-WgCkILRZfJwJ4Da92a6t3ozN/zcvYyJGUTmfGbgS/FkCcoCjl7G4FJaCDN1ySdvLvemnQeo25FdkyMSTSwulsw==", "license": "Apache-2.0", "dependencies": { - "@smithy/property-provider": "^4.0.1", - "@smithy/shared-ini-file-loader": "^4.0.1", - "@smithy/types": "^4.1.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -12235,9 +13302,9 @@ } }, "node_modules/@smithy/node-config-provider/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -12247,15 +13314,15 @@ } }, "node_modules/@smithy/node-http-handler": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.3.tgz", - "integrity": "sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.4.tgz", + "integrity": "sha512-/mdqabuAT3o/ihBGjL94PUbTSPSRJ0eeVTdgADzow0wRJ0rN4A27EOrtlK56MYiO1fDvlO3jVTCxQtQmK9dZ1g==", "license": "Apache-2.0", "dependencies": { - "@smithy/abort-controller": "^4.0.1", - "@smithy/protocol-http": "^5.0.1", - "@smithy/querystring-builder": "^4.0.1", - "@smithy/types": "^4.1.0", + "@smithy/abort-controller": "^4.0.2", + "@smithy/protocol-http": "^5.1.0", + "@smithy/querystring-builder": "^4.0.2", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -12263,9 +13330,9 @@ } }, "node_modules/@smithy/node-http-handler/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -12275,12 +13342,12 @@ } }, "node_modules/@smithy/property-provider": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", - "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.2.tgz", + "integrity": "sha512-wNRoQC1uISOuNc2s4hkOYwYllmiyrvVXWMtq+TysNRVQaHm4yoafYQyjN/goYZS+QbYlPIbb/QRjaUZMuzwQ7A==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.1.0", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -12288,9 +13355,9 @@ } }, "node_modules/@smithy/property-provider/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -12300,12 +13367,12 @@ } }, "node_modules/@smithy/protocol-http": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.0.1.tgz", - "integrity": "sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.1.0.tgz", + "integrity": "sha512-KxAOL1nUNw2JTYrtviRRjEnykIDhxc84qMBzxvu1MUfQfHTuBlCG7PA6EdVwqpJjH7glw7FqQoFxUJSyBQgu7g==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.1.0", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -12313,9 +13380,9 @@ } }, "node_modules/@smithy/protocol-http/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -12325,12 +13392,12 @@ } }, "node_modules/@smithy/querystring-builder": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.1.tgz", - "integrity": "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.2.tgz", + "integrity": "sha512-NTOs0FwHw1vimmQM4ebh+wFQvOwkEf/kQL6bSM1Lock+Bv4I89B3hGYoUEPkmvYPkDKyp5UdXJYu+PoTQ3T31Q==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.1.0", + "@smithy/types": "^4.2.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" }, @@ -12339,9 +13406,9 @@ } }, "node_modules/@smithy/querystring-builder/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -12351,12 +13418,12 @@ } }, "node_modules/@smithy/querystring-parser": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.0.1.tgz", - "integrity": "sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.0.2.tgz", + "integrity": "sha512-v6w8wnmZcVXjfVLjxw8qF7OwESD9wnpjp0Dqry/Pod0/5vcEA3qxCr+BhbOHlxS8O+29eLpT3aagxXGwIoEk7Q==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.1.0", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -12364,9 +13431,9 @@ } }, "node_modules/@smithy/querystring-parser/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -12376,21 +13443,21 @@ } }, "node_modules/@smithy/service-error-classification": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.0.1.tgz", - "integrity": "sha512-3JNjBfOWpj/mYfjXJHB4Txc/7E4LVq32bwzE7m28GN79+M1f76XHflUaSUkhOriprPDzev9cX/M+dEB80DNDKA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.0.2.tgz", + "integrity": "sha512-LA86xeFpTKn270Hbkixqs5n73S+LVM0/VZco8dqd+JT75Dyx3Lcw/MraL7ybjmz786+160K8rPOmhsq0SocoJQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.1.0" + "@smithy/types": "^4.2.0" }, "engines": { "node": ">=18.0.0" } }, "node_modules/@smithy/service-error-classification/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -12400,12 +13467,12 @@ } }, "node_modules/@smithy/shared-ini-file-loader": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", - "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.2.tgz", + "integrity": "sha512-J9/gTWBGVuFZ01oVA6vdb4DAjf1XbDhK6sLsu3OS9qmLrS6KB5ygpeHiM3miIbj1qgSJ96GYszXFWv6ErJ8QEw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.1.0", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -12413,9 +13480,9 @@ } }, "node_modules/@smithy/shared-ini-file-loader/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -12425,16 +13492,16 @@ } }, "node_modules/@smithy/signature-v4": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.0.1.tgz", - "integrity": "sha512-nCe6fQ+ppm1bQuw5iKoeJ0MJfz2os7Ic3GBjOkLOPtavbD1ONoyE3ygjBfz2ythFWm4YnRm6OxW+8p/m9uCoIA==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.0.2.tgz", + "integrity": "sha512-Mz+mc7okA73Lyz8zQKJNyr7lIcHLiPYp0+oiqiMNc/t7/Kf2BENs5d63pEj7oPqdjaum6g0Fc8wC78dY1TgtXw==", "license": "Apache-2.0", "dependencies": { "@smithy/is-array-buffer": "^4.0.0", - "@smithy/protocol-http": "^5.0.1", - "@smithy/types": "^4.1.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", "@smithy/util-hex-encoding": "^4.0.0", - "@smithy/util-middleware": "^4.0.1", + "@smithy/util-middleware": "^4.0.2", "@smithy/util-uri-escape": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" @@ -12444,9 +13511,9 @@ } }, "node_modules/@smithy/signature-v4/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -12481,17 +13548,17 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.1.6.tgz", - "integrity": "sha512-UYDolNg6h2O0L+cJjtgSyKKvEKCOa/8FHYJnBobyeoeWDmNpXjwOAtw16ezyeu1ETuuLEOZbrynK0ZY1Lx9Jbw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.2.0.tgz", + "integrity": "sha512-Qs65/w30pWV7LSFAez9DKy0Koaoh3iHhpcpCCJ4waj/iqwsuSzJna2+vYwq46yBaqO5ZbP9TjUsATUNxrKeBdw==", "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^3.1.5", - "@smithy/middleware-endpoint": "^4.0.6", - "@smithy/middleware-stack": "^4.0.1", - "@smithy/protocol-http": "^5.0.1", - "@smithy/types": "^4.1.0", - "@smithy/util-stream": "^4.1.2", + "@smithy/core": "^3.2.0", + "@smithy/middleware-endpoint": "^4.1.0", + "@smithy/middleware-stack": "^4.0.2", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", + "@smithy/util-stream": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -12499,9 +13566,9 @@ } }, "node_modules/@smithy/smithy-client/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -12523,13 +13590,13 @@ } }, "node_modules/@smithy/url-parser": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.0.1.tgz", - "integrity": "sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.0.2.tgz", + "integrity": "sha512-Bm8n3j2ScqnT+kJaClSVCMeiSenK6jVAzZCNewsYWuZtnBehEz4r2qP0riZySZVfzB+03XZHJeqfmJDkeeSLiQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/querystring-parser": "^4.0.1", - "@smithy/types": "^4.1.0", + "@smithy/querystring-parser": "^4.0.2", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -12537,9 +13604,9 @@ } }, "node_modules/@smithy/url-parser/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -12625,14 +13692,14 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.0.7.tgz", - "integrity": "sha512-CZgDDrYHLv0RUElOsmZtAnp1pIjwDVCSuZWOPhIOBvG36RDfX1Q9+6lS61xBf+qqvHoqRjHxgINeQz47cYFC2Q==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.0.8.tgz", + "integrity": "sha512-ZTypzBra+lI/LfTYZeop9UjoJhhGRTg3pxrNpfSTQLd3AJ37r2z4AXTKpq1rFXiiUIJsYyFgNJdjWRGP/cbBaQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/property-provider": "^4.0.1", - "@smithy/smithy-client": "^4.1.6", - "@smithy/types": "^4.1.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/smithy-client": "^4.2.0", + "@smithy/types": "^4.2.0", "bowser": "^2.11.0", "tslib": "^2.6.2" }, @@ -12641,9 +13708,9 @@ } }, "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -12653,17 +13720,17 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.0.7.tgz", - "integrity": "sha512-79fQW3hnfCdrfIi1soPbK3zmooRFnLpSx3Vxi6nUlqaaQeC5dm8plt4OTNDNqEEEDkvKghZSaoti684dQFVrGQ==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.0.8.tgz", + "integrity": "sha512-Rgk0Jc/UDfRTzVthye/k2dDsz5Xxs9LZaKCNPgJTRyoyBoeiNCnHsYGOyu1PKN+sDyPnJzMOz22JbwxzBp9NNA==", "license": "Apache-2.0", "dependencies": { - "@smithy/config-resolver": "^4.0.1", - "@smithy/credential-provider-imds": "^4.0.1", - "@smithy/node-config-provider": "^4.0.1", - "@smithy/property-provider": "^4.0.1", - "@smithy/smithy-client": "^4.1.6", - "@smithy/types": "^4.1.0", + "@smithy/config-resolver": "^4.1.0", + "@smithy/credential-provider-imds": "^4.0.2", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/property-provider": "^4.0.2", + "@smithy/smithy-client": "^4.2.0", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -12671,9 +13738,9 @@ } }, "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -12683,13 +13750,13 @@ } }, "node_modules/@smithy/util-endpoints": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.0.1.tgz", - "integrity": "sha512-zVdUENQpdtn9jbpD9SCFK4+aSiavRb9BxEtw9ZGUR1TYo6bBHbIoi7VkrFQ0/RwZlzx0wRBaRmPclj8iAoJCLA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.0.2.tgz", + "integrity": "sha512-6QSutU5ZyrpNbnd51zRTL7goojlcnuOB55+F9VBD+j8JpRY50IGamsjlycrmpn8PQkmJucFW8A0LSfXj7jjtLQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.0.1", - "@smithy/types": "^4.1.0", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -12697,9 +13764,9 @@ } }, "node_modules/@smithy/util-endpoints/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -12721,12 +13788,12 @@ } }, "node_modules/@smithy/util-middleware": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.1.tgz", - "integrity": "sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.2.tgz", + "integrity": "sha512-6GDamTGLuBQVAEuQ4yDQ+ti/YINf/MEmIegrEeg7DdB/sld8BX1lqt9RRuIcABOhAGTA50bRbPzErez7SlDtDQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.1.0", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -12734,9 +13801,9 @@ } }, "node_modules/@smithy/util-middleware/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -12746,13 +13813,13 @@ } }, "node_modules/@smithy/util-retry": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.0.1.tgz", - "integrity": "sha512-WmRHqNVwn3kI3rKk1LsKcVgPBG6iLTBGC1iYOV3GQegwJ3E8yjzHytPt26VNzOWr1qu0xE03nK0Ug8S7T7oufw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.0.2.tgz", + "integrity": "sha512-Qryc+QG+7BCpvjloFLQrmlSd0RsVRHejRXd78jNO3+oREueCjwG1CCEH1vduw/ZkM1U9TztwIKVIi3+8MJScGg==", "license": "Apache-2.0", "dependencies": { - "@smithy/service-error-classification": "^4.0.1", - "@smithy/types": "^4.1.0", + "@smithy/service-error-classification": "^4.0.2", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -12760,9 +13827,9 @@ } }, "node_modules/@smithy/util-retry/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -12772,14 +13839,14 @@ } }, "node_modules/@smithy/util-stream": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.1.2.tgz", - "integrity": "sha512-44PKEqQ303d3rlQuiDpcCcu//hV8sn+u2JBo84dWCE0rvgeiVl0IlLMagbU++o0jCWhYCsHaAt9wZuZqNe05Hw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.2.0.tgz", + "integrity": "sha512-Vj1TtwWnuWqdgQI6YTUF5hQ/0jmFiOYsc51CSMgj7QfyO+RF4EnT2HNjoviNlOOmgzgvf3f5yno+EiC4vrnaWQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/fetch-http-handler": "^5.0.1", - "@smithy/node-http-handler": "^4.0.3", - "@smithy/types": "^4.1.0", + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/types": "^4.2.0", "@smithy/util-base64": "^4.0.0", "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-hex-encoding": "^4.0.0", @@ -12791,9 +13858,9 @@ } }, "node_modules/@smithy/util-stream/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -12878,13 +13945,13 @@ } }, "node_modules/@smithy/util-waiter": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.0.2.tgz", - "integrity": "sha512-piUTHyp2Axx3p/kc2CIJkYSv0BAaheBQmbACZgQSSfWUumWNW+R1lL+H9PDBxKJkvOeEX+hKYEFiwO8xagL8AQ==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.0.3.tgz", + "integrity": "sha512-JtaY3FxmD+te+KSI2FJuEcfNC9T/DGGVf551babM7fAaXhjJUt7oSYurH1Devxd2+BOSUACCgt3buinx4UnmEA==", "license": "Apache-2.0", "dependencies": { - "@smithy/abort-controller": "^4.0.1", - "@smithy/types": "^4.1.0", + "@smithy/abort-controller": "^4.0.2", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -12892,9 +13959,9 @@ } }, "node_modules/@smithy/util-waiter/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -13339,17 +14406,23 @@ "version": "22.13.13", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.13.tgz", "integrity": "sha512-ClsL5nMwKaBRwPcCvH8E7+nU4GxHVx1axNvMZTFHMEfNI7oahimt26P5zjVCRrjiIWj6YFXfE1v3dEp94wLcGQ==", - "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.20.0" } }, + "node_modules/@types/node-jose": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@types/node-jose/-/node-jose-1.1.13.tgz", + "integrity": "sha512-QjMd4yhwy1EvSToQn0YI3cD29YhyfxFwj7NecuymjLys2/P0FwxWnkgBlFxCai6Y3aBCe7rbwmqwJJawxlgcXw==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/node/node_modules/undici-types": { "version": "6.20.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, "license": "MIT" }, "node_modules/@types/normalize-package-data": { @@ -15128,6 +16201,15 @@ ], "license": "MIT" }, + "node_modules/base64url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", + "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/basic-ftp": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", @@ -16992,6 +18074,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, "node_modules/esbuild": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz", @@ -21600,6 +22688,10 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/jwks-key-rotation": { + "resolved": "lambdas/jwks-key-rotation", + "link": true + }, "node_modules/jws": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", @@ -21907,6 +22999,12 @@ "node": ">= 12.0.0" } }, + "node_modules/long": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.1.tgz", + "integrity": "sha512-ka87Jz3gcx/I7Hal94xaN2tZEOPoUOEVftkQqZx2EeQRN7LGdfLlI3FvZ+7WDplm+vK2Urx9ULrvSowtdCieng==", + "dev": true + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -22415,12 +23513,68 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", "license": "MIT" }, + "node_modules/node-jose": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/node-jose/-/node-jose-2.2.0.tgz", + "integrity": "sha512-XPCvJRr94SjLrSIm4pbYHKLEaOsDvJCpyFw/6V/KK/IXmyZ6SFBzAUDO9HQf4DB/nTEFcRGH87mNciOP23kFjw==", + "dev": true, + "dependencies": { + "base64url": "^3.0.1", + "buffer": "^6.0.3", + "es6-promise": "^4.2.8", + "lodash": "^4.17.21", + "long": "^5.2.0", + "node-forge": "^1.2.1", + "pako": "^2.0.4", + "process": "^0.11.10", + "uuid": "^9.0.0" + } + }, + "node_modules/node-jose/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/node-jose/node_modules/pako": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==", + "dev": true + }, "node_modules/node-releases": { "version": "2.0.19", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", diff --git a/package.json b/package.json index 25f93de5..f431290b 100644 --- a/package.json +++ b/package.json @@ -4,11 +4,13 @@ "workspaces": [ "frontend", "lambdas/cis2-api", + "lambdas/jwks-key-rotation", "tests/test-team", "utils/logger" ], "scripts": { "build": "npm run --workspace frontend build --if-present", + "build-lambda": "npm run --workspaces build-lambda --if-present", "create-backend-sandbox": "./scripts/create_backend_sandbox.sh", "destroy-backend-sandbox": "./scripts/destroy_backend_sandbox.sh", "dev": "npm run --workspace frontend dev --if-present", diff --git a/scripts/config/sonar-scanner.properties b/scripts/config/sonar-scanner.properties index f5cfeb26..39602d71 100644 --- a/scripts/config/sonar-scanner.properties +++ b/scripts/config/sonar-scanner.properties @@ -3,8 +3,8 @@ sonar.host.url=https://sonarcloud.io sonar.qualitygate.wait=true sonar.sourceEncoding=UTF-8 -sonar.sources=frontend/src/, lambdas/cis2-api -sonar.tests=tests/, frontend/src/__tests__, lambdas/cis2-api/src/__tests__ +sonar.sources=frontend/src/, lambdas/cis2-api, lambdas/jwks-key-rotation +sonar.tests=tests/, frontend/src/__tests__, lambdas/cis2-api/src/__tests__, lambdas/jwks-key-rotation/src/__tests__ sonar.exclusions=frontend/src/__tests__/**/*, lambdas/*/src/__tests__/**/* sonar.terraform.provider.aws.version=5.54.1 sonar.cpd.exclusions=**.test.* From 99820ca5618c3fbd862463025205f1e44fd918ee Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Wed, 16 Apr 2025 16:01:43 +0100 Subject: [PATCH 10/54] CCM-8897: jwks key rotation WIP --- .../module_lambda_jwks_key_rotation.tf | 25 +- lambdas/jwks-key-rotation/package.json | 1 + lambdas/jwks-key-rotation/src/handler.ts | 84 +-- .../src/utils/{ => aws}/kms-util.ts | 26 +- .../src/utils/aws/s3-util.ts | 33 + .../src/utils/{ => aws}/ssm-util.ts | 22 + .../utils/{aws-utils.ts => aws/tag-util.ts} | 0 .../jwks-key-rotation/src/utils/jwks-util.ts | 50 ++ .../src/utils/key-directory-repository.ts | 12 +- .../jwks-key-rotation/src/utils/key-util.ts | 13 +- package-lock.json | 714 +++++++++++++++++- 11 files changed, 909 insertions(+), 71 deletions(-) rename lambdas/jwks-key-rotation/src/utils/{ => aws}/kms-util.ts (60%) create mode 100644 lambdas/jwks-key-rotation/src/utils/aws/s3-util.ts rename lambdas/jwks-key-rotation/src/utils/{ => aws}/ssm-util.ts (51%) rename lambdas/jwks-key-rotation/src/utils/{aws-utils.ts => aws/tag-util.ts} (100%) create mode 100644 lambdas/jwks-key-rotation/src/utils/jwks-util.ts diff --git a/infrastructure/terraform/modules/public-signing-keys/module_lambda_jwks_key_rotation.tf b/infrastructure/terraform/modules/public-signing-keys/module_lambda_jwks_key_rotation.tf index 48dab4ad..819a8af3 100644 --- a/infrastructure/terraform/modules/public-signing-keys/module_lambda_jwks_key_rotation.tf +++ b/infrastructure/terraform/modules/public-signing-keys/module_lambda_jwks_key_rotation.tf @@ -35,11 +35,12 @@ module "lambda_jwks_key_rotation" { force_lambda_code_deploy = true lambda_env_vars = { - "SSM_KEY_DIRECTORY_NAME" = local.ssm_key_directory_name, - "SSM_ASYMMETRIC_KEY_POLICY" = local.ssm_asymmetric_key_policy_name, - "KEY_TAGS" = join(",", formatlist("%s=%s", keys(var.default_tags), values(var.default_tags))), - "REGION" = var.region, - "ACCOUNT_ID" = var.aws_account_id + "SSM_KEY_DIRECTORY_NAME" = local.ssm_key_directory_name, + "SSM_ASYMMETRIC_KEY_POLICY" = local.ssm_asymmetric_key_policy_name, + "KEY_TAGS" = join(",", formatlist("%s=%s", keys(var.default_tags), values(var.default_tags))), + "REGION" = var.region, + "ACCOUNT_ID" = var.aws_account_id + "S3_PUBLIC_KEYS_BUCKET_NAME" = module.s3bucket_public_signing_keys.bucket } } @@ -85,4 +86,18 @@ data "aws_iam_policy_document" "lambda_jwks_key_rotation" { "arn:aws:ssm:${var.region}:${var.aws_account_id}:parameter${local.ssm_key_directory_name}" ] } + + statement { + sid = "AllowS3PublicSigningKeysWrite" + effect = "Allow" + + actions = [ + "s3:PutObject", + "s3:PutObjectVersion", + "s3:PutObjectTagging", + "s3:PutObjectVersionTagging", + ] + + resources = ["${module.s3bucket_public_signing_keys.arn}/*"] + } } diff --git a/lambdas/jwks-key-rotation/package.json b/lambdas/jwks-key-rotation/package.json index 9a4e36f2..265f77f4 100644 --- a/lambdas/jwks-key-rotation/package.json +++ b/lambdas/jwks-key-rotation/package.json @@ -21,6 +21,7 @@ }, "dependencies": { "@aws-sdk/client-kms": "^3.782.0", + "@aws-sdk/client-s3": "^3.787.0", "@aws-sdk/client-ssm": "^3.782.0", "@types/node-jose": "^1.1.13", "winston": "^3.14.2", diff --git a/lambdas/jwks-key-rotation/src/handler.ts b/lambdas/jwks-key-rotation/src/handler.ts index dcd90425..f06ae34b 100644 --- a/lambdas/jwks-key-rotation/src/handler.ts +++ b/lambdas/jwks-key-rotation/src/handler.ts @@ -3,12 +3,15 @@ import { logger } from './utils/logger'; import { getKeyDirectory, SigningKeyDirectory, + writeKeyDirectory, } from './utils/key-directory-repository'; -import { createPublicKey } from 'node:crypto'; -import { JWK } from 'node-jose'; -import { generateKey, getPublicKey } from './utils/key-util'; - -const algorithm = 'RS512'; +import { + generateJwksFormat, + generateKey, + getPublicKey, +} from './utils/key-util'; +import { updateJwksFile } from './utils/jwks-util'; +import { deleteKey } from './utils/aws/kms-util'; const keyLifetimeDays = Number.parseInt(process.env.KEY_LIFETIME_DAYS ?? '28'); const keyLifetimeMillis = keyLifetimeDays * 24 * 60 * 60 * 1000; @@ -29,46 +32,29 @@ function getKeysToDelete( ); } -async function generateJwksFormat( - keyId: string, - publicKeyBytes: Uint8Array -): Promise { - const base64EncodedPublicKey = Buffer.from(publicKeyBytes).toString('base64'); - const pemFormat = `-----BEGIN PUBLIC KEY-----\n${base64EncodedPublicKey - .match(/(.{1,64})/g)!! - .join('\n')}\n-----END PUBLIC KEY-----`; - - const key = createPublicKey(pemFormat); - - const joseKey = await JWK.asKey( - key.export({ - type: 'spki', - format: 'pem', - }), - 'pem' - ); - - const publicKeyJwks = { - ...joseKey.toJSON(), - use: 'sig', - alg: algorithm, - kid: keyId, - }; - - return publicKeyJwks; +function buildPublicKeyMap( + publicKeys: Array<{ keyId: string; publicKey?: Uint8Array }> +) { + return publicKeys + .filter((publicKeyMetadata) => !!publicKeyMetadata.publicKey) + .reduce( + (acc, publicKeyMetadata) => { + acc[publicKeyMetadata.keyId] = publicKeyMetadata.publicKey!; + return acc; + }, + {} as Record + ); } export const handler: ScheduledHandler = async () => { // Get the existing key directory const keyDirectory = await getKeyDirectory(); - logger.info(keyDirectory); // Dertermine which keys we should remove const keysToDelete = getKeysToDelete(keyDirectory); const keyIdsToDelete = new Set( keysToDelete.map((keyMetadata) => keyMetadata.kid) ); - logger.info(keysToDelete); // Start creating new directory of remaining keys let newKeyDirectory = keyDirectory.filter( @@ -81,41 +67,33 @@ export const handler: ScheduledHandler = async () => { createdDate: formattedDate(), kid: keyId, }); - logger.info(keyId); - logger.info(newKeyDirectory); // Get the public keys const publicKeys = await Promise.all( newKeyDirectory.map((keyMetadata) => getPublicKey(keyMetadata.kid)) ); - logger.info(publicKeys); // Make sure that the directory stays in sync with the KMS keys (i.e. remove any that may have been manually removed) - const validPublicKeyMap = publicKeys - .filter((publicKeyMetadata) => !!publicKeyMetadata.publicKey) - .reduce( - (acc, publicKeyMetadata) => { - acc[publicKeyMetadata.keyId] = publicKeyMetadata.publicKey!; - return acc; - }, - {} as Record - ); - + const validPublicKeyMap = buildPublicKeyMap(publicKeys); newKeyDirectory = newKeyDirectory.filter( (keyMetadata) => !!validPublicKeyMap[keyMetadata.kid] ); // Generate new public key file - const publicKeysArray = await newKeyDirectory.map((keyMetadata) => { - const publicKeyBytes = validPublicKeyMap[keyMetadata.kid]; - return generateJwksFormat(keyMetadata.kid, publicKeyBytes); - }); - - logger.info('Generated public keys', { publicKeysArray }); + const publicKeysArray: Array<{ keyId: string; publicKey: Uint8Array }> = + newKeyDirectory.map((keyMetadata) => ({ + keyId: keyMetadata.kid, + publicKey: validPublicKeyMap[keyMetadata.kid], + })); // Write public key file to S3 + await updateJwksFile(publicKeysArray); // Update Key directory + await writeKeyDirectory(newKeyDirectory); // Delete old keys + await Promise.all( + keysToDelete.map((keyMetaData) => deleteKey(keyMetaData.kid)) + ); }; diff --git a/lambdas/jwks-key-rotation/src/utils/kms-util.ts b/lambdas/jwks-key-rotation/src/utils/aws/kms-util.ts similarity index 60% rename from lambdas/jwks-key-rotation/src/utils/kms-util.ts rename to lambdas/jwks-key-rotation/src/utils/aws/kms-util.ts index 375abdae..d2bc3273 100644 --- a/lambdas/jwks-key-rotation/src/utils/kms-util.ts +++ b/lambdas/jwks-key-rotation/src/utils/aws/kms-util.ts @@ -2,8 +2,9 @@ import { CreateKeyCommand, GetPublicKeyCommand, KMSClient, + ScheduleKeyDeletionCommand, } from '@aws-sdk/client-kms'; -import { logger } from './logger'; +import { logger } from '../logger'; const kmsClient = new KMSClient({ region: process.env.REGION, @@ -13,17 +14,21 @@ const kmsClient = new KMSClient({ export async function createKmsKey(input: CreateKeyCommand): Promise { const result = await kmsClient.send(input); + const keyId = result.KeyMetadata?.KeyId; - if (!result.KeyMetadata?.KeyId) { + if (!keyId) { logger.error(result); throw new Error('Failed to create key'); } - return result.KeyMetadata?.KeyId; + + logger.info(`Created key ${keyId}`); + return keyId; } -export async function getKmsPublicKey(keyId: string): Promise { +export async function getKmsPublicKey( + keyId: string +): Promise { const keyArn = `arn:aws:kms:${process.env.REGION}:${process.env.ACCOUNT_ID}:key/${keyId}`; - logger.info(keyArn); const result = await kmsClient.send( new GetPublicKeyCommand({ @@ -34,6 +39,15 @@ export async function getKmsPublicKey(keyId: string): Promise { + logger.info(`Deleting key ${keyId}`); + + await kmsClient.send( + new ScheduleKeyDeletionCommand({ + KeyId: keyId, + }) + ); +} diff --git a/lambdas/jwks-key-rotation/src/utils/aws/s3-util.ts b/lambdas/jwks-key-rotation/src/utils/aws/s3-util.ts new file mode 100644 index 00000000..98f1a642 --- /dev/null +++ b/lambdas/jwks-key-rotation/src/utils/aws/s3-util.ts @@ -0,0 +1,33 @@ +import { + PutObjectCommand, + PutObjectCommandOutput, + S3Client, +} from '@aws-sdk/client-s3'; +import { logger } from '../logger'; + +const s3Client = new S3Client({ + region: process.env.REGION, + retryMode: 'standard', + maxAttempts: 10, +}); + +export async function writeJsonToFile( + path: string, + content: string, + bucket = '' +): Promise { + if (!bucket) { + throw new Error('Missing bucket'); + } + + logger.info(`Writing to ${path}, in bucket ${bucket}`); + + return s3Client.send( + new PutObjectCommand({ + Bucket: bucket, + Key: path, + Body: content, + ContentType: 'application/json', + }) + ); +} diff --git a/lambdas/jwks-key-rotation/src/utils/ssm-util.ts b/lambdas/jwks-key-rotation/src/utils/aws/ssm-util.ts similarity index 51% rename from lambdas/jwks-key-rotation/src/utils/ssm-util.ts rename to lambdas/jwks-key-rotation/src/utils/aws/ssm-util.ts index 5ba37faf..3ecdb1e7 100644 --- a/lambdas/jwks-key-rotation/src/utils/ssm-util.ts +++ b/lambdas/jwks-key-rotation/src/utils/aws/ssm-util.ts @@ -1,8 +1,11 @@ import { GetParameterCommand, GetParameterCommandOutput, + PutParameterCommand, + PutParameterCommandOutput, SSMClient, } from '@aws-sdk/client-ssm'; +import { logger } from '../logger'; const ssmClient = new SSMClient({ region: process.env.REGION, @@ -23,3 +26,22 @@ export async function getParameter( }) ); } + +export async function putParameter( + value: string, + name = '' +): Promise { + if (!name) { + throw new Error('Missing parameter name'); + } + + logger.info(`Updating parameter ${name}`); + + return ssmClient.send( + new PutParameterCommand({ + Name: name, + Value: value, + Overwrite: true + }) + ); +} diff --git a/lambdas/jwks-key-rotation/src/utils/aws-utils.ts b/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts similarity index 100% rename from lambdas/jwks-key-rotation/src/utils/aws-utils.ts rename to lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts diff --git a/lambdas/jwks-key-rotation/src/utils/jwks-util.ts b/lambdas/jwks-key-rotation/src/utils/jwks-util.ts new file mode 100644 index 00000000..da41b0b3 --- /dev/null +++ b/lambdas/jwks-key-rotation/src/utils/jwks-util.ts @@ -0,0 +1,50 @@ +import { createPublicKey } from 'node:crypto'; +import { JWK } from 'node-jose'; +import { writeJsonToFile } from './aws/s3-util'; +import { logger } from './logger'; + +const ALGORITHM_RSA_512 = 'RS512'; +const KEY_USE_SIGNING = 'sig'; + +export async function generateJwksFormat( + keyId: string, + publicKey: Uint8Array +): Promise { + const base64EncodedPublicKey = Buffer.from(publicKey).toString('base64'); + const pemFormat = `-----BEGIN PUBLIC KEY-----\n${base64EncodedPublicKey + .match(/(.{1,64})/g)!! + .join('\n')}\n-----END PUBLIC KEY-----`; + + const key = createPublicKey(pemFormat); + + const joseKey = await JWK.asKey( + key.export({ + type: 'spki', + format: 'pem', + }), + 'pem' + ); + + const publicKeyJwks = { + ...joseKey.toJSON(), + use: KEY_USE_SIGNING, + alg: ALGORITHM_RSA_512, + kid: keyId, + }; + + return publicKeyJwks; +} + +export async function updateJwksFile( + publicKeys: Array<{ keyId: string; publicKey: Uint8Array }> +): Promise { + const publicKeysArray = await Promise.all( + publicKeys.map((keyMetadata) => + generateJwksFormat(keyMetadata.keyId, keyMetadata.publicKey) + ) + ); + + const jwksFileContents = JSON.stringify(publicKeysArray); + logger.info(`Generated JWKS file content with ${publicKeysArray.length} public keys`); + await writeJsonToFile('jwks', jwksFileContents, process.env.S3_PUBLIC_KEYS_BUCKET_NAME); +} diff --git a/lambdas/jwks-key-rotation/src/utils/key-directory-repository.ts b/lambdas/jwks-key-rotation/src/utils/key-directory-repository.ts index 414912f3..6c4e9305 100644 --- a/lambdas/jwks-key-rotation/src/utils/key-directory-repository.ts +++ b/lambdas/jwks-key-rotation/src/utils/key-directory-repository.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; import { logger } from './logger'; -import { getParameter } from './ssm-util'; +import { getParameter, putParameter } from './aws/ssm-util'; const schemaFor = () => @@ -41,3 +41,13 @@ export async function getKeyDirectory(): Promise { } return parseResult.data; } + +export async function writeKeyDirectory( + keyDirectory: SigningKeyDirectory +): Promise { + logger.info(`Storing key directory with ${keyDirectory.length} keys`); + await putParameter( + JSON.stringify(keyDirectory), + process.env.SSM_KEY_DIRECTORY_NAME + ); +} diff --git a/lambdas/jwks-key-rotation/src/utils/key-util.ts b/lambdas/jwks-key-rotation/src/utils/key-util.ts index 0a4e2f58..104af075 100644 --- a/lambdas/jwks-key-rotation/src/utils/key-util.ts +++ b/lambdas/jwks-key-rotation/src/utils/key-util.ts @@ -2,13 +2,17 @@ import { CreateKeyCommand, KeySpec, KeyUsageType, + KMSInvalidStateException, + KMSServiceException, NotFoundException, } from '@aws-sdk/client-kms'; -import { getKeyTags } from './aws-utils'; -import { createKmsKey, getKmsPublicKey } from './kms-util'; -import { getParameter } from './ssm-util'; +import { getKeyTags } from './aws/tag-util'; +import { createKmsKey, getKmsPublicKey } from './aws/kms-util'; +import { getParameter } from './aws/ssm-util'; import { logger } from './logger'; +const NO_OP_ERRORS = [NotFoundException, KMSInvalidStateException]; + async function getKeyPolicy(): Promise { const ssmResult = await getParameter(process.env.SSM_ASYMMETRIC_KEY_POLICY); if (!ssmResult.Parameter?.Value) { @@ -40,10 +44,11 @@ export async function getPublicKey( keyId: string ): Promise<{ keyId: string; publicKey?: Uint8Array }> { const publicKey = await getKmsPublicKey(keyId).catch((err) => { - if (err instanceof NotFoundException) { + if (NO_OP_ERRORS.findIndex((errorType) => err instanceof errorType) > -1) { logger.warn(`Key not found: ${keyId}`); return undefined; } + throw err; }); diff --git a/package-lock.json b/package-lock.json index 69f46984..56cdff9b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -115,6 +115,7 @@ "lambdas/jwks-key-rotation": { "dependencies": { "@aws-sdk/client-kms": "^3.782.0", + "@aws-sdk/client-s3": "^3.787.0", "@aws-sdk/client-ssm": "^3.782.0", "@types/node-jose": "^1.1.13", "winston": "^3.14.2", @@ -133,11 +134,533 @@ "typescript": "^5.8.2" } }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/client-s3": { + "version": "3.787.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.787.0.tgz", + "integrity": "sha512-eGLCWkN0NlntJ9yPU6OKUggVS4cFvuZJog+cFg1KD5hniLqz7Y0YRtB4uBxW212fK3XCfddgyscEOEeHaTQQTw==", + "dependencies": { + "@aws-crypto/sha1-browser": "5.2.0", + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.775.0", + "@aws-sdk/credential-provider-node": "3.787.0", + "@aws-sdk/middleware-bucket-endpoint": "3.775.0", + "@aws-sdk/middleware-expect-continue": "3.775.0", + "@aws-sdk/middleware-flexible-checksums": "3.787.0", + "@aws-sdk/middleware-host-header": "3.775.0", + "@aws-sdk/middleware-location-constraint": "3.775.0", + "@aws-sdk/middleware-logger": "3.775.0", + "@aws-sdk/middleware-recursion-detection": "3.775.0", + "@aws-sdk/middleware-sdk-s3": "3.775.0", + "@aws-sdk/middleware-ssec": "3.775.0", + "@aws-sdk/middleware-user-agent": "3.787.0", + "@aws-sdk/region-config-resolver": "3.775.0", + "@aws-sdk/signature-v4-multi-region": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@aws-sdk/util-endpoints": "3.787.0", + "@aws-sdk/util-user-agent-browser": "3.775.0", + "@aws-sdk/util-user-agent-node": "3.787.0", + "@aws-sdk/xml-builder": "3.775.0", + "@smithy/config-resolver": "^4.1.0", + "@smithy/core": "^3.2.0", + "@smithy/eventstream-serde-browser": "^4.0.2", + "@smithy/eventstream-serde-config-resolver": "^4.1.0", + "@smithy/eventstream-serde-node": "^4.0.2", + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/hash-blob-browser": "^4.0.2", + "@smithy/hash-node": "^4.0.2", + "@smithy/hash-stream-node": "^4.0.2", + "@smithy/invalid-dependency": "^4.0.2", + "@smithy/md5-js": "^4.0.2", + "@smithy/middleware-content-length": "^4.0.2", + "@smithy/middleware-endpoint": "^4.1.0", + "@smithy/middleware-retry": "^4.1.0", + "@smithy/middleware-serde": "^4.0.3", + "@smithy/middleware-stack": "^4.0.2", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/protocol-http": "^5.1.0", + "@smithy/smithy-client": "^4.2.0", + "@smithy/types": "^4.2.0", + "@smithy/url-parser": "^4.0.2", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.8", + "@smithy/util-defaults-mode-node": "^4.0.8", + "@smithy/util-endpoints": "^3.0.2", + "@smithy/util-middleware": "^4.0.2", + "@smithy/util-retry": "^4.0.2", + "@smithy/util-stream": "^4.2.0", + "@smithy/util-utf8": "^4.0.0", + "@smithy/util-waiter": "^4.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/client-sso": { + "version": "3.787.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.787.0.tgz", + "integrity": "sha512-L8R+Mh258G0DC73ktpSVrG4TT9i2vmDLecARTDR/4q5sRivdDQSL5bUp3LKcK80Bx+FRw3UETIlX6mYMLL9PJQ==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.775.0", + "@aws-sdk/middleware-host-header": "3.775.0", + "@aws-sdk/middleware-logger": "3.775.0", + "@aws-sdk/middleware-recursion-detection": "3.775.0", + "@aws-sdk/middleware-user-agent": "3.787.0", + "@aws-sdk/region-config-resolver": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@aws-sdk/util-endpoints": "3.787.0", + "@aws-sdk/util-user-agent-browser": "3.775.0", + "@aws-sdk/util-user-agent-node": "3.787.0", + "@smithy/config-resolver": "^4.1.0", + "@smithy/core": "^3.2.0", + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/hash-node": "^4.0.2", + "@smithy/invalid-dependency": "^4.0.2", + "@smithy/middleware-content-length": "^4.0.2", + "@smithy/middleware-endpoint": "^4.1.0", + "@smithy/middleware-retry": "^4.1.0", + "@smithy/middleware-serde": "^4.0.3", + "@smithy/middleware-stack": "^4.0.2", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/protocol-http": "^5.1.0", + "@smithy/smithy-client": "^4.2.0", + "@smithy/types": "^4.2.0", + "@smithy/url-parser": "^4.0.2", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.8", + "@smithy/util-defaults-mode-node": "^4.0.8", + "@smithy/util-endpoints": "^3.0.2", + "@smithy/util-middleware": "^4.0.2", + "@smithy/util-retry": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/core": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.775.0.tgz", + "integrity": "sha512-8vpW4WihVfz0DX+7WnnLGm3GuQER++b0IwQG35JlQMlgqnc44M//KbJPsIHA0aJUJVwJAEShgfr5dUbY8WUzaA==", + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/core": "^3.2.0", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/property-provider": "^4.0.2", + "@smithy/protocol-http": "^5.1.0", + "@smithy/signature-v4": "^5.0.2", + "@smithy/smithy-client": "^4.2.0", + "@smithy/types": "^4.2.0", + "@smithy/util-middleware": "^4.0.2", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.775.0.tgz", + "integrity": "sha512-6ESVxwCbGm7WZ17kY1fjmxQud43vzJFoLd4bmlR+idQSWdqlzGDYdcfzpjDKTcivdtNrVYmFvcH1JBUwCRAZhw==", + "dependencies": { + "@aws-sdk/core": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.775.0.tgz", + "integrity": "sha512-PjDQeDH/J1S0yWV32wCj2k5liRo0ssXMseCBEkCsD3SqsU8o5cU82b0hMX4sAib/RkglCSZqGO0xMiN0/7ndww==", + "dependencies": { + "@aws-sdk/core": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/property-provider": "^4.0.2", + "@smithy/protocol-http": "^5.1.0", + "@smithy/smithy-client": "^4.2.0", + "@smithy/types": "^4.2.0", + "@smithy/util-stream": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.787.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.787.0.tgz", + "integrity": "sha512-hc2taRoDlXn2uuNuHWDJljVWYrp3r9JF1a/8XmOAZhVUNY+ImeeStylHXhXXKEA4JOjW+5PdJj0f1UDkVCHJiQ==", + "dependencies": { + "@aws-sdk/core": "3.775.0", + "@aws-sdk/credential-provider-env": "3.775.0", + "@aws-sdk/credential-provider-http": "3.775.0", + "@aws-sdk/credential-provider-process": "3.775.0", + "@aws-sdk/credential-provider-sso": "3.787.0", + "@aws-sdk/credential-provider-web-identity": "3.787.0", + "@aws-sdk/nested-clients": "3.787.0", + "@aws-sdk/types": "3.775.0", + "@smithy/credential-provider-imds": "^4.0.2", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.787.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.787.0.tgz", + "integrity": "sha512-JioVi44B1vDMaK2CdzqimwvJD3uzvzbQhaEWXsGMBcMcNHajXAXf08EF50JG3ZhLrhhUsT1ObXpbTaPINOhh+g==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.775.0", + "@aws-sdk/credential-provider-http": "3.775.0", + "@aws-sdk/credential-provider-ini": "3.787.0", + "@aws-sdk/credential-provider-process": "3.775.0", + "@aws-sdk/credential-provider-sso": "3.787.0", + "@aws-sdk/credential-provider-web-identity": "3.787.0", + "@aws-sdk/types": "3.775.0", + "@smithy/credential-provider-imds": "^4.0.2", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.775.0.tgz", + "integrity": "sha512-A6k68H9rQp+2+7P7SGO90Csw6nrUEm0Qfjpn9Etc4EboZhhCLs9b66umUsTsSBHus4FDIe5JQxfCUyt1wgNogg==", + "dependencies": { + "@aws-sdk/core": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.787.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.787.0.tgz", + "integrity": "sha512-fHc08bsvwm4+dEMEQKnQ7c1irEQmmxbgS+Fq41y09pPvPh31nAhoMcjBSTWAaPHvvsRbTYvmP4Mf12ZGr8/nfg==", + "dependencies": { + "@aws-sdk/client-sso": "3.787.0", + "@aws-sdk/core": "3.775.0", + "@aws-sdk/token-providers": "3.787.0", + "@aws-sdk/types": "3.775.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.787.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.787.0.tgz", + "integrity": "sha512-SobmCwNbk6TfEsF283mZPQEI5vV2j6eY5tOCj8Er4Lzraxu9fBPADV+Bib2A8F6jlB1lMPJzOuDCbEasSt/RIw==", + "dependencies": { + "@aws-sdk/core": "3.775.0", + "@aws-sdk/nested-clients": "3.787.0", + "@aws-sdk/types": "3.775.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/middleware-bucket-endpoint": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.775.0.tgz", + "integrity": "sha512-qogMIpVChDYr4xiUNC19/RDSw/sKoHkAhouS6Skxiy6s27HBhow1L3Z1qVYXuBmOZGSWPU0xiyZCvOyWrv9s+Q==", + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@aws-sdk/util-arn-parser": "3.723.0", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", + "@smithy/util-config-provider": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/middleware-expect-continue": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.775.0.tgz", + "integrity": "sha512-Apd3owkIeUW5dnk3au9np2IdW2N0zc9NjTjHiH+Mx3zqwSrc+m+ANgJVgk9mnQjMzU/vb7VuxJ0eqdEbp5gYsg==", + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/middleware-flexible-checksums": { + "version": "3.787.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.787.0.tgz", + "integrity": "sha512-X71qEwWoixFmwowWzlPoZUR3u1CWJ7iAzU0EzIxqmPhQpQJLFmdL1+SRjqATynDPZQzLs1a5HBtPT++EnZ+Quw==", + "dependencies": { + "@aws-crypto/crc32": "5.2.0", + "@aws-crypto/crc32c": "5.2.0", + "@aws-crypto/util": "5.2.0", + "@aws-sdk/core": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@smithy/is-array-buffer": "^4.0.0", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", + "@smithy/util-middleware": "^4.0.2", + "@smithy/util-stream": "^4.2.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.775.0.tgz", + "integrity": "sha512-tkSegM0Z6WMXpLB8oPys/d+umYIocvO298mGvcMCncpRl77L9XkvSLJIFzaHes+o7djAgIduYw8wKIMStFss2w==", + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/middleware-location-constraint": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.775.0.tgz", + "integrity": "sha512-8TMXEHZXZTFTckQLyBT5aEI8fX11HZcwZseRifvBKKpj0RZDk4F0EEYGxeNSPpUQ7n+PRWyfAEnnZNRdAj/1NQ==", + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/middleware-logger": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.775.0.tgz", + "integrity": "sha512-FaxO1xom4MAoUJsldmR92nT1G6uZxTdNYOFYtdHfd6N2wcNaTuxgjIvqzg5y7QIH9kn58XX/dzf1iTjgqUStZw==", + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.775.0.tgz", + "integrity": "sha512-GLCzC8D0A0YDG5u3F5U03Vb9j5tcOEFhr8oc6PDk0k0vm5VwtZOE6LvK7hcCSoAB4HXyOUM0sQuXrbaAh9OwXA==", + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/middleware-sdk-s3": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.775.0.tgz", + "integrity": "sha512-zsvcu7cWB28JJ60gVvjxPCI7ZU7jWGcpNACPiZGyVtjYXwcxyhXbYEVDSWKsSA6ERpz9XrpLYod8INQWfW3ECg==", + "dependencies": { + "@aws-sdk/core": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@aws-sdk/util-arn-parser": "3.723.0", + "@smithy/core": "^3.2.0", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/protocol-http": "^5.1.0", + "@smithy/signature-v4": "^5.0.2", + "@smithy/smithy-client": "^4.2.0", + "@smithy/types": "^4.2.0", + "@smithy/util-config-provider": "^4.0.0", + "@smithy/util-middleware": "^4.0.2", + "@smithy/util-stream": "^4.2.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/middleware-ssec": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.775.0.tgz", + "integrity": "sha512-Iw1RHD8vfAWWPzBBIKaojO4GAvQkHOYIpKdAfis/EUSUmSa79QsnXnRqsdcE0mCB0Ylj23yi+ah4/0wh9FsekA==", + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.787.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.787.0.tgz", + "integrity": "sha512-Lnfj8SmPLYtrDFthNIaNj66zZsBCam+E4XiUDr55DIHTGstH6qZ/q6vg0GfbukxwSmUcGMwSR4Qbn8rb8yd77g==", + "dependencies": { + "@aws-sdk/core": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@aws-sdk/util-endpoints": "3.787.0", + "@smithy/core": "^3.2.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/nested-clients": { + "version": "3.787.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.787.0.tgz", + "integrity": "sha512-xk03q1xpKNHgbuo+trEf1dFrI239kuMmjKKsqLEsHlAZbuFq4yRGMlHBrVMnKYOPBhVFDS/VineM991XI52fKg==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.775.0", + "@aws-sdk/middleware-host-header": "3.775.0", + "@aws-sdk/middleware-logger": "3.775.0", + "@aws-sdk/middleware-recursion-detection": "3.775.0", + "@aws-sdk/middleware-user-agent": "3.787.0", + "@aws-sdk/region-config-resolver": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@aws-sdk/util-endpoints": "3.787.0", + "@aws-sdk/util-user-agent-browser": "3.775.0", + "@aws-sdk/util-user-agent-node": "3.787.0", + "@smithy/config-resolver": "^4.1.0", + "@smithy/core": "^3.2.0", + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/hash-node": "^4.0.2", + "@smithy/invalid-dependency": "^4.0.2", + "@smithy/middleware-content-length": "^4.0.2", + "@smithy/middleware-endpoint": "^4.1.0", + "@smithy/middleware-retry": "^4.1.0", + "@smithy/middleware-serde": "^4.0.3", + "@smithy/middleware-stack": "^4.0.2", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/protocol-http": "^5.1.0", + "@smithy/smithy-client": "^4.2.0", + "@smithy/types": "^4.2.0", + "@smithy/url-parser": "^4.0.2", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.8", + "@smithy/util-defaults-mode-node": "^4.0.8", + "@smithy/util-endpoints": "^3.0.2", + "@smithy/util-middleware": "^4.0.2", + "@smithy/util-retry": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.775.0.tgz", + "integrity": "sha512-40iH3LJjrQS3LKUJAl7Wj0bln7RFPEvUYKFxtP8a+oKFDO0F65F52xZxIJbPn6sHkxWDAnZlGgdjZXM3p2g5wQ==", + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/types": "^4.2.0", + "@smithy/util-config-provider": "^4.0.0", + "@smithy/util-middleware": "^4.0.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.775.0.tgz", + "integrity": "sha512-cnGk8GDfTMJ8p7+qSk92QlIk2bmTmFJqhYxcXZ9PysjZtx0xmfCMxnG3Hjy1oU2mt5boPCVSOptqtWixayM17g==", + "dependencies": { + "@aws-sdk/middleware-sdk-s3": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/signature-v4": "^5.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/token-providers": { + "version": "3.787.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.787.0.tgz", + "integrity": "sha512-d7/NIqxq308Zg0RPMNrmn0QvzniL4Hx8Qdwzr6YZWLYAbUSvZYS2ppLR3BFWSkV6SsTJUx8BuDaj3P8vttkrog==", + "dependencies": { + "@aws-sdk/nested-clients": "3.787.0", + "@aws-sdk/types": "3.775.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "lambdas/jwks-key-rotation/node_modules/@aws-sdk/types": { "version": "3.775.0", "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.775.0.tgz", "integrity": "sha512-ZoGKwa4C9fC9Av6bdfqcW6Ix5ot05F/S4VxWR2nHuMv7hzfmAjTOcUiWT7UR4hM/U0whf84VhDtXN/DWAk52KA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.2.0", @@ -147,11 +670,175 @@ "node": ">=18.0.0" } }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/util-endpoints": { + "version": "3.787.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.787.0.tgz", + "integrity": "sha512-fd3zkiOkwnbdbN0Xp9TsP5SWrmv0SpT70YEdbb8wAj2DWQwiCmFszaSs+YCvhoCdmlR3Wl9Spu0pGpSAGKeYvQ==", + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/types": "^4.2.0", + "@smithy/util-endpoints": "^3.0.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.775.0.tgz", + "integrity": "sha512-txw2wkiJmZKVdDbscK7VBK+u+TJnRtlUjRTLei+elZg2ADhpQxfVAQl436FUeIv6AhB/oRHW6/K/EAGXUSWi0A==", + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/types": "^4.2.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.787.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.787.0.tgz", + "integrity": "sha512-mG7Lz8ydfG4SF9e8WSXiPQ/Lsn3n8A5B5jtPROidafi06I3ckV2WxyMLdwG14m919NoS6IOfWHyRGSqWIwbVKA==", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.787.0", + "@aws-sdk/types": "3.775.0", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "lambdas/jwks-key-rotation/node_modules/@aws-sdk/xml-builder": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.775.0.tgz", + "integrity": "sha512-b9NGO6FKJeLGYnV7Z1yvcP1TNU4dkD5jNsLWOF1/sygZoASaQhNOlaiJ/1OH331YQ1R1oWk38nBb0frsYkDsOQ==", + "dependencies": { + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@smithy/eventstream-codec": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.0.2.tgz", + "integrity": "sha512-p+f2kLSK7ZrXVfskU/f5dzksKTewZk8pJLPvER3aFHPt76C2MxD9vNatSfLzzQSQB4FNO96RK4PSXfhD1TTeMQ==", + "dependencies": { + "@aws-crypto/crc32": "5.2.0", + "@smithy/types": "^4.2.0", + "@smithy/util-hex-encoding": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@smithy/eventstream-serde-browser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.0.2.tgz", + "integrity": "sha512-CepZCDs2xgVUtH7ZZ7oDdZFH8e6Y2zOv8iiX6RhndH69nlojCALSKK+OXwZUgOtUZEUaZ5e1hULVCHYbCn7pug==", + "dependencies": { + "@smithy/eventstream-serde-universal": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@smithy/eventstream-serde-config-resolver": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.1.0.tgz", + "integrity": "sha512-1PI+WPZ5TWXrfj3CIoKyUycYynYJgZjuQo8U+sphneOtjsgrttYybdqESFReQrdWJ+LKt6NEdbYzmmfDBmjX2A==", + "dependencies": { + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@smithy/eventstream-serde-node": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.0.2.tgz", + "integrity": "sha512-C5bJ/C6x9ENPMx2cFOirspnF9ZsBVnBMtP6BdPl/qYSuUawdGQ34Lq0dMcf42QTjUZgWGbUIZnz6+zLxJlb9aw==", + "dependencies": { + "@smithy/eventstream-serde-universal": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@smithy/eventstream-serde-universal": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.0.2.tgz", + "integrity": "sha512-St8h9JqzvnbB52FtckiHPN4U/cnXcarMniXRXTKn0r4b4XesZOGiAyUdj1aXbqqn1icSqBlzzUsCl6nPB018ng==", + "dependencies": { + "@smithy/eventstream-codec": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@smithy/hash-blob-browser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-4.0.2.tgz", + "integrity": "sha512-3g188Z3DyhtzfBRxpZjU8R9PpOQuYsbNnyStc/ZVS+9nVX1f6XeNOa9IrAh35HwwIZg+XWk8bFVtNINVscBP+g==", + "dependencies": { + "@smithy/chunked-blob-reader": "^5.0.0", + "@smithy/chunked-blob-reader-native": "^4.0.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@smithy/hash-stream-node": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-4.0.2.tgz", + "integrity": "sha512-POWDuTznzbIwlEXEvvXoPMS10y0WKXK790soe57tFRfvf4zBHyzE529HpZMqmDdwG9MfFflnyzndUQ8j78ZdSg==", + "dependencies": { + "@smithy/types": "^4.2.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@smithy/md5-js": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-4.0.2.tgz", + "integrity": "sha512-Hc0R8EiuVunUewCse2syVgA2AfSRco3LyAv07B/zCOMa+jpXI9ll+Q21Nc6FAlYPcpNcAXqBzMhNs1CD/pP2bA==", + "dependencies": { + "@smithy/types": "^4.2.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "lambdas/jwks-key-rotation/node_modules/@smithy/types": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", - "dev": true, "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -160,6 +847,29 @@ "node": ">=18.0.0" } }, + "lambdas/jwks-key-rotation/node_modules/@smithy/util-hex-encoding": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz", + "integrity": "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/jwks-key-rotation/node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "lambdas/jwks-key-rotation/node_modules/@types/node": { "version": "22.14.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.0.tgz", From 3745bb23ba8499608b9c4cf9a5a4137f7f65f597 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Wed, 23 Apr 2025 14:26:10 +0100 Subject: [PATCH 11/54] CCM-8897: unit tests --- lambdas/jwks-key-rotation/.eslintrc.json | 33 +----------- lambdas/jwks-key-rotation/jest.config.ts | 7 +++ lambdas/jwks-key-rotation/package.json | 5 +- .../src/__tests__/utils/jwks-util.test.ts | 51 ++++++++++++++++++ .../src/__tests__/utils/test-public-key-1.der | Bin 0 -> 550 bytes .../src/__tests__/utils/test-public-key-2.der | Bin 0 -> 550 bytes .../src/__tests__/utils/test-public-key.jwks | 18 +++++++ lambdas/jwks-key-rotation/src/handler.ts | 13 +++-- .../src/utils/aws/kms-util.ts | 2 +- .../src/utils/aws/ssm-util.ts | 2 +- .../src/utils/aws/tag-util.ts | 2 +- .../jwks-key-rotation/src/utils/jwks-util.ts | 16 ++++-- .../jwks-key-rotation/src/utils/key-util.ts | 9 ++-- lambdas/jwks-key-rotation/tsconfig.json | 10 +++- 14 files changed, 114 insertions(+), 54 deletions(-) create mode 100644 lambdas/jwks-key-rotation/src/__tests__/utils/jwks-util.test.ts create mode 100644 lambdas/jwks-key-rotation/src/__tests__/utils/test-public-key-1.der create mode 100644 lambdas/jwks-key-rotation/src/__tests__/utils/test-public-key-2.der create mode 100644 lambdas/jwks-key-rotation/src/__tests__/utils/test-public-key.jwks diff --git a/lambdas/jwks-key-rotation/.eslintrc.json b/lambdas/jwks-key-rotation/.eslintrc.json index 4218c6ab..21758ea0 100644 --- a/lambdas/jwks-key-rotation/.eslintrc.json +++ b/lambdas/jwks-key-rotation/.eslintrc.json @@ -1,34 +1,5 @@ { "extends": [ - "airbnb", - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "plugin:jest/recommended", - "plugin:jsx-a11y/recommended", - "plugin:prettier/recommended", - "plugin:security/recommended-legacy", - "plugin:sonarjs/recommended-legacy", - "plugin:unicorn/recommended" - ], - "plugins": [ - "@typescript-eslint", - "html", - "import", - "jest", - "jsx-a11y", - "prettier", - "security", - "sonarjs", - "unicorn" - ], - "rules": { - "import/extensions": "off", - "import/prefer-default-export": "off", - "@next/next/no-html-link-for-pages": "off" - }, - "settings": { - "import/resolver": { - "typescript": {} // this loads /tsconfig.json to eslint - } - } + "../../.eslintrc" + ] } diff --git a/lambdas/jwks-key-rotation/jest.config.ts b/lambdas/jwks-key-rotation/jest.config.ts index 246436d9..a3b6b0ce 100644 --- a/lambdas/jwks-key-rotation/jest.config.ts +++ b/lambdas/jwks-key-rotation/jest.config.ts @@ -4,6 +4,8 @@ */ import type { Config } from 'jest'; +import { pathsToModuleNameMapper } from 'ts-jest'; +import { compilerOptions } from './tsconfig.json'; const config: Config = { preset: 'ts-jest', @@ -31,6 +33,11 @@ const config: Config = { collectCoverageFrom: ['src/**/*.ts*'], + // Set the absolute path for imports + moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { + prefix: '/', + }), + // Use this configuration option to add custom reporters to Jest reporters: [ 'default', diff --git a/lambdas/jwks-key-rotation/package.json b/lambdas/jwks-key-rotation/package.json index 265f77f4..25510ebf 100644 --- a/lambdas/jwks-key-rotation/package.json +++ b/lambdas/jwks-key-rotation/package.json @@ -2,7 +2,8 @@ "name": "jwks-key-rotation", "main": "handler.ts", "scripts": { - "lint": "eslint .", + "lint": "eslint ./src", + "lint:fix": "eslint ./src --fix", "test:unit": "jest", "build-lambda": "rm -rf dist && npx esbuild --bundle --minify --sourcemap --target=es2020 --platform=node --entry-names=[name] --outdir=dist src/handler.ts" }, @@ -27,4 +28,4 @@ "winston": "^3.14.2", "zod": "^3.24.2" } -} +} \ No newline at end of file diff --git a/lambdas/jwks-key-rotation/src/__tests__/utils/jwks-util.test.ts b/lambdas/jwks-key-rotation/src/__tests__/utils/jwks-util.test.ts new file mode 100644 index 00000000..d3031f94 --- /dev/null +++ b/lambdas/jwks-key-rotation/src/__tests__/utils/jwks-util.test.ts @@ -0,0 +1,51 @@ +import { readFileSync } from 'node:fs'; +import { updateJwksFile } from '../../utils/jwks-util'; +import { writeJsonToFile } from '@/src/utils/aws/s3-util'; + +jest.mock('@/src/utils/aws/s3-util'); + +const TEST_PUBLIC_KEY_FILE_1 = 'src/__tests__/utils/test-public-key-1.der'; +const TEST_PUBLIC_KEY_FILE_2 = 'src/__tests__/utils/test-public-key-2.der'; +const TEST_JWKS_FILE = 'src/__tests__/utils/test-public-key.jwks'; +const MOCK_BUCKET_NAME = + 'nhs-notify-000000000000-eu-west-2-abcd12-sbx-public-keys'; + +describe('jwks-util', () => { + describe('updateJwksFile', () => { + const OLD_ENV = { ...process.env }; + afterAll(() => { + process.env = OLD_ENV; + }); + + test('should generate jwks format public key', async () => { + // arrange + const fileWriteMock = jest.mocked(writeJsonToFile); + + const publicKey1 = readFileSync(TEST_PUBLIC_KEY_FILE_1); + const publicKey2 = readFileSync(TEST_PUBLIC_KEY_FILE_2); + const expectedJwks = JSON.stringify( + JSON.parse(readFileSync(TEST_JWKS_FILE).toString('utf8')) + ); + process.env.S3_PUBLIC_KEYS_BUCKET_NAME = MOCK_BUCKET_NAME; + + // act + await updateJwksFile([ + { + keyId: 'test-key-id-1', + publicKey: publicKey1, + }, + { + keyId: 'test-key-id-2', + publicKey: publicKey2, + }, + ]); + + // assert + expect(fileWriteMock).toHaveBeenCalledWith( + 'jwks', + expectedJwks, + MOCK_BUCKET_NAME + ); + }); + }); +}); diff --git a/lambdas/jwks-key-rotation/src/__tests__/utils/test-public-key-1.der b/lambdas/jwks-key-rotation/src/__tests__/utils/test-public-key-1.der new file mode 100644 index 0000000000000000000000000000000000000000..e1f4d04037e55c94762ba309d21d2bf491d8023b GIT binary patch literal 550 zcmV+>0@?jAf&wBi4F(A+hDe6@4FLfG1potr0uKN%f&vNxf&u{mxx>m^1<8%GmdBrj zZMF4boAY-yL$wATRWBZ2I}SIGxpVBc5T^<21O?Qk?s2CuNwNq5Tt zc=nd96rqoCHMOa^g2rjhgyURk4(<`ToldrT7oQY@;IiBlPzPhd+#hF@G*bvC04dJn z(r6pQs1yx$HUQCxyDP94zU{1=m0DNC7peE#e%s1?N*liRqK#dQ6>zQFtVv?wObFzcEAKM1GmJagzDW%rPYZnmFrqc!3el&u zgFA@2hk`deZ*FJfVpG-^bJ%n0lq<|m}4TqY!xUqnNbN55QA^%3p o&udA=I@R6IFKrgYe+<+gA~<22O_u*{OH`|Y0LQ9F0s{d60YT&Y(f|Me literal 0 HcmV?d00001 diff --git a/lambdas/jwks-key-rotation/src/__tests__/utils/test-public-key-2.der b/lambdas/jwks-key-rotation/src/__tests__/utils/test-public-key-2.der new file mode 100644 index 0000000000000000000000000000000000000000..80e181b16ca2d7a8d0aba312b581db4e363b2283 GIT binary patch literal 550 zcmV+>0@?jAf&wBi4F(A+hDe6@4FLfG1potr0uKN%f&vNxf&u{mwM0WOVQabQt%guO z8L(A3+-N`0pnFIs#!C~l|MPlmU2+MZAR$B+R?2B!-W;5Ye8&`mc}H; z8%xs2kt5NaX`kv{rjSg}vT6TJ?4+A6O30^kFn{*|4jl?$DTP)KdXd%zj4Qtl(z%3VKfMm57Ro8&z{#A=?GByiuS2LJ_JQjx(`i z(7r<5i0=;;RBrMSg!=gZ^F9-_Q#|?wnx=~w456jJ8~E>#ln+4Z%U0BrP8xb3>m!hy zX_3i17+7F9s{BxlRMx_2MX`uM=y^#1IXpHnl%1$SxacN4{H-*#|I1@Fh-<=j;Wf+Z zkqgXTpxx8xObLuTH%nq23g>YOdBc|dJ>CCCjwB}i5&vB5B&^8yB2r_3T2GO`-Qdl) z+ije#aV*57pM4L(j;~2Az4gR`SfWre{ttGuRE(}E3d~&d@3&0HM76_nsHy)rWTNjJ z2!7#SVI%6ps=aodl&(jwWb|hj%nQA0s{d60pU~!UH||9 literal 0 HcmV?d00001 diff --git a/lambdas/jwks-key-rotation/src/__tests__/utils/test-public-key.jwks b/lambdas/jwks-key-rotation/src/__tests__/utils/test-public-key.jwks new file mode 100644 index 00000000..2f903e45 --- /dev/null +++ b/lambdas/jwks-key-rotation/src/__tests__/utils/test-public-key.jwks @@ -0,0 +1,18 @@ +[ + { + "kty": "RSA", + "kid": "test-key-id-1", + "n": "ucPKWwXJjbOWx5-EbbX1YZvzdzVDtQYeVS8eXzsON4-5c-y2EKcJ6wQFjBEJ_T_8llQSCdMKfaIMuZXKjo3uARxDsZh0CDqhBvHVx188cYVxdHvyhwqPh9fLsTx8BZsR069WQ1SX77nfHRpwLzmcZw5MmMw4Y6WdPyNig4dJKdCLPpsLPKsZZGiuCNVFX90HyF6fH2n-xtU0EPvY0hWqv0wm2mTpEvbByWlSnPnfOpKlQZvOAMsMsiRi3SKJdwNPNEgyXl5k7gzQFYU9NuOmiu1wNE4Gr7DTSXfLAHj2lq0UoY9xNbWpuYLGac2E41xpDu4RuZ1OtnoXnxSC4LLcFFAHY8HcH2eUNFMIJwApzuPSaBvDqBQNdjYA0Yi7K7AXvu2sm5VaV8QXqffbftvKfEobvvaijV2MFXCt2-TfTEk2aVvMsotHJrP9WPMvVEwuUU_AvrklrGqsSWLhTAjklyvvMrMzjDvZvkkNIE8LfQMwojXgCtGntIM7iLqHgjc8b25n4-RlH7es8NWDGMjqYSJUsFezRfkSipF67n-B0FMsqWmvkMmYu7oksfu7WlhwtBgAeYyWlGXWYCcvzj47f2j0niOfTEvtPYRaaKSAIA4Nh5q5uLGAgXP3Q8Ah_0bLz2tJxTrV3c4vbRbEfwzUHyI4YZtNlv9tS1SrgQDHqkc", + "e": "AQAB", + "use": "sig", + "alg": "RS512" + }, + { + "kty": "RSA", + "kid": "test-key-id-2", + "n": "tURDMGFrueithlA-GbBVOdxoP9Cge0g6fMmPZwC38UyqWTPHlT85y5ZyULxtRujD2tGtBsOFFaZrQWyMlsYkxhtL0siRI9GdaZ_qXaaQTM-yaf9M7KSbLkrIp3Mwf_cADh0KYCmFVg96kdYF45VuOHZSI3XVloWZG5gMyJ3q9mk1vNfCIeD1zKzgZvcKek7tlYiKiRtVc1sh2wWzvFGf_kIRqhyOM7Fj0L5C3YjvDxZUbvIRhPr4__M-E7RTPPoFmqaLGAyhpb8b-O-QlA9A6ctW1JNOGnog6yOQnGmRyTwYWGA4qvxQjFTWwmlFsYhB6HlJADk8NjCUnahBuOgmPPytNLX_y2M1iGvCduE1y-qRC8xeoN3T6EwJjDs3S2IdCudxCnnDlv093f9GjiQm_RH_XOwkrMj3IlJjgFpPkb_d4M23222crnEsxKSffQ_Bjq9JLb31xIJYolAy_g92s1SMrikKzFzz77dMx0S1w3Ooqf84ZKLvHAh-4V5hI-rDqr1-StvebTgg16GWGyheTkOTaQpnSMwrydebyWiheXB72DEV4a74vizYEiGUKI6A0qZJYD6L1fa99xPAzJhFjaaNq6YacybRhNRVVvo5ATlvzGAVkjGBZ2UjouzCrZgP9i28wvasi4kAAAVjTSwhL3UnMLp7GAGYtaYdXI5p3N8", + "e": "AQAB", + "use": "sig", + "alg": "RS512" + } +] \ No newline at end of file diff --git a/lambdas/jwks-key-rotation/src/handler.ts b/lambdas/jwks-key-rotation/src/handler.ts index f06ae34b..79a7fa46 100644 --- a/lambdas/jwks-key-rotation/src/handler.ts +++ b/lambdas/jwks-key-rotation/src/handler.ts @@ -1,19 +1,18 @@ +/* eslint-disable unicorn/no-array-reduce */ import type { ScheduledHandler } from 'aws-lambda'; -import { logger } from './utils/logger'; import { getKeyDirectory, SigningKeyDirectory, writeKeyDirectory, } from './utils/key-directory-repository'; -import { - generateJwksFormat, - generateKey, - getPublicKey, -} from './utils/key-util'; +import { generateKey, getPublicKey } from './utils/key-util'; import { updateJwksFile } from './utils/jwks-util'; import { deleteKey } from './utils/aws/kms-util'; -const keyLifetimeDays = Number.parseInt(process.env.KEY_LIFETIME_DAYS ?? '28'); +const keyLifetimeDays = Number.parseInt( + process.env.KEY_LIFETIME_DAYS ?? '28', + 10 +); const keyLifetimeMillis = keyLifetimeDays * 24 * 60 * 60 * 1000; function formattedDate(offsetMillis = 0): string { diff --git a/lambdas/jwks-key-rotation/src/utils/aws/kms-util.ts b/lambdas/jwks-key-rotation/src/utils/aws/kms-util.ts index d2bc3273..345f7f9d 100644 --- a/lambdas/jwks-key-rotation/src/utils/aws/kms-util.ts +++ b/lambdas/jwks-key-rotation/src/utils/aws/kms-util.ts @@ -44,7 +44,7 @@ export async function getKmsPublicKey( export async function deleteKey(keyId: string): Promise { logger.info(`Deleting key ${keyId}`); - + await kmsClient.send( new ScheduleKeyDeletionCommand({ KeyId: keyId, diff --git a/lambdas/jwks-key-rotation/src/utils/aws/ssm-util.ts b/lambdas/jwks-key-rotation/src/utils/aws/ssm-util.ts index 3ecdb1e7..37bbff7d 100644 --- a/lambdas/jwks-key-rotation/src/utils/aws/ssm-util.ts +++ b/lambdas/jwks-key-rotation/src/utils/aws/ssm-util.ts @@ -41,7 +41,7 @@ export async function putParameter( new PutParameterCommand({ Name: name, Value: value, - Overwrite: true + Overwrite: true, }) ); } diff --git a/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts b/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts index e541303f..0c567bed 100644 --- a/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts +++ b/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts @@ -1,6 +1,6 @@ import { Tag } from '@aws-sdk/client-kms'; -const tagsMatcher = /^(([^,^=]+=[^,^=]+),?)*$/; +const tagsMatcher = /^(\w=\w,?)*$/; export function getKeyTags(): Array { const keyTags: string = process.env.KEY_TAGS || ''; diff --git a/lambdas/jwks-key-rotation/src/utils/jwks-util.ts b/lambdas/jwks-key-rotation/src/utils/jwks-util.ts index da41b0b3..8374ff56 100644 --- a/lambdas/jwks-key-rotation/src/utils/jwks-util.ts +++ b/lambdas/jwks-key-rotation/src/utils/jwks-util.ts @@ -1,18 +1,18 @@ import { createPublicKey } from 'node:crypto'; import { JWK } from 'node-jose'; -import { writeJsonToFile } from './aws/s3-util'; +import { writeJsonToFile } from '@/src/utils/aws/s3-util'; import { logger } from './logger'; const ALGORITHM_RSA_512 = 'RS512'; const KEY_USE_SIGNING = 'sig'; -export async function generateJwksFormat( +async function generateJwksFormat( keyId: string, publicKey: Uint8Array ): Promise { const base64EncodedPublicKey = Buffer.from(publicKey).toString('base64'); const pemFormat = `-----BEGIN PUBLIC KEY-----\n${base64EncodedPublicKey - .match(/(.{1,64})/g)!! + .match(/(.{1,64})/g)! .join('\n')}\n-----END PUBLIC KEY-----`; const key = createPublicKey(pemFormat); @@ -45,6 +45,12 @@ export async function updateJwksFile( ); const jwksFileContents = JSON.stringify(publicKeysArray); - logger.info(`Generated JWKS file content with ${publicKeysArray.length} public keys`); - await writeJsonToFile('jwks', jwksFileContents, process.env.S3_PUBLIC_KEYS_BUCKET_NAME); + logger.info( + `Generated JWKS file content with ${publicKeysArray.length} public keys` + ); + await writeJsonToFile( + 'jwks', + jwksFileContents, + process.env.S3_PUBLIC_KEYS_BUCKET_NAME + ); } diff --git a/lambdas/jwks-key-rotation/src/utils/key-util.ts b/lambdas/jwks-key-rotation/src/utils/key-util.ts index 104af075..f9c99092 100644 --- a/lambdas/jwks-key-rotation/src/utils/key-util.ts +++ b/lambdas/jwks-key-rotation/src/utils/key-util.ts @@ -3,7 +3,6 @@ import { KeySpec, KeyUsageType, KMSInvalidStateException, - KMSServiceException, NotFoundException, } from '@aws-sdk/client-kms'; import { getKeyTags } from './aws/tag-util'; @@ -43,13 +42,13 @@ export async function generateKey(): Promise { export async function getPublicKey( keyId: string ): Promise<{ keyId: string; publicKey?: Uint8Array }> { - const publicKey = await getKmsPublicKey(keyId).catch((err) => { - if (NO_OP_ERRORS.findIndex((errorType) => err instanceof errorType) > -1) { + const publicKey = await getKmsPublicKey(keyId).catch((error) => { + if (NO_OP_ERRORS.some((errorType) => error instanceof errorType)) { logger.warn(`Key not found: ${keyId}`); - return undefined; + return; } - throw err; + throw error; }); return { keyId, publicKey }; diff --git a/lambdas/jwks-key-rotation/tsconfig.json b/lambdas/jwks-key-rotation/tsconfig.json index e1ea40cd..81685260 100644 --- a/lambdas/jwks-key-rotation/tsconfig.json +++ b/lambdas/jwks-key-rotation/tsconfig.json @@ -3,4 +3,12 @@ "include": [ "**/*.ts" ], -} + "compilerOptions": { + "paths": { + "@/*": [ + "./*" + ] + }, + "resolveJsonModule": true + } +} \ No newline at end of file From d10f2841adeb8d5795f6f0e234ee0b3b650be7e8 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Wed, 23 Apr 2025 15:43:13 +0100 Subject: [PATCH 12/54] CCM-8897: unit tests --- .../public-signing-keys/ssm_key_directory.tf | 2 +- .../src/__tests__/utils/jwks-util.test.ts | 9 +- .../utils/key-directory-repository.test.ts | 100 ++++++++++++++++++ ...ic-key-1.der => test-public-key-1.der.bin} | Bin ...ic-key-2.der => test-public-key-2.der.bin} | Bin ...lic-key.jwks => test-public-key.jwks.json} | 2 +- .../jwks-key-rotation/src/utils/jwks-util.ts | 2 +- .../src/utils/key-directory-repository.ts | 4 +- 8 files changed, 110 insertions(+), 9 deletions(-) create mode 100644 lambdas/jwks-key-rotation/src/__tests__/utils/key-directory-repository.test.ts rename lambdas/jwks-key-rotation/src/__tests__/utils/{test-public-key-1.der => test-public-key-1.der.bin} (100%) rename lambdas/jwks-key-rotation/src/__tests__/utils/{test-public-key-2.der => test-public-key-2.der.bin} (100%) rename lambdas/jwks-key-rotation/src/__tests__/utils/{test-public-key.jwks => test-public-key.jwks.json} (99%) diff --git a/infrastructure/terraform/modules/public-signing-keys/ssm_key_directory.tf b/infrastructure/terraform/modules/public-signing-keys/ssm_key_directory.tf index cb1bea94..5582727c 100644 --- a/infrastructure/terraform/modules/public-signing-keys/ssm_key_directory.tf +++ b/infrastructure/terraform/modules/public-signing-keys/ssm_key_directory.tf @@ -7,4 +7,4 @@ resource "aws_ssm_parameter" "key_directory" { lifecycle { ignore_changes = [value] } -} \ No newline at end of file +} diff --git a/lambdas/jwks-key-rotation/src/__tests__/utils/jwks-util.test.ts b/lambdas/jwks-key-rotation/src/__tests__/utils/jwks-util.test.ts index d3031f94..dbbb56bf 100644 --- a/lambdas/jwks-key-rotation/src/__tests__/utils/jwks-util.test.ts +++ b/lambdas/jwks-key-rotation/src/__tests__/utils/jwks-util.test.ts @@ -3,10 +3,11 @@ import { updateJwksFile } from '../../utils/jwks-util'; import { writeJsonToFile } from '@/src/utils/aws/s3-util'; jest.mock('@/src/utils/aws/s3-util'); +jest.mock('@/src/utils/logger'); -const TEST_PUBLIC_KEY_FILE_1 = 'src/__tests__/utils/test-public-key-1.der'; -const TEST_PUBLIC_KEY_FILE_2 = 'src/__tests__/utils/test-public-key-2.der'; -const TEST_JWKS_FILE = 'src/__tests__/utils/test-public-key.jwks'; +const TEST_PUBLIC_KEY_FILE_1 = 'src/__tests__/utils/test-public-key-1.der.bin'; +const TEST_PUBLIC_KEY_FILE_2 = 'src/__tests__/utils/test-public-key-2.der.bin'; +const TEST_JWKS_FILE = 'src/__tests__/utils/test-public-key.jwks.json'; const MOCK_BUCKET_NAME = 'nhs-notify-000000000000-eu-west-2-abcd12-sbx-public-keys'; @@ -24,7 +25,7 @@ describe('jwks-util', () => { const publicKey1 = readFileSync(TEST_PUBLIC_KEY_FILE_1); const publicKey2 = readFileSync(TEST_PUBLIC_KEY_FILE_2); const expectedJwks = JSON.stringify( - JSON.parse(readFileSync(TEST_JWKS_FILE).toString('utf8')) + JSON.parse(readFileSync(TEST_JWKS_FILE).toString('utf8').trim()) ); process.env.S3_PUBLIC_KEYS_BUCKET_NAME = MOCK_BUCKET_NAME; diff --git a/lambdas/jwks-key-rotation/src/__tests__/utils/key-directory-repository.test.ts b/lambdas/jwks-key-rotation/src/__tests__/utils/key-directory-repository.test.ts new file mode 100644 index 00000000..acf88a1c --- /dev/null +++ b/lambdas/jwks-key-rotation/src/__tests__/utils/key-directory-repository.test.ts @@ -0,0 +1,100 @@ +import { + getKeyDirectory, + writeKeyDirectory, +} from '@/src/utils/key-directory-repository'; +import { getParameter, putParameter } from '@/src/utils/aws/ssm-util'; + +jest.mock('@/src/utils/aws/ssm-util'); +jest.mock('@/src/utils/logger'); + +const mockKeyDirectory = [ + { createdDate: '2025-04-01', kid: '00000000-0000-0000-0000-000000000000' }, + { createdDate: '2025-05-01', kid: '00000000-0000-0000-0000-000000000001' }, +]; + +describe('key-directory-repository', () => { + describe('getKeyDirectory', () => { + test('should get key directory from SSM', async () => { + // arrange + const mockGetParameter = jest.mocked(getParameter); + mockGetParameter.mockImplementation(() => + Promise.resolve({ + $metadata: {}, + Parameter: { + Value: JSON.stringify(mockKeyDirectory), + }, + }) + ); + + // act + const result = await getKeyDirectory(); + + // assert + expect(result).toMatchObject(mockKeyDirectory); + }); + + test('should handle empty parameter', async () => { + // arrange + const mockGetParameter = jest.mocked(getParameter); + mockGetParameter.mockImplementation(() => + Promise.resolve({ + $metadata: {}, + }) + ); + + // act + const result = await getKeyDirectory(); + + // assert + expect(result).toMatchObject([]); + }); + + test('should propagate parsing errors', async () => { + // arrange + const mockGetParameter = jest.mocked(getParameter); + mockGetParameter.mockImplementation(() => + Promise.resolve({ + $metadata: {}, + Parameter: { + Value: '[{"a":"b"}]', + }, + }) + ); + + // act + let error; + try { + await getKeyDirectory(); + } catch (err) { + error = err; + } + + // assert + expect(error).toBeTruthy(); + expect((error as Error).message).toBe('Failed to parse key directory'); + }); + }); + + describe('writeKeyDirectory', () => { + const OLD_ENV = { ...process.env }; + afterAll(() => { + process.env = OLD_ENV; + }); + + test('should store key directory to SSM', async () => { + // arrange + const MOCK_KEY_DIRECTORY_SSM = '/nhs-notify-abcd12-sbx-psk/key_directory'; + const mockPutParameter = jest.mocked(putParameter); + process.env.SSM_KEY_DIRECTORY_NAME = MOCK_KEY_DIRECTORY_SSM; + + // act + await writeKeyDirectory(mockKeyDirectory); + + // assert + expect(mockPutParameter).toHaveBeenCalledWith( + JSON.stringify(mockKeyDirectory), + MOCK_KEY_DIRECTORY_SSM + ); + }); + }); +}); diff --git a/lambdas/jwks-key-rotation/src/__tests__/utils/test-public-key-1.der b/lambdas/jwks-key-rotation/src/__tests__/utils/test-public-key-1.der.bin similarity index 100% rename from lambdas/jwks-key-rotation/src/__tests__/utils/test-public-key-1.der rename to lambdas/jwks-key-rotation/src/__tests__/utils/test-public-key-1.der.bin diff --git a/lambdas/jwks-key-rotation/src/__tests__/utils/test-public-key-2.der b/lambdas/jwks-key-rotation/src/__tests__/utils/test-public-key-2.der.bin similarity index 100% rename from lambdas/jwks-key-rotation/src/__tests__/utils/test-public-key-2.der rename to lambdas/jwks-key-rotation/src/__tests__/utils/test-public-key-2.der.bin diff --git a/lambdas/jwks-key-rotation/src/__tests__/utils/test-public-key.jwks b/lambdas/jwks-key-rotation/src/__tests__/utils/test-public-key.jwks.json similarity index 99% rename from lambdas/jwks-key-rotation/src/__tests__/utils/test-public-key.jwks rename to lambdas/jwks-key-rotation/src/__tests__/utils/test-public-key.jwks.json index 2f903e45..129ac84e 100644 --- a/lambdas/jwks-key-rotation/src/__tests__/utils/test-public-key.jwks +++ b/lambdas/jwks-key-rotation/src/__tests__/utils/test-public-key.jwks.json @@ -15,4 +15,4 @@ "use": "sig", "alg": "RS512" } -] \ No newline at end of file +] diff --git a/lambdas/jwks-key-rotation/src/utils/jwks-util.ts b/lambdas/jwks-key-rotation/src/utils/jwks-util.ts index 8374ff56..4c0df8b1 100644 --- a/lambdas/jwks-key-rotation/src/utils/jwks-util.ts +++ b/lambdas/jwks-key-rotation/src/utils/jwks-util.ts @@ -1,7 +1,7 @@ import { createPublicKey } from 'node:crypto'; import { JWK } from 'node-jose'; import { writeJsonToFile } from '@/src/utils/aws/s3-util'; -import { logger } from './logger'; +import { logger } from '@/src/utils/logger'; const ALGORITHM_RSA_512 = 'RS512'; const KEY_USE_SIGNING = 'sig'; diff --git a/lambdas/jwks-key-rotation/src/utils/key-directory-repository.ts b/lambdas/jwks-key-rotation/src/utils/key-directory-repository.ts index 6c4e9305..66882247 100644 --- a/lambdas/jwks-key-rotation/src/utils/key-directory-repository.ts +++ b/lambdas/jwks-key-rotation/src/utils/key-directory-repository.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; -import { logger } from './logger'; -import { getParameter, putParameter } from './aws/ssm-util'; +import { logger } from '@/src/utils/logger'; +import { getParameter, putParameter } from '@/src/utils/aws/ssm-util'; const schemaFor = () => From 72499d867e83959df3e49c5940cc00ccb5bdafc1 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Wed, 23 Apr 2025 22:02:58 +0100 Subject: [PATCH 13/54] CCM-8897: unit tests --- .../utils/key-directory-repository.test.ts | 8 +++ .../src/__tests__/utils/key-util.test.ts | 62 +++++++++++++++++++ .../jwks-key-rotation/src/utils/key-util.ts | 10 +-- lambdas/jwks-key-rotation/tsconfig.json | 2 +- 4 files changed, 76 insertions(+), 6 deletions(-) create mode 100644 lambdas/jwks-key-rotation/src/__tests__/utils/key-util.test.ts diff --git a/lambdas/jwks-key-rotation/src/__tests__/utils/key-directory-repository.test.ts b/lambdas/jwks-key-rotation/src/__tests__/utils/key-directory-repository.test.ts index acf88a1c..2d01a1cd 100644 --- a/lambdas/jwks-key-rotation/src/__tests__/utils/key-directory-repository.test.ts +++ b/lambdas/jwks-key-rotation/src/__tests__/utils/key-directory-repository.test.ts @@ -13,9 +13,16 @@ const mockKeyDirectory = [ ]; describe('key-directory-repository', () => { + const OLD_ENV = { ...process.env }; + afterAll(() => { + process.env = OLD_ENV; + }); + describe('getKeyDirectory', () => { test('should get key directory from SSM', async () => { // arrange + const mockKeyDirectorySsm = '/nhs-notify-abcd12-sbx-psk/key_directory'; + process.env.SSM_KEY_DIRECTORY_NAME = mockKeyDirectorySsm; const mockGetParameter = jest.mocked(getParameter); mockGetParameter.mockImplementation(() => Promise.resolve({ @@ -31,6 +38,7 @@ describe('key-directory-repository', () => { // assert expect(result).toMatchObject(mockKeyDirectory); + expect(mockGetParameter.mock.lastCall?.[0]).toBe(mockKeyDirectorySsm); }); test('should handle empty parameter', async () => { diff --git a/lambdas/jwks-key-rotation/src/__tests__/utils/key-util.test.ts b/lambdas/jwks-key-rotation/src/__tests__/utils/key-util.test.ts new file mode 100644 index 00000000..53463962 --- /dev/null +++ b/lambdas/jwks-key-rotation/src/__tests__/utils/key-util.test.ts @@ -0,0 +1,62 @@ +import { getParameter } from '@/src/utils/aws/ssm-util'; +import { generateKey } from '@/src/utils/key-util'; +import { getKeyTags } from '@/src/utils/aws/tag-util'; +import { createKmsKey } from '@/src/utils/aws/kms-util'; + +jest.mock('@/src/utils/logger'); +jest.mock('@/src/utils/aws/ssm-util'); +jest.mock('@/src/utils/aws/tag-util'); +jest.mock('@/src/utils/aws/kms-util'); + +describe('key-util', () => { + const OLD_ENV = { ...process.env }; + afterAll(() => { + process.env = OLD_ENV; + }); + + describe('generateKey', () => { + test('should generate KMS asymmetric key', async () => { + // arrange + const mockKeyPolicy = '/nhs-notify-abcd12-sbx-psk/asymmetric_key_policy'; + process.env.SSM_ASYMMETRIC_KEY_POLICY = mockKeyPolicy; + + const mockGetParameter = jest.mocked(getParameter); + const mockGetKeyTags = jest.mocked(getKeyTags); + const mockCreateKmsKey = jest.mocked(createKmsKey); + + mockGetParameter.mockImplementation(() => + Promise.resolve({ + $metadata: {}, + Parameter: { + Value: '{"Statement":[]}', + }, + }) + ); + + mockGetKeyTags.mockImplementation(() => [ + { TagKey: 'TEST_1', TagValue: 'v1' }, + { TagKey: 'TEST_2', TagValue: 'v2' }, + ]); + + // act + const result = await generateKey(); + + // assert + expect(mockGetParameter.mock.lastCall?.[0]).toBe(mockKeyPolicy); + expect(mockCreateKmsKey).toHaveBeenCalledWith( + expect.objectContaining({ + input: { + Description: 'Used for JWKS auth for CIS2 login', + KeySpec: 'RSA_4096', + KeyUsage: 'SIGN_VERIFY', + Policy: '{"Statement":[]}', + Tags: [ + { TagKey: 'TEST_1', TagValue: 'v1' }, + { TagKey: 'TEST_2', TagValue: 'v2' }, + ], + }, + }) + ); + }); + }); +}); diff --git a/lambdas/jwks-key-rotation/src/utils/key-util.ts b/lambdas/jwks-key-rotation/src/utils/key-util.ts index f9c99092..27db6144 100644 --- a/lambdas/jwks-key-rotation/src/utils/key-util.ts +++ b/lambdas/jwks-key-rotation/src/utils/key-util.ts @@ -5,10 +5,10 @@ import { KMSInvalidStateException, NotFoundException, } from '@aws-sdk/client-kms'; -import { getKeyTags } from './aws/tag-util'; -import { createKmsKey, getKmsPublicKey } from './aws/kms-util'; -import { getParameter } from './aws/ssm-util'; -import { logger } from './logger'; +import { getKeyTags } from '@/src/utils/aws/tag-util'; +import { createKmsKey, getKmsPublicKey } from '@/src/utils/aws/kms-util'; +import { getParameter } from '@/src/utils/aws/ssm-util'; +import { logger } from '@/src/utils/logger'; const NO_OP_ERRORS = [NotFoundException, KMSInvalidStateException]; @@ -45,7 +45,7 @@ export async function getPublicKey( const publicKey = await getKmsPublicKey(keyId).catch((error) => { if (NO_OP_ERRORS.some((errorType) => error instanceof errorType)) { logger.warn(`Key not found: ${keyId}`); - return; + return undefined; } throw error; diff --git a/lambdas/jwks-key-rotation/tsconfig.json b/lambdas/jwks-key-rotation/tsconfig.json index 81685260..9d3bf119 100644 --- a/lambdas/jwks-key-rotation/tsconfig.json +++ b/lambdas/jwks-key-rotation/tsconfig.json @@ -11,4 +11,4 @@ }, "resolveJsonModule": true } -} \ No newline at end of file +} From 60e03e14a13b2ee0204aa81ecbdb30ebe1170590 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Wed, 23 Apr 2025 22:04:35 +0100 Subject: [PATCH 14/54] CCM-8897: file format --- lambdas/jwks-key-rotation/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lambdas/jwks-key-rotation/package.json b/lambdas/jwks-key-rotation/package.json index 25510ebf..eb50d466 100644 --- a/lambdas/jwks-key-rotation/package.json +++ b/lambdas/jwks-key-rotation/package.json @@ -28,4 +28,4 @@ "winston": "^3.14.2", "zod": "^3.24.2" } -} \ No newline at end of file +} From 218ac848423d5f62c67d5d8507fb3c4a645315b2 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Thu, 24 Apr 2025 07:44:33 +0100 Subject: [PATCH 15/54] CCM-8897: linting --- .../src/__tests__/utils/jwks-util.test.ts | 2 +- .../src/__tests__/utils/key-directory-repository.test.ts | 9 ++------- .../src/__tests__/utils/key-util.test.ts | 5 +++++ lambdas/jwks-key-rotation/src/utils/key-util.ts | 5 ++--- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/lambdas/jwks-key-rotation/src/__tests__/utils/jwks-util.test.ts b/lambdas/jwks-key-rotation/src/__tests__/utils/jwks-util.test.ts index dbbb56bf..fea405ed 100644 --- a/lambdas/jwks-key-rotation/src/__tests__/utils/jwks-util.test.ts +++ b/lambdas/jwks-key-rotation/src/__tests__/utils/jwks-util.test.ts @@ -1,5 +1,5 @@ import { readFileSync } from 'node:fs'; -import { updateJwksFile } from '../../utils/jwks-util'; +import { updateJwksFile } from '@/src/utils/jwks-util'; import { writeJsonToFile } from '@/src/utils/aws/s3-util'; jest.mock('@/src/utils/aws/s3-util'); diff --git a/lambdas/jwks-key-rotation/src/__tests__/utils/key-directory-repository.test.ts b/lambdas/jwks-key-rotation/src/__tests__/utils/key-directory-repository.test.ts index 2d01a1cd..caf73761 100644 --- a/lambdas/jwks-key-rotation/src/__tests__/utils/key-directory-repository.test.ts +++ b/lambdas/jwks-key-rotation/src/__tests__/utils/key-directory-repository.test.ts @@ -73,8 +73,8 @@ describe('key-directory-repository', () => { let error; try { await getKeyDirectory(); - } catch (err) { - error = err; + } catch (caughtError) { + error = caughtError; } // assert @@ -84,11 +84,6 @@ describe('key-directory-repository', () => { }); describe('writeKeyDirectory', () => { - const OLD_ENV = { ...process.env }; - afterAll(() => { - process.env = OLD_ENV; - }); - test('should store key directory to SSM', async () => { // arrange const MOCK_KEY_DIRECTORY_SSM = '/nhs-notify-abcd12-sbx-psk/key_directory'; diff --git a/lambdas/jwks-key-rotation/src/__tests__/utils/key-util.test.ts b/lambdas/jwks-key-rotation/src/__tests__/utils/key-util.test.ts index 53463962..7ebfa7a7 100644 --- a/lambdas/jwks-key-rotation/src/__tests__/utils/key-util.test.ts +++ b/lambdas/jwks-key-rotation/src/__tests__/utils/key-util.test.ts @@ -38,10 +38,15 @@ describe('key-util', () => { { TagKey: 'TEST_2', TagValue: 'v2' }, ]); + mockCreateKmsKey.mockImplementation(() => + Promise.resolve('12dfbf31-c65e-4966-9010-3dfde426e8f4') + ); + // act const result = await generateKey(); // assert + expect(result).toBe('12dfbf31-c65e-4966-9010-3dfde426e8f4'); expect(mockGetParameter.mock.lastCall?.[0]).toBe(mockKeyPolicy); expect(mockCreateKmsKey).toHaveBeenCalledWith( expect.objectContaining({ diff --git a/lambdas/jwks-key-rotation/src/utils/key-util.ts b/lambdas/jwks-key-rotation/src/utils/key-util.ts index 27db6144..813f1749 100644 --- a/lambdas/jwks-key-rotation/src/utils/key-util.ts +++ b/lambdas/jwks-key-rotation/src/utils/key-util.ts @@ -45,11 +45,10 @@ export async function getPublicKey( const publicKey = await getKmsPublicKey(keyId).catch((error) => { if (NO_OP_ERRORS.some((errorType) => error instanceof errorType)) { logger.warn(`Key not found: ${keyId}`); - return undefined; + return; } - throw error; }); - return { keyId, publicKey }; + return { keyId, publicKey: publicKey as Uint8Array | undefined }; } From a2cf7436cd354e45ed0c12075c573b427e0e2fbf Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Thu, 24 Apr 2025 11:37:55 +0100 Subject: [PATCH 16/54] CCM-8897: unit tests --- .../src/__tests__/utils/key-util.test.ts | 101 +++++++++++++++++- .../jwks-key-rotation/src/utils/constants.ts | 6 ++ .../jwks-key-rotation/src/utils/key-util.ts | 13 +-- 3 files changed, 108 insertions(+), 12 deletions(-) create mode 100644 lambdas/jwks-key-rotation/src/utils/constants.ts diff --git a/lambdas/jwks-key-rotation/src/__tests__/utils/key-util.test.ts b/lambdas/jwks-key-rotation/src/__tests__/utils/key-util.test.ts index 7ebfa7a7..1ef78ee8 100644 --- a/lambdas/jwks-key-rotation/src/__tests__/utils/key-util.test.ts +++ b/lambdas/jwks-key-rotation/src/__tests__/utils/key-util.test.ts @@ -1,12 +1,14 @@ import { getParameter } from '@/src/utils/aws/ssm-util'; -import { generateKey } from '@/src/utils/key-util'; +import { generateKey, getPublicKey } from '@/src/utils/key-util'; import { getKeyTags } from '@/src/utils/aws/tag-util'; -import { createKmsKey } from '@/src/utils/aws/kms-util'; +import { createKmsKey, getKmsPublicKey } from '@/src/utils/aws/kms-util'; +import { KMS_NO_OP_ERRORS } from '@/src/utils/constants'; jest.mock('@/src/utils/logger'); jest.mock('@/src/utils/aws/ssm-util'); jest.mock('@/src/utils/aws/tag-util'); jest.mock('@/src/utils/aws/kms-util'); +jest.mock('@/src/utils/constants'); describe('key-util', () => { const OLD_ENV = { ...process.env }; @@ -63,5 +65,100 @@ describe('key-util', () => { }) ); }); + + test('should propagate miussing key policy error', async () => { + // arrange + const mockKeyPolicy = '/nhs-notify-abcd12-sbx-psk/asymmetric_key_policy'; + process.env.SSM_ASYMMETRIC_KEY_POLICY = mockKeyPolicy; + + const mockGetParameter = jest.mocked(getParameter); + const mockCreateKmsKey = jest.mocked(createKmsKey); + + mockGetParameter.mockImplementation(() => + Promise.resolve({ + $metadata: {}, + Parameter: {}, + }) + ); + + // act + let error; + try { + await generateKey(); + } catch (caughtError) { + error = caughtError; + } + + // assert + expect(error).toBeTruthy(); + expect((error as Error).message).toBe( + 'Failed to retrieve key policy from /nhs-notify-abcd12-sbx-psk/asymmetric_key_policy' + ); + expect(mockCreateKmsKey).not.toHaveBeenCalled(); + }); + }); + + describe('getPublicKey', () => { + test('should get the public key from KMS', async () => { + // arrange + const mockGetKmsPublicKey = jest.mocked(getKmsPublicKey); + const mockPublicKey = Uint8Array.from([1, 2, 3]); + + mockGetKmsPublicKey.mockImplementation(() => + Promise.resolve(mockPublicKey) + ); + + // act + const result = await getPublicKey('12dfbf31-c65e-4966-9010-3dfde426e8f4'); + + // assert + expect(result).toMatchObject({ + keyId: '12dfbf31-c65e-4966-9010-3dfde426e8f4', + publicKey: mockPublicKey, + }); + }); + + test('should no-op specific KMS errors', async () => { + // arrange + const mockGetKmsPublicKey = jest.mocked(getKmsPublicKey); + + class TestError1 extends Error {} + + (jest.mocked(KMS_NO_OP_ERRORS) as Array).push(TestError1); + + mockGetKmsPublicKey.mockImplementation(() => + Promise.reject(new TestError1('TEST')) + ); + + // act + const result = await getPublicKey('12dfbf31-c65e-4966-9010-3dfde426e8f4'); + + // assert + expect(result).toMatchObject({ + keyId: '12dfbf31-c65e-4966-9010-3dfde426e8f4', + publicKey: undefined, + }); + }); + + test('should propagate general errors', async () => { + // arrange + const mockGetKmsPublicKey = jest.mocked(getKmsPublicKey); + + mockGetKmsPublicKey.mockImplementation(() => + Promise.reject(new Error('TEST')) + ); + + // act + let error; + try { + await getPublicKey('12dfbf31-c65e-4966-9010-3dfde426e8f4'); + } catch (caughtError) { + error = caughtError; + } + + // assert + expect(error).toBeTruthy(); + expect((error as Error).message).toBe('TEST'); + }); }); }); diff --git a/lambdas/jwks-key-rotation/src/utils/constants.ts b/lambdas/jwks-key-rotation/src/utils/constants.ts new file mode 100644 index 00000000..c197b7d1 --- /dev/null +++ b/lambdas/jwks-key-rotation/src/utils/constants.ts @@ -0,0 +1,6 @@ +import { + KMSInvalidStateException, + NotFoundException, +} from '@aws-sdk/client-kms'; + +export const KMS_NO_OP_ERRORS = [NotFoundException, KMSInvalidStateException]; diff --git a/lambdas/jwks-key-rotation/src/utils/key-util.ts b/lambdas/jwks-key-rotation/src/utils/key-util.ts index 813f1749..a145b8cf 100644 --- a/lambdas/jwks-key-rotation/src/utils/key-util.ts +++ b/lambdas/jwks-key-rotation/src/utils/key-util.ts @@ -1,16 +1,9 @@ -import { - CreateKeyCommand, - KeySpec, - KeyUsageType, - KMSInvalidStateException, - NotFoundException, -} from '@aws-sdk/client-kms'; +import { CreateKeyCommand, KeySpec, KeyUsageType } from '@aws-sdk/client-kms'; import { getKeyTags } from '@/src/utils/aws/tag-util'; import { createKmsKey, getKmsPublicKey } from '@/src/utils/aws/kms-util'; import { getParameter } from '@/src/utils/aws/ssm-util'; import { logger } from '@/src/utils/logger'; - -const NO_OP_ERRORS = [NotFoundException, KMSInvalidStateException]; +import { KMS_NO_OP_ERRORS } from '@/src/utils/constants'; async function getKeyPolicy(): Promise { const ssmResult = await getParameter(process.env.SSM_ASYMMETRIC_KEY_POLICY); @@ -43,7 +36,7 @@ export async function getPublicKey( keyId: string ): Promise<{ keyId: string; publicKey?: Uint8Array }> { const publicKey = await getKmsPublicKey(keyId).catch((error) => { - if (NO_OP_ERRORS.some((errorType) => error instanceof errorType)) { + if (KMS_NO_OP_ERRORS.some((errorType) => error instanceof errorType)) { logger.warn(`Key not found: ${keyId}`); return; } From 21e2b0efc13494110211f57ed2eda37d09b49463 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Thu, 24 Apr 2025 15:13:14 +0100 Subject: [PATCH 17/54] CCM-8897: unit tests --- .../src/__tests__/utils/aws/kms-util.test.ts | 67 +++++++++++++++++++ .../src/utils/aws/kms-util.ts | 2 +- 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 lambdas/jwks-key-rotation/src/__tests__/utils/aws/kms-util.test.ts diff --git a/lambdas/jwks-key-rotation/src/__tests__/utils/aws/kms-util.test.ts b/lambdas/jwks-key-rotation/src/__tests__/utils/aws/kms-util.test.ts new file mode 100644 index 00000000..fc69e01b --- /dev/null +++ b/lambdas/jwks-key-rotation/src/__tests__/utils/aws/kms-util.test.ts @@ -0,0 +1,67 @@ +import { createKmsKey } from '@/src/utils/aws/kms-util'; +import { + CreateKeyCommand, + KeySpec, + KeyUsageType, + KMSClient, +} from '@aws-sdk/client-kms'; + +jest.mock('@/src/utils/logger'); +jest.mock('@aws-sdk/client-kms', () => ({ + ...jest.requireActual('@aws-sdk/client-kms'), +})); + +describe('kms-util', () => { + describe('createKmsKey', () => { + test('should create asymmetric KMS key', async () => { + // arrange + const sendSpy = jest.spyOn(KMSClient.prototype, 'send'); + sendSpy.mockImplementation(() => ({ + KeyMetadata: { KeyId: 'test-key-id' }, + })); + + const testCreateKeyCommand = new CreateKeyCommand({ + Policy: '{\"Statement\":[]}', + Description: 'Test description', + KeyUsage: KeyUsageType.SIGN_VERIFY, + KeySpec: KeySpec.RSA_4096, + Tags: [], + }); + + // act + const result = await createKmsKey(testCreateKeyCommand); + + // assert + expect(sendSpy).toHaveBeenCalledWith(testCreateKeyCommand); + expect(result).toBe('test-key-id'); + }); + + test('should propagate missing key ID error', async () => { + // arrange + const sendSpy = jest.spyOn(KMSClient.prototype, 'send'); + sendSpy.mockImplementation(() => ({ + KeyMetadata: {}, + })); + + const testCreateKeyCommand = new CreateKeyCommand({ + Policy: '{\"Statement\":[]}', + Description: 'Test description', + KeyUsage: KeyUsageType.SIGN_VERIFY, + KeySpec: KeySpec.RSA_4096, + Tags: [], + }); + + // act + let error; + try { + await createKmsKey(testCreateKeyCommand); + } catch (caughtError) { + error = caughtError; + } + + // assert + expect(error).toBeTruthy(); + expect((error as Error).message).toBe('Failed to create key'); + }); + }); +}); diff --git a/lambdas/jwks-key-rotation/src/utils/aws/kms-util.ts b/lambdas/jwks-key-rotation/src/utils/aws/kms-util.ts index 345f7f9d..ba306fe8 100644 --- a/lambdas/jwks-key-rotation/src/utils/aws/kms-util.ts +++ b/lambdas/jwks-key-rotation/src/utils/aws/kms-util.ts @@ -4,7 +4,7 @@ import { KMSClient, ScheduleKeyDeletionCommand, } from '@aws-sdk/client-kms'; -import { logger } from '../logger'; +import { logger } from '@/src/utils/logger'; const kmsClient = new KMSClient({ region: process.env.REGION, From 25b97bd6049e0b31804681729e8d70ff144edd21 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Thu, 24 Apr 2025 15:14:11 +0100 Subject: [PATCH 18/54] CCM-8897: linting --- .../src/__tests__/utils/aws/kms-util.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lambdas/jwks-key-rotation/src/__tests__/utils/aws/kms-util.test.ts b/lambdas/jwks-key-rotation/src/__tests__/utils/aws/kms-util.test.ts index fc69e01b..9f1f41b7 100644 --- a/lambdas/jwks-key-rotation/src/__tests__/utils/aws/kms-util.test.ts +++ b/lambdas/jwks-key-rotation/src/__tests__/utils/aws/kms-util.test.ts @@ -21,7 +21,7 @@ describe('kms-util', () => { })); const testCreateKeyCommand = new CreateKeyCommand({ - Policy: '{\"Statement\":[]}', + Policy: '{"Statement":[]}', Description: 'Test description', KeyUsage: KeyUsageType.SIGN_VERIFY, KeySpec: KeySpec.RSA_4096, @@ -44,8 +44,8 @@ describe('kms-util', () => { })); const testCreateKeyCommand = new CreateKeyCommand({ - Policy: '{\"Statement\":[]}', - Description: 'Test description', + Policy: '', + Description: '', KeyUsage: KeyUsageType.SIGN_VERIFY, KeySpec: KeySpec.RSA_4096, Tags: [], From b2de9c27596a6513ef5df278ffc0a464efd49a82 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Thu, 24 Apr 2025 20:51:20 +0100 Subject: [PATCH 19/54] CCM-8897: unit tests --- .../src/__tests__/utils/aws/kms-util.test.ts | 50 ++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/lambdas/jwks-key-rotation/src/__tests__/utils/aws/kms-util.test.ts b/lambdas/jwks-key-rotation/src/__tests__/utils/aws/kms-util.test.ts index 9f1f41b7..2918e5ab 100644 --- a/lambdas/jwks-key-rotation/src/__tests__/utils/aws/kms-util.test.ts +++ b/lambdas/jwks-key-rotation/src/__tests__/utils/aws/kms-util.test.ts @@ -1,4 +1,4 @@ -import { createKmsKey } from '@/src/utils/aws/kms-util'; +import { createKmsKey, getKmsPublicKey } from '@/src/utils/aws/kms-util'; import { CreateKeyCommand, KeySpec, @@ -12,6 +12,11 @@ jest.mock('@aws-sdk/client-kms', () => ({ })); describe('kms-util', () => { + const OLD_ENV = { ...process.env }; + afterAll(() => { + process.env = OLD_ENV; + }); + describe('createKmsKey', () => { test('should create asymmetric KMS key', async () => { // arrange @@ -64,4 +69,47 @@ describe('kms-util', () => { expect((error as Error).message).toBe('Failed to create key'); }); }); + + describe('getKmsPublicKey', () => { + test('should key public key from KMS', async () => { + // arrange + process.env.REGION = 'eu-west-2'; + process.env.ACCOUNT_ID = '000000000000'; + const testPublicKey = Uint8Array.from([1, 2, 3]); + + const sendSpy = jest.spyOn(KMSClient.prototype, 'send'); + sendSpy.mockImplementation(() => ({ + PublicKey: testPublicKey, + })); + + // act + const result = await getKmsPublicKey('test-key-id'); + + // assert + expect(result).toBe(testPublicKey); + expect(sendSpy).toHaveBeenCalledWith( + expect.objectContaining({ + input: { + KeyId: 'arn:aws:kms:eu-west-2:000000000000:key/test-key-id', + }, + }) + ); + }); + + test('should handle missing key', async () => { + // arrange + process.env.REGION = 'eu-west-2'; + process.env.ACCOUNT_ID = '000000000000'; + const testPublicKey = Uint8Array.from([1, 2, 3]); + + const sendSpy = jest.spyOn(KMSClient.prototype, 'send'); + sendSpy.mockImplementation(() => ({})); + + // act + const result = await getKmsPublicKey('test-key-id'); + + // assert + expect(result).toBe(undefined); + }); + }); }); From 847a914f8318ca6959f6fba5677bc07259029278 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Thu, 24 Apr 2025 21:45:44 +0100 Subject: [PATCH 20/54] CCM-8897: unit tests --- .../src/__tests__/utils/aws/kms-util.test.ts | 32 +++++++++-- .../src/__tests__/utils/aws/s3-util.test.ts | 53 +++++++++++++++++++ .../src/utils/aws/s3-util.ts | 2 +- 3 files changed, 81 insertions(+), 6 deletions(-) create mode 100644 lambdas/jwks-key-rotation/src/__tests__/utils/aws/s3-util.test.ts diff --git a/lambdas/jwks-key-rotation/src/__tests__/utils/aws/kms-util.test.ts b/lambdas/jwks-key-rotation/src/__tests__/utils/aws/kms-util.test.ts index 2918e5ab..fb261504 100644 --- a/lambdas/jwks-key-rotation/src/__tests__/utils/aws/kms-util.test.ts +++ b/lambdas/jwks-key-rotation/src/__tests__/utils/aws/kms-util.test.ts @@ -1,9 +1,15 @@ -import { createKmsKey, getKmsPublicKey } from '@/src/utils/aws/kms-util'; +import { + createKmsKey, + deleteKey, + getKmsPublicKey, +} from '@/src/utils/aws/kms-util'; import { CreateKeyCommand, + GetPublicKeyCommand, KeySpec, KeyUsageType, KMSClient, + ScheduleKeyDeletionCommand, } from '@aws-sdk/client-kms'; jest.mock('@/src/utils/logger'); @@ -94,14 +100,11 @@ describe('kms-util', () => { }, }) ); + expect(sendSpy).toHaveBeenCalledWith(expect.any(GetPublicKeyCommand)); }); test('should handle missing key', async () => { // arrange - process.env.REGION = 'eu-west-2'; - process.env.ACCOUNT_ID = '000000000000'; - const testPublicKey = Uint8Array.from([1, 2, 3]); - const sendSpy = jest.spyOn(KMSClient.prototype, 'send'); sendSpy.mockImplementation(() => ({})); @@ -112,4 +115,23 @@ describe('kms-util', () => { expect(result).toBe(undefined); }); }); + + describe('deleteKey', () => { + test('should schedule KMS key deletion', async () => { + // arrange + const sendSpy = jest.spyOn(KMSClient.prototype, 'send'); + sendSpy.mockImplementation(() => ({})); + + // act + await deleteKey('test-key-id'); + + // assert + expect(sendSpy).toHaveBeenCalledWith( + expect.objectContaining({ input: { KeyId: 'test-key-id' } }) + ); + expect(sendSpy).toHaveBeenCalledWith( + expect.any(ScheduleKeyDeletionCommand) + ); + }); + }); }); diff --git a/lambdas/jwks-key-rotation/src/__tests__/utils/aws/s3-util.test.ts b/lambdas/jwks-key-rotation/src/__tests__/utils/aws/s3-util.test.ts new file mode 100644 index 00000000..25508ef6 --- /dev/null +++ b/lambdas/jwks-key-rotation/src/__tests__/utils/aws/s3-util.test.ts @@ -0,0 +1,53 @@ +import { writeJsonToFile } from '@/src/utils/aws/s3-util'; +import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3'; + +jest.mock('@aws-sdk/client-s3', () => ({ + ...jest.requireActual('@aws-sdk/client-s3'), +})); +jest.mock('@/src/utils/logger'); + +describe('s3-util', () => { + describe('writeJsonToFile', () => { + test('should write JSON file to S3', async () => { + // arrange + const mockResponse = {}; + const sendSpy = jest.spyOn(S3Client.prototype, 'send'); + sendSpy.mockImplementation(() => mockResponse); + + // act + const result = await writeJsonToFile( + 'jwks', + '{"test":123}', + 'bucket-name' + ); + + // assert + expect(result).toBe(mockResponse); + expect(sendSpy).toHaveBeenCalledWith(expect.any(PutObjectCommand)); + expect(sendSpy).toHaveBeenCalledWith( + expect.objectContaining({ + input: { + Body: '{"test":123}', + Bucket: 'bucket-name', + ContentType: 'application/json', + Key: 'jwks', + }, + }) + ); + }); + + test('should reject missing bucket', async () => { + // act + let error; + try { + await writeJsonToFile('jwks', '{"test":123}'); + } catch (caughtError) { + error = caughtError; + } + + // assert + expect(error).toBeTruthy(); + expect((error as Error).message).toBe('Missing bucket'); + }); + }); +}); diff --git a/lambdas/jwks-key-rotation/src/utils/aws/s3-util.ts b/lambdas/jwks-key-rotation/src/utils/aws/s3-util.ts index 98f1a642..fe2b07ee 100644 --- a/lambdas/jwks-key-rotation/src/utils/aws/s3-util.ts +++ b/lambdas/jwks-key-rotation/src/utils/aws/s3-util.ts @@ -3,7 +3,7 @@ import { PutObjectCommandOutput, S3Client, } from '@aws-sdk/client-s3'; -import { logger } from '../logger'; +import { logger } from '@/src/utils/logger'; const s3Client = new S3Client({ region: process.env.REGION, From 2b35829523eb56a7f29d3027ca773ddc2b947cec Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Fri, 25 Apr 2025 22:20:43 +0100 Subject: [PATCH 21/54] CCM-8897: unit tests --- .../src/__tests__/handler.test.ts | 197 ++++++++++++++++++ .../src/__tests__/utils/aws/ssm-util.test.ts | 91 ++++++++ .../src/__tests__/utils/aws/tag-util.test.ts | 114 ++++++++++ lambdas/jwks-key-rotation/src/handler.ts | 8 +- .../src/utils/aws/ssm-util.ts | 9 +- .../src/utils/aws/tag-util.ts | 23 +- 6 files changed, 425 insertions(+), 17 deletions(-) create mode 100644 lambdas/jwks-key-rotation/src/__tests__/handler.test.ts create mode 100644 lambdas/jwks-key-rotation/src/__tests__/utils/aws/ssm-util.test.ts create mode 100644 lambdas/jwks-key-rotation/src/__tests__/utils/aws/tag-util.test.ts diff --git a/lambdas/jwks-key-rotation/src/__tests__/handler.test.ts b/lambdas/jwks-key-rotation/src/__tests__/handler.test.ts new file mode 100644 index 00000000..b3eb5b5d --- /dev/null +++ b/lambdas/jwks-key-rotation/src/__tests__/handler.test.ts @@ -0,0 +1,197 @@ +import { handler } from '@/src/handler'; +import { Context, EventBridgeEvent, Callback } from 'aws-lambda'; +import { + getKeyDirectory, + SigningKeyDirectory, + writeKeyDirectory, +} from '@/src/utils/key-directory-repository'; +import { generateKey, getPublicKey } from '@/src/utils/key-util'; +import { updateJwksFile } from '@/src/utils/jwks-util'; +import { deleteKey } from '@/src/utils/aws/kms-util'; + +jest.mock('@/src/utils/key-directory-repository', () => ({ + ...jest.requireActual('@/src/utils/key-directory-repository'), + getKeyDirectory: jest.fn(), + writeKeyDirectory: jest.fn(), +})); +jest.mock('@/src/utils/key-util'); +jest.mock('@/src/utils/jwks-util'); +jest.mock('@/src/utils/aws/kms-util'); + +// import type { ScheduledHandler } from 'aws-lambda'; +// import { +// getKeyDirectory, +// SigningKeyDirectory, +// writeKeyDirectory, +// } from '@/src/utils/key-directory-repository'; +// import { generateKey, getPublicKey } from '@/src/utils/key-util'; +// import { updateJwksFile } from '@/src/utils/jwks-util'; +// import { deleteKey } from '@/src/utils/aws/kms-util'; + +describe('handler', () => { + describe('perform key rotation (generate new KMS key, update public jwks file, update key directory and delete old keys)', () => { + test('should perform key rotation with no existing keys', async () => { + // arrange + const mockEvent = {} as EventBridgeEvent<'Scheduled Event', any>; + const mockContext = {} as Context; + const mockCallback = (() => {}) as Callback; + const mockKeyDirectory: SigningKeyDirectory = []; + const mockPublicKey = Uint8Array.from([1, 2, 3]); + const todayFormatted = new Date().toISOString().split('T')[0]; + + const mockedGetKeyDirectory = jest.mocked(getKeyDirectory); + const mockedGenerateKey = jest.mocked(generateKey); + const mockedGetPublicKey = jest.mocked(getPublicKey); + const mockedWriteKeyDirectory = jest.mocked(writeKeyDirectory); + + mockedGetKeyDirectory.mockImplementation(() => + Promise.resolve(mockKeyDirectory) + ); + mockedGenerateKey.mockImplementation(() => + Promise.resolve('new-test-key-id') + ); + mockedGetPublicKey.mockImplementation((keyId) => + Promise.resolve({ keyId, publicKey: mockPublicKey }) + ); + + // act + await handler(mockEvent, mockContext, mockCallback); + + // assert + expect(mockedGenerateKey).toHaveBeenCalled(); + expect(updateJwksFile).toHaveBeenCalledWith([ + { keyId: 'new-test-key-id', publicKey: mockPublicKey }, + ]); + expect(mockedWriteKeyDirectory).toHaveBeenCalledWith([ + { createdDate: todayFormatted, kid: 'new-test-key-id' }, + ]); + expect(deleteKey).not.toHaveBeenCalled(); + }); + + test('should perform key rotation with one existing key', async () => { + // arrange + const mockEvent = {} as EventBridgeEvent<'Scheduled Event', any>; + const mockContext = {} as Context; + const mockCallback = (() => {}) as Callback; + const startOfMonth = new Date(); + startOfMonth.setDate(1); + + const todayFormatted = new Date().toISOString().split('T')[0]; + const startOfMonthFormatted = startOfMonth.toISOString().split('T')[0]; + + const mockKeyDirectory: SigningKeyDirectory = [ + { + createdDate: startOfMonthFormatted, + kid: '00000000-0000-0000-0000-000000000001', + }, + ]; + const mockPublicKey = Uint8Array.from([1, 2, 3]); + + const mockedGetKeyDirectory = jest.mocked(getKeyDirectory); + const mockedGenerateKey = jest.mocked(generateKey); + const mockedGetPublicKey = jest.mocked(getPublicKey); + const mockedWriteKeyDirectory = jest.mocked(writeKeyDirectory); + + mockedGetKeyDirectory.mockImplementation(() => + Promise.resolve(mockKeyDirectory) + ); + mockedGenerateKey.mockImplementation(() => + Promise.resolve('new-test-key-id') + ); + mockedGetPublicKey.mockImplementation((keyId) => + Promise.resolve({ keyId, publicKey: mockPublicKey }) + ); + + // act + await handler(mockEvent, mockContext, mockCallback); + + // assert + expect(mockedGenerateKey).toHaveBeenCalled(); + expect(updateJwksFile).toHaveBeenCalledWith([ + { + keyId: '00000000-0000-0000-0000-000000000001', + publicKey: mockPublicKey, + }, + { keyId: 'new-test-key-id', publicKey: mockPublicKey }, + ]); + expect(mockedWriteKeyDirectory).toHaveBeenCalledWith([ + { + createdDate: startOfMonthFormatted, + kid: '00000000-0000-0000-0000-000000000001', + }, + { createdDate: todayFormatted, kid: 'new-test-key-id' }, + ]); + expect(deleteKey).not.toHaveBeenCalled(); + }); + + test('should perform key rotation with two existing keys', async () => { + // arrange + const mockEvent = {} as EventBridgeEvent<'Scheduled Event', any>; + const mockContext = {} as Context; + const mockCallback = (() => {}) as Callback; + const startOfMonth = new Date(); + startOfMonth.setDate(1); + + const startOfPreviousMonth = new Date( + startOfMonth.getTime() - 25 * 60 * 60 * 1000 + ); + startOfPreviousMonth.setDate(1); + const todayFormatted = new Date().toISOString().split('T')[0]; + const startOfMonthFormatted = startOfMonth.toISOString().split('T')[0]; + const startOfPreviousMonthFormatted = startOfPreviousMonth + .toISOString() + .split('T')[0]; + + const mockKeyDirectory: SigningKeyDirectory = [ + { + createdDate: startOfPreviousMonthFormatted, + kid: '00000000-0000-0000-0000-000000000000', + }, + { + createdDate: startOfMonthFormatted, + kid: '00000000-0000-0000-0000-000000000001', + }, + ]; + const mockPublicKey = Uint8Array.from([1, 2, 3]); + + const mockedGetKeyDirectory = jest.mocked(getKeyDirectory); + const mockedGenerateKey = jest.mocked(generateKey); + const mockedGetPublicKey = jest.mocked(getPublicKey); + const mockedWriteKeyDirectory = jest.mocked(writeKeyDirectory); + + mockedGetKeyDirectory.mockImplementation(() => + Promise.resolve(mockKeyDirectory) + ); + mockedGenerateKey.mockImplementation(() => + Promise.resolve('new-test-key-id') + ); + mockedGetPublicKey.mockImplementation((keyId) => + Promise.resolve({ keyId, publicKey: mockPublicKey }) + ); + + // act + await handler(mockEvent, mockContext, mockCallback); + + // assert + expect(mockedGenerateKey).toHaveBeenCalled(); + expect(updateJwksFile).toHaveBeenCalledWith([ + { + keyId: '00000000-0000-0000-0000-000000000001', + publicKey: mockPublicKey, + }, + { keyId: 'new-test-key-id', publicKey: mockPublicKey }, + ]); + expect(mockedWriteKeyDirectory).toHaveBeenCalledWith([ + { + createdDate: startOfMonthFormatted, + kid: '00000000-0000-0000-0000-000000000001', + }, + { createdDate: todayFormatted, kid: 'new-test-key-id' }, + ]); + expect(deleteKey).toHaveBeenCalledTimes(1); + expect(deleteKey).toHaveBeenCalledWith( + '00000000-0000-0000-0000-000000000000' + ); + }); + }); +}); diff --git a/lambdas/jwks-key-rotation/src/__tests__/utils/aws/ssm-util.test.ts b/lambdas/jwks-key-rotation/src/__tests__/utils/aws/ssm-util.test.ts new file mode 100644 index 00000000..51f2b199 --- /dev/null +++ b/lambdas/jwks-key-rotation/src/__tests__/utils/aws/ssm-util.test.ts @@ -0,0 +1,91 @@ +import { getParameter, putParameter } from '@/src/utils/aws/ssm-util'; +import { + GetParameterCommand, + PutParameterCommand, + SSMClient, +} from '@aws-sdk/client-ssm'; + +jest.mock('@aws-sdk/client-ssm', () => ({ + ...jest.requireActual('@aws-sdk/client-ssm'), +})); +jest.mock('@/src/utils/logger'); + +describe('ssm-util', () => { + describe('getParameter', () => { + test('should get SSM parameter', async () => { + // arrange + const mockResponse = { + Parameter: { Value: 'test value' }, + }; + const ssmClientSpy = jest + .spyOn(SSMClient.prototype, 'send') + .mockImplementation(() => mockResponse); + + // act + const result = await getParameter('test_parameter/name'); + + // assert + expect(result).toMatchObject(mockResponse); + expect(ssmClientSpy).toHaveBeenCalledWith( + expect.any(GetParameterCommand) + ); + expect(ssmClientSpy).toHaveBeenCalledWith( + expect.objectContaining({ input: { Name: 'test_parameter/name' } }) + ); + }); + + test('should reject missing parmeter name', async () => { + // act + let error; + try { + await getParameter(); + } catch (caughtError) { + error = caughtError; + } + + // assert + expect(error).toBeTruthy(); + expect((error as Error).message).toBe('Missing parameter name'); + }); + }); + + describe('putParameter', () => { + test('should update SSM parameter', async () => { + //arrange + const ssmClientSpy = jest + .spyOn(SSMClient.prototype, 'send') + .mockImplementation(() => ({})); + + //act + await putParameter('{"test":123}', 'test_parameter/name'); + + //assert + expect(ssmClientSpy).toHaveBeenCalledWith( + expect.any(PutParameterCommand) + ); + expect(ssmClientSpy).toHaveBeenCalledWith( + expect.objectContaining({ + input: { + Name: 'test_parameter/name', + Overwrite: true, + Value: '{"test":123}', + }, + }) + ); + }); + + test('should reject missing parmeter name', async () => { + //act + let error; + try { + await putParameter('{"test":123}'); + } catch (caughtError) { + error = caughtError; + } + + // assert + expect(error).toBeTruthy(); + expect((error as Error).message).toBe('Missing parameter name'); + }); + }); +}); diff --git a/lambdas/jwks-key-rotation/src/__tests__/utils/aws/tag-util.test.ts b/lambdas/jwks-key-rotation/src/__tests__/utils/aws/tag-util.test.ts new file mode 100644 index 00000000..d3a96a70 --- /dev/null +++ b/lambdas/jwks-key-rotation/src/__tests__/utils/aws/tag-util.test.ts @@ -0,0 +1,114 @@ +import { getKeyTags } from '@/src/utils/aws/tag-util'; + +describe('tag-util', () => { + const OLD_ENV = { ...process.env }; + afterAll(() => { + process.env = OLD_ENV; + }); + + describe('getKeyTags', () => { + test('should parse multiple key tags', () => { + // arrange + process.env.KEY_TAGS = + 'Component=abc,Environment=abcd12,Group=dev,Name=def,Project=NHS Notify'; + + // act + const result = getKeyTags(); + + // assert + expect(result).toMatchObject([ + { TagKey: 'Component', TagValue: 'abc' }, + { TagKey: 'Environment', TagValue: 'abcd12' }, + { TagKey: 'Group', TagValue: 'dev' }, + { TagKey: 'Name', TagValue: 'def' }, + { TagKey: 'Project', TagValue: 'NHS Notify' }, + ]); + }); + + test('should parse a single key tag', () => { + // arrange + process.env.KEY_TAGS = 'Component=abc 123'; + + // act + const result = getKeyTags(); + + // assert + expect(result).toMatchObject([ + { TagKey: 'Component', TagValue: 'abc 123' }, + ]); + }); + + test('should parse unset key tags', () => { + // arrange + delete process.env.KEY_TAGS; + + // act + const result = getKeyTags(); + + // assert + expect(result).toMatchObject([]); + }); + + test('should parse empty key tags', () => { + // arrange + process.env.KEY_TAGS = ''; + + // act + const result = getKeyTags(); + + // assert + expect(result).toMatchObject([]); + }); + + test('should ignore empty tags', () => { + // arrange + process.env.KEY_TAGS = 'Component=abc 123,'; + + // act + const result = getKeyTags(); + + // assert + expect(result).toMatchObject([ + { TagKey: 'Component', TagValue: 'abc 123' }, + ]); + }); + + test('should reject invalid comma separted list', () => { + // arrange + process.env.KEY_TAGS = '{"parameter1":"value1"}'; + + // act + let error; + try { + getKeyTags(); + } catch (caughtError) { + error = caughtError; + } + + // assert + expect(error).toBeTruthy(); + expect((error as Error).message).toBe( + 'Invalid tags {"parameter1":"value1"}' + ); + }); + + test('should reject invalid parameter', () => { + // arrange + process.env.KEY_TAGS = 'Component=abc 123='; + + // act + let error; + try { + getKeyTags(); + } catch (caughtError) { + error = caughtError; + } + + // assert + expect(error).toBeTruthy(); + expect((error as Error).message).toBe( + 'Invalid tag parameter Component=abc 123=' + ); + }); + }); +}); diff --git a/lambdas/jwks-key-rotation/src/handler.ts b/lambdas/jwks-key-rotation/src/handler.ts index 79a7fa46..0fddefcc 100644 --- a/lambdas/jwks-key-rotation/src/handler.ts +++ b/lambdas/jwks-key-rotation/src/handler.ts @@ -4,10 +4,10 @@ import { getKeyDirectory, SigningKeyDirectory, writeKeyDirectory, -} from './utils/key-directory-repository'; -import { generateKey, getPublicKey } from './utils/key-util'; -import { updateJwksFile } from './utils/jwks-util'; -import { deleteKey } from './utils/aws/kms-util'; +} from '@/src/utils/key-directory-repository'; +import { generateKey, getPublicKey } from '@/src/utils/key-util'; +import { updateJwksFile } from '@/src/utils/jwks-util'; +import { deleteKey } from '@/src/utils/aws/kms-util'; const keyLifetimeDays = Number.parseInt( process.env.KEY_LIFETIME_DAYS ?? '28', diff --git a/lambdas/jwks-key-rotation/src/utils/aws/ssm-util.ts b/lambdas/jwks-key-rotation/src/utils/aws/ssm-util.ts index 37bbff7d..9d1071a8 100644 --- a/lambdas/jwks-key-rotation/src/utils/aws/ssm-util.ts +++ b/lambdas/jwks-key-rotation/src/utils/aws/ssm-util.ts @@ -5,7 +5,7 @@ import { PutParameterCommandOutput, SSMClient, } from '@aws-sdk/client-ssm'; -import { logger } from '../logger'; +import { logger } from '@/src/utils/logger'; const ssmClient = new SSMClient({ region: process.env.REGION, @@ -27,17 +27,14 @@ export async function getParameter( ); } -export async function putParameter( - value: string, - name = '' -): Promise { +export async function putParameter(value: string, name = ''): Promise { if (!name) { throw new Error('Missing parameter name'); } logger.info(`Updating parameter ${name}`); - return ssmClient.send( + ssmClient.send( new PutParameterCommand({ Name: name, Value: value, diff --git a/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts b/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts index 0c567bed..31a6a8cd 100644 --- a/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts +++ b/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts @@ -1,17 +1,26 @@ import { Tag } from '@aws-sdk/client-kms'; -const tagsMatcher = /^(\w=\w,?)*$/; +const commaSeparatedMatcher = /^([\w -=,?])*$/; +const parameterMatcher = /^([\w -])+=([\w -])+$/; export function getKeyTags(): Array { - const keyTags: string = process.env.KEY_TAGS || ''; - if (!tagsMatcher.test(keyTags)) { - throw new Error(`Invalid tags ${keyTags}`); + const commaSeparatedKeyTags: string = process.env.KEY_TAGS || ''; + if (!commaSeparatedMatcher.test(commaSeparatedKeyTags)) { + throw new Error(`Invalid tags ${commaSeparatedKeyTags}`); } - return keyTags + const parameters = commaSeparatedKeyTags .split(',') - .filter((keyTag) => !!keyTag) - .map((keyTag) => keyTag.split('=')) + .filter((parameter) => !!parameter); + + if ( + parameters.findIndex((parameter) => !parameterMatcher.test(parameter)) > -1 + ) { + throw new Error(`Invalid tag parameter ${commaSeparatedKeyTags}`); + } + + return parameters + .map((parameter) => parameter.split('=')) .map((keyTag) => ({ TagKey: keyTag[0], TagValue: keyTag[1], From 638accded2705b7a8ac8f134108fa7615c8da22b Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Mon, 28 Apr 2025 09:15:11 +0100 Subject: [PATCH 22/54] CCM-8897: unit tests --- lambdas/jwks-key-rotation/package.json | 1 + .../src/__tests__/handler.test.ts | 16 +- .../src/__tests__/utils/aws/ssm-util.test.ts | 8 +- .../src/utils/aws/ssm-util.ts | 1 - .../src/utils/aws/tag-util.ts | 7 +- package-lock.json | 226 ++++++++++++++++++ 6 files changed, 237 insertions(+), 22 deletions(-) diff --git a/lambdas/jwks-key-rotation/package.json b/lambdas/jwks-key-rotation/package.json index eb50d466..cde35c6c 100644 --- a/lambdas/jwks-key-rotation/package.json +++ b/lambdas/jwks-key-rotation/package.json @@ -13,6 +13,7 @@ "@tsconfig/node20": "^20.1.5", "@types/aws-lambda": "^8.10.147", "@types/node": "^22.14.0", + "aws-lambda": "^1.0.7", "jest": "^29.7.0", "jest-html-reporter": "^3.10.2", "jest-mock-extended": "^4.0.0-beta1", diff --git a/lambdas/jwks-key-rotation/src/__tests__/handler.test.ts b/lambdas/jwks-key-rotation/src/__tests__/handler.test.ts index b3eb5b5d..cb578187 100644 --- a/lambdas/jwks-key-rotation/src/__tests__/handler.test.ts +++ b/lambdas/jwks-key-rotation/src/__tests__/handler.test.ts @@ -18,21 +18,11 @@ jest.mock('@/src/utils/key-util'); jest.mock('@/src/utils/jwks-util'); jest.mock('@/src/utils/aws/kms-util'); -// import type { ScheduledHandler } from 'aws-lambda'; -// import { -// getKeyDirectory, -// SigningKeyDirectory, -// writeKeyDirectory, -// } from '@/src/utils/key-directory-repository'; -// import { generateKey, getPublicKey } from '@/src/utils/key-util'; -// import { updateJwksFile } from '@/src/utils/jwks-util'; -// import { deleteKey } from '@/src/utils/aws/kms-util'; - describe('handler', () => { describe('perform key rotation (generate new KMS key, update public jwks file, update key directory and delete old keys)', () => { test('should perform key rotation with no existing keys', async () => { // arrange - const mockEvent = {} as EventBridgeEvent<'Scheduled Event', any>; + const mockEvent = {} as EventBridgeEvent<'Scheduled Event', unknown>; const mockContext = {} as Context; const mockCallback = (() => {}) as Callback; const mockKeyDirectory: SigningKeyDirectory = []; @@ -70,7 +60,7 @@ describe('handler', () => { test('should perform key rotation with one existing key', async () => { // arrange - const mockEvent = {} as EventBridgeEvent<'Scheduled Event', any>; + const mockEvent = {} as EventBridgeEvent<'Scheduled Event', unknown>; const mockContext = {} as Context; const mockCallback = (() => {}) as Callback; const startOfMonth = new Date(); @@ -126,7 +116,7 @@ describe('handler', () => { test('should perform key rotation with two existing keys', async () => { // arrange - const mockEvent = {} as EventBridgeEvent<'Scheduled Event', any>; + const mockEvent = {} as EventBridgeEvent<'Scheduled Event', unknown>; const mockContext = {} as Context; const mockCallback = (() => {}) as Callback; const startOfMonth = new Date(); diff --git a/lambdas/jwks-key-rotation/src/__tests__/utils/aws/ssm-util.test.ts b/lambdas/jwks-key-rotation/src/__tests__/utils/aws/ssm-util.test.ts index 51f2b199..7ba46830 100644 --- a/lambdas/jwks-key-rotation/src/__tests__/utils/aws/ssm-util.test.ts +++ b/lambdas/jwks-key-rotation/src/__tests__/utils/aws/ssm-util.test.ts @@ -51,15 +51,15 @@ describe('ssm-util', () => { describe('putParameter', () => { test('should update SSM parameter', async () => { - //arrange + // arrange const ssmClientSpy = jest .spyOn(SSMClient.prototype, 'send') .mockImplementation(() => ({})); - //act + // act await putParameter('{"test":123}', 'test_parameter/name'); - //assert + // assert expect(ssmClientSpy).toHaveBeenCalledWith( expect.any(PutParameterCommand) ); @@ -75,7 +75,7 @@ describe('ssm-util', () => { }); test('should reject missing parmeter name', async () => { - //act + // act let error; try { await putParameter('{"test":123}'); diff --git a/lambdas/jwks-key-rotation/src/utils/aws/ssm-util.ts b/lambdas/jwks-key-rotation/src/utils/aws/ssm-util.ts index 9d1071a8..bad079ec 100644 --- a/lambdas/jwks-key-rotation/src/utils/aws/ssm-util.ts +++ b/lambdas/jwks-key-rotation/src/utils/aws/ssm-util.ts @@ -2,7 +2,6 @@ import { GetParameterCommand, GetParameterCommandOutput, PutParameterCommand, - PutParameterCommandOutput, SSMClient, } from '@aws-sdk/client-ssm'; import { logger } from '@/src/utils/logger'; diff --git a/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts b/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts index 31a6a8cd..470a6b69 100644 --- a/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts +++ b/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts @@ -1,6 +1,7 @@ import { Tag } from '@aws-sdk/client-kms'; -const commaSeparatedMatcher = /^([\w -=,?])*$/; +// eslint-disable-next-line sonarjs/slow-regex, sonarjs/empty-string-repetition, security/detect-unsafe-regex +const commaSeparatedMatcher = /^([\w =-]*,?)*$/; const parameterMatcher = /^([\w -])+=([\w -])+$/; export function getKeyTags(): Array { @@ -13,9 +14,7 @@ export function getKeyTags(): Array { .split(',') .filter((parameter) => !!parameter); - if ( - parameters.findIndex((parameter) => !parameterMatcher.test(parameter)) > -1 - ) { + if (parameters.some((parameter) => !parameterMatcher.test(parameter))) { throw new Error(`Invalid tag parameter ${commaSeparatedKeyTags}`); } diff --git a/package-lock.json b/package-lock.json index 56cdff9b..b818a941 100644 --- a/package-lock.json +++ b/package-lock.json @@ -126,6 +126,7 @@ "@tsconfig/node20": "^20.1.5", "@types/aws-lambda": "^8.10.147", "@types/node": "^22.14.0", + "aws-lambda": "^1.0.7", "jest": "^29.7.0", "jest-html-reporter": "^3.10.2", "jest-mock-extended": "^4.0.0-beta1", @@ -16490,6 +16491,121 @@ "node": ">=14.0.0" } }, + "node_modules/aws-lambda": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/aws-lambda/-/aws-lambda-1.0.7.tgz", + "integrity": "sha512-9GNFMRrEMG5y3Jvv+V4azWvc+qNWdWLTjDdhf/zgMlz8haaaLWv0xeAIWxz9PuWUBawsVxy0zZotjCdR3Xq+2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "aws-sdk": "^2.814.0", + "commander": "^3.0.2", + "js-yaml": "^3.14.1", + "watchpack": "^2.0.0-beta.10" + }, + "bin": { + "lambda": "bin/lambda" + } + }, + "node_modules/aws-lambda/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/aws-lambda/node_modules/commander": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", + "dev": true, + "license": "MIT" + }, + "node_modules/aws-lambda/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/aws-lambda/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/aws-sdk": { + "version": "2.1692.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1692.0.tgz", + "integrity": "sha512-x511uiJ/57FIsbgUe5csJ13k3uzu25uWQE+XqfBis/sB0SFoiElJWXRkgEAUh0U6n40eT3ay5Ue4oPkRMu1LYw==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.16.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "util": "^0.12.4", + "uuid": "8.0.0", + "xml2js": "0.6.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aws-sdk/node_modules/ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/aws-sdk/node_modules/sax": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==", + "dev": true, + "license": "ISC" + }, + "node_modules/aws-sdk/node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/aws-sdk/node_modules/uuid": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", + "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/axe-core": { "version": "4.10.3", "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.3.tgz", @@ -19752,6 +19868,16 @@ "dev": true, "license": "MIT" }, + "node_modules/events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.x" + } + }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -20471,6 +20597,13 @@ "node": ">=10.13.0" } }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true, + "license": "BSD-2-Clause" + }, "node_modules/glob/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -21071,6 +21204,23 @@ "node": ">=0.10.0" } }, + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-array-buffer": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", @@ -23145,6 +23295,16 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/jmespath": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/joi": { "version": "17.13.3", "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.3.tgz", @@ -25995,6 +26155,16 @@ "node": ">=10.13.0" } }, + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, "node_modules/querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", @@ -28641,6 +28811,17 @@ "punycode": "^2.1.0" } }, + "node_modules/url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, "node_modules/url-parse": { "version": "1.5.10", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", @@ -28652,6 +28833,13 @@ "requires-port": "^1.0.0" } }, + "node_modules/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==", + "dev": true, + "license": "MIT" + }, "node_modules/urlpattern-polyfill": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz", @@ -28859,6 +29047,20 @@ "makeerror": "1.0.12" } }, + "node_modules/watchpack": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/web-streams-polyfill": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", @@ -29158,6 +29360,30 @@ "node": ">=12" } }, + "node_modules/xml2js": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", + "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", + "dev": true, + "license": "MIT", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xml2js/node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, "node_modules/xmlbuilder": { "version": "15.0.0", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.0.0.tgz", From d164a8014c027878a383f14e74d25fd6d1c1d949 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Mon, 28 Apr 2025 09:34:12 +0100 Subject: [PATCH 23/54] CCM-8897: unit tests --- lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts b/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts index 470a6b69..b6d68038 100644 --- a/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts +++ b/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts @@ -1,7 +1,7 @@ import { Tag } from '@aws-sdk/client-kms'; -// eslint-disable-next-line sonarjs/slow-regex, sonarjs/empty-string-repetition, security/detect-unsafe-regex -const commaSeparatedMatcher = /^([\w =-]*,?)*$/; +// eslint-disable-next-line sonarjs/slow-regex, security/detect-unsafe-regex +const commaSeparatedMatcher = /^(?:[\w =-]+,?)*$/; const parameterMatcher = /^([\w -])+=([\w -])+$/; export function getKeyTags(): Array { From ba8a9b64757f4f58b839711d1416c7ecbbfef937 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Mon, 28 Apr 2025 14:28:54 +0100 Subject: [PATCH 24/54] CCM-8897: pipeline debugging --- infrastructure/terraform/components/app/pre.sh | 7 ++++++- infrastructure/terraform/components/sandbox/pre.sh | 6 +++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/infrastructure/terraform/components/app/pre.sh b/infrastructure/terraform/components/app/pre.sh index 76f2b9d9..270f6125 100644 --- a/infrastructure/terraform/components/app/pre.sh +++ b/infrastructure/terraform/components/app/pre.sh @@ -1,2 +1,7 @@ +echo Running pre.sh +pwd + npm ci -(cd ../../../.. && npm run build-lambda) + +echo About to build lambdas +(cd ../../../.. && pwd && ls && npm run build-lambda) diff --git a/infrastructure/terraform/components/sandbox/pre.sh b/infrastructure/terraform/components/sandbox/pre.sh index c3449226..4a55e0bd 100644 --- a/infrastructure/terraform/components/sandbox/pre.sh +++ b/infrastructure/terraform/components/sandbox/pre.sh @@ -1,6 +1,10 @@ +echo Running pre.sh +pwd + if [ "$SUPPRESS_SANDBOX_CI" != "true" ] then npm ci fi -(cd ../../../.. && npm run build-lambda) +echo About to build lambdas +(cd ../../../.. && pwd && ls && npm run build-lambda) From 2a0b3204fc1798c9787effe7d0f24f315d92f996 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Tue, 29 Apr 2025 11:50:46 +0100 Subject: [PATCH 25/54] CCM-8897: remove debug logging --- infrastructure/terraform/components/app/pre.sh | 3 +-- infrastructure/terraform/components/sandbox/pre.sh | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/infrastructure/terraform/components/app/pre.sh b/infrastructure/terraform/components/app/pre.sh index 270f6125..9690ae95 100644 --- a/infrastructure/terraform/components/app/pre.sh +++ b/infrastructure/terraform/components/app/pre.sh @@ -1,7 +1,6 @@ echo Running pre.sh -pwd npm ci echo About to build lambdas -(cd ../../../.. && pwd && ls && npm run build-lambda) +(cd ../../../.. && npm run build-lambda) diff --git a/infrastructure/terraform/components/sandbox/pre.sh b/infrastructure/terraform/components/sandbox/pre.sh index 4a55e0bd..409f648a 100644 --- a/infrastructure/terraform/components/sandbox/pre.sh +++ b/infrastructure/terraform/components/sandbox/pre.sh @@ -1,5 +1,4 @@ echo Running pre.sh -pwd if [ "$SUPPRESS_SANDBOX_CI" != "true" ] then @@ -7,4 +6,4 @@ if [ "$SUPPRESS_SANDBOX_CI" != "true" ] fi echo About to build lambdas -(cd ../../../.. && pwd && ls && npm run build-lambda) +(cd ../../../.. && npm run build-lambda) From 1d3bdab3bf3b87379ed48ea75a8bf3b72bfc6f5b Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Tue, 29 Apr 2025 13:14:01 +0100 Subject: [PATCH 26/54] CCM-8897: fix --- lambdas/jwks-key-rotation/src/handler.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lambdas/jwks-key-rotation/src/handler.ts b/lambdas/jwks-key-rotation/src/handler.ts index 0fddefcc..04023192 100644 --- a/lambdas/jwks-key-rotation/src/handler.ts +++ b/lambdas/jwks-key-rotation/src/handler.ts @@ -25,9 +25,10 @@ function getKeysToDelete( if (keyDirectory.length <= 1) { return []; } + const cutOffDate = formattedDate(-keyLifetimeMillis); return keyDirectory.filter( - (keyMetadata) => keyMetadata.createdDate <= cutOffDate + (keyMetadata) => keyMetadata.createdDate.localeCompare(cutOffDate) < 0 ); } From ea4c469a936b88437aaaaaff160b11900027a879 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Tue, 29 Apr 2025 13:53:38 +0100 Subject: [PATCH 27/54] CCM-8897: self review --- .../ssm_parameter_asymmetric_key_policy.tf | 4 ---- 1 file changed, 4 deletions(-) diff --git a/infrastructure/terraform/modules/public-signing-keys/ssm_parameter_asymmetric_key_policy.tf b/infrastructure/terraform/modules/public-signing-keys/ssm_parameter_asymmetric_key_policy.tf index a664178c..d1ac75ba 100644 --- a/infrastructure/terraform/modules/public-signing-keys/ssm_parameter_asymmetric_key_policy.tf +++ b/infrastructure/terraform/modules/public-signing-keys/ssm_parameter_asymmetric_key_policy.tf @@ -3,10 +3,6 @@ resource "aws_ssm_parameter" "asymmetric_key_policy" { description = "The IAM policy applied to new asymmetric KMS keys used for CIS2 auth" type = "String" value = data.aws_iam_policy_document.asymmetric_key_policy.minified_json - - lifecycle { - ignore_changes = [value] - } } data "aws_iam_policy_document" "asymmetric_key_policy" { From 8a52d28ca30e36148fee0d9b5b5fa5b6c06aba5e Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Tue, 29 Apr 2025 15:00:24 +0100 Subject: [PATCH 28/54] CCM-8897: review --- .../terraform/components/sandbox/pre.sh | 5 +---- .../module_lambda_jwks_key_rotation.tf | 4 ++-- lambdas/jwks-key-rotation/package.json | 5 +++-- package-lock.json | 17 +++++------------ 4 files changed, 11 insertions(+), 20 deletions(-) diff --git a/infrastructure/terraform/components/sandbox/pre.sh b/infrastructure/terraform/components/sandbox/pre.sh index 409f648a..9964b566 100644 --- a/infrastructure/terraform/components/sandbox/pre.sh +++ b/infrastructure/terraform/components/sandbox/pre.sh @@ -1,9 +1,6 @@ echo Running pre.sh -if [ "$SUPPRESS_SANDBOX_CI" != "true" ] - then - npm ci -fi +if [ -z "$SKIP_SANDBOX_INSTALL" ]; then npm ci; fi echo About to build lambdas (cd ../../../.. && npm run build-lambda) diff --git a/infrastructure/terraform/modules/public-signing-keys/module_lambda_jwks_key_rotation.tf b/infrastructure/terraform/modules/public-signing-keys/module_lambda_jwks_key_rotation.tf index 819a8af3..7ff3b8d8 100644 --- a/infrastructure/terraform/modules/public-signing-keys/module_lambda_jwks_key_rotation.tf +++ b/infrastructure/terraform/modules/public-signing-keys/module_lambda_jwks_key_rotation.tf @@ -1,5 +1,5 @@ module "lambda_jwks_key_rotation" { - source = "git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/lambda?ref=v1.0.9" + source = "git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/lambda?ref=v2.0.2" providers = { aws = aws @@ -12,7 +12,7 @@ module "lambda_jwks_key_rotation" { component = var.component environment = var.environment project = var.project - region = "eu-west-2" + region = var.region group = var.group log_retention_in_days = var.log_retention_in_days diff --git a/lambdas/jwks-key-rotation/package.json b/lambdas/jwks-key-rotation/package.json index cde35c6c..ee6bfb55 100644 --- a/lambdas/jwks-key-rotation/package.json +++ b/lambdas/jwks-key-rotation/package.json @@ -2,17 +2,18 @@ "name": "jwks-key-rotation", "main": "handler.ts", "scripts": { + "build-lambda": "rm -rf dist && npx esbuild --bundle --minify --sourcemap --target=es2020 --platform=node --entry-names=[name] --outdir=dist src/handler.ts", "lint": "eslint ./src", "lint:fix": "eslint ./src --fix", "test:unit": "jest", - "build-lambda": "rm -rf dist && npx esbuild --bundle --minify --sourcemap --target=es2020 --platform=node --entry-names=[name] --outdir=dist src/handler.ts" + "typecheck": "tsc --noEmit" }, "description": "Runs periodically to generate a new public-private key pair and update the published public keys", "devDependencies": { "@aws-sdk/types": "^3.775.0", "@tsconfig/node20": "^20.1.5", "@types/aws-lambda": "^8.10.147", - "@types/node": "^22.14.0", + "@types/node": "^20.17.32", "aws-lambda": "^1.0.7", "jest": "^29.7.0", "jest-html-reporter": "^3.10.2", diff --git a/package-lock.json b/package-lock.json index b818a941..0e4780a9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -125,7 +125,7 @@ "@aws-sdk/types": "^3.775.0", "@tsconfig/node20": "^20.1.5", "@types/aws-lambda": "^8.10.147", - "@types/node": "^22.14.0", + "@types/node": "^20.17.32", "aws-lambda": "^1.0.7", "jest": "^29.7.0", "jest-html-reporter": "^3.10.2", @@ -872,13 +872,13 @@ } }, "lambdas/jwks-key-rotation/node_modules/@types/node": { - "version": "22.14.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.0.tgz", - "integrity": "sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA==", + "version": "20.17.32", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.32.tgz", + "integrity": "sha512-zeMXFn8zQ+UkjK4ws0RiOC9EWByyW1CcVmLe+2rQocXRsGEDxUCwPEIVgpsGcLHS/P8JkT0oa3839BRABS0oPw==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.21.0" + "undici-types": "~6.19.2" } }, "lambdas/jwks-key-rotation/node_modules/jest-mock-extended": { @@ -895,13 +895,6 @@ "typescript": "^3.0.0 || ^4.0.0 || ^5.0.0" } }, - "lambdas/jwks-key-rotation/node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, - "license": "MIT" - }, "node_modules/@adobe/css-tools": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.2.tgz", From 1df1ffc7d40c7289f13d364e9892287329f2eafb Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Tue, 29 Apr 2025 15:39:35 +0100 Subject: [PATCH 29/54] CCM-8897: review --- lambdas/jwks-key-rotation/src/__tests__/utils/key-util.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lambdas/jwks-key-rotation/src/__tests__/utils/key-util.test.ts b/lambdas/jwks-key-rotation/src/__tests__/utils/key-util.test.ts index 1ef78ee8..661af15c 100644 --- a/lambdas/jwks-key-rotation/src/__tests__/utils/key-util.test.ts +++ b/lambdas/jwks-key-rotation/src/__tests__/utils/key-util.test.ts @@ -66,7 +66,7 @@ describe('key-util', () => { ); }); - test('should propagate miussing key policy error', async () => { + test('should propagate missing key policy error', async () => { // arrange const mockKeyPolicy = '/nhs-notify-abcd12-sbx-psk/asymmetric_key_policy'; process.env.SSM_ASYMMETRIC_KEY_POLICY = mockKeyPolicy; From 3f51a6efaa28531a6e38c5615814b1f167d971d4 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Wed, 30 Apr 2025 09:22:18 +0100 Subject: [PATCH 30/54] CCM-8897: review --- infrastructure/terraform/modules/public-signing-keys/locals.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infrastructure/terraform/modules/public-signing-keys/locals.tf b/infrastructure/terraform/modules/public-signing-keys/locals.tf index 248a27a8..161a9e88 100644 --- a/infrastructure/terraform/modules/public-signing-keys/locals.tf +++ b/infrastructure/terraform/modules/public-signing-keys/locals.tf @@ -1,6 +1,6 @@ locals { root_domain_name = "jwks.${var.environment}.${data.aws_route53_zone.main.name}" # e.g. jwks.[main|dev|abxy0].foo.[dev|nonprod|prod].nhsnotify.national.nhs.uk - lambdas_source_code_dir = "/../../../../lambdas" + lambdas_source_code_dir = "../../../../lambdas" ssm_asymmetric_key_policy_name = "/${local.csi}/asymmetric_key_policy" ssm_key_directory_name = "/${local.csi}/key_directory" } From 57f6354c366c7e74615f031465e9049f2cb31eaf Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Wed, 30 Apr 2025 15:14:58 +0100 Subject: [PATCH 31/54] CCM-8897: review --- infrastructure/terraform/components/app/pre.sh | 2 +- infrastructure/terraform/components/sandbox/pre.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/infrastructure/terraform/components/app/pre.sh b/infrastructure/terraform/components/app/pre.sh index 9690ae95..8bd24612 100644 --- a/infrastructure/terraform/components/app/pre.sh +++ b/infrastructure/terraform/components/app/pre.sh @@ -3,4 +3,4 @@ echo Running pre.sh npm ci echo About to build lambdas -(cd ../../../.. && npm run build-lambda) +npm run build-lambda diff --git a/infrastructure/terraform/components/sandbox/pre.sh b/infrastructure/terraform/components/sandbox/pre.sh index 9964b566..5d903a76 100644 --- a/infrastructure/terraform/components/sandbox/pre.sh +++ b/infrastructure/terraform/components/sandbox/pre.sh @@ -3,4 +3,4 @@ echo Running pre.sh if [ -z "$SKIP_SANDBOX_INSTALL" ]; then npm ci; fi echo About to build lambdas -(cd ../../../.. && npm run build-lambda) +npm run build-lambda From 847426f2199a1ed1de2c9def80f580bffb5af6da Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Wed, 30 Apr 2025 16:01:57 +0100 Subject: [PATCH 32/54] CCM-8897: fix --- .../src/__tests__/handler.test.ts | 72 ++++++++++++++++++- lambdas/jwks-key-rotation/src/handler.ts | 13 +++- 2 files changed, 79 insertions(+), 6 deletions(-) diff --git a/lambdas/jwks-key-rotation/src/__tests__/handler.test.ts b/lambdas/jwks-key-rotation/src/__tests__/handler.test.ts index cb578187..bde015e6 100644 --- a/lambdas/jwks-key-rotation/src/__tests__/handler.test.ts +++ b/lambdas/jwks-key-rotation/src/__tests__/handler.test.ts @@ -126,8 +126,9 @@ describe('handler', () => { startOfMonth.getTime() - 25 * 60 * 60 * 1000 ); startOfPreviousMonth.setDate(1); + const recentKey = new Date(Date.now() - 24 * 60 * 60 * 1000); const todayFormatted = new Date().toISOString().split('T')[0]; - const startOfMonthFormatted = startOfMonth.toISOString().split('T')[0]; + const recentKeyFormatted = recentKey.toISOString().split('T')[0]; const startOfPreviousMonthFormatted = startOfPreviousMonth .toISOString() .split('T')[0]; @@ -138,7 +139,7 @@ describe('handler', () => { kid: '00000000-0000-0000-0000-000000000000', }, { - createdDate: startOfMonthFormatted, + createdDate: recentKeyFormatted, kid: '00000000-0000-0000-0000-000000000001', }, ]; @@ -173,7 +174,7 @@ describe('handler', () => { ]); expect(mockedWriteKeyDirectory).toHaveBeenCalledWith([ { - createdDate: startOfMonthFormatted, + createdDate: recentKeyFormatted, kid: '00000000-0000-0000-0000-000000000001', }, { createdDate: todayFormatted, kid: 'new-test-key-id' }, @@ -183,5 +184,70 @@ describe('handler', () => { '00000000-0000-0000-0000-000000000000' ); }); + + test('should perform key rotation with three existing keys that are all old', async () => { + // arrange + const mockEvent = {} as EventBridgeEvent<'Scheduled Event', unknown>; + const mockContext = {} as Context; + const mockCallback = (() => {}) as Callback; + const todayFormatted = new Date().toISOString().split('T')[0]; + const mockKeyDirectory: SigningKeyDirectory = [ + { + createdDate: '2000-01-01', + kid: '00000000-0000-0000-0000-000000000000', + }, + { + createdDate: '2000-01-02', + kid: '00000000-0000-0000-0000-000000000001', + }, + { + createdDate: '2000-01-03', + kid: '00000000-0000-0000-0000-000000000002', + }, + ]; + const mockPublicKey = Uint8Array.from([1, 2, 3]); + + const mockedGetKeyDirectory = jest.mocked(getKeyDirectory); + const mockedGenerateKey = jest.mocked(generateKey); + const mockedGetPublicKey = jest.mocked(getPublicKey); + const mockedWriteKeyDirectory = jest.mocked(writeKeyDirectory); + + mockedGetKeyDirectory.mockImplementation(() => + Promise.resolve(mockKeyDirectory) + ); + mockedGenerateKey.mockImplementation(() => + Promise.resolve('new-test-key-id') + ); + mockedGetPublicKey.mockImplementation((keyId) => + Promise.resolve({ keyId, publicKey: mockPublicKey }) + ); + + // act + await handler(mockEvent, mockContext, mockCallback); + + // assert + expect(mockedGenerateKey).toHaveBeenCalled(); + expect(updateJwksFile).toHaveBeenCalledWith([ + { + keyId: '00000000-0000-0000-0000-000000000002', + publicKey: mockPublicKey, + }, + { keyId: 'new-test-key-id', publicKey: mockPublicKey }, + ]); + expect(mockedWriteKeyDirectory).toHaveBeenCalledWith([ + { + createdDate: '2000-01-03', + kid: '00000000-0000-0000-0000-000000000002', + }, + { createdDate: todayFormatted, kid: 'new-test-key-id' }, + ]); + expect(deleteKey).toHaveBeenCalledTimes(2); + expect(deleteKey).toHaveBeenCalledWith( + '00000000-0000-0000-0000-000000000000' + ); + expect(deleteKey).toHaveBeenCalledWith( + '00000000-0000-0000-0000-000000000001' + ); + }); }); }); diff --git a/lambdas/jwks-key-rotation/src/handler.ts b/lambdas/jwks-key-rotation/src/handler.ts index 04023192..48a6fde4 100644 --- a/lambdas/jwks-key-rotation/src/handler.ts +++ b/lambdas/jwks-key-rotation/src/handler.ts @@ -1,4 +1,4 @@ -/* eslint-disable unicorn/no-array-reduce */ +/* eslint-disable unicorn/no-array-reduce, unicorn/prefer-at */ import type { ScheduledHandler } from 'aws-lambda'; import { getKeyDirectory, @@ -22,13 +22,20 @@ function formattedDate(offsetMillis = 0): string { function getKeysToDelete( keyDirectory: SigningKeyDirectory ): SigningKeyDirectory { - if (keyDirectory.length <= 1) { + if (keyDirectory.length <= 0) { return []; } + keyDirectory.sort((a, b) => a.createdDate.localeCompare(b.createdDate)); + const latestKey = keyDirectory[keyDirectory.length - 1]; const cutOffDate = formattedDate(-keyLifetimeMillis); + // Delete any keys that are suffiently old whilst ensuring that we retain the latest key. + // This is intended to ensure a continued service where public keys may be cached or + // logins may be in progress whist the key rotation occurs. return keyDirectory.filter( - (keyMetadata) => keyMetadata.createdDate.localeCompare(cutOffDate) < 0 + (keyMetadata) => + keyMetadata.kid !== latestKey.kid && + keyMetadata.createdDate.localeCompare(cutOffDate) < 0 ); } From cf2645a13ab869be94b86c17193242e5163aa282 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Fri, 2 May 2025 15:09:02 +0100 Subject: [PATCH 33/54] CCM-9554: key rotation tests - wip --- .../terraform/components/sandbox/outputs.tf | 12 +++ .../modules/public-signing-keys/outputs.tf | 3 + lambdas/jwks-key-rotation/src/handler.ts | 3 + .../src/utils/aws/tag-util.ts | 22 +++-- package-lock.json | 46 ++++++++- package.json | 1 + scripts/create_backend_sandbox.sh | 2 +- .../jwks-key-rotation.backend.spec.ts | 28 ++++++ ...omponent.ts => inactive.component.spec.ts} | 0 ....component.ts => signin.component.spec.ts} | 0 ...component.ts => signout.component.spec.ts} | 0 .../config/backend/backend.config.ts | 20 ++++ .../test-team/config/backend/backend.setup.ts | 11 +++ .../component.config.ts} | 4 +- tests/test-team/helpers/kms-util.ts | 95 +++++++++++++++++++ tests/test-team/helpers/logger.ts | 15 +++ tests/test-team/helpers/ssm-util.ts | 27 ++++++ tests/test-team/package.json | 10 +- utils/backend-config/jest.config.ts | 53 +++++++++++ utils/backend-config/package.json | 14 +++ utils/backend-config/src/backend-config.ts | 27 ++++++ utils/backend-config/src/index.ts | 1 + utils/backend-config/tsconfig.json | 8 ++ 23 files changed, 390 insertions(+), 12 deletions(-) create mode 100644 infrastructure/terraform/modules/public-signing-keys/outputs.tf create mode 100644 tests/test-team/backend-tests/jwks-key-rotation.backend.spec.ts rename tests/test-team/component-tests/{inactive.component.ts => inactive.component.spec.ts} (100%) rename tests/test-team/component-tests/{signin.component.ts => signin.component.spec.ts} (100%) rename tests/test-team/component-tests/{signout.component.ts => signout.component.spec.ts} (100%) create mode 100644 tests/test-team/config/backend/backend.config.ts create mode 100644 tests/test-team/config/backend/backend.setup.ts rename tests/test-team/config/{local.config.ts => component/component.config.ts} (90%) create mode 100644 tests/test-team/helpers/kms-util.ts create mode 100644 tests/test-team/helpers/logger.ts create mode 100644 tests/test-team/helpers/ssm-util.ts create mode 100644 utils/backend-config/jest.config.ts create mode 100644 utils/backend-config/package.json create mode 100644 utils/backend-config/src/backend-config.ts create mode 100644 utils/backend-config/src/index.ts create mode 100644 utils/backend-config/tsconfig.json diff --git a/infrastructure/terraform/components/sandbox/outputs.tf b/infrastructure/terraform/components/sandbox/outputs.tf index d76e3509..c192f34a 100644 --- a/infrastructure/terraform/components/sandbox/outputs.tf +++ b/infrastructure/terraform/components/sandbox/outputs.tf @@ -39,3 +39,15 @@ output "csrf_secret" { sensitive = true } + +output "name_tag" { + value = local.default_tags["Name"] +} + +output "group_tag" { + value = local.default_tags["Group"] +} + +output "key_directory_ssm_parameter_name" { + value = module.public_signing_keys.key_directory_ssm_parameter_name +} diff --git a/infrastructure/terraform/modules/public-signing-keys/outputs.tf b/infrastructure/terraform/modules/public-signing-keys/outputs.tf new file mode 100644 index 00000000..e47a1218 --- /dev/null +++ b/infrastructure/terraform/modules/public-signing-keys/outputs.tf @@ -0,0 +1,3 @@ +output "key_directory_ssm_parameter_name" { + value = local.ssm_key_directory_name +} diff --git a/lambdas/jwks-key-rotation/src/handler.ts b/lambdas/jwks-key-rotation/src/handler.ts index 48a6fde4..a2f38d60 100644 --- a/lambdas/jwks-key-rotation/src/handler.ts +++ b/lambdas/jwks-key-rotation/src/handler.ts @@ -75,6 +75,9 @@ export const handler: ScheduledHandler = async () => { kid: keyId, }); + TODO - get public key immediately from generated key due to eventual consistency issue + https://docs.aws.amazon.com/kms/latest/developerguide/accessing-kms.html#programming-eventual-consistency + // Get the public keys const publicKeys = await Promise.all( newKeyDirectory.map((keyMetadata) => getPublicKey(keyMetadata.kid)) diff --git a/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts b/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts index b6d68038..18f3df3e 100644 --- a/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts +++ b/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts @@ -4,6 +4,9 @@ import { Tag } from '@aws-sdk/client-kms'; const commaSeparatedMatcher = /^(?:[\w =-]+,?)*$/; const parameterMatcher = /^([\w -])+=([\w -])+$/; +const USAGE_TAG_NAME = 'Usage'; +const USAGE_TAG_VALUE = 'CIS2-JWKS-AUTH'; + export function getKeyTags(): Array { const commaSeparatedKeyTags: string = process.env.KEY_TAGS || ''; if (!commaSeparatedMatcher.test(commaSeparatedKeyTags)) { @@ -18,10 +21,17 @@ export function getKeyTags(): Array { throw new Error(`Invalid tag parameter ${commaSeparatedKeyTags}`); } - return parameters - .map((parameter) => parameter.split('=')) - .map((keyTag) => ({ - TagKey: keyTag[0], - TagValue: keyTag[1], - })); + const tags = parameters + .map((parameter) => parameter.split('=')) + .map((keyTag) => ({ + TagKey: keyTag[0], + TagValue: keyTag[1], + })); + + tags.push({ + TagKey: USAGE_TAG_NAME, + TagValue: USAGE_TAG_VALUE + }) + + return tags; } diff --git a/package-lock.json b/package-lock.json index 0e4780a9..56cc6e2d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "lambdas/cis2-api", "lambdas/jwks-key-rotation", "tests/test-team", + "utils/backend-config", "utils/logger" ], "devDependencies": { @@ -24274,6 +24275,10 @@ "resolved": "tests/test-team", "link": true }, + "node_modules/nhs-notify-iam-webauth-util-backend-config": { + "resolved": "utils/backend-config", + "link": true + }, "node_modules/nhsuk-frontend": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/nhsuk-frontend/-/nhsuk-frontend-9.3.0.tgz", @@ -29561,10 +29566,42 @@ "version": "0.1.0", "devDependencies": { "@aws-sdk/client-cognito-identity-provider": "^3.772.0", + "@aws-sdk/client-kms": "^3.782.0", + "@aws-sdk/client-ssm": "^3.782.0", + "@aws-sdk/types": "^3.775.0", "@playwright/test": "^1.51.1", "@tsconfig/node20": "^20.1.5", "@types/uuid": "^10.0.0", - "generate-password": "^1.7.1" + "generate-password": "^1.7.1", + "nhs-notify-iam-webauth-util-backend-config": "^0.0.1", + "winston": "^3.14.2" + } + }, + "tests/test-team/node_modules/@aws-sdk/types": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.775.0.tgz", + "integrity": "sha512-ZoGKwa4C9fC9Av6bdfqcW6Ix5ot05F/S4VxWR2nHuMv7hzfmAjTOcUiWT7UR4hM/U0whf84VhDtXN/DWAk52KA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "tests/test-team/node_modules/@smithy/types": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "tests/test-team/node_modules/@types/uuid": { @@ -29574,6 +29611,13 @@ "dev": true, "license": "MIT" }, + "utils/backend-config": { + "name": "nhs-notify-iam-webauth-util-backend-config", + "version": "0.0.1", + "devDependencies": { + "@tsconfig/node20": "^20.1.5" + } + }, "utils/logger": { "name": "@nhs-notify-iam-webauth/utils-logger", "version": "0.0.1", diff --git a/package.json b/package.json index f431290b..fbad50b0 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "lambdas/cis2-api", "lambdas/jwks-key-rotation", "tests/test-team", + "utils/backend-config", "utils/logger" ], "scripts": { diff --git a/scripts/create_backend_sandbox.sh b/scripts/create_backend_sandbox.sh index 08338a73..5130bf24 100755 --- a/scripts/create_backend_sandbox.sh +++ b/scripts/create_backend_sandbox.sh @@ -13,7 +13,7 @@ COMPONENT="sandbox" AWS_ACCOUNT_ID="$(aws sts get-caller-identity --query Account --output text)" AWS_REGION="eu-west-2" PROJECT="nhs-notify" -GROUP="nhs-notify-template-management-dev" +GROUP="nhs-notify-iam-dev" root_dir=$(git rev-parse --show-toplevel) terraform_dir=$root_dir/infrastructure/terraform diff --git a/tests/test-team/backend-tests/jwks-key-rotation.backend.spec.ts b/tests/test-team/backend-tests/jwks-key-rotation.backend.spec.ts new file mode 100644 index 00000000..ee416b4f --- /dev/null +++ b/tests/test-team/backend-tests/jwks-key-rotation.backend.spec.ts @@ -0,0 +1,28 @@ +import { test, expect } from '@playwright/test'; +import { deleteAllKeysForTags } from '../helpers/kms-util'; +import { putParameter } from '../helpers/ssm-util'; + +const nameTag = process.env.NAME_TAG || 'unknown'; +const groupTag = process.env.GROUP_TAG || 'unknown'; +const usageTag = 'CIS2-JWKS-AUTH'; + +test.describe('jwks-key-rotation', () => { + test('should generate first key', async () => { + // arrange + + // Delete any existing KMS key rotation keys for the environment + await deleteAllKeysForTags(nameTag, groupTag, usageTag); + + // Clear key directory + await putParameter('[]', process.env.KEY_DIRECTORY_SSM_PARAMETER_NAME); + + // act + // Invoke the key rotation lambda + + // assert + + // Verify the contents of the JWKS public keys file in S3 + // Verify the contents of the key directory + // Verify the existance of the key in KMS + }); +}); diff --git a/tests/test-team/component-tests/inactive.component.ts b/tests/test-team/component-tests/inactive.component.spec.ts similarity index 100% rename from tests/test-team/component-tests/inactive.component.ts rename to tests/test-team/component-tests/inactive.component.spec.ts diff --git a/tests/test-team/component-tests/signin.component.ts b/tests/test-team/component-tests/signin.component.spec.ts similarity index 100% rename from tests/test-team/component-tests/signin.component.ts rename to tests/test-team/component-tests/signin.component.spec.ts diff --git a/tests/test-team/component-tests/signout.component.ts b/tests/test-team/component-tests/signout.component.spec.ts similarity index 100% rename from tests/test-team/component-tests/signout.component.ts rename to tests/test-team/component-tests/signout.component.spec.ts diff --git a/tests/test-team/config/backend/backend.config.ts b/tests/test-team/config/backend/backend.config.ts new file mode 100644 index 00000000..d11f6212 --- /dev/null +++ b/tests/test-team/config/backend/backend.config.ts @@ -0,0 +1,20 @@ +import { defineConfig } from '@playwright/test'; +import baseConfig from '../playwright.config'; + +export default defineConfig({ + ...baseConfig, + + timeout: 10_000, + workers: 1, + projects: [ + { + name: 'backend:setup', + testMatch: 'backend.setup.ts', + }, + { + name: 'backend', + testMatch: '*.backend.spec.ts', + dependencies: ['backend:setup'], + }, + ], +}); diff --git a/tests/test-team/config/backend/backend.setup.ts b/tests/test-team/config/backend/backend.setup.ts new file mode 100644 index 00000000..a72abe95 --- /dev/null +++ b/tests/test-team/config/backend/backend.setup.ts @@ -0,0 +1,11 @@ +import path from 'node:path'; +import { test as setup } from '@playwright/test'; +import { BackendConfigHelper } from 'nhs-notify-iam-webauth-util-backend-config'; + +setup('backend test setup', async () => { + const backendConfig = BackendConfigHelper.fromTerraformOutputsFile( + path.join(__dirname, '..', '..', '..', '..', 'sandbox_tf_outputs.json') + ); + + BackendConfigHelper.toEnv(backendConfig); +}); diff --git a/tests/test-team/config/local.config.ts b/tests/test-team/config/component/component.config.ts similarity index 90% rename from tests/test-team/config/local.config.ts rename to tests/test-team/config/component/component.config.ts index f99ed07d..ebca19a2 100644 --- a/tests/test-team/config/local.config.ts +++ b/tests/test-team/config/component/component.config.ts @@ -1,6 +1,6 @@ import path from 'node:path'; import { defineConfig, devices } from '@playwright/test'; -import baseConfig from './playwright.config'; +import baseConfig from '../playwright.config'; export default defineConfig({ ...baseConfig, @@ -10,7 +10,7 @@ export default defineConfig({ projects: [ { name: 'component', - testMatch: '*.component.ts', + testMatch: '*.component.spec.ts', use: { screenshot: 'only-on-failure', baseURL: 'http://localhost:3000', diff --git a/tests/test-team/helpers/kms-util.ts b/tests/test-team/helpers/kms-util.ts new file mode 100644 index 00000000..a96c7a83 --- /dev/null +++ b/tests/test-team/helpers/kms-util.ts @@ -0,0 +1,95 @@ +import { + KMSClient, + ListKeysCommand, + ListKeysCommandOutput, + ListResourceTagsCommand, + ScheduleKeyDeletionCommand, +} from '@aws-sdk/client-kms'; +import { logger } from './logger'; + +const kmsClient = new KMSClient({ + region: process.env.REGION, + retryMode: 'standard', + maxAttempts: 10, +}); + +async function listAllKeyIds(): Promise> { + let truncated = false; + let marker; + const allKeyIds: Array = []; + do { + const keysBatch: ListKeysCommandOutput = await kmsClient.send( + new ListKeysCommand({ + Limit: 1000, + Marker: marker, + }) + ); + + truncated = keysBatch.Truncated || false; + marker = keysBatch.NextMarker; + + keysBatch.Keys?.map((key) => key.KeyId || '') + .filter((keyId) => !!keyId) + .forEach((keyId) => allKeyIds.push(keyId)); + } while (truncated); + + return allKeyIds; +} + +async function getKeyTags( + keyId: string +): Promise<{ keyId: string; tags: Record }> { + const response = await kmsClient.send( + new ListResourceTagsCommand({ + KeyId: keyId, + }) + ); + const tags = response.Tags || []; + + logger.info(`Got key tags for ${keyId}: ${JSON.stringify(tags)}`); + const tagMap = tags.reduce( + (acc, tag) => { + const key = tag.TagKey || 'unknown'; + const value = tag.TagValue || ''; + acc[key] = value; + return acc; + }, + {} as Record + ); + return { keyId, tags: tagMap }; +} + +async function deleteKey(keyId: string): Promise { + logger.info(`Deleting key ${keyId}`); + + await kmsClient.send( + new ScheduleKeyDeletionCommand({ + KeyId: keyId, + }) + ); +} + +export async function deleteAllKeysForTags( + name: string, + group: string, + usage: string +): Promise { + logger.info( + `Looking for keys to delete using tags Name: ${name}, Group: ${group}, Usage: ${usage}` + ); + + const allKeyIds = await listAllKeyIds(); + logger.info(`allKeyIds (${allKeyIds.length}): ${JSON.stringify(allKeyIds)}`); + const taggedKeys = await Promise.all( + allKeyIds.map((keyId) => getKeyTags(keyId)) + ); + + const keysToDelete = taggedKeys + .filter((keyMetadata) => keyMetadata.tags['Name'] === name) + .filter((keyMetadata) => keyMetadata.tags['Group'] === group) + .filter((keyMetadata) => keyMetadata.tags['Usage'] === usage) + .map((keyMetadata) => keyMetadata.keyId); + + logger.info(`About to delete ${keysToDelete.length} keys`); + await Promise.all(keysToDelete.map((keyId) => deleteKey(keyId))); +} diff --git a/tests/test-team/helpers/logger.ts b/tests/test-team/helpers/logger.ts new file mode 100644 index 00000000..1d144664 --- /dev/null +++ b/tests/test-team/helpers/logger.ts @@ -0,0 +1,15 @@ +import winston from 'winston'; + +const { combine, timestamp, json, errors } = winston.format; + +const logger = winston.createLogger({ + level: 'info', + format: combine(errors({ stack: true }), timestamp(), json()), + transports: [ + new winston.transports.Stream({ + stream: process.stdout, + }), + ], +}); + +export { logger }; diff --git a/tests/test-team/helpers/ssm-util.ts b/tests/test-team/helpers/ssm-util.ts new file mode 100644 index 00000000..fba2a1e4 --- /dev/null +++ b/tests/test-team/helpers/ssm-util.ts @@ -0,0 +1,27 @@ +import { + PutParameterCommand, + SSMClient, +} from '@aws-sdk/client-ssm'; +import { logger } from './logger'; + +const ssmClient = new SSMClient({ + region: process.env.REGION, + retryMode: 'standard', + maxAttempts: 10, +}); + +export async function putParameter(value: string, name = ''): Promise { + if (!name) { + throw new Error('Missing parameter name'); + } + + logger.info(`Updating parameter ${name}`); + + ssmClient.send( + new PutParameterCommand({ + Name: name, + Value: value, + Overwrite: true, + }) + ); +} diff --git a/tests/test-team/package.json b/tests/test-team/package.json index add6dd5b..fca982b2 100644 --- a/tests/test-team/package.json +++ b/tests/test-team/package.json @@ -4,16 +4,22 @@ "private": true, "scripts": { "lint": "eslint .", - "test:local-ui": "playwright test --project component -c config/local.config.ts", + "test:local-ui": "playwright test --project component -c config/component/component.config.ts", + "test:backend": "playwright test --project backend -c config/backend/backend.config.ts", "test:story": "echo 'Not implemented'", "test:unit": "echo 'unit tests not required'", "typecheck": "tsc --noEmit" }, "devDependencies": { "@aws-sdk/client-cognito-identity-provider": "^3.772.0", + "@aws-sdk/client-kms": "^3.782.0", + "@aws-sdk/client-ssm": "^3.782.0", + "@aws-sdk/types": "^3.775.0", "@playwright/test": "^1.51.1", "@tsconfig/node20": "^20.1.5", "@types/uuid": "^10.0.0", - "generate-password": "^1.7.1" + "generate-password": "^1.7.1", + "nhs-notify-iam-webauth-util-backend-config": "^0.0.1", + "winston": "^3.14.2" } } diff --git a/utils/backend-config/jest.config.ts b/utils/backend-config/jest.config.ts new file mode 100644 index 00000000..0129f9c7 --- /dev/null +++ b/utils/backend-config/jest.config.ts @@ -0,0 +1,53 @@ +import type { Config } from 'jest'; + +export const baseJestConfig: Config = { + preset: 'ts-jest', + + // Automatically clear mock calls, instances, contexts and results before every test + clearMocks: true, + + // Indicates whether the coverage information should be collected while executing the test + collectCoverage: true, + + // The directory where Jest should output its coverage files + coverageDirectory: './.reports/unit/coverage', + + // Indicates which provider should be used to instrument code for coverage + coverageProvider: 'babel', + + coverageThreshold: { + global: { + branches: 100, + functions: 100, + lines: 100, + statements: -10, + }, + }, + + transform: { '\\.ts$': '@swc/jest' }, + testPathIgnorePatterns: ['.build'], + + // Use this configuration option to add custom reporters to Jest + reporters: [ + 'default', + [ + 'jest-html-reporter', + { + pageTitle: 'Test Report', + outputPath: './.reports/unit/test-report.html', + includeFailureMsg: true, + }, + ], + ], + + // The test environment that will be used for testing + testEnvironment: 'jsdom', +}; + +const utilsJestConfig = { + ...baseJestConfig, + + coveragePathIgnorePatterns: ['enum.ts', 'zod-validators.ts'], +}; + +export default utilsJestConfig; diff --git a/utils/backend-config/package.json b/utils/backend-config/package.json new file mode 100644 index 00000000..46d5863f --- /dev/null +++ b/utils/backend-config/package.json @@ -0,0 +1,14 @@ +{ + "name": "nhs-notify-iam-webauth-util-backend-config", + "version": "0.0.1", + "main": "src/index.ts", + "scripts": { + "lint": "eslint .", + "lint:fix": "eslint . --fix", + "test:unit": "echo \"No unit tests\"", + "typecheck": "tsc --noEmit" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.5" + } +} diff --git a/utils/backend-config/src/backend-config.ts b/utils/backend-config/src/backend-config.ts new file mode 100644 index 00000000..cfd0016a --- /dev/null +++ b/utils/backend-config/src/backend-config.ts @@ -0,0 +1,27 @@ +/* eslint-disable security/detect-non-literal-fs-filename */ + +import fs from 'node:fs'; + +export type BackendConfig = { + groupTag: string; + nameTag: string; + keyDirectorySsmParameterName: string; +}; + +export const BackendConfigHelper = { + fromTerraformOutputsFile(filepath: string): BackendConfig { + const outputs = JSON.parse(fs.readFileSync(filepath, 'utf8')); + + return { + groupTag: outputs.group_tag.value, + nameTag: outputs.name_tag.value, + keyDirectorySsmParameterName: outputs.key_directory_ssm_parameter_name.value + }; + }, + + toEnv(config: BackendConfig): void { + process.env.GROUP_TAG = config.groupTag; + process.env.NAME_TAG = config.nameTag; + process.env.KEY_DIRECTORY_SSM_PARAMETER_NAME = config.keyDirectorySsmParameterName; + }, +}; diff --git a/utils/backend-config/src/index.ts b/utils/backend-config/src/index.ts new file mode 100644 index 00000000..0c980406 --- /dev/null +++ b/utils/backend-config/src/index.ts @@ -0,0 +1 @@ +export * from './backend-config'; diff --git a/utils/backend-config/tsconfig.json b/utils/backend-config/tsconfig.json new file mode 100644 index 00000000..01edd6e5 --- /dev/null +++ b/utils/backend-config/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@tsconfig/node20/tsconfig.json", + "include": [ + "src/*", + "src/**/*", + "../backend-config/src/backend-config.ts" + ] +} From 558ce9d69a67420e68692f125121cd3fcf580d46 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Tue, 6 May 2025 11:17:15 +0100 Subject: [PATCH 34/54] CCM-9554: key rotation tests - wip --- tests/test-team/helpers/kms-util.ts | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/tests/test-team/helpers/kms-util.ts b/tests/test-team/helpers/kms-util.ts index a96c7a83..632fa666 100644 --- a/tests/test-team/helpers/kms-util.ts +++ b/tests/test-team/helpers/kms-util.ts @@ -4,6 +4,7 @@ import { ListKeysCommandOutput, ListResourceTagsCommand, ScheduleKeyDeletionCommand, + Tag, } from '@aws-sdk/client-kms'; import { logger } from './logger'; @@ -39,14 +40,20 @@ async function listAllKeyIds(): Promise> { async function getKeyTags( keyId: string ): Promise<{ keyId: string; tags: Record }> { - const response = await kmsClient.send( - new ListResourceTagsCommand({ - KeyId: keyId, - }) - ); - const tags = response.Tags || []; + const tags: Array = await kmsClient + .send( + new ListResourceTagsCommand({ + KeyId: keyId, + }) + ) + .then((response) => response.Tags || []) + .catch((error) => { + if (error['__type'] === 'AccessDeniedException') { + return []; + } + throw error; + }); - logger.info(`Got key tags for ${keyId}: ${JSON.stringify(tags)}`); const tagMap = tags.reduce( (acc, tag) => { const key = tag.TagKey || 'unknown'; @@ -74,12 +81,15 @@ export async function deleteAllKeysForTags( group: string, usage: string ): Promise { + if (!name.endsWith('-sbx')) { + throw new Error(`Should only be deleting keys from a sandbox: ${name}`); + } + logger.info( `Looking for keys to delete using tags Name: ${name}, Group: ${group}, Usage: ${usage}` ); const allKeyIds = await listAllKeyIds(); - logger.info(`allKeyIds (${allKeyIds.length}): ${JSON.stringify(allKeyIds)}`); const taggedKeys = await Promise.all( allKeyIds.map((keyId) => getKeyTags(keyId)) ); From 062a72bdaf89651e702046465235499e78bb1e17 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Wed, 7 May 2025 14:00:02 +0100 Subject: [PATCH 35/54] CCM-9554: fix s3 permissions for public keys --- .../module_s3bucket_public_signing_keys.tf | 75 +------------------ .../s3_bucket_policy_public_signing_keys.tf | 10 +-- 2 files changed, 5 insertions(+), 80 deletions(-) diff --git a/infrastructure/terraform/modules/public-signing-keys/module_s3bucket_public_signing_keys.tf b/infrastructure/terraform/modules/public-signing-keys/module_s3bucket_public_signing_keys.tf index 9cdb532b..8ddf5ea5 100644 --- a/infrastructure/terraform/modules/public-signing-keys/module_s3bucket_public_signing_keys.tf +++ b/infrastructure/terraform/modules/public-signing-keys/module_s3bucket_public_signing_keys.tf @@ -39,7 +39,7 @@ module "s3bucket_public_signing_keys" { ] policy_documents = [ - data.aws_iam_policy_document.s3bucket_public_keys.json + data.aws_iam_policy_document.bucket_policy_public_signing_keys.json ] public_access = { @@ -55,79 +55,6 @@ module "s3bucket_public_signing_keys" { } } -data "aws_iam_policy_document" "s3bucket_public_keys" { - statement { - sid = "DontAllowNonSecureConnection" - effect = "Deny" - - actions = [ - "s3:*", - ] - - resources = [ - module.s3bucket_public_signing_keys.arn, - "${module.s3bucket_public_signing_keys.arn}/*", - ] - - principals { - type = "AWS" - - identifiers = [ - "*", - ] - } - - condition { - test = "Bool" - variable = "aws:SecureTransport" - - values = [ - "false", - ] - } - } - - statement { - sid = "AllowManagedAccountsToList" - effect = "Allow" - - actions = [ - "s3:ListBucket", - ] - - resources = [ - module.s3bucket_public_signing_keys.arn, - ] - - principals { - type = "AWS" - identifiers = [ - "arn:aws:iam::${var.aws_account_id}:root" - ] - } - } - - statement { - sid = "AllowManagedAccountsToGet" - effect = "Allow" - - actions = [ - "s3:GetObject", - ] - - resources = [ - "${module.s3bucket_public_signing_keys.arn}/*", - ] - - principals { - type = "AWS" - identifiers = [ - "arn:aws:iam::${var.aws_account_id}:root" - ] - } - } -} - resource "aws_s3_bucket_cors_configuration" "public_public_keys" { bucket = module.s3bucket_public_signing_keys.bucket diff --git a/infrastructure/terraform/modules/public-signing-keys/s3_bucket_policy_public_signing_keys.tf b/infrastructure/terraform/modules/public-signing-keys/s3_bucket_policy_public_signing_keys.tf index 68d1cae6..3aa1ec5e 100644 --- a/infrastructure/terraform/modules/public-signing-keys/s3_bucket_policy_public_signing_keys.tf +++ b/infrastructure/terraform/modules/public-signing-keys/s3_bucket_policy_public_signing_keys.tf @@ -1,10 +1,6 @@ -resource "aws_s3_bucket_policy" "public_signing_keys" { - bucket = module.s3bucket_public_signing_keys.id - policy = data.aws_iam_policy_document.bucket_policy_public_signing_keys.json -} - data "aws_iam_policy_document" "bucket_policy_public_signing_keys" { statement { + sid = "AllowManagedAccountsToRead" actions = ["s3:GetObject", "s3:ListBucket"] resources = [ module.s3bucket_public_signing_keys.arn, @@ -18,8 +14,9 @@ data "aws_iam_policy_document" "bucket_policy_public_signing_keys" { } dynamic "statement" { - for_each = var.deploy_cdn ? [1]: [] + for_each = var.deploy_cdn ? [1] : [] content { + sid = "AllowCDNAccess" actions = ["s3:GetObject", "s3:ListBucket"] resources = [ module.s3bucket_public_signing_keys.arn, @@ -34,6 +31,7 @@ data "aws_iam_policy_document" "bucket_policy_public_signing_keys" { } statement { + sid = "DontAllowNonSecureConnection" effect = "Deny" actions = ["s3:*"] resources = [ From 7bf369fa29c2d75410090598ce38edc3375f2187 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Fri, 9 May 2025 08:53:40 +0100 Subject: [PATCH 36/54] CCM-9554: merge --- lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts b/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts index db5a5c5e..18f3df3e 100644 --- a/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts +++ b/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts @@ -21,7 +21,6 @@ export function getKeyTags(): Array { throw new Error(`Invalid tag parameter ${commaSeparatedKeyTags}`); } -<<<<<<< HEAD const tags = parameters .map((parameter) => parameter.split('=')) .map((keyTag) => ({ @@ -35,12 +34,4 @@ export function getKeyTags(): Array { }) return tags; -======= - return parameters - .map((parameter) => parameter.split('=')) - .map((keyTag) => ({ - TagKey: keyTag[0], - TagValue: keyTag[1], - })); ->>>>>>> origin/main } From 646467f70382e3507afbe7e016d72873133f3f2a Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Mon, 12 May 2025 13:42:52 +0100 Subject: [PATCH 37/54] CCM-9554: key rotation tests - wip --- .../terraform/components/sandbox/outputs.tf | 8 + .../modules/public-signing-keys/outputs.tf | 8 + package-lock.json | 4452 +++++++++++------ .../jwks-key-rotation.backend.spec.ts | 103 +- .../config/backend/backend.config.ts | 3 + tests/test-team/helpers/jwks-key-parser.ts | 8 + tests/test-team/helpers/kms-util.ts | 38 +- tests/test-team/helpers/lambda-util.ts | 20 + tests/test-team/helpers/s3-util.ts | 23 + tests/test-team/helpers/ssm-util.ts | 16 +- tests/test-team/package.json | 5 + utils/backend-config/src/backend-config.ts | 14 +- 12 files changed, 3030 insertions(+), 1668 deletions(-) create mode 100644 tests/test-team/helpers/jwks-key-parser.ts create mode 100644 tests/test-team/helpers/lambda-util.ts create mode 100644 tests/test-team/helpers/s3-util.ts diff --git a/infrastructure/terraform/components/sandbox/outputs.tf b/infrastructure/terraform/components/sandbox/outputs.tf index c192f34a..c8026a7b 100644 --- a/infrastructure/terraform/components/sandbox/outputs.tf +++ b/infrastructure/terraform/components/sandbox/outputs.tf @@ -51,3 +51,11 @@ output "group_tag" { output "key_directory_ssm_parameter_name" { value = module.public_signing_keys.key_directory_ssm_parameter_name } + +output "key_rotation_lambda_name" { + value = module.public_signing_keys.key_rotation_lambda_name +} + +output "public_keys_s3_bucket_name" { + value = module.public_signing_keys.public_keys_s3_bucket_name +} diff --git a/infrastructure/terraform/modules/public-signing-keys/outputs.tf b/infrastructure/terraform/modules/public-signing-keys/outputs.tf index e47a1218..7de138f4 100644 --- a/infrastructure/terraform/modules/public-signing-keys/outputs.tf +++ b/infrastructure/terraform/modules/public-signing-keys/outputs.tf @@ -1,3 +1,11 @@ output "key_directory_ssm_parameter_name" { value = local.ssm_key_directory_name } + +output "key_rotation_lambda_name" { + value = module.lambda_jwks_key_rotation.function_name +} + +output "public_keys_s3_bucket_name" { + value = module.s3bucket_public_signing_keys.bucket +} diff --git a/package-lock.json b/package-lock.json index 56cc6e2d..d39b6959 100644 --- a/package-lock.json +++ b/package-lock.json @@ -732,71 +732,6 @@ "node": ">=18.0.0" } }, - "lambdas/jwks-key-rotation/node_modules/@smithy/eventstream-codec": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.0.2.tgz", - "integrity": "sha512-p+f2kLSK7ZrXVfskU/f5dzksKTewZk8pJLPvER3aFHPt76C2MxD9vNatSfLzzQSQB4FNO96RK4PSXfhD1TTeMQ==", - "dependencies": { - "@aws-crypto/crc32": "5.2.0", - "@smithy/types": "^4.2.0", - "@smithy/util-hex-encoding": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "lambdas/jwks-key-rotation/node_modules/@smithy/eventstream-serde-browser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.0.2.tgz", - "integrity": "sha512-CepZCDs2xgVUtH7ZZ7oDdZFH8e6Y2zOv8iiX6RhndH69nlojCALSKK+OXwZUgOtUZEUaZ5e1hULVCHYbCn7pug==", - "dependencies": { - "@smithy/eventstream-serde-universal": "^4.0.2", - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "lambdas/jwks-key-rotation/node_modules/@smithy/eventstream-serde-config-resolver": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.1.0.tgz", - "integrity": "sha512-1PI+WPZ5TWXrfj3CIoKyUycYynYJgZjuQo8U+sphneOtjsgrttYybdqESFReQrdWJ+LKt6NEdbYzmmfDBmjX2A==", - "dependencies": { - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "lambdas/jwks-key-rotation/node_modules/@smithy/eventstream-serde-node": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.0.2.tgz", - "integrity": "sha512-C5bJ/C6x9ENPMx2cFOirspnF9ZsBVnBMtP6BdPl/qYSuUawdGQ34Lq0dMcf42QTjUZgWGbUIZnz6+zLxJlb9aw==", - "dependencies": { - "@smithy/eventstream-serde-universal": "^4.0.2", - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "lambdas/jwks-key-rotation/node_modules/@smithy/eventstream-serde-universal": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.0.2.tgz", - "integrity": "sha512-St8h9JqzvnbB52FtckiHPN4U/cnXcarMniXRXTKn0r4b4XesZOGiAyUdj1aXbqqn1icSqBlzzUsCl6nPB018ng==", - "dependencies": { - "@smithy/eventstream-codec": "^4.0.2", - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "lambdas/jwks-key-rotation/node_modules/@smithy/hash-blob-browser": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-4.0.2.tgz", @@ -849,17 +784,6 @@ "node": ">=18.0.0" } }, - "lambdas/jwks-key-rotation/node_modules/@smithy/util-hex-encoding": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz", - "integrity": "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "lambdas/jwks-key-rotation/node_modules/@smithy/util-utf8": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", @@ -4926,462 +4850,489 @@ "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-personalize-events/-/client-personalize-events-3.621.0.tgz", - "integrity": "sha512-qkVkqYvOe3WVuVNL/gRITGYFfHJCx2ijGFK7H3hNUJH3P4AwskmouAd1pWf+3cbGedRnj2is7iw7E602LeJIHA==", + "node_modules/@aws-sdk/client-lambda": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.806.0.tgz", + "integrity": "sha512-Fxh08DKju+wzRlGPs+p9yaNDc5IC8hftJi+p6kkQ5DRCqshL/MtH9uGMYL7krYPMSO9ulnmcCWoaHioUvCFE2g==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.621.0", - "@aws-sdk/client-sts": "3.621.0", - "@aws-sdk/core": "3.621.0", - "@aws-sdk/credential-provider-node": "3.621.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.1", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.13", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.13", - "@smithy/util-defaults-mode-node": "^3.0.13", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", + "@aws-sdk/core": "3.806.0", + "@aws-sdk/credential-provider-node": "3.806.0", + "@aws-sdk/middleware-host-header": "3.804.0", + "@aws-sdk/middleware-logger": "3.804.0", + "@aws-sdk/middleware-recursion-detection": "3.804.0", + "@aws-sdk/middleware-user-agent": "3.806.0", + "@aws-sdk/region-config-resolver": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@aws-sdk/util-endpoints": "3.806.0", + "@aws-sdk/util-user-agent-browser": "3.804.0", + "@aws-sdk/util-user-agent-node": "3.806.0", + "@smithy/config-resolver": "^4.1.1", + "@smithy/core": "^3.3.1", + "@smithy/eventstream-serde-browser": "^4.0.2", + "@smithy/eventstream-serde-config-resolver": "^4.1.0", + "@smithy/eventstream-serde-node": "^4.0.2", + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/hash-node": "^4.0.2", + "@smithy/invalid-dependency": "^4.0.2", + "@smithy/middleware-content-length": "^4.0.2", + "@smithy/middleware-endpoint": "^4.1.3", + "@smithy/middleware-retry": "^4.1.4", + "@smithy/middleware-serde": "^4.0.3", + "@smithy/middleware-stack": "^4.0.2", + "@smithy/node-config-provider": "^4.1.0", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/protocol-http": "^5.1.0", + "@smithy/smithy-client": "^4.2.3", + "@smithy/types": "^4.2.0", + "@smithy/url-parser": "^4.0.2", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.11", + "@smithy/util-defaults-mode-node": "^4.0.11", + "@smithy/util-endpoints": "^3.0.3", + "@smithy/util-middleware": "^4.0.2", + "@smithy/util-retry": "^4.0.3", + "@smithy/util-stream": "^4.2.0", + "@smithy/util-utf8": "^4.0.0", + "@smithy/util-waiter": "^4.0.3", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/client-sso": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.621.0.tgz", - "integrity": "sha512-xpKfikN4u0BaUYZA9FGUMkkDmfoIP0Q03+A86WjqDWhcOoqNA1DkHsE4kZ+r064ifkPUfcNuUvlkVTEoBZoFjA==", + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/client-sso": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.806.0.tgz", + "integrity": "sha512-X0p/9/u9e6b22rlQqKucdtjdqmjSNB4c/8zDEoD5MvgYAAbMF9HNE0ST2xaA/WsJ7uE0jFfhPY2/00pslL1DqQ==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.621.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.1", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.13", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.13", - "@smithy/util-defaults-mode-node": "^3.0.13", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", + "@aws-sdk/core": "3.806.0", + "@aws-sdk/middleware-host-header": "3.804.0", + "@aws-sdk/middleware-logger": "3.804.0", + "@aws-sdk/middleware-recursion-detection": "3.804.0", + "@aws-sdk/middleware-user-agent": "3.806.0", + "@aws-sdk/region-config-resolver": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@aws-sdk/util-endpoints": "3.806.0", + "@aws-sdk/util-user-agent-browser": "3.804.0", + "@aws-sdk/util-user-agent-node": "3.806.0", + "@smithy/config-resolver": "^4.1.1", + "@smithy/core": "^3.3.1", + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/hash-node": "^4.0.2", + "@smithy/invalid-dependency": "^4.0.2", + "@smithy/middleware-content-length": "^4.0.2", + "@smithy/middleware-endpoint": "^4.1.3", + "@smithy/middleware-retry": "^4.1.4", + "@smithy/middleware-serde": "^4.0.3", + "@smithy/middleware-stack": "^4.0.2", + "@smithy/node-config-provider": "^4.1.0", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/protocol-http": "^5.1.0", + "@smithy/smithy-client": "^4.2.3", + "@smithy/types": "^4.2.0", + "@smithy/url-parser": "^4.0.2", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.11", + "@smithy/util-defaults-mode-node": "^4.0.11", + "@smithy/util-endpoints": "^3.0.3", + "@smithy/util-middleware": "^4.0.2", + "@smithy/util-retry": "^4.0.3", + "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/client-sts": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.621.0.tgz", - "integrity": "sha512-707uiuReSt+nAx6d0c21xLjLm2lxeKc7padxjv92CIrIocnQSlJPxSCM7r5zBhwiahJA6MNQwmTl2xznU67KgA==", + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/core": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.806.0.tgz", + "integrity": "sha512-HJRINPncdjPK0iL3f6cBpqCMaxVwq2oDbRCzOx04tsLZ0tNgRACBfT3d/zNVRvMt6fnOVKXoN1LAtQaw50pjEA==", + "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.621.0", - "@aws-sdk/core": "3.621.0", - "@aws-sdk/credential-provider-node": "3.621.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.1", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.13", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.13", - "@smithy/util-defaults-mode-node": "^3.0.13", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", + "@aws-sdk/types": "3.804.0", + "@smithy/core": "^3.3.1", + "@smithy/node-config-provider": "^4.1.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/protocol-http": "^5.1.0", + "@smithy/signature-v4": "^5.1.0", + "@smithy/smithy-client": "^4.2.3", + "@smithy/types": "^4.2.0", + "@smithy/util-middleware": "^4.0.2", + "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/core": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.621.0.tgz", - "integrity": "sha512-CtOwWmDdEiINkGXD93iGfXjN0WmCp9l45cDWHHGa8lRgEDyhuL7bwd/pH5aSzj0j8SiQBG2k0S7DHbd5RaqvbQ==", + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.806.0.tgz", + "integrity": "sha512-nbPwmZn0kt6Q1XI2FaJWP6AhF9tro4cO5HlmZQx8NU+B0H1y9WMo659Q5zLLY46BXgoQVIJEsPSZpcZk27O4aw==", + "dev": true, "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^2.3.1", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/signature-v4": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/util-middleware": "^3.0.3", - "fast-xml-parser": "4.4.1", + "@aws-sdk/core": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/credential-provider-env": { - "version": "3.620.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.620.1.tgz", - "integrity": "sha512-ExuILJ2qLW5ZO+rgkNRj0xiAipKT16Rk77buvPP8csR7kkCflT/gXTyzRe/uzIiETTxM7tr8xuO9MP/DQXqkfg==", + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.806.0.tgz", + "integrity": "sha512-e/gB2iJQQ4ZpecOVpEFhEvjGwuTqNCzhVaVsFYVc49FPfR1seuN7qBGYe1MO7mouGDQFInzJgcNup0DnYUrLiw==", + "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/types": "^3.3.0", + "@aws-sdk/core": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/property-provider": "^4.0.2", + "@smithy/protocol-http": "^5.1.0", + "@smithy/smithy-client": "^4.2.3", + "@smithy/types": "^4.2.0", + "@smithy/util-stream": "^4.2.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/credential-provider-http": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.621.0.tgz", - "integrity": "sha512-/jc2tEsdkT1QQAI5Dvoci50DbSxtJrevemwFsm0B73pwCcOQZ5ZwwSdVqGsPutzYzUVx3bcXg3LRL7jLACqRIg==", + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.806.0.tgz", + "integrity": "sha512-FogfbuYSEZgFxbNy0QcsBZHHe5mSv5HV3+JyB5n0kCyjOISCVCZD7gwxKdXjt8O1hXq5k5SOdQvydGULlB6rew==", + "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/property-provider": "^3.1.3", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/util-stream": "^3.1.3", + "@aws-sdk/core": "3.806.0", + "@aws-sdk/credential-provider-env": "3.806.0", + "@aws-sdk/credential-provider-http": "3.806.0", + "@aws-sdk/credential-provider-process": "3.806.0", + "@aws-sdk/credential-provider-sso": "3.806.0", + "@aws-sdk/credential-provider-web-identity": "3.806.0", + "@aws-sdk/nested-clients": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@smithy/credential-provider-imds": "^4.0.2", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.621.0.tgz", - "integrity": "sha512-0EWVnSc+JQn5HLnF5Xv405M8n4zfdx9gyGdpnCmAmFqEDHA8LmBdxJdpUk1Ovp/I5oPANhjojxabIW5f1uU0RA==", + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.806.0.tgz", + "integrity": "sha512-fZX8xP2Kf0k70kDTog/87fh/M+CV0E2yujSw1cUBJhDSwDX3RlUahiJk7TpB/KGw6hEFESMd6+7kq3UzYuw3rg==", + "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.621.0", - "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.621.0", - "@aws-sdk/credential-provider-web-identity": "3.621.0", - "@aws-sdk/types": "3.609.0", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", + "@aws-sdk/credential-provider-env": "3.806.0", + "@aws-sdk/credential-provider-http": "3.806.0", + "@aws-sdk/credential-provider-ini": "3.806.0", + "@aws-sdk/credential-provider-process": "3.806.0", + "@aws-sdk/credential-provider-sso": "3.806.0", + "@aws-sdk/credential-provider-web-identity": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@smithy/credential-provider-imds": "^4.0.2", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.621.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/credential-provider-node": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.621.0.tgz", - "integrity": "sha512-4JqpccUgz5Snanpt2+53hbOBbJQrSFq7E1sAAbgY6BKVQUsW5qyXqnjvSF32kDeKa5JpBl3bBWLZl04IadcPHw==", + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.806.0.tgz", + "integrity": "sha512-8Y8GYEw/1e5IZRDQL02H6nsTDcRWid/afRMeWg+93oLQmbHcTtdm48tjis+7Xwqy+XazhMDmkbUht11QPTDJcQ==", + "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.621.0", - "@aws-sdk/credential-provider-ini": "3.621.0", - "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.621.0", - "@aws-sdk/credential-provider-web-identity": "3.621.0", - "@aws-sdk/types": "3.609.0", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", + "@aws-sdk/core": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/credential-provider-process": { - "version": "3.620.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.620.1.tgz", - "integrity": "sha512-hWqFMidqLAkaV9G460+1at6qa9vySbjQKKc04p59OT7lZ5cO5VH5S4aI05e+m4j364MBROjjk2ugNvfNf/8ILg==", + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.806.0.tgz", + "integrity": "sha512-hT9OBwCxWMPBydNhXm2gdNNzx5AJNheS9RglwDDvXWzQ9qDuRztjuMBilMSUMb0HF9K4IqQjYzGqczMuktz4qQ==", + "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", + "@aws-sdk/client-sso": "3.806.0", + "@aws-sdk/core": "3.806.0", + "@aws-sdk/token-providers": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.621.0.tgz", - "integrity": "sha512-Kza0jcFeA/GEL6xJlzR2KFf1PfZKMFnxfGzJzl5yN7EjoGdMijl34KaRyVnfRjnCWcsUpBWKNIDk9WZVMY9yiw==", + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.806.0.tgz", + "integrity": "sha512-XxaSY9Zd3D4ClUGENYMvi52ac5FuJPPAsvRtEfyrSdEpf6QufbMpnexWBZMYRF31h/VutgqtJwosGgNytpxMEg==", + "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/client-sso": "3.621.0", - "@aws-sdk/token-providers": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", + "@aws-sdk/core": "3.806.0", + "@aws-sdk/nested-clients": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers": { - "version": "3.614.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.614.0.tgz", - "integrity": "sha512-okItqyY6L9IHdxqs+Z116y5/nda7rHxLvROxtAJdLavWTYDydxrZstImNgGWTeVdmc0xX2gJCI77UYUTQWnhRw==", + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.804.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.804.0.tgz", + "integrity": "sha512-bum1hLVBrn2lJCi423Z2fMUYtsbkGI2s4N+2RI2WSjvbaVyMSv/WcejIrjkqiiMR+2Y7m5exgoKeg4/TODLDPQ==", + "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", + "@aws-sdk/types": "3.804.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sso-oidc": "^3.614.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.621.0.tgz", - "integrity": "sha512-w7ASSyfNvcx7+bYGep3VBgC3K6vEdLmlpjT7nSIHxxQf+WSdvy+HynwJosrpZax0sK5q0D1Jpn/5q+r5lwwW6w==", + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/middleware-logger": { + "version": "3.804.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.804.0.tgz", + "integrity": "sha512-w/qLwL3iq0KOPQNat0Kb7sKndl9BtceigINwBU7SpkYWX9L/Lem6f8NPEKrC9Tl4wDBht3Yztub4oRTy/horJA==", + "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/types": "^3.3.0", + "@aws-sdk/types": "3.804.0", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.621.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/middleware-host-header": { - "version": "3.620.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.620.0.tgz", - "integrity": "sha512-VMtPEZwqYrII/oUkffYsNWY9PZ9xpNJpMgmyU0rlDQ25O1c0Hk3fJmZRe6pEkAJ0omD7kLrqGl1DUjQVxpd/Rg==", + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.804.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.804.0.tgz", + "integrity": "sha512-zqHOrvLRdsUdN/ehYfZ9Tf8svhbiLLz5VaWUz22YndFv6m9qaAcijkpAOlKexsv3nLBMJdSdJ6GUTAeIy3BZzw==", + "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", + "@aws-sdk/types": "3.804.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/middleware-logger": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.609.0.tgz", - "integrity": "sha512-S62U2dy4jMDhDFDK5gZ4VxFdWzCtLzwbYyFZx2uvPYTECkepLUfzLic2BHg2Qvtu4QjX+oGE3P/7fwaGIsGNuQ==", + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.806.0.tgz", + "integrity": "sha512-XoIromVffgXnc+/mjlR2EVzQVIei3bPVtafIZNsHuEmUvIWJXiWsa2eJpt3BUqa0HF9YPknK7ommNEhqRb8ucg==", + "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/types": "^3.3.0", + "@aws-sdk/core": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@aws-sdk/util-endpoints": "3.806.0", + "@smithy/core": "^3.3.1", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.620.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.620.0.tgz", - "integrity": "sha512-nh91S7aGK3e/o1ck64sA/CyoFw+gAYj2BDOnoNa6ouyCrVJED96ZXWbhye/fz9SgmNUZR2g7GdVpiLpMKZoI5w==", + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/nested-clients": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.806.0.tgz", + "integrity": "sha512-ua2gzpfQ9MF8Rny+tOAivowOWWvqEusez2rdcQK8jdBjA1ANd/0xzToSZjZh0ziN8Kl8jOhNnHbQJ0v6dT6+hg==", + "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.806.0", + "@aws-sdk/middleware-host-header": "3.804.0", + "@aws-sdk/middleware-logger": "3.804.0", + "@aws-sdk/middleware-recursion-detection": "3.804.0", + "@aws-sdk/middleware-user-agent": "3.806.0", + "@aws-sdk/region-config-resolver": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@aws-sdk/util-endpoints": "3.806.0", + "@aws-sdk/util-user-agent-browser": "3.804.0", + "@aws-sdk/util-user-agent-node": "3.806.0", + "@smithy/config-resolver": "^4.1.1", + "@smithy/core": "^3.3.1", + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/hash-node": "^4.0.2", + "@smithy/invalid-dependency": "^4.0.2", + "@smithy/middleware-content-length": "^4.0.2", + "@smithy/middleware-endpoint": "^4.1.3", + "@smithy/middleware-retry": "^4.1.4", + "@smithy/middleware-serde": "^4.0.3", + "@smithy/middleware-stack": "^4.0.2", + "@smithy/node-config-provider": "^4.1.0", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/protocol-http": "^5.1.0", + "@smithy/smithy-client": "^4.2.3", + "@smithy/types": "^4.2.0", + "@smithy/url-parser": "^4.0.2", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.11", + "@smithy/util-defaults-mode-node": "^4.0.11", + "@smithy/util-endpoints": "^3.0.3", + "@smithy/util-middleware": "^4.0.2", + "@smithy/util-retry": "^4.0.3", + "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.620.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.620.0.tgz", - "integrity": "sha512-bvS6etn+KsuL32ubY5D3xNof1qkenpbJXf/ugGXbg0n98DvDFQ/F+SMLxHgbnER5dsKYchNnhmtI6/FC3HFu/A==", + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.806.0.tgz", + "integrity": "sha512-cuv5pX55JOlzKC/iLsB5nZ9eUyVgncim3VhhWHZA/KYPh7rLMjOEfZ+xyaE9uLJXGmzOJboFH7+YdTRdIcOgrg==", + "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", + "@aws-sdk/types": "3.804.0", + "@smithy/node-config-provider": "^4.1.0", + "@smithy/types": "^4.2.0", + "@smithy/util-config-provider": "^4.0.0", + "@smithy/util-middleware": "^4.0.2", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/region-config-resolver": { - "version": "3.614.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.614.0.tgz", - "integrity": "sha512-vDCeMXvic/LU0KFIUjpC3RiSTIkkvESsEfbVHiHH0YINfl8HnEqR5rj+L8+phsCeVg2+LmYwYxd5NRz4PHxt5g==", + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/token-providers": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.806.0.tgz", + "integrity": "sha512-I6SxcsvV7yinJZmPgGullFHS0tsTKa7K3jEc5dmyCz8X+kZPfsWNffZmtmnCvWXPqMXWBvK6hVaxwomx79yeHA==", + "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/types": "^3.3.0", - "@smithy/util-config-provider": "^3.0.0", - "@smithy/util-middleware": "^3.0.3", + "@aws-sdk/nested-clients": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/types": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", - "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/types": { + "version": "3.804.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.804.0.tgz", + "integrity": "sha512-A9qnsy9zQ8G89vrPPlNG9d1d8QcKRGqJKqwyGgS0dclJpwy6d1EWgQLIolKPl6vcFpLoe6avLOLxr+h8ur5wpg==", + "dev": true, "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.3.0", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/util-endpoints": { - "version": "3.614.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.614.0.tgz", - "integrity": "sha512-wK2cdrXHH4oz4IomV/yrGkftU9A+ITB6nFL+rxxyO78is2ifHJpFdV4aqk4LSkXYPi6CXWNru/Dqc7yiKXgJPw==", + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/util-endpoints": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.806.0.tgz", + "integrity": "sha512-3YRRgZ+qFuWDdm5uAbxKsr65UAil4KkrFKua9f4m7Be3v24ETiFOOqhanFUIk9/WOtvzF7oFEiDjYKDGlwV2xg==", + "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/types": "^3.3.0", - "@smithy/util-endpoints": "^2.0.5", + "@aws-sdk/types": "3.804.0", + "@smithy/types": "^4.2.0", + "@smithy/util-endpoints": "^3.0.3", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.609.0.tgz", - "integrity": "sha512-fojPU+mNahzQ0YHYBsx0ZIhmMA96H+ZIZ665ObU9tl+SGdbLneVZVikGve+NmHTQwHzwkFsZYYnVKAkreJLAtA==", + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.804.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.804.0.tgz", + "integrity": "sha512-KfW6T6nQHHM/vZBBdGn6fMyG/MgX5lq82TDdX4HRQRRuHKLgBWGpKXqqvBwqIaCdXwWHgDrg2VQups6GqOWW2A==", + "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/types": "^3.3.0", + "@aws-sdk/types": "3.804.0", + "@smithy/types": "^4.2.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.614.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.614.0.tgz", - "integrity": "sha512-15ElZT88peoHnq5TEoEtZwoXTXRxNrk60TZNdpl/TUBJ5oNJ9Dqb5Z4ryb8ofN6nm9aFf59GVAerFDz8iUoHBA==", + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.806.0.tgz", + "integrity": "sha512-Az2e4/gmPZ4BpB7QRj7U76I+fctXhNcxlcgsaHnMhvt+R30nvzM2EhsyBUvsWl8+r9bnLeYt9BpvEZeq2ANDzA==", + "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/types": "^3.3.0", + "@aws-sdk/middleware-user-agent": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@smithy/node-config-provider": "^4.1.0", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { "aws-crt": ">=1.0.0" @@ -5392,47 +5343,78 @@ } } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/abort-controller": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.9.tgz", - "integrity": "sha512-yiW0WI30zj8ZKoSYNx90no7ugVn3khlyH/z5W8qtKBtVE6awRALbhSG+2SAHA1r6bO/6M9utxYKVZ3PCJ1rWxw==", + "node_modules/@aws-sdk/client-lambda/node_modules/@smithy/types": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", + "dev": true, "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/config-resolver": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.13.tgz", - "integrity": "sha512-Gr/qwzyPaTL1tZcq8WQyHhTZREER5R1Wytmz4WnVGL4onA3dNk6Btll55c8Vr58pLdvWZmtG8oZxJTw3t3q7Jg==", + "node_modules/@aws-sdk/client-lambda/node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "dev": true, "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^3.1.12", - "@smithy/types": "^3.7.2", - "@smithy/util-config-provider": "^3.0.0", - "@smithy/util-middleware": "^3.0.11", + "@smithy/util-buffer-from": "^4.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/core": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.5.7.tgz", - "integrity": "sha512-8olpW6mKCa0v+ibCjoCzgZHQx1SQmZuW/WkrdZo73wiTprTH6qhmskT60QLFdT9DRa5mXxjz89kQPZ7ZSsoqqg==", + "node_modules/@aws-sdk/client-personalize-events": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-personalize-events/-/client-personalize-events-3.621.0.tgz", + "integrity": "sha512-qkVkqYvOe3WVuVNL/gRITGYFfHJCx2ijGFK7H3hNUJH3P4AwskmouAd1pWf+3cbGedRnj2is7iw7E602LeJIHA==", "license": "Apache-2.0", "dependencies": { - "@smithy/middleware-serde": "^3.0.11", - "@smithy/protocol-http": "^4.1.8", - "@smithy/types": "^3.7.2", + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.3.1", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.5", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.13", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-middleware": "^3.0.11", - "@smithy/util-stream": "^3.3.4", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, @@ -5440,315 +5422,461 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/credential-provider-imds": { - "version": "3.2.8", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.8.tgz", - "integrity": "sha512-ZCY2yD0BY+K9iMXkkbnjo+08T2h8/34oHd0Jmh6BZUSZwaaGlGCyBT/3wnS7u7Xl33/EEfN4B6nQr3Gx5bYxgw==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/client-sso": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.621.0.tgz", + "integrity": "sha512-xpKfikN4u0BaUYZA9FGUMkkDmfoIP0Q03+A86WjqDWhcOoqNA1DkHsE4kZ+r064ifkPUfcNuUvlkVTEoBZoFjA==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^3.1.12", - "@smithy/property-provider": "^3.1.11", - "@smithy/types": "^3.7.2", - "@smithy/url-parser": "^3.0.11", + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.3.1", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.5", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.13", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/fetch-http-handler": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.9.tgz", - "integrity": "sha512-hYNVQOqhFQ6vOpenifFME546f0GfJn2OiQ3M0FDmuUu8V/Uiwy2wej7ZXxFBNqdx0R5DZAqWM1l6VRhGz8oE6A==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/client-sts": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.621.0.tgz", + "integrity": "sha512-707uiuReSt+nAx6d0c21xLjLm2lxeKc7padxjv92CIrIocnQSlJPxSCM7r5zBhwiahJA6MNQwmTl2xznU67KgA==", "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^4.1.4", - "@smithy/querystring-builder": "^3.0.7", - "@smithy/types": "^3.5.0", + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.3.1", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.5", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.13", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/hash-node": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.11.tgz", - "integrity": "sha512-emP23rwYyZhQBvklqTtwetkQlqbNYirDiEEwXl2v0GYWMnCzxst7ZaRAnWuy28njp5kAH54lvkdG37MblZzaHA==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/core": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.621.0.tgz", + "integrity": "sha512-CtOwWmDdEiINkGXD93iGfXjN0WmCp9l45cDWHHGa8lRgEDyhuL7bwd/pH5aSzj0j8SiQBG2k0S7DHbd5RaqvbQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.7.2", - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", + "@smithy/core": "^2.3.1", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/signature-v4": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/invalid-dependency": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.11.tgz", - "integrity": "sha512-NuQmVPEJjUX6c+UELyVz8kUx8Q539EDeNwbRyu4IIF8MeV7hUtq1FB3SHVyki2u++5XLMFqngeMKk7ccspnNyQ==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.620.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.620.1.tgz", + "integrity": "sha512-ExuILJ2qLW5ZO+rgkNRj0xiAipKT16Rk77buvPP8csR7kkCflT/gXTyzRe/uzIiETTxM7tr8xuO9MP/DQXqkfg==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.7.2", + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/is-array-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", - "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.621.0.tgz", + "integrity": "sha512-/jc2tEsdkT1QQAI5Dvoci50DbSxtJrevemwFsm0B73pwCcOQZ5ZwwSdVqGsPutzYzUVx3bcXg3LRL7jLACqRIg==", "license": "Apache-2.0", "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/property-provider": "^3.1.3", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/util-stream": "^3.1.3", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/middleware-content-length": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.13.tgz", - "integrity": "sha512-zfMhzojhFpIX3P5ug7jxTjfUcIPcGjcQYzB9t+rv0g1TX7B0QdwONW+ATouaLoD7h7LOw/ZlXfkq4xJ/g2TrIw==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.621.0.tgz", + "integrity": "sha512-0EWVnSc+JQn5HLnF5Xv405M8n4zfdx9gyGdpnCmAmFqEDHA8LmBdxJdpUk1Ovp/I5oPANhjojxabIW5f1uU0RA==", "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^4.1.8", - "@smithy/types": "^3.7.2", + "@aws-sdk/credential-provider-env": "3.620.1", + "@aws-sdk/credential-provider-http": "3.621.0", + "@aws-sdk/credential-provider-process": "3.620.1", + "@aws-sdk/credential-provider-sso": "3.621.0", + "@aws-sdk/credential-provider-web-identity": "3.621.0", + "@aws-sdk/types": "3.609.0", + "@smithy/credential-provider-imds": "^3.2.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.621.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/middleware-endpoint": { - "version": "3.2.8", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.2.8.tgz", - "integrity": "sha512-OEJZKVUEhMOqMs3ktrTWp7UvvluMJEvD5XgQwRePSbDg1VvBaL8pX8mwPltFn6wk1GySbcVwwyldL8S+iqnrEQ==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.621.0.tgz", + "integrity": "sha512-4JqpccUgz5Snanpt2+53hbOBbJQrSFq7E1sAAbgY6BKVQUsW5qyXqnjvSF32kDeKa5JpBl3bBWLZl04IadcPHw==", "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^2.5.7", - "@smithy/middleware-serde": "^3.0.11", - "@smithy/node-config-provider": "^3.1.12", - "@smithy/shared-ini-file-loader": "^3.1.12", - "@smithy/types": "^3.7.2", - "@smithy/url-parser": "^3.0.11", - "@smithy/util-middleware": "^3.0.11", + "@aws-sdk/credential-provider-env": "3.620.1", + "@aws-sdk/credential-provider-http": "3.621.0", + "@aws-sdk/credential-provider-ini": "3.621.0", + "@aws-sdk/credential-provider-process": "3.620.1", + "@aws-sdk/credential-provider-sso": "3.621.0", + "@aws-sdk/credential-provider-web-identity": "3.621.0", + "@aws-sdk/types": "3.609.0", + "@smithy/credential-provider-imds": "^3.2.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/middleware-retry": { - "version": "3.0.34", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.34.tgz", - "integrity": "sha512-yVRr/AAtPZlUvwEkrq7S3x7Z8/xCd97m2hLDaqdz6ucP2RKHsBjEqaUA2ebNv2SsZoPEi+ZD0dZbOB1u37tGCA==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.620.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.620.1.tgz", + "integrity": "sha512-hWqFMidqLAkaV9G460+1at6qa9vySbjQKKc04p59OT7lZ5cO5VH5S4aI05e+m4j364MBROjjk2ugNvfNf/8ILg==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^3.1.12", - "@smithy/protocol-http": "^4.1.8", - "@smithy/service-error-classification": "^3.0.11", - "@smithy/smithy-client": "^3.7.0", - "@smithy/types": "^3.7.2", - "@smithy/util-middleware": "^3.0.11", - "@smithy/util-retry": "^3.0.11", - "tslib": "^2.6.2", - "uuid": "^9.0.1" + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/middleware-serde": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.11.tgz", - "integrity": "sha512-KzPAeySp/fOoQA82TpnwItvX8BBURecpx6ZMu75EZDkAcnPtO6vf7q4aH5QHs/F1s3/snQaSFbbUMcFFZ086Mw==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.621.0.tgz", + "integrity": "sha512-Kza0jcFeA/GEL6xJlzR2KFf1PfZKMFnxfGzJzl5yN7EjoGdMijl34KaRyVnfRjnCWcsUpBWKNIDk9WZVMY9yiw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.7.2", + "@aws-sdk/client-sso": "3.621.0", + "@aws-sdk/token-providers": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/middleware-stack": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.11.tgz", - "integrity": "sha512-1HGo9a6/ikgOMrTrWL/WiN9N8GSVYpuRQO5kjstAq4CvV59bjqnh7TbdXGQ4vxLD3xlSjfBjq5t1SOELePsLnA==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.614.0.tgz", + "integrity": "sha512-okItqyY6L9IHdxqs+Z116y5/nda7rHxLvROxtAJdLavWTYDydxrZstImNgGWTeVdmc0xX2gJCI77UYUTQWnhRw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.7.2", + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sso-oidc": "^3.614.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/node-config-provider": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.12.tgz", - "integrity": "sha512-O9LVEu5J/u/FuNlZs+L7Ikn3lz7VB9hb0GtPT9MQeiBmtK8RSY3ULmsZgXhe6VAlgTw0YO+paQx4p8xdbs43vQ==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.621.0.tgz", + "integrity": "sha512-w7ASSyfNvcx7+bYGep3VBgC3K6vEdLmlpjT7nSIHxxQf+WSdvy+HynwJosrpZax0sK5q0D1Jpn/5q+r5lwwW6w==", "license": "Apache-2.0", "dependencies": { - "@smithy/property-provider": "^3.1.11", - "@smithy/shared-ini-file-loader": "^3.1.12", - "@smithy/types": "^3.7.2", + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.621.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/node-http-handler": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.3.3.tgz", - "integrity": "sha512-BrpZOaZ4RCbcJ2igiSNG16S+kgAc65l/2hmxWdmhyoGWHTLlzQzr06PXavJp9OBlPEG/sHlqdxjWmjzV66+BSQ==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.620.0.tgz", + "integrity": "sha512-VMtPEZwqYrII/oUkffYsNWY9PZ9xpNJpMgmyU0rlDQ25O1c0Hk3fJmZRe6pEkAJ0omD7kLrqGl1DUjQVxpd/Rg==", "license": "Apache-2.0", "dependencies": { - "@smithy/abort-controller": "^3.1.9", - "@smithy/protocol-http": "^4.1.8", - "@smithy/querystring-builder": "^3.0.11", - "@smithy/types": "^3.7.2", + "@aws-sdk/types": "3.609.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/property-provider": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.11.tgz", - "integrity": "sha512-I/+TMc4XTQ3QAjXfOcUWbSS073oOEAxgx4aZy8jHaf8JQnRkq2SZWw8+PfDtBvLUjcGMdxl+YwtzWe6i5uhL/A==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/middleware-logger": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.609.0.tgz", + "integrity": "sha512-S62U2dy4jMDhDFDK5gZ4VxFdWzCtLzwbYyFZx2uvPYTECkepLUfzLic2BHg2Qvtu4QjX+oGE3P/7fwaGIsGNuQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.7.2", + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/protocol-http": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.8.tgz", - "integrity": "sha512-hmgIAVyxw1LySOwkgMIUN0kjN8TG9Nc85LJeEmEE/cNEe2rkHDUWhnJf2gxcSRFLWsyqWsrZGw40ROjUogg+Iw==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.620.0.tgz", + "integrity": "sha512-nh91S7aGK3e/o1ck64sA/CyoFw+gAYj2BDOnoNa6ouyCrVJED96ZXWbhye/fz9SgmNUZR2g7GdVpiLpMKZoI5w==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.7.2", + "@aws-sdk/types": "3.609.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/querystring-builder": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.11.tgz", - "integrity": "sha512-u+5HV/9uJaeLj5XTb6+IEF/dokWWkEqJ0XiaRRogyREmKGUgZnNecLucADLdauWFKUNbQfulHFEZEdjwEBjXRg==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.620.0.tgz", + "integrity": "sha512-bvS6etn+KsuL32ubY5D3xNof1qkenpbJXf/ugGXbg0n98DvDFQ/F+SMLxHgbnER5dsKYchNnhmtI6/FC3HFu/A==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.7.2", - "@smithy/util-uri-escape": "^3.0.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/querystring-parser": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.11.tgz", - "integrity": "sha512-Je3kFvCsFMnso1ilPwA7GtlbPaTixa3WwC+K21kmMZHsBEOZYQaqxcMqeFFoU7/slFjKDIpiiPydvdJm8Q/MCw==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.614.0.tgz", + "integrity": "sha512-vDCeMXvic/LU0KFIUjpC3RiSTIkkvESsEfbVHiHH0YINfl8HnEqR5rj+L8+phsCeVg2+LmYwYxd5NRz4PHxt5g==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.7.2", + "@aws-sdk/types": "3.609.0", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.3", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/service-error-classification": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.11.tgz", - "integrity": "sha512-QnYDPkyewrJzCyaeI2Rmp7pDwbUETe+hU8ADkXmgNusO1bgHBH7ovXJiYmba8t0fNfJx75fE8dlM6SEmZxheog==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/types": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", + "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.7.2" + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/shared-ini-file-loader": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.12.tgz", - "integrity": "sha512-1xKSGI+U9KKdbG2qDvIR9dGrw3CNx+baqJfyr0igKEpjbHL5stsqAesYBzHChYHlelWtb87VnLWlhvfCz13H8Q==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/util-endpoints": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.614.0.tgz", + "integrity": "sha512-wK2cdrXHH4oz4IomV/yrGkftU9A+ITB6nFL+rxxyO78is2ifHJpFdV4aqk4LSkXYPi6CXWNru/Dqc7yiKXgJPw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.7.2", + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "@smithy/util-endpoints": "^2.0.5", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/signature-v4": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-4.2.4.tgz", - "integrity": "sha512-5JWeMQYg81TgU4cG+OexAWdvDTs5JDdbEZx+Qr1iPbvo91QFGzjy0IkXAKaXUHqmKUJgSHK0ZxnCkgZpzkeNTA==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.609.0.tgz", + "integrity": "sha512-fojPU+mNahzQ0YHYBsx0ZIhmMA96H+ZIZ665ObU9tl+SGdbLneVZVikGve+NmHTQwHzwkFsZYYnVKAkreJLAtA==", "license": "Apache-2.0", "dependencies": { - "@smithy/is-array-buffer": "^3.0.0", - "@smithy/protocol-http": "^4.1.8", - "@smithy/types": "^3.7.2", - "@smithy/util-hex-encoding": "^3.0.0", - "@smithy/util-middleware": "^3.0.11", - "@smithy/util-uri-escape": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-personalize-events/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.614.0.tgz", + "integrity": "sha512-15ElZT88peoHnq5TEoEtZwoXTXRxNrk60TZNdpl/TUBJ5oNJ9Dqb5Z4ryb8ofN6nm9aFf59GVAerFDz8iUoHBA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/smithy-client": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.7.0.tgz", - "integrity": "sha512-9wYrjAZFlqWhgVo3C4y/9kpc68jgiSsKUnsFPzr/MSiRL93+QRDafGTfhhKAb2wsr69Ru87WTiqSfQusSmWipA==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/abort-controller": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.9.tgz", + "integrity": "sha512-yiW0WI30zj8ZKoSYNx90no7ugVn3khlyH/z5W8qtKBtVE6awRALbhSG+2SAHA1r6bO/6M9utxYKVZ3PCJ1rWxw==", "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^2.5.7", - "@smithy/middleware-endpoint": "^3.2.8", - "@smithy/middleware-stack": "^3.0.11", - "@smithy/protocol-http": "^4.1.8", "@smithy/types": "^3.7.2", - "@smithy/util-stream": "^3.3.4", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/url-parser": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.11.tgz", - "integrity": "sha512-TmlqXkSk8ZPhfc+SQutjmFr5FjC0av3GZP4B/10caK1SbRwe/v+Wzu/R6xEKxoNqL+8nY18s1byiy6HqPG37Aw==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/config-resolver": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.13.tgz", + "integrity": "sha512-Gr/qwzyPaTL1tZcq8WQyHhTZREER5R1Wytmz4WnVGL4onA3dNk6Btll55c8Vr58pLdvWZmtG8oZxJTw3t3q7Jg==", "license": "Apache-2.0", "dependencies": { - "@smithy/querystring-parser": "^3.0.11", + "@smithy/node-config-provider": "^3.1.12", "@smithy/types": "^3.7.2", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.11", "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-base64": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", - "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/core": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.5.7.tgz", + "integrity": "sha512-8olpW6mKCa0v+ibCjoCzgZHQx1SQmZuW/WkrdZo73wiTprTH6qhmskT60QLFdT9DRa5mXxjz89kQPZ7ZSsoqqg==", + "license": "Apache-2.0", "dependencies": { - "@smithy/util-buffer-from": "^3.0.0", + "@smithy/middleware-serde": "^3.0.11", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-stream": "^3.3.4", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, @@ -5756,93 +5884,144 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-body-length-browser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-3.0.0.tgz", - "integrity": "sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/credential-provider-imds": { + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.8.tgz", + "integrity": "sha512-ZCY2yD0BY+K9iMXkkbnjo+08T2h8/34oHd0Jmh6BZUSZwaaGlGCyBT/3wnS7u7Xl33/EEfN4B6nQr3Gx5bYxgw==", "license": "Apache-2.0", "dependencies": { + "@smithy/node-config-provider": "^3.1.12", + "@smithy/property-provider": "^3.1.11", + "@smithy/types": "^3.7.2", + "@smithy/url-parser": "^3.0.11", "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-body-length-node": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-3.0.0.tgz", - "integrity": "sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/fetch-http-handler": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.9.tgz", + "integrity": "sha512-hYNVQOqhFQ6vOpenifFME546f0GfJn2OiQ3M0FDmuUu8V/Uiwy2wej7ZXxFBNqdx0R5DZAqWM1l6VRhGz8oE6A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^4.1.4", + "@smithy/querystring-builder": "^3.0.7", + "@smithy/types": "^3.5.0", + "@smithy/util-base64": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/hash-node": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.11.tgz", + "integrity": "sha512-emP23rwYyZhQBvklqTtwetkQlqbNYirDiEEwXl2v0GYWMnCzxst7ZaRAnWuy28njp5kAH54lvkdG37MblZzaHA==", "license": "Apache-2.0", "dependencies": { + "@smithy/types": "^3.7.2", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-buffer-from": { + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/invalid-dependency": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.11.tgz", + "integrity": "sha512-NuQmVPEJjUX6c+UELyVz8kUx8Q539EDeNwbRyu4IIF8MeV7hUtq1FB3SHVyki2u++5XLMFqngeMKk7ccspnNyQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/is-array-buffer": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", - "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-config-provider": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz", - "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/middleware-content-length": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.13.tgz", + "integrity": "sha512-zfMhzojhFpIX3P5ug7jxTjfUcIPcGjcQYzB9t+rv0g1TX7B0QdwONW+ATouaLoD7h7LOw/ZlXfkq4xJ/g2TrIw==", "license": "Apache-2.0", "dependencies": { + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-defaults-mode-browser": { - "version": "3.0.34", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.34.tgz", - "integrity": "sha512-FumjjF631lR521cX+svMLBj3SwSDh9VdtyynTYDAiBDEf8YPP5xORNXKQ9j0105o5+ARAGnOOP/RqSl40uXddA==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/middleware-endpoint": { + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.2.8.tgz", + "integrity": "sha512-OEJZKVUEhMOqMs3ktrTWp7UvvluMJEvD5XgQwRePSbDg1VvBaL8pX8mwPltFn6wk1GySbcVwwyldL8S+iqnrEQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/property-provider": "^3.1.11", - "@smithy/smithy-client": "^3.7.0", + "@smithy/core": "^2.5.7", + "@smithy/middleware-serde": "^3.0.11", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/shared-ini-file-loader": "^3.1.12", "@smithy/types": "^3.7.2", - "bowser": "^2.11.0", + "@smithy/url-parser": "^3.0.11", + "@smithy/util-middleware": "^3.0.11", "tslib": "^2.6.2" }, "engines": { - "node": ">= 10.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-defaults-mode-node": { + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/middleware-retry": { "version": "3.0.34", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.34.tgz", - "integrity": "sha512-vN6aHfzW9dVVzkI0wcZoUXvfjkl4CSbM9nE//08lmUMyf00S75uuCpTrqF9uD4bD9eldIXlt53colrlwKAT8Gw==", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.34.tgz", + "integrity": "sha512-yVRr/AAtPZlUvwEkrq7S3x7Z8/xCd97m2hLDaqdz6ucP2RKHsBjEqaUA2ebNv2SsZoPEi+ZD0dZbOB1u37tGCA==", "license": "Apache-2.0", "dependencies": { - "@smithy/config-resolver": "^3.0.13", - "@smithy/credential-provider-imds": "^3.2.8", "@smithy/node-config-provider": "^3.1.12", - "@smithy/property-provider": "^3.1.11", + "@smithy/protocol-http": "^4.1.8", + "@smithy/service-error-classification": "^3.0.11", "@smithy/smithy-client": "^3.7.0", + "@smithy/types": "^3.7.2", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-retry": "^3.0.11", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/middleware-serde": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.11.tgz", + "integrity": "sha512-KzPAeySp/fOoQA82TpnwItvX8BBURecpx6ZMu75EZDkAcnPtO6vf7q4aH5QHs/F1s3/snQaSFbbUMcFFZ086Mw==", + "license": "Apache-2.0", + "dependencies": { "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { - "node": ">= 10.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-endpoints": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.1.7.tgz", - "integrity": "sha512-tSfcqKcN/Oo2STEYCABVuKgJ76nyyr6skGl9t15hs+YaiU06sgMkN7QYjo0BbVw+KT26zok3IzbdSOksQ4YzVw==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/middleware-stack": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.11.tgz", + "integrity": "sha512-1HGo9a6/ikgOMrTrWL/WiN9N8GSVYpuRQO5kjstAq4CvV59bjqnh7TbdXGQ4vxLD3xlSjfBjq5t1SOELePsLnA==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^3.1.12", "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, @@ -5850,24 +6029,30 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-hex-encoding": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", - "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/node-config-provider": { + "version": "3.1.12", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.12.tgz", + "integrity": "sha512-O9LVEu5J/u/FuNlZs+L7Ikn3lz7VB9hb0GtPT9MQeiBmtK8RSY3ULmsZgXhe6VAlgTw0YO+paQx4p8xdbs43vQ==", "license": "Apache-2.0", "dependencies": { + "@smithy/property-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-middleware": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.11.tgz", - "integrity": "sha512-dWpyc1e1R6VoXrwLoLDd57U1z6CwNSdkM69Ie4+6uYh2GC7Vg51Qtan7ITzczuVpqezdDTKJGJB95fFvvjU/ow==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/node-http-handler": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.3.3.tgz", + "integrity": "sha512-BrpZOaZ4RCbcJ2igiSNG16S+kgAc65l/2hmxWdmhyoGWHTLlzQzr06PXavJp9OBlPEG/sHlqdxjWmjzV66+BSQ==", "license": "Apache-2.0", "dependencies": { + "@smithy/abort-controller": "^3.1.9", + "@smithy/protocol-http": "^4.1.8", + "@smithy/querystring-builder": "^3.0.11", "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, @@ -5875,13 +6060,12 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-retry": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.11.tgz", - "integrity": "sha512-hJUC6W7A3DQgaee3Hp9ZFcOxVDZzmBIRBPlUAk8/fSOEl7pE/aX7Dci0JycNOnm9Mfr0KV2XjIlUOcGWXQUdVQ==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/property-provider": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.11.tgz", + "integrity": "sha512-I/+TMc4XTQ3QAjXfOcUWbSS073oOEAxgx4aZy8jHaf8JQnRkq2SZWw8+PfDtBvLUjcGMdxl+YwtzWe6i5uhL/A==", "license": "Apache-2.0", "dependencies": { - "@smithy/service-error-classification": "^3.0.11", "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, @@ -5889,487 +6073,425 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-stream": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.3.4.tgz", - "integrity": "sha512-SGhGBG/KupieJvJSZp/rfHHka8BFgj56eek9px4pp7lZbOF+fRiVr4U7A3y3zJD8uGhxq32C5D96HxsTC9BckQ==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/protocol-http": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.8.tgz", + "integrity": "sha512-hmgIAVyxw1LySOwkgMIUN0kjN8TG9Nc85LJeEmEE/cNEe2rkHDUWhnJf2gxcSRFLWsyqWsrZGw40ROjUogg+Iw==", "license": "Apache-2.0", "dependencies": { - "@smithy/fetch-http-handler": "^4.1.3", - "@smithy/node-http-handler": "^3.3.3", "@smithy/types": "^3.7.2", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-hex-encoding": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-stream/node_modules/@smithy/fetch-http-handler": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-4.1.3.tgz", - "integrity": "sha512-6SxNltSncI8s689nvnzZQc/dPXcpHQ34KUj6gR/HBroytKOd/isMG3gJF/zBE1TBmTT18TXyzhg3O3SOOqGEhA==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/querystring-builder": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.11.tgz", + "integrity": "sha512-u+5HV/9uJaeLj5XTb6+IEF/dokWWkEqJ0XiaRRogyREmKGUgZnNecLucADLdauWFKUNbQfulHFEZEdjwEBjXRg==", "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^4.1.8", - "@smithy/querystring-builder": "^3.0.11", "@smithy/types": "^3.7.2", - "@smithy/util-base64": "^3.0.0", + "@smithy/util-uri-escape": "^3.0.0", "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-uri-escape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", - "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/querystring-parser": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.11.tgz", + "integrity": "sha512-Je3kFvCsFMnso1ilPwA7GtlbPaTixa3WwC+K21kmMZHsBEOZYQaqxcMqeFFoU7/slFjKDIpiiPydvdJm8Q/MCw==", "license": "Apache-2.0", "dependencies": { + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-utf8": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", - "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/service-error-classification": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.11.tgz", + "integrity": "sha512-QnYDPkyewrJzCyaeI2Rmp7pDwbUETe+hU8ADkXmgNusO1bgHBH7ovXJiYmba8t0fNfJx75fE8dlM6SEmZxheog==", "license": "Apache-2.0", "dependencies": { - "@smithy/util-buffer-from": "^3.0.0", + "@smithy/types": "^3.7.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/shared-ini-file-loader": { + "version": "3.1.12", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.12.tgz", + "integrity": "sha512-1xKSGI+U9KKdbG2qDvIR9dGrw3CNx+baqJfyr0igKEpjbHL5stsqAesYBzHChYHlelWtb87VnLWlhvfCz13H8Q==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-s3": { - "version": "3.772.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.772.0.tgz", - "integrity": "sha512-HQXlQIyyLp47h1/Hdjr36yK8/gsAAFX2vRzgDJhSRaz0vWZlWX07AJdYfrxapLUXfVU6DbBu3rwi2UGqM7ixqQ==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/signature-v4": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-4.2.4.tgz", + "integrity": "sha512-5JWeMQYg81TgU4cG+OexAWdvDTs5JDdbEZx+Qr1iPbvo91QFGzjy0IkXAKaXUHqmKUJgSHK0ZxnCkgZpzkeNTA==", "license": "Apache-2.0", "dependencies": { - "@aws-crypto/sha1-browser": "5.2.0", - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.758.0", - "@aws-sdk/credential-provider-node": "3.772.0", - "@aws-sdk/middleware-bucket-endpoint": "3.734.0", - "@aws-sdk/middleware-expect-continue": "3.734.0", - "@aws-sdk/middleware-flexible-checksums": "3.758.0", - "@aws-sdk/middleware-host-header": "3.734.0", - "@aws-sdk/middleware-location-constraint": "3.734.0", - "@aws-sdk/middleware-logger": "3.734.0", - "@aws-sdk/middleware-recursion-detection": "3.772.0", - "@aws-sdk/middleware-sdk-s3": "3.758.0", - "@aws-sdk/middleware-ssec": "3.734.0", - "@aws-sdk/middleware-user-agent": "3.758.0", - "@aws-sdk/region-config-resolver": "3.734.0", - "@aws-sdk/signature-v4-multi-region": "3.758.0", - "@aws-sdk/types": "3.734.0", - "@aws-sdk/util-endpoints": "3.743.0", - "@aws-sdk/util-user-agent-browser": "3.734.0", - "@aws-sdk/util-user-agent-node": "3.758.0", - "@aws-sdk/xml-builder": "3.734.0", - "@smithy/config-resolver": "^4.0.1", - "@smithy/core": "^3.1.5", - "@smithy/eventstream-serde-browser": "^4.0.1", - "@smithy/eventstream-serde-config-resolver": "^4.0.1", - "@smithy/eventstream-serde-node": "^4.0.1", - "@smithy/fetch-http-handler": "^5.0.1", - "@smithy/hash-blob-browser": "^4.0.1", - "@smithy/hash-node": "^4.0.1", - "@smithy/hash-stream-node": "^4.0.1", - "@smithy/invalid-dependency": "^4.0.1", - "@smithy/md5-js": "^4.0.1", - "@smithy/middleware-content-length": "^4.0.1", - "@smithy/middleware-endpoint": "^4.0.6", - "@smithy/middleware-retry": "^4.0.7", - "@smithy/middleware-serde": "^4.0.2", - "@smithy/middleware-stack": "^4.0.1", - "@smithy/node-config-provider": "^4.0.1", - "@smithy/node-http-handler": "^4.0.3", - "@smithy/protocol-http": "^5.0.1", - "@smithy/smithy-client": "^4.1.6", - "@smithy/types": "^4.1.0", - "@smithy/url-parser": "^4.0.1", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.7", - "@smithy/util-defaults-mode-node": "^4.0.7", - "@smithy/util-endpoints": "^3.0.1", - "@smithy/util-middleware": "^4.0.1", - "@smithy/util-retry": "^4.0.1", - "@smithy/util-stream": "^4.1.2", - "@smithy/util-utf8": "^4.0.0", - "@smithy/util-waiter": "^4.0.2", + "@smithy/is-array-buffer": "^3.0.0", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "@smithy/util-hex-encoding": "^3.0.0", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-uri-escape": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-s3/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/smithy-client": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.7.0.tgz", + "integrity": "sha512-9wYrjAZFlqWhgVo3C4y/9kpc68jgiSsKUnsFPzr/MSiRL93+QRDafGTfhhKAb2wsr69Ru87WTiqSfQusSmWipA==", "license": "Apache-2.0", "dependencies": { + "@smithy/core": "^2.5.7", + "@smithy/middleware-endpoint": "^3.2.8", + "@smithy/middleware-stack": "^3.0.11", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "@smithy/util-stream": "^3.3.4", "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-s3/node_modules/@smithy/util-utf8": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", - "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/url-parser": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.11.tgz", + "integrity": "sha512-TmlqXkSk8ZPhfc+SQutjmFr5FjC0av3GZP4B/10caK1SbRwe/v+Wzu/R6xEKxoNqL+8nY18s1byiy6HqPG37Aw==", "license": "Apache-2.0", "dependencies": { - "@smithy/util-buffer-from": "^4.0.0", + "@smithy/querystring-parser": "^3.0.11", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-ssm": { - "version": "3.782.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-ssm/-/client-ssm-3.782.0.tgz", - "integrity": "sha512-Y3x5KOJ0HL50JMcRIvLILmkBUbnn335LpGM25gmPPhkDPR7cta3sclgZ8ioz16QDORlu0nClAF8ou2Arce+KaQ==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-base64": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", + "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", "license": "Apache-2.0", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.775.0", - "@aws-sdk/credential-provider-node": "3.782.0", - "@aws-sdk/middleware-host-header": "3.775.0", - "@aws-sdk/middleware-logger": "3.775.0", - "@aws-sdk/middleware-recursion-detection": "3.775.0", - "@aws-sdk/middleware-user-agent": "3.782.0", - "@aws-sdk/region-config-resolver": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-endpoints": "3.782.0", - "@aws-sdk/util-user-agent-browser": "3.775.0", - "@aws-sdk/util-user-agent-node": "3.782.0", - "@smithy/config-resolver": "^4.1.0", - "@smithy/core": "^3.2.0", - "@smithy/fetch-http-handler": "^5.0.2", - "@smithy/hash-node": "^4.0.2", - "@smithy/invalid-dependency": "^4.0.2", - "@smithy/middleware-content-length": "^4.0.2", - "@smithy/middleware-endpoint": "^4.1.0", - "@smithy/middleware-retry": "^4.1.0", - "@smithy/middleware-serde": "^4.0.3", - "@smithy/middleware-stack": "^4.0.2", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/node-http-handler": "^4.0.4", - "@smithy/protocol-http": "^5.1.0", - "@smithy/smithy-client": "^4.2.0", - "@smithy/types": "^4.2.0", - "@smithy/url-parser": "^4.0.2", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.8", - "@smithy/util-defaults-mode-node": "^4.0.8", - "@smithy/util-endpoints": "^3.0.2", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-retry": "^4.0.2", - "@smithy/util-utf8": "^4.0.0", - "@smithy/util-waiter": "^4.0.3", - "@types/uuid": "^9.0.1", - "tslib": "^2.6.2", - "uuid": "^9.0.1" + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/client-sso": { - "version": "3.782.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.782.0.tgz", - "integrity": "sha512-5GlJBejo8wqMpSSEKb45WE82YxI2k73YuebjLH/eWDNQeE6VI5Bh9lA1YQ7xNkLLH8hIsb0pSfKVuwh0VEzVrg==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-body-length-browser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-3.0.0.tgz", + "integrity": "sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==", "license": "Apache-2.0", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.775.0", - "@aws-sdk/middleware-host-header": "3.775.0", - "@aws-sdk/middleware-logger": "3.775.0", - "@aws-sdk/middleware-recursion-detection": "3.775.0", - "@aws-sdk/middleware-user-agent": "3.782.0", - "@aws-sdk/region-config-resolver": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-endpoints": "3.782.0", - "@aws-sdk/util-user-agent-browser": "3.775.0", - "@aws-sdk/util-user-agent-node": "3.782.0", - "@smithy/config-resolver": "^4.1.0", - "@smithy/core": "^3.2.0", - "@smithy/fetch-http-handler": "^5.0.2", - "@smithy/hash-node": "^4.0.2", - "@smithy/invalid-dependency": "^4.0.2", - "@smithy/middleware-content-length": "^4.0.2", - "@smithy/middleware-endpoint": "^4.1.0", - "@smithy/middleware-retry": "^4.1.0", - "@smithy/middleware-serde": "^4.0.3", - "@smithy/middleware-stack": "^4.0.2", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/node-http-handler": "^4.0.4", - "@smithy/protocol-http": "^5.1.0", - "@smithy/smithy-client": "^4.2.0", - "@smithy/types": "^4.2.0", - "@smithy/url-parser": "^4.0.2", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.8", - "@smithy/util-defaults-mode-node": "^4.0.8", - "@smithy/util-endpoints": "^3.0.2", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-retry": "^4.0.2", - "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/core": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.775.0.tgz", - "integrity": "sha512-8vpW4WihVfz0DX+7WnnLGm3GuQER++b0IwQG35JlQMlgqnc44M//KbJPsIHA0aJUJVwJAEShgfr5dUbY8WUzaA==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-body-length-node": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-3.0.0.tgz", + "integrity": "sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/core": "^3.2.0", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/property-provider": "^4.0.2", - "@smithy/protocol-http": "^5.1.0", - "@smithy/signature-v4": "^5.0.2", - "@smithy/smithy-client": "^4.2.0", - "@smithy/types": "^4.2.0", - "@smithy/util-middleware": "^4.0.2", - "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/credential-provider-env": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.775.0.tgz", - "integrity": "sha512-6ESVxwCbGm7WZ17kY1fjmxQud43vzJFoLd4bmlR+idQSWdqlzGDYdcfzpjDKTcivdtNrVYmFvcH1JBUwCRAZhw==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/credential-provider-http": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.775.0.tgz", - "integrity": "sha512-PjDQeDH/J1S0yWV32wCj2k5liRo0ssXMseCBEkCsD3SqsU8o5cU82b0hMX4sAib/RkglCSZqGO0xMiN0/7ndww==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-config-provider": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz", + "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@smithy/fetch-http-handler": "^5.0.2", - "@smithy/node-http-handler": "^4.0.4", - "@smithy/property-provider": "^4.0.2", - "@smithy/protocol-http": "^5.1.0", - "@smithy/smithy-client": "^4.2.0", - "@smithy/types": "^4.2.0", - "@smithy/util-stream": "^4.2.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.782.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.782.0.tgz", - "integrity": "sha512-wd4KdRy2YjLsE4Y7pz00470Iip06GlRHkG4dyLW7/hFMzEO2o7ixswCWp6J2VGZVAX64acknlv2Q0z02ebjmhw==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-defaults-mode-browser": { + "version": "3.0.34", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.34.tgz", + "integrity": "sha512-FumjjF631lR521cX+svMLBj3SwSDh9VdtyynTYDAiBDEf8YPP5xORNXKQ9j0105o5+ARAGnOOP/RqSl40uXddA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.775.0", - "@aws-sdk/credential-provider-env": "3.775.0", - "@aws-sdk/credential-provider-http": "3.775.0", - "@aws-sdk/credential-provider-process": "3.775.0", - "@aws-sdk/credential-provider-sso": "3.782.0", - "@aws-sdk/credential-provider-web-identity": "3.782.0", - "@aws-sdk/nested-clients": "3.782.0", - "@aws-sdk/types": "3.775.0", - "@smithy/credential-provider-imds": "^4.0.2", - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/property-provider": "^3.1.11", + "@smithy/smithy-client": "^3.7.0", + "@smithy/types": "^3.7.2", + "bowser": "^2.11.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">= 10.0.0" } }, - "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/credential-provider-node": { - "version": "3.782.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.782.0.tgz", - "integrity": "sha512-HZiAF+TCEyKjju9dgysjiPIWgt/+VerGaeEp18mvKLNfgKz1d+/82A2USEpNKTze7v3cMFASx3CvL8yYyF7mJw==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-defaults-mode-node": { + "version": "3.0.34", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.34.tgz", + "integrity": "sha512-vN6aHfzW9dVVzkI0wcZoUXvfjkl4CSbM9nE//08lmUMyf00S75uuCpTrqF9uD4bD9eldIXlt53colrlwKAT8Gw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/credential-provider-env": "3.775.0", - "@aws-sdk/credential-provider-http": "3.775.0", - "@aws-sdk/credential-provider-ini": "3.782.0", - "@aws-sdk/credential-provider-process": "3.775.0", - "@aws-sdk/credential-provider-sso": "3.782.0", - "@aws-sdk/credential-provider-web-identity": "3.782.0", - "@aws-sdk/types": "3.775.0", - "@smithy/credential-provider-imds": "^4.0.2", - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/config-resolver": "^3.0.13", + "@smithy/credential-provider-imds": "^3.2.8", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/property-provider": "^3.1.11", + "@smithy/smithy-client": "^3.7.0", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">= 10.0.0" } }, - "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/credential-provider-process": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.775.0.tgz", - "integrity": "sha512-A6k68H9rQp+2+7P7SGO90Csw6nrUEm0Qfjpn9Etc4EboZhhCLs9b66umUsTsSBHus4FDIe5JQxfCUyt1wgNogg==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-endpoints": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.1.7.tgz", + "integrity": "sha512-tSfcqKcN/Oo2STEYCABVuKgJ76nyyr6skGl9t15hs+YaiU06sgMkN7QYjo0BbVw+KT26zok3IzbdSOksQ4YzVw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.782.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.782.0.tgz", - "integrity": "sha512-1y1ucxTtTIGDSNSNxriQY8msinilhe9gGvQpUDYW9gboyC7WQJPDw66imy258V6osdtdi+xoHzVCbCz3WhosMQ==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-hex-encoding": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", + "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/client-sso": "3.782.0", - "@aws-sdk/core": "3.775.0", - "@aws-sdk/token-providers": "3.782.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.782.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.782.0.tgz", - "integrity": "sha512-xCna0opVPaueEbJoclj5C6OpDNi0Gynj+4d7tnuXGgQhTHPyAz8ZyClkVqpi5qvHTgxROdUEDxWqEO5jqRHZHQ==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-middleware": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.11.tgz", + "integrity": "sha512-dWpyc1e1R6VoXrwLoLDd57U1z6CwNSdkM69Ie4+6uYh2GC7Vg51Qtan7ITzczuVpqezdDTKJGJB95fFvvjU/ow==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.775.0", - "@aws-sdk/nested-clients": "3.782.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/middleware-host-header": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.775.0.tgz", - "integrity": "sha512-tkSegM0Z6WMXpLB8oPys/d+umYIocvO298mGvcMCncpRl77L9XkvSLJIFzaHes+o7djAgIduYw8wKIMStFss2w==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-retry": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.11.tgz", + "integrity": "sha512-hJUC6W7A3DQgaee3Hp9ZFcOxVDZzmBIRBPlUAk8/fSOEl7pE/aX7Dci0JycNOnm9Mfr0KV2XjIlUOcGWXQUdVQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", + "@smithy/service-error-classification": "^3.0.11", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/middleware-logger": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.775.0.tgz", - "integrity": "sha512-FaxO1xom4MAoUJsldmR92nT1G6uZxTdNYOFYtdHfd6N2wcNaTuxgjIvqzg5y7QIH9kn58XX/dzf1iTjgqUStZw==", + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-stream": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.3.4.tgz", + "integrity": "sha512-SGhGBG/KupieJvJSZp/rfHHka8BFgj56eek9px4pp7lZbOF+fRiVr4U7A3y3zJD8uGhxq32C5D96HxsTC9BckQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/types": "^4.2.0", + "@smithy/fetch-http-handler": "^4.1.3", + "@smithy/node-http-handler": "^3.3.3", + "@smithy/types": "^3.7.2", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-hex-encoding": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-stream/node_modules/@smithy/fetch-http-handler": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-4.1.3.tgz", + "integrity": "sha512-6SxNltSncI8s689nvnzZQc/dPXcpHQ34KUj6gR/HBroytKOd/isMG3gJF/zBE1TBmTT18TXyzhg3O3SOOqGEhA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^4.1.8", + "@smithy/querystring-builder": "^3.0.11", + "@smithy/types": "^3.7.2", + "@smithy/util-base64": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-uri-escape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", + "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-personalize-events/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-s3": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.772.0.tgz", + "integrity": "sha512-HQXlQIyyLp47h1/Hdjr36yK8/gsAAFX2vRzgDJhSRaz0vWZlWX07AJdYfrxapLUXfVU6DbBu3rwi2UGqM7ixqQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha1-browser": "5.2.0", + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/credential-provider-node": "3.772.0", + "@aws-sdk/middleware-bucket-endpoint": "3.734.0", + "@aws-sdk/middleware-expect-continue": "3.734.0", + "@aws-sdk/middleware-flexible-checksums": "3.758.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-location-constraint": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.772.0", + "@aws-sdk/middleware-sdk-s3": "3.758.0", + "@aws-sdk/middleware-ssec": "3.734.0", + "@aws-sdk/middleware-user-agent": "3.758.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/signature-v4-multi-region": "3.758.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.743.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.758.0", + "@aws-sdk/xml-builder": "3.734.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.5", + "@smithy/eventstream-serde-browser": "^4.0.1", + "@smithy/eventstream-serde-config-resolver": "^4.0.1", + "@smithy/eventstream-serde-node": "^4.0.1", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-blob-browser": "^4.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/hash-stream-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/md5-js": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.6", + "@smithy/middleware-retry": "^4.0.7", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.3", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.6", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.7", + "@smithy/util-defaults-mode-node": "^4.0.7", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-stream": "^4.1.2", + "@smithy/util-utf8": "^4.0.0", + "@smithy/util-waiter": "^4.0.2", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.775.0.tgz", - "integrity": "sha512-GLCzC8D0A0YDG5u3F5U03Vb9j5tcOEFhr8oc6PDk0k0vm5VwtZOE6LvK7hcCSoAB4HXyOUM0sQuXrbaAh9OwXA==", + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.782.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.782.0.tgz", - "integrity": "sha512-i32H2R6IItX+bQ2p4+v2gGO2jA80jQoJO2m1xjU9rYWQW3+ErWy4I5YIuQHTBfb6hSdAHbaRfqPDgbv9J2rjEg==", + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-endpoints": "3.782.0", - "@smithy/core": "^3.2.0", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", + "@smithy/util-buffer-from": "^4.0.0", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/nested-clients": { + "node_modules/@aws-sdk/client-ssm": { "version": "3.782.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.782.0.tgz", - "integrity": "sha512-QOYC8q7luzHFXrP0xYAqBctoPkynjfV0r9dqntFu4/IWMTyC1vlo1UTxFAjIPyclYw92XJyEkVCVg9v/nQnsUA==", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-ssm/-/client-ssm-3.782.0.tgz", + "integrity": "sha512-Y3x5KOJ0HL50JMcRIvLILmkBUbnn335LpGM25gmPPhkDPR7cta3sclgZ8ioz16QDORlu0nClAF8ou2Arce+KaQ==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.775.0", + "@aws-sdk/credential-provider-node": "3.782.0", "@aws-sdk/middleware-host-header": "3.775.0", "@aws-sdk/middleware-logger": "3.775.0", "@aws-sdk/middleware-recursion-detection": "3.775.0", @@ -6404,52 +6526,95 @@ "@smithy/util-middleware": "^4.0.2", "@smithy/util-retry": "^4.0.2", "@smithy/util-utf8": "^4.0.0", - "tslib": "^2.6.2" + "@smithy/util-waiter": "^4.0.3", + "@types/uuid": "^9.0.1", + "tslib": "^2.6.2", + "uuid": "^9.0.1" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/region-config-resolver": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.775.0.tgz", - "integrity": "sha512-40iH3LJjrQS3LKUJAl7Wj0bln7RFPEvUYKFxtP8a+oKFDO0F65F52xZxIJbPn6sHkxWDAnZlGgdjZXM3p2g5wQ==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/client-sso": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.782.0.tgz", + "integrity": "sha512-5GlJBejo8wqMpSSEKb45WE82YxI2k73YuebjLH/eWDNQeE6VI5Bh9lA1YQ7xNkLLH8hIsb0pSfKVuwh0VEzVrg==", + "license": "Apache-2.0", "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.775.0", + "@aws-sdk/middleware-host-header": "3.775.0", + "@aws-sdk/middleware-logger": "3.775.0", + "@aws-sdk/middleware-recursion-detection": "3.775.0", + "@aws-sdk/middleware-user-agent": "3.782.0", + "@aws-sdk/region-config-resolver": "3.775.0", "@aws-sdk/types": "3.775.0", + "@aws-sdk/util-endpoints": "3.782.0", + "@aws-sdk/util-user-agent-browser": "3.775.0", + "@aws-sdk/util-user-agent-node": "3.782.0", + "@smithy/config-resolver": "^4.1.0", + "@smithy/core": "^3.2.0", + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/hash-node": "^4.0.2", + "@smithy/invalid-dependency": "^4.0.2", + "@smithy/middleware-content-length": "^4.0.2", + "@smithy/middleware-endpoint": "^4.1.0", + "@smithy/middleware-retry": "^4.1.0", + "@smithy/middleware-serde": "^4.0.3", + "@smithy/middleware-stack": "^4.0.2", "@smithy/node-config-provider": "^4.0.2", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/protocol-http": "^5.1.0", + "@smithy/smithy-client": "^4.2.0", "@smithy/types": "^4.2.0", - "@smithy/util-config-provider": "^4.0.0", + "@smithy/url-parser": "^4.0.2", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.8", + "@smithy/util-defaults-mode-node": "^4.0.8", + "@smithy/util-endpoints": "^3.0.2", "@smithy/util-middleware": "^4.0.2", + "@smithy/util-retry": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/token-providers": { - "version": "3.782.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.782.0.tgz", - "integrity": "sha512-4tPuk/3+THPrzKaXW4jE2R67UyGwHLFizZ47pcjJWbhb78IIJAy94vbeqEQ+veS84KF5TXcU7g5jGTXC0D70Wg==", + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/core": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.775.0.tgz", + "integrity": "sha512-8vpW4WihVfz0DX+7WnnLGm3GuQER++b0IwQG35JlQMlgqnc44M//KbJPsIHA0aJUJVwJAEShgfr5dUbY8WUzaA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/nested-clients": "3.782.0", "@aws-sdk/types": "3.775.0", + "@smithy/core": "^3.2.0", + "@smithy/node-config-provider": "^4.0.2", "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/protocol-http": "^5.1.0", + "@smithy/signature-v4": "^5.0.2", + "@smithy/smithy-client": "^4.2.0", "@smithy/types": "^4.2.0", + "@smithy/util-middleware": "^4.0.2", + "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/types": { + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/credential-provider-env": { "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.775.0.tgz", - "integrity": "sha512-ZoGKwa4C9fC9Av6bdfqcW6Ix5ot05F/S4VxWR2nHuMv7hzfmAjTOcUiWT7UR4hM/U0whf84VhDtXN/DWAk52KA==", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.775.0.tgz", + "integrity": "sha512-6ESVxwCbGm7WZ17kY1fjmxQud43vzJFoLd4bmlR+idQSWdqlzGDYdcfzpjDKTcivdtNrVYmFvcH1JBUwCRAZhw==", "license": "Apache-2.0", "dependencies": { + "@aws-sdk/core": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@smithy/property-provider": "^4.0.2", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, @@ -6457,534 +6622,813 @@ "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/util-endpoints": { - "version": "3.782.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.782.0.tgz", - "integrity": "sha512-/RJOAO7o7HI6lEa4ASbFFLHGU9iPK876BhsVfnl54MvApPVYWQ9sHO0anOUim2S5lQTwd/6ghuH3rFYSq/+rdw==", + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.775.0.tgz", + "integrity": "sha512-PjDQeDH/J1S0yWV32wCj2k5liRo0ssXMseCBEkCsD3SqsU8o5cU82b0hMX4sAib/RkglCSZqGO0xMiN0/7ndww==", "license": "Apache-2.0", "dependencies": { + "@aws-sdk/core": "3.775.0", "@aws-sdk/types": "3.775.0", + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/property-provider": "^4.0.2", + "@smithy/protocol-http": "^5.1.0", + "@smithy/smithy-client": "^4.2.0", "@smithy/types": "^4.2.0", - "@smithy/util-endpoints": "^3.0.2", + "@smithy/util-stream": "^4.2.0", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.775.0.tgz", - "integrity": "sha512-txw2wkiJmZKVdDbscK7VBK+u+TJnRtlUjRTLei+elZg2ADhpQxfVAQl436FUeIv6AhB/oRHW6/K/EAGXUSWi0A==", + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.782.0.tgz", + "integrity": "sha512-wd4KdRy2YjLsE4Y7pz00470Iip06GlRHkG4dyLW7/hFMzEO2o7ixswCWp6J2VGZVAX64acknlv2Q0z02ebjmhw==", "license": "Apache-2.0", "dependencies": { + "@aws-sdk/core": "3.775.0", + "@aws-sdk/credential-provider-env": "3.775.0", + "@aws-sdk/credential-provider-http": "3.775.0", + "@aws-sdk/credential-provider-process": "3.775.0", + "@aws-sdk/credential-provider-sso": "3.782.0", + "@aws-sdk/credential-provider-web-identity": "3.782.0", + "@aws-sdk/nested-clients": "3.782.0", "@aws-sdk/types": "3.775.0", + "@smithy/credential-provider-imds": "^4.0.2", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", "@smithy/types": "^4.2.0", - "bowser": "^2.11.0", "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/util-user-agent-node": { + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/credential-provider-node": { "version": "3.782.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.782.0.tgz", - "integrity": "sha512-dMFkUBgh2Bxuw8fYZQoH/u3H4afQ12VSkzEi//qFiDTwbKYq+u+RYjc8GLDM6JSK1BShMu5AVR7HD4ap1TYUnA==", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.782.0.tgz", + "integrity": "sha512-HZiAF+TCEyKjju9dgysjiPIWgt/+VerGaeEp18mvKLNfgKz1d+/82A2USEpNKTze7v3cMFASx3CvL8yYyF7mJw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/middleware-user-agent": "3.782.0", + "@aws-sdk/credential-provider-env": "3.775.0", + "@aws-sdk/credential-provider-http": "3.775.0", + "@aws-sdk/credential-provider-ini": "3.782.0", + "@aws-sdk/credential-provider-process": "3.775.0", + "@aws-sdk/credential-provider-sso": "3.782.0", + "@aws-sdk/credential-provider-web-identity": "3.782.0", "@aws-sdk/types": "3.775.0", - "@smithy/node-config-provider": "^4.0.2", + "@smithy/credential-provider-imds": "^4.0.2", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" - }, - "peerDependencies": { - "aws-crt": ">=1.0.0" - }, - "peerDependenciesMeta": { - "aws-crt": { - "optional": true - } } }, - "node_modules/@aws-sdk/client-ssm/node_modules/@smithy/types": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", - "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.775.0.tgz", + "integrity": "sha512-A6k68H9rQp+2+7P7SGO90Csw6nrUEm0Qfjpn9Etc4EboZhhCLs9b66umUsTsSBHus4FDIe5JQxfCUyt1wgNogg==", "license": "Apache-2.0", "dependencies": { + "@aws-sdk/core": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-ssm/node_modules/@smithy/util-utf8": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", - "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.782.0.tgz", + "integrity": "sha512-1y1ucxTtTIGDSNSNxriQY8msinilhe9gGvQpUDYW9gboyC7WQJPDw66imy258V6osdtdi+xoHzVCbCz3WhosMQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/util-buffer-from": "^4.0.0", + "@aws-sdk/client-sso": "3.782.0", + "@aws-sdk/core": "3.775.0", + "@aws-sdk/token-providers": "3.782.0", + "@aws-sdk/types": "3.775.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-sso": { - "version": "3.772.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.772.0.tgz", - "integrity": "sha512-sDdxepi74+cL6gXJJ2yw3UNSI7GBvoGTwZqFyPoNAzcURvaYwo8dBr7G4jS9GDanjTlO3CGVAf2VMcpqEvmoEw==", + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.782.0.tgz", + "integrity": "sha512-xCna0opVPaueEbJoclj5C6OpDNi0Gynj+4d7tnuXGgQhTHPyAz8ZyClkVqpi5qvHTgxROdUEDxWqEO5jqRHZHQ==", "license": "Apache-2.0", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.758.0", - "@aws-sdk/middleware-host-header": "3.734.0", - "@aws-sdk/middleware-logger": "3.734.0", - "@aws-sdk/middleware-recursion-detection": "3.772.0", - "@aws-sdk/middleware-user-agent": "3.758.0", - "@aws-sdk/region-config-resolver": "3.734.0", - "@aws-sdk/types": "3.734.0", - "@aws-sdk/util-endpoints": "3.743.0", - "@aws-sdk/util-user-agent-browser": "3.734.0", - "@aws-sdk/util-user-agent-node": "3.758.0", - "@smithy/config-resolver": "^4.0.1", - "@smithy/core": "^3.1.5", - "@smithy/fetch-http-handler": "^5.0.1", - "@smithy/hash-node": "^4.0.1", - "@smithy/invalid-dependency": "^4.0.1", - "@smithy/middleware-content-length": "^4.0.1", - "@smithy/middleware-endpoint": "^4.0.6", - "@smithy/middleware-retry": "^4.0.7", - "@smithy/middleware-serde": "^4.0.2", - "@smithy/middleware-stack": "^4.0.1", - "@smithy/node-config-provider": "^4.0.1", - "@smithy/node-http-handler": "^4.0.3", - "@smithy/protocol-http": "^5.0.1", - "@smithy/smithy-client": "^4.1.6", - "@smithy/types": "^4.1.0", - "@smithy/url-parser": "^4.0.1", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.7", - "@smithy/util-defaults-mode-node": "^4.0.7", - "@smithy/util-endpoints": "^3.0.1", - "@smithy/util-middleware": "^4.0.1", - "@smithy/util-retry": "^4.0.1", - "@smithy/util-utf8": "^4.0.0", + "@aws-sdk/core": "3.775.0", + "@aws-sdk/nested-clients": "3.782.0", + "@aws-sdk/types": "3.775.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.621.0.tgz", - "integrity": "sha512-mMjk3mFUwV2Y68POf1BQMTF+F6qxt5tPu6daEUCNGC9Cenk3h2YXQQoS4/eSyYzuBiYk3vx49VgleRvdvkg8rg==", + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.775.0.tgz", + "integrity": "sha512-tkSegM0Z6WMXpLB8oPys/d+umYIocvO298mGvcMCncpRl77L9XkvSLJIFzaHes+o7djAgIduYw8wKIMStFss2w==", "license": "Apache-2.0", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.621.0", - "@aws-sdk/credential-provider-node": "3.621.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.1", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.13", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.13", - "@smithy/util-defaults-mode-node": "^3.0.13", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", + "@aws-sdk/types": "3.775.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.621.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/client-sso": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.621.0.tgz", - "integrity": "sha512-xpKfikN4u0BaUYZA9FGUMkkDmfoIP0Q03+A86WjqDWhcOoqNA1DkHsE4kZ+r064ifkPUfcNuUvlkVTEoBZoFjA==", + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/middleware-logger": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.775.0.tgz", + "integrity": "sha512-FaxO1xom4MAoUJsldmR92nT1G6uZxTdNYOFYtdHfd6N2wcNaTuxgjIvqzg5y7QIH9kn58XX/dzf1iTjgqUStZw==", "license": "Apache-2.0", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.621.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.1", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.13", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.13", - "@smithy/util-defaults-mode-node": "^3.0.13", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", + "@aws-sdk/types": "3.775.0", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/core": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.621.0.tgz", - "integrity": "sha512-CtOwWmDdEiINkGXD93iGfXjN0WmCp9l45cDWHHGa8lRgEDyhuL7bwd/pH5aSzj0j8SiQBG2k0S7DHbd5RaqvbQ==", + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.775.0.tgz", + "integrity": "sha512-GLCzC8D0A0YDG5u3F5U03Vb9j5tcOEFhr8oc6PDk0k0vm5VwtZOE6LvK7hcCSoAB4HXyOUM0sQuXrbaAh9OwXA==", "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^2.3.1", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/signature-v4": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/util-middleware": "^3.0.3", - "fast-xml-parser": "4.4.1", + "@aws-sdk/types": "3.775.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/credential-provider-env": { - "version": "3.620.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.620.1.tgz", - "integrity": "sha512-ExuILJ2qLW5ZO+rgkNRj0xiAipKT16Rk77buvPP8csR7kkCflT/gXTyzRe/uzIiETTxM7tr8xuO9MP/DQXqkfg==", + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.782.0.tgz", + "integrity": "sha512-i32H2R6IItX+bQ2p4+v2gGO2jA80jQoJO2m1xjU9rYWQW3+ErWy4I5YIuQHTBfb6hSdAHbaRfqPDgbv9J2rjEg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/types": "^3.3.0", + "@aws-sdk/core": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@aws-sdk/util-endpoints": "3.782.0", + "@smithy/core": "^3.2.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/credential-provider-http": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.621.0.tgz", - "integrity": "sha512-/jc2tEsdkT1QQAI5Dvoci50DbSxtJrevemwFsm0B73pwCcOQZ5ZwwSdVqGsPutzYzUVx3bcXg3LRL7jLACqRIg==", + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/nested-clients": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.782.0.tgz", + "integrity": "sha512-QOYC8q7luzHFXrP0xYAqBctoPkynjfV0r9dqntFu4/IWMTyC1vlo1UTxFAjIPyclYw92XJyEkVCVg9v/nQnsUA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/property-provider": "^3.1.3", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/util-stream": "^3.1.3", + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.775.0", + "@aws-sdk/middleware-host-header": "3.775.0", + "@aws-sdk/middleware-logger": "3.775.0", + "@aws-sdk/middleware-recursion-detection": "3.775.0", + "@aws-sdk/middleware-user-agent": "3.782.0", + "@aws-sdk/region-config-resolver": "3.775.0", + "@aws-sdk/types": "3.775.0", + "@aws-sdk/util-endpoints": "3.782.0", + "@aws-sdk/util-user-agent-browser": "3.775.0", + "@aws-sdk/util-user-agent-node": "3.782.0", + "@smithy/config-resolver": "^4.1.0", + "@smithy/core": "^3.2.0", + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/hash-node": "^4.0.2", + "@smithy/invalid-dependency": "^4.0.2", + "@smithy/middleware-content-length": "^4.0.2", + "@smithy/middleware-endpoint": "^4.1.0", + "@smithy/middleware-retry": "^4.1.0", + "@smithy/middleware-serde": "^4.0.3", + "@smithy/middleware-stack": "^4.0.2", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/protocol-http": "^5.1.0", + "@smithy/smithy-client": "^4.2.0", + "@smithy/types": "^4.2.0", + "@smithy/url-parser": "^4.0.2", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.8", + "@smithy/util-defaults-mode-node": "^4.0.8", + "@smithy/util-endpoints": "^3.0.2", + "@smithy/util-middleware": "^4.0.2", + "@smithy/util-retry": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.621.0.tgz", - "integrity": "sha512-0EWVnSc+JQn5HLnF5Xv405M8n4zfdx9gyGdpnCmAmFqEDHA8LmBdxJdpUk1Ovp/I5oPANhjojxabIW5f1uU0RA==", + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.775.0.tgz", + "integrity": "sha512-40iH3LJjrQS3LKUJAl7Wj0bln7RFPEvUYKFxtP8a+oKFDO0F65F52xZxIJbPn6sHkxWDAnZlGgdjZXM3p2g5wQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.621.0", - "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.621.0", - "@aws-sdk/credential-provider-web-identity": "3.621.0", - "@aws-sdk/types": "3.609.0", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", + "@aws-sdk/types": "3.775.0", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/types": "^4.2.0", + "@smithy/util-config-provider": "^4.0.0", + "@smithy/util-middleware": "^4.0.2", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.621.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/credential-provider-node": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.621.0.tgz", - "integrity": "sha512-4JqpccUgz5Snanpt2+53hbOBbJQrSFq7E1sAAbgY6BKVQUsW5qyXqnjvSF32kDeKa5JpBl3bBWLZl04IadcPHw==", + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/token-providers": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.782.0.tgz", + "integrity": "sha512-4tPuk/3+THPrzKaXW4jE2R67UyGwHLFizZ47pcjJWbhb78IIJAy94vbeqEQ+veS84KF5TXcU7g5jGTXC0D70Wg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.621.0", - "@aws-sdk/credential-provider-ini": "3.621.0", - "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.621.0", - "@aws-sdk/credential-provider-web-identity": "3.621.0", - "@aws-sdk/types": "3.609.0", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", + "@aws-sdk/nested-clients": "3.782.0", + "@aws-sdk/types": "3.775.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/credential-provider-process": { - "version": "3.620.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.620.1.tgz", - "integrity": "sha512-hWqFMidqLAkaV9G460+1at6qa9vySbjQKKc04p59OT7lZ5cO5VH5S4aI05e+m4j364MBROjjk2ugNvfNf/8ILg==", + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/types": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.775.0.tgz", + "integrity": "sha512-ZoGKwa4C9fC9Av6bdfqcW6Ix5ot05F/S4VxWR2nHuMv7hzfmAjTOcUiWT7UR4hM/U0whf84VhDtXN/DWAk52KA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.621.0.tgz", - "integrity": "sha512-Kza0jcFeA/GEL6xJlzR2KFf1PfZKMFnxfGzJzl5yN7EjoGdMijl34KaRyVnfRjnCWcsUpBWKNIDk9WZVMY9yiw==", + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/util-endpoints": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.782.0.tgz", + "integrity": "sha512-/RJOAO7o7HI6lEa4ASbFFLHGU9iPK876BhsVfnl54MvApPVYWQ9sHO0anOUim2S5lQTwd/6ghuH3rFYSq/+rdw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/client-sso": "3.621.0", - "@aws-sdk/token-providers": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", + "@aws-sdk/types": "3.775.0", + "@smithy/types": "^4.2.0", + "@smithy/util-endpoints": "^3.0.2", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.621.0.tgz", - "integrity": "sha512-w7ASSyfNvcx7+bYGep3VBgC3K6vEdLmlpjT7nSIHxxQf+WSdvy+HynwJosrpZax0sK5q0D1Jpn/5q+r5lwwW6w==", + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.775.0.tgz", + "integrity": "sha512-txw2wkiJmZKVdDbscK7VBK+u+TJnRtlUjRTLei+elZg2ADhpQxfVAQl436FUeIv6AhB/oRHW6/K/EAGXUSWi0A==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/types": "^3.3.0", + "@aws-sdk/types": "3.775.0", + "@smithy/types": "^4.2.0", + "bowser": "^2.11.0", "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.621.0" } }, - "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/middleware-host-header": { - "version": "3.620.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.620.0.tgz", - "integrity": "sha512-VMtPEZwqYrII/oUkffYsNWY9PZ9xpNJpMgmyU0rlDQ25O1c0Hk3fJmZRe6pEkAJ0omD7kLrqGl1DUjQVxpd/Rg==", + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.782.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.782.0.tgz", + "integrity": "sha512-dMFkUBgh2Bxuw8fYZQoH/u3H4afQ12VSkzEi//qFiDTwbKYq+u+RYjc8GLDM6JSK1BShMu5AVR7HD4ap1TYUnA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", + "@aws-sdk/middleware-user-agent": "3.782.0", + "@aws-sdk/types": "3.775.0", + "@smithy/node-config-provider": "^4.0.2", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } } }, - "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/middleware-logger": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.609.0.tgz", - "integrity": "sha512-S62U2dy4jMDhDFDK5gZ4VxFdWzCtLzwbYyFZx2uvPYTECkepLUfzLic2BHg2Qvtu4QjX+oGE3P/7fwaGIsGNuQ==", + "node_modules/@aws-sdk/client-ssm/node_modules/@smithy/types": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.620.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.620.0.tgz", - "integrity": "sha512-nh91S7aGK3e/o1ck64sA/CyoFw+gAYj2BDOnoNa6ouyCrVJED96ZXWbhye/fz9SgmNUZR2g7GdVpiLpMKZoI5w==", + "node_modules/@aws-sdk/client-ssm/node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", + "@smithy/util-buffer-from": "^4.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.620.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.620.0.tgz", - "integrity": "sha512-bvS6etn+KsuL32ubY5D3xNof1qkenpbJXf/ugGXbg0n98DvDFQ/F+SMLxHgbnER5dsKYchNnhmtI6/FC3HFu/A==", + "node_modules/@aws-sdk/client-sso": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.772.0.tgz", + "integrity": "sha512-sDdxepi74+cL6gXJJ2yw3UNSI7GBvoGTwZqFyPoNAzcURvaYwo8dBr7G4jS9GDanjTlO3CGVAf2VMcpqEvmoEw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.772.0", + "@aws-sdk/middleware-user-agent": "3.758.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.743.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.758.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.5", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.6", + "@smithy/middleware-retry": "^4.0.7", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.3", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.6", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.7", + "@smithy/util-defaults-mode-node": "^4.0.7", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/region-config-resolver": { - "version": "3.614.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.614.0.tgz", - "integrity": "sha512-vDCeMXvic/LU0KFIUjpC3RiSTIkkvESsEfbVHiHH0YINfl8HnEqR5rj+L8+phsCeVg2+LmYwYxd5NRz4PHxt5g==", + "node_modules/@aws-sdk/client-sso-oidc": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.621.0.tgz", + "integrity": "sha512-mMjk3mFUwV2Y68POf1BQMTF+F6qxt5tPu6daEUCNGC9Cenk3h2YXQQoS4/eSyYzuBiYk3vx49VgleRvdvkg8rg==", "license": "Apache-2.0", "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.3.1", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.5", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.13", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", - "@smithy/util-config-provider": "^3.0.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", + "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.621.0" } }, - "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/token-providers": { - "version": "3.614.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.614.0.tgz", - "integrity": "sha512-okItqyY6L9IHdxqs+Z116y5/nda7rHxLvROxtAJdLavWTYDydxrZstImNgGWTeVdmc0xX2gJCI77UYUTQWnhRw==", + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/client-sso": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.621.0.tgz", + "integrity": "sha512-xpKfikN4u0BaUYZA9FGUMkkDmfoIP0Q03+A86WjqDWhcOoqNA1DkHsE4kZ+r064ifkPUfcNuUvlkVTEoBZoFjA==", "license": "Apache-2.0", "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.3.1", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.5", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.13", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sso-oidc": "^3.614.0" } }, - "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/types": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", - "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/core": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.621.0.tgz", + "integrity": "sha512-CtOwWmDdEiINkGXD93iGfXjN0WmCp9l45cDWHHGa8lRgEDyhuL7bwd/pH5aSzj0j8SiQBG2k0S7DHbd5RaqvbQ==", "license": "Apache-2.0", "dependencies": { + "@smithy/core": "^2.3.1", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/signature-v4": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/util-endpoints": { - "version": "3.614.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.614.0.tgz", - "integrity": "sha512-wK2cdrXHH4oz4IomV/yrGkftU9A+ITB6nFL+rxxyO78is2ifHJpFdV4aqk4LSkXYPi6CXWNru/Dqc7yiKXgJPw==", + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.620.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.620.1.tgz", + "integrity": "sha512-ExuILJ2qLW5ZO+rgkNRj0xiAipKT16Rk77buvPP8csR7kkCflT/gXTyzRe/uzIiETTxM7tr8xuO9MP/DQXqkfg==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", "@smithy/types": "^3.3.0", - "@smithy/util-endpoints": "^2.0.5", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.609.0.tgz", - "integrity": "sha512-fojPU+mNahzQ0YHYBsx0ZIhmMA96H+ZIZ665ObU9tl+SGdbLneVZVikGve+NmHTQwHzwkFsZYYnVKAkreJLAtA==", + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.621.0.tgz", + "integrity": "sha512-/jc2tEsdkT1QQAI5Dvoci50DbSxtJrevemwFsm0B73pwCcOQZ5ZwwSdVqGsPutzYzUVx3bcXg3LRL7jLACqRIg==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.609.0", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/property-provider": "^3.1.3", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", - "bowser": "^2.11.0", + "@smithy/util-stream": "^3.1.3", "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.614.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.614.0.tgz", - "integrity": "sha512-15ElZT88peoHnq5TEoEtZwoXTXRxNrk60TZNdpl/TUBJ5oNJ9Dqb5Z4ryb8ofN6nm9aFf59GVAerFDz8iUoHBA==", + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.621.0.tgz", + "integrity": "sha512-0EWVnSc+JQn5HLnF5Xv405M8n4zfdx9gyGdpnCmAmFqEDHA8LmBdxJdpUk1Ovp/I5oPANhjojxabIW5f1uU0RA==", "license": "Apache-2.0", "dependencies": { + "@aws-sdk/credential-provider-env": "3.620.1", + "@aws-sdk/credential-provider-http": "3.621.0", + "@aws-sdk/credential-provider-process": "3.620.1", + "@aws-sdk/credential-provider-sso": "3.621.0", + "@aws-sdk/credential-provider-web-identity": "3.621.0", "@aws-sdk/types": "3.609.0", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" + "@smithy/credential-provider-imds": "^3.2.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.621.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.621.0.tgz", + "integrity": "sha512-4JqpccUgz5Snanpt2+53hbOBbJQrSFq7E1sAAbgY6BKVQUsW5qyXqnjvSF32kDeKa5JpBl3bBWLZl04IadcPHw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.620.1", + "@aws-sdk/credential-provider-http": "3.621.0", + "@aws-sdk/credential-provider-ini": "3.621.0", + "@aws-sdk/credential-provider-process": "3.620.1", + "@aws-sdk/credential-provider-sso": "3.621.0", + "@aws-sdk/credential-provider-web-identity": "3.621.0", + "@aws-sdk/types": "3.609.0", + "@smithy/credential-provider-imds": "^3.2.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.620.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.620.1.tgz", + "integrity": "sha512-hWqFMidqLAkaV9G460+1at6qa9vySbjQKKc04p59OT7lZ5cO5VH5S4aI05e+m4j364MBROjjk2ugNvfNf/8ILg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.621.0.tgz", + "integrity": "sha512-Kza0jcFeA/GEL6xJlzR2KFf1PfZKMFnxfGzJzl5yN7EjoGdMijl34KaRyVnfRjnCWcsUpBWKNIDk9WZVMY9yiw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.621.0", + "@aws-sdk/token-providers": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.621.0.tgz", + "integrity": "sha512-w7ASSyfNvcx7+bYGep3VBgC3K6vEdLmlpjT7nSIHxxQf+WSdvy+HynwJosrpZax0sK5q0D1Jpn/5q+r5lwwW6w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.621.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.620.0.tgz", + "integrity": "sha512-VMtPEZwqYrII/oUkffYsNWY9PZ9xpNJpMgmyU0rlDQ25O1c0Hk3fJmZRe6pEkAJ0omD7kLrqGl1DUjQVxpd/Rg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/middleware-logger": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.609.0.tgz", + "integrity": "sha512-S62U2dy4jMDhDFDK5gZ4VxFdWzCtLzwbYyFZx2uvPYTECkepLUfzLic2BHg2Qvtu4QjX+oGE3P/7fwaGIsGNuQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.620.0.tgz", + "integrity": "sha512-nh91S7aGK3e/o1ck64sA/CyoFw+gAYj2BDOnoNa6ouyCrVJED96ZXWbhye/fz9SgmNUZR2g7GdVpiLpMKZoI5w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.620.0.tgz", + "integrity": "sha512-bvS6etn+KsuL32ubY5D3xNof1qkenpbJXf/ugGXbg0n98DvDFQ/F+SMLxHgbnER5dsKYchNnhmtI6/FC3HFu/A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.614.0.tgz", + "integrity": "sha512-vDCeMXvic/LU0KFIUjpC3RiSTIkkvESsEfbVHiHH0YINfl8HnEqR5rj+L8+phsCeVg2+LmYwYxd5NRz4PHxt5g==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/token-providers": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.614.0.tgz", + "integrity": "sha512-okItqyY6L9IHdxqs+Z116y5/nda7rHxLvROxtAJdLavWTYDydxrZstImNgGWTeVdmc0xX2gJCI77UYUTQWnhRw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sso-oidc": "^3.614.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/types": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", + "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/util-endpoints": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.614.0.tgz", + "integrity": "sha512-wK2cdrXHH4oz4IomV/yrGkftU9A+ITB6nFL+rxxyO78is2ifHJpFdV4aqk4LSkXYPi6CXWNru/Dqc7yiKXgJPw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "@smithy/util-endpoints": "^2.0.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.609.0.tgz", + "integrity": "sha512-fojPU+mNahzQ0YHYBsx0ZIhmMA96H+ZIZ665ObU9tl+SGdbLneVZVikGve+NmHTQwHzwkFsZYYnVKAkreJLAtA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.614.0.tgz", + "integrity": "sha512-15ElZT88peoHnq5TEoEtZwoXTXRxNrk60TZNdpl/TUBJ5oNJ9Dqb5Z4ryb8ofN6nm9aFf59GVAerFDz8iUoHBA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" @@ -13401,12 +13845,12 @@ } }, "node_modules/@smithy/config-resolver": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.1.0.tgz", - "integrity": "sha512-8smPlwhga22pwl23fM5ew4T9vfLUCeFXlcqNOCD5M5h8VmNPNUE9j6bQSuRXpDSV11L/E/SwEBQuW8hr6+nS1A==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.1.1.tgz", + "integrity": "sha512-FZUtpiDnPZQmuIl4lfbdO+u3foNLmRCKct/2w2nRwgB99Yvaq4SHcfxyzMfxkyBrBmgnF1kdXzhHNXN7ycDvWg==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.0.2", + "@smithy/node-config-provider": "^4.1.0", "@smithy/types": "^4.2.0", "@smithy/util-config-provider": "^4.0.0", "@smithy/util-middleware": "^4.0.2", @@ -13429,9 +13873,9 @@ } }, "node_modules/@smithy/core": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.2.0.tgz", - "integrity": "sha512-k17bgQhVZ7YmUvA8at4af1TDpl0NDMBuBKJl8Yg0nrefwmValU+CnA5l/AriVdQNthU/33H3nK71HrLgqOPr1Q==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.3.1.tgz", + "integrity": "sha512-W7AppgQD3fP1aBmo8wWo0id5zeR2/aYRy067vZsDVaa6v/mdhkg6DxXwEVuSPjZl+ZnvWAQbUMCd5ckw38+tHQ==", "license": "Apache-2.0", "dependencies": { "@smithy/middleware-serde": "^4.0.3", @@ -13473,12 +13917,12 @@ } }, "node_modules/@smithy/credential-provider-imds": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.0.2.tgz", - "integrity": "sha512-32lVig6jCaWBHnY+OEQ6e6Vnt5vDHaLiydGrwYMW9tPqO688hPGTYRamYJ1EptxEC2rAwJrHWmPoKRBl4iTa8w==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.0.3.tgz", + "integrity": "sha512-UdNvGjZnunS9+45gHYtVXDynoWH1X0tYY0pS368k1zUZum6Mm4ivU4Se0WhFJf8jNocD+p94khzTtrx4ha3OOQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.0.2", + "@smithy/node-config-provider": "^4.1.0", "@smithy/property-provider": "^4.0.2", "@smithy/types": "^4.2.0", "@smithy/url-parser": "^4.0.2", @@ -13501,13 +13945,13 @@ } }, "node_modules/@smithy/eventstream-codec": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.0.1.tgz", - "integrity": "sha512-Q2bCAAR6zXNVtJgifsU16ZjKGqdw/DyecKNgIgi7dlqw04fqDu0mnq+JmGphqheypVc64CYq3azSuCpAdFk2+A==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.0.2.tgz", + "integrity": "sha512-p+f2kLSK7ZrXVfskU/f5dzksKTewZk8pJLPvER3aFHPt76C2MxD9vNatSfLzzQSQB4FNO96RK4PSXfhD1TTeMQ==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/crc32": "5.2.0", - "@smithy/types": "^4.1.0", + "@smithy/types": "^4.2.0", "@smithy/util-hex-encoding": "^4.0.0", "tslib": "^2.6.2" }, @@ -13516,9 +13960,9 @@ } }, "node_modules/@smithy/eventstream-codec/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -13540,13 +13984,13 @@ } }, "node_modules/@smithy/eventstream-serde-browser": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.0.1.tgz", - "integrity": "sha512-HbIybmz5rhNg+zxKiyVAnvdM3vkzjE6ccrJ620iPL8IXcJEntd3hnBl+ktMwIy12Te/kyrSbUb8UCdnUT4QEdA==", - "license": "Apache-2.0", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.0.2.tgz", + "integrity": "sha512-CepZCDs2xgVUtH7ZZ7oDdZFH8e6Y2zOv8iiX6RhndH69nlojCALSKK+OXwZUgOtUZEUaZ5e1hULVCHYbCn7pug==", + "license": "Apache-2.0", "dependencies": { - "@smithy/eventstream-serde-universal": "^4.0.1", - "@smithy/types": "^4.1.0", + "@smithy/eventstream-serde-universal": "^4.0.2", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -13554,9 +13998,9 @@ } }, "node_modules/@smithy/eventstream-serde-browser/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -13566,12 +14010,12 @@ } }, "node_modules/@smithy/eventstream-serde-config-resolver": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.0.1.tgz", - "integrity": "sha512-lSipaiq3rmHguHa3QFF4YcCM3VJOrY9oq2sow3qlhFY+nBSTF/nrO82MUQRPrxHQXA58J5G1UnU2WuJfi465BA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.1.0.tgz", + "integrity": "sha512-1PI+WPZ5TWXrfj3CIoKyUycYynYJgZjuQo8U+sphneOtjsgrttYybdqESFReQrdWJ+LKt6NEdbYzmmfDBmjX2A==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.1.0", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -13579,9 +14023,9 @@ } }, "node_modules/@smithy/eventstream-serde-config-resolver/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -13591,13 +14035,13 @@ } }, "node_modules/@smithy/eventstream-serde-node": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.0.1.tgz", - "integrity": "sha512-o4CoOI6oYGYJ4zXo34U8X9szDe3oGjmHgsMGiZM0j4vtNoT+h80TLnkUcrLZR3+E6HIxqW+G+9WHAVfl0GXK0Q==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.0.2.tgz", + "integrity": "sha512-C5bJ/C6x9ENPMx2cFOirspnF9ZsBVnBMtP6BdPl/qYSuUawdGQ34Lq0dMcf42QTjUZgWGbUIZnz6+zLxJlb9aw==", "license": "Apache-2.0", "dependencies": { - "@smithy/eventstream-serde-universal": "^4.0.1", - "@smithy/types": "^4.1.0", + "@smithy/eventstream-serde-universal": "^4.0.2", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -13605,9 +14049,9 @@ } }, "node_modules/@smithy/eventstream-serde-node/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -13617,13 +14061,13 @@ } }, "node_modules/@smithy/eventstream-serde-universal": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.0.1.tgz", - "integrity": "sha512-Z94uZp0tGJuxds3iEAZBqGU2QiaBHP4YytLUjwZWx+oUeohCsLyUm33yp4MMBmhkuPqSbQCXq5hDet6JGUgHWA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.0.2.tgz", + "integrity": "sha512-St8h9JqzvnbB52FtckiHPN4U/cnXcarMniXRXTKn0r4b4XesZOGiAyUdj1aXbqqn1icSqBlzzUsCl6nPB018ng==", "license": "Apache-2.0", "dependencies": { - "@smithy/eventstream-codec": "^4.0.1", - "@smithy/types": "^4.1.0", + "@smithy/eventstream-codec": "^4.0.2", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -13631,9 +14075,9 @@ } }, "node_modules/@smithy/eventstream-serde-universal/node_modules/@smithy/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", - "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -13879,14 +14323,14 @@ } }, "node_modules/@smithy/middleware-endpoint": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.1.0.tgz", - "integrity": "sha512-xhLimgNCbCzsUppRTGXWkZywksuTThxaIB0HwbpsVLY5sceac4e1TZ/WKYqufQLaUy+gUSJGNdwD2jo3cXL0iA==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.1.3.tgz", + "integrity": "sha512-w7fJjCSqdTVTs1o1O7SRZm+Umf6r/FzkdlO5OH6tboASeUeugnMgQAs7gnc2dXvJVJtEGrmrBgPZFPxq3wWyzw==", "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^3.2.0", + "@smithy/core": "^3.3.1", "@smithy/middleware-serde": "^4.0.3", - "@smithy/node-config-provider": "^4.0.2", + "@smithy/node-config-provider": "^4.1.0", "@smithy/shared-ini-file-loader": "^4.0.2", "@smithy/types": "^4.2.0", "@smithy/url-parser": "^4.0.2", @@ -13910,18 +14354,18 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.1.0.tgz", - "integrity": "sha512-2zAagd1s6hAaI/ap6SXi5T3dDwBOczOMCSkkYzktqN1+tzbk1GAsHNAdo/1uzxz3Ky02jvZQwbi/vmDA6z4Oyg==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.1.4.tgz", + "integrity": "sha512-QtWuD7bd7AAEFKvBmLQdOax25bXv4BACLQNWi3ddvpWwUUSAkAku9mzI+28jbjg48qw28lbzJ+YoYbbaXhLUjw==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.0.2", + "@smithy/node-config-provider": "^4.1.0", "@smithy/protocol-http": "^5.1.0", - "@smithy/service-error-classification": "^4.0.2", - "@smithy/smithy-client": "^4.2.0", + "@smithy/service-error-classification": "^4.0.3", + "@smithy/smithy-client": "^4.2.3", "@smithy/types": "^4.2.0", "@smithy/util-middleware": "^4.0.2", - "@smithy/util-retry": "^4.0.2", + "@smithy/util-retry": "^4.0.3", "tslib": "^2.6.2", "uuid": "^9.0.1" }, @@ -13992,9 +14436,9 @@ } }, "node_modules/@smithy/node-config-provider": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.2.tgz", - "integrity": "sha512-WgCkILRZfJwJ4Da92a6t3ozN/zcvYyJGUTmfGbgS/FkCcoCjl7G4FJaCDN1ySdvLvemnQeo25FdkyMSTSwulsw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.1.0.tgz", + "integrity": "sha512-gmPsv6L3ZRlBinv+vtSGUwfhTMh4+SgjbgGdX7bqYEs3Ys5RYVQtLuZ/WgZZdxn8QrDSUqLmTWunLM96WyM7UQ==", "license": "Apache-2.0", "dependencies": { "@smithy/property-provider": "^4.0.2", @@ -14148,9 +14592,9 @@ } }, "node_modules/@smithy/service-error-classification": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.0.2.tgz", - "integrity": "sha512-LA86xeFpTKn270Hbkixqs5n73S+LVM0/VZco8dqd+JT75Dyx3Lcw/MraL7ybjmz786+160K8rPOmhsq0SocoJQ==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.0.3.tgz", + "integrity": "sha512-FTbcajmltovWMjj3tksDQdD23b2w6gH+A0DYA1Yz3iSpjDj8fmkwy62UnXcWMy4d5YoMoSyLFHMfkEVEzbiN8Q==", "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.2.0" @@ -14197,9 +14641,9 @@ } }, "node_modules/@smithy/signature-v4": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.0.2.tgz", - "integrity": "sha512-Mz+mc7okA73Lyz8zQKJNyr7lIcHLiPYp0+oiqiMNc/t7/Kf2BENs5d63pEj7oPqdjaum6g0Fc8wC78dY1TgtXw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.1.0.tgz", + "integrity": "sha512-4t5WX60sL3zGJF/CtZsUQTs3UrZEDO2P7pEaElrekbLqkWPYkgqNW1oeiNYC6xXifBnT9dVBOnNQRvOE9riU9w==", "license": "Apache-2.0", "dependencies": { "@smithy/is-array-buffer": "^4.0.0", @@ -14253,13 +14697,13 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.2.0.tgz", - "integrity": "sha512-Qs65/w30pWV7LSFAez9DKy0Koaoh3iHhpcpCCJ4waj/iqwsuSzJna2+vYwq46yBaqO5ZbP9TjUsATUNxrKeBdw==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.2.3.tgz", + "integrity": "sha512-j/RRx6N007rJQ3qyjN4yuX9B0bxTn9ynDVxYQ43mcs7fluVJXmQGquy0TrWJfOPZcIikpY377GunZ2UK90GHYQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^3.2.0", - "@smithy/middleware-endpoint": "^4.1.0", + "@smithy/core": "^3.3.1", + "@smithy/middleware-endpoint": "^4.1.3", "@smithy/middleware-stack": "^4.0.2", "@smithy/protocol-http": "^5.1.0", "@smithy/types": "^4.2.0", @@ -14397,13 +14841,13 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.0.8.tgz", - "integrity": "sha512-ZTypzBra+lI/LfTYZeop9UjoJhhGRTg3pxrNpfSTQLd3AJ37r2z4AXTKpq1rFXiiUIJsYyFgNJdjWRGP/cbBaQ==", + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.0.11.tgz", + "integrity": "sha512-Z49QNUSKbEj7JVZqaSUZkTkexRciQBbmonJ8AMar4fA0S2kvVpgjeVyGXnZYWTFzkgEwStacjFq4cQKbaQ8AnQ==", "license": "Apache-2.0", "dependencies": { "@smithy/property-provider": "^4.0.2", - "@smithy/smithy-client": "^4.2.0", + "@smithy/smithy-client": "^4.2.3", "@smithy/types": "^4.2.0", "bowser": "^2.11.0", "tslib": "^2.6.2" @@ -14425,16 +14869,16 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.0.8.tgz", - "integrity": "sha512-Rgk0Jc/UDfRTzVthye/k2dDsz5Xxs9LZaKCNPgJTRyoyBoeiNCnHsYGOyu1PKN+sDyPnJzMOz22JbwxzBp9NNA==", + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.0.11.tgz", + "integrity": "sha512-y9UYcXjz4ry5sDPX40Vy6224Cw2/dch+wET6giaRoeXpyh56DCUVxW+Mgc/gO2uczAKktWd4ZWs2LWcW+PHz3Q==", "license": "Apache-2.0", "dependencies": { - "@smithy/config-resolver": "^4.1.0", - "@smithy/credential-provider-imds": "^4.0.2", - "@smithy/node-config-provider": "^4.0.2", + "@smithy/config-resolver": "^4.1.1", + "@smithy/credential-provider-imds": "^4.0.3", + "@smithy/node-config-provider": "^4.1.0", "@smithy/property-provider": "^4.0.2", - "@smithy/smithy-client": "^4.2.0", + "@smithy/smithy-client": "^4.2.3", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, @@ -14455,12 +14899,12 @@ } }, "node_modules/@smithy/util-endpoints": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.0.2.tgz", - "integrity": "sha512-6QSutU5ZyrpNbnd51zRTL7goojlcnuOB55+F9VBD+j8JpRY50IGamsjlycrmpn8PQkmJucFW8A0LSfXj7jjtLQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.0.3.tgz", + "integrity": "sha512-284PZFhCMdudqq61/E67zJ3i10gCYrMBjXcMg3h048qI39gTXQCCeNZvtJhL4vrj9yMpJ/y9M+Ek7V0o5tak3w==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.0.2", + "@smithy/node-config-provider": "^4.1.0", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, @@ -14518,12 +14962,12 @@ } }, "node_modules/@smithy/util-retry": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.0.2.tgz", - "integrity": "sha512-Qryc+QG+7BCpvjloFLQrmlSd0RsVRHejRXd78jNO3+oREueCjwG1CCEH1vduw/ZkM1U9TztwIKVIi3+8MJScGg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.0.3.tgz", + "integrity": "sha512-DPuYjZQDXmKr/sNvy9Spu8R/ESa2e22wXZzSAY6NkjOLj6spbIje/Aq8rT97iUMdDj0qHMRIe+bTxvlU74d9Ng==", "license": "Apache-2.0", "dependencies": { - "@smithy/service-error-classification": "^4.0.2", + "@smithy/service-error-classification": "^4.0.3", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, @@ -29195,396 +29639,1098 @@ "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", "license": "MIT", "dependencies": { - "is-map": "^2.0.3", - "is-set": "^2.0.3", - "is-weakmap": "^2.0.2", - "is-weakset": "^2.0.3" + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "license": "ISC" + }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/winston": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz", + "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==", + "license": "MIT", + "dependencies": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.7.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.9.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", + "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", + "license": "MIT", + "dependencies": { + "logform": "^2.7.0", + "readable-stream": "^3.6.2", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston/node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "license": "MIT" + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12" + } + }, + "node_modules/xml2js": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", + "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", + "dev": true, + "license": "MIT", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xml2js/node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xmlbuilder": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.0.0.tgz", + "integrity": "sha512-KLu/G0DoWhkncQ9eHSI6s0/w+T4TM7rQaLhtCaL6tORv8jFlJPlnGumsgTcGfYeS1qZ/IHqrvDG7zJZ4d7e+nw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/xstate": { + "version": "4.38.3", + "resolved": "https://registry.npmjs.org/xstate/-/xstate-4.38.3.tgz", + "integrity": "sha512-SH7nAaaPQx57dx6qvfcIgqKRXIh4L0A1iYEqim4s1u7c9VoCgzZc+63FY90AKU4ZzOC2cfJzTnpO4zK7fCUzzw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/xstate" + } + }, + "node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "license": "ISC" + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, + "node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "license": "MIT", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.24.2", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz", + "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "tests/test-team": { + "name": "nhs-notify-iam-webauth-ui-tests", + "version": "0.1.0", + "devDependencies": { + "@aws-sdk/client-cognito-identity-provider": "^3.772.0", + "@aws-sdk/client-kms": "^3.782.0", + "@aws-sdk/client-lambda": "^3.806.0", + "@aws-sdk/client-s3": "^3.806.0", + "@aws-sdk/client-ssm": "^3.782.0", + "@aws-sdk/types": "^3.775.0", + "@playwright/test": "^1.51.1", + "@tsconfig/node20": "^20.1.5", + "@types/node-jose": "^1.1.13", + "@types/uuid": "^10.0.0", + "generate-password": "^1.7.1", + "nhs-notify-iam-webauth-util-backend-config": "^0.0.1", + "node-jose": "^2.2.0", + "winston": "^3.14.2" + } + }, + "tests/test-team/node_modules/@aws-sdk/client-s3": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.806.0.tgz", + "integrity": "sha512-kQaBBBxEBU/IJ2wKG+LL2BK+uvBwpdvOA9jy1WhW+U2/DIMwMrjVs7M/ZvTlmVOJwhZaONcJbgQqsN4Yirjj4g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha1-browser": "5.2.0", + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.806.0", + "@aws-sdk/credential-provider-node": "3.806.0", + "@aws-sdk/middleware-bucket-endpoint": "3.806.0", + "@aws-sdk/middleware-expect-continue": "3.804.0", + "@aws-sdk/middleware-flexible-checksums": "3.806.0", + "@aws-sdk/middleware-host-header": "3.804.0", + "@aws-sdk/middleware-location-constraint": "3.804.0", + "@aws-sdk/middleware-logger": "3.804.0", + "@aws-sdk/middleware-recursion-detection": "3.804.0", + "@aws-sdk/middleware-sdk-s3": "3.806.0", + "@aws-sdk/middleware-ssec": "3.804.0", + "@aws-sdk/middleware-user-agent": "3.806.0", + "@aws-sdk/region-config-resolver": "3.806.0", + "@aws-sdk/signature-v4-multi-region": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@aws-sdk/util-endpoints": "3.806.0", + "@aws-sdk/util-user-agent-browser": "3.804.0", + "@aws-sdk/util-user-agent-node": "3.806.0", + "@aws-sdk/xml-builder": "3.804.0", + "@smithy/config-resolver": "^4.1.1", + "@smithy/core": "^3.3.1", + "@smithy/eventstream-serde-browser": "^4.0.2", + "@smithy/eventstream-serde-config-resolver": "^4.1.0", + "@smithy/eventstream-serde-node": "^4.0.2", + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/hash-blob-browser": "^4.0.2", + "@smithy/hash-node": "^4.0.2", + "@smithy/hash-stream-node": "^4.0.2", + "@smithy/invalid-dependency": "^4.0.2", + "@smithy/md5-js": "^4.0.2", + "@smithy/middleware-content-length": "^4.0.2", + "@smithy/middleware-endpoint": "^4.1.3", + "@smithy/middleware-retry": "^4.1.4", + "@smithy/middleware-serde": "^4.0.3", + "@smithy/middleware-stack": "^4.0.2", + "@smithy/node-config-provider": "^4.1.0", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/protocol-http": "^5.1.0", + "@smithy/smithy-client": "^4.2.3", + "@smithy/types": "^4.2.0", + "@smithy/url-parser": "^4.0.2", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.11", + "@smithy/util-defaults-mode-node": "^4.0.11", + "@smithy/util-endpoints": "^3.0.3", + "@smithy/util-middleware": "^4.0.2", + "@smithy/util-retry": "^4.0.3", + "@smithy/util-stream": "^4.2.0", + "@smithy/util-utf8": "^4.0.0", + "@smithy/util-waiter": "^4.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "tests/test-team/node_modules/@aws-sdk/client-sso": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.806.0.tgz", + "integrity": "sha512-X0p/9/u9e6b22rlQqKucdtjdqmjSNB4c/8zDEoD5MvgYAAbMF9HNE0ST2xaA/WsJ7uE0jFfhPY2/00pslL1DqQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.806.0", + "@aws-sdk/middleware-host-header": "3.804.0", + "@aws-sdk/middleware-logger": "3.804.0", + "@aws-sdk/middleware-recursion-detection": "3.804.0", + "@aws-sdk/middleware-user-agent": "3.806.0", + "@aws-sdk/region-config-resolver": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@aws-sdk/util-endpoints": "3.806.0", + "@aws-sdk/util-user-agent-browser": "3.804.0", + "@aws-sdk/util-user-agent-node": "3.806.0", + "@smithy/config-resolver": "^4.1.1", + "@smithy/core": "^3.3.1", + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/hash-node": "^4.0.2", + "@smithy/invalid-dependency": "^4.0.2", + "@smithy/middleware-content-length": "^4.0.2", + "@smithy/middleware-endpoint": "^4.1.3", + "@smithy/middleware-retry": "^4.1.4", + "@smithy/middleware-serde": "^4.0.3", + "@smithy/middleware-stack": "^4.0.2", + "@smithy/node-config-provider": "^4.1.0", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/protocol-http": "^5.1.0", + "@smithy/smithy-client": "^4.2.3", + "@smithy/types": "^4.2.0", + "@smithy/url-parser": "^4.0.2", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.11", + "@smithy/util-defaults-mode-node": "^4.0.11", + "@smithy/util-endpoints": "^3.0.3", + "@smithy/util-middleware": "^4.0.2", + "@smithy/util-retry": "^4.0.3", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "tests/test-team/node_modules/@aws-sdk/core": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.806.0.tgz", + "integrity": "sha512-HJRINPncdjPK0iL3f6cBpqCMaxVwq2oDbRCzOx04tsLZ0tNgRACBfT3d/zNVRvMt6fnOVKXoN1LAtQaw50pjEA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.804.0", + "@smithy/core": "^3.3.1", + "@smithy/node-config-provider": "^4.1.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/protocol-http": "^5.1.0", + "@smithy/signature-v4": "^5.1.0", + "@smithy/smithy-client": "^4.2.3", + "@smithy/types": "^4.2.0", + "@smithy/util-middleware": "^4.0.2", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "tests/test-team/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.806.0.tgz", + "integrity": "sha512-nbPwmZn0kt6Q1XI2FaJWP6AhF9tro4cO5HlmZQx8NU+B0H1y9WMo659Q5zLLY46BXgoQVIJEsPSZpcZk27O4aw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "tests/test-team/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.806.0.tgz", + "integrity": "sha512-e/gB2iJQQ4ZpecOVpEFhEvjGwuTqNCzhVaVsFYVc49FPfR1seuN7qBGYe1MO7mouGDQFInzJgcNup0DnYUrLiw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/property-provider": "^4.0.2", + "@smithy/protocol-http": "^5.1.0", + "@smithy/smithy-client": "^4.2.3", + "@smithy/types": "^4.2.0", + "@smithy/util-stream": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "tests/test-team/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.806.0.tgz", + "integrity": "sha512-FogfbuYSEZgFxbNy0QcsBZHHe5mSv5HV3+JyB5n0kCyjOISCVCZD7gwxKdXjt8O1hXq5k5SOdQvydGULlB6rew==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.806.0", + "@aws-sdk/credential-provider-env": "3.806.0", + "@aws-sdk/credential-provider-http": "3.806.0", + "@aws-sdk/credential-provider-process": "3.806.0", + "@aws-sdk/credential-provider-sso": "3.806.0", + "@aws-sdk/credential-provider-web-identity": "3.806.0", + "@aws-sdk/nested-clients": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@smithy/credential-provider-imds": "^4.0.2", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=18.0.0" } }, - "node_modules/which-module": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", - "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", - "license": "ISC" - }, - "node_modules/which-typed-array": { - "version": "1.1.19", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", - "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", - "license": "MIT", + "tests/test-team/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.806.0.tgz", + "integrity": "sha512-fZX8xP2Kf0k70kDTog/87fh/M+CV0E2yujSw1cUBJhDSwDX3RlUahiJk7TpB/KGw6hEFESMd6+7kq3UzYuw3rg==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "for-each": "^0.3.5", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2" + "@aws-sdk/credential-provider-env": "3.806.0", + "@aws-sdk/credential-provider-http": "3.806.0", + "@aws-sdk/credential-provider-ini": "3.806.0", + "@aws-sdk/credential-provider-process": "3.806.0", + "@aws-sdk/credential-provider-sso": "3.806.0", + "@aws-sdk/credential-provider-web-identity": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@smithy/credential-provider-imds": "^4.0.2", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=18.0.0" } }, - "node_modules/winston": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz", - "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==", - "license": "MIT", + "tests/test-team/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.806.0.tgz", + "integrity": "sha512-8Y8GYEw/1e5IZRDQL02H6nsTDcRWid/afRMeWg+93oLQmbHcTtdm48tjis+7Xwqy+XazhMDmkbUht11QPTDJcQ==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "@colors/colors": "^1.6.0", - "@dabh/diagnostics": "^2.0.2", - "async": "^3.2.3", - "is-stream": "^2.0.0", - "logform": "^2.7.0", - "one-time": "^1.0.0", - "readable-stream": "^3.4.0", - "safe-stable-stringify": "^2.3.1", - "stack-trace": "0.0.x", - "triple-beam": "^1.3.0", - "winston-transport": "^4.9.0" + "@aws-sdk/core": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">= 12.0.0" + "node": ">=18.0.0" } }, - "node_modules/winston-transport": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", - "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", - "license": "MIT", + "tests/test-team/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.806.0.tgz", + "integrity": "sha512-hT9OBwCxWMPBydNhXm2gdNNzx5AJNheS9RglwDDvXWzQ9qDuRztjuMBilMSUMb0HF9K4IqQjYzGqczMuktz4qQ==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "logform": "^2.7.0", - "readable-stream": "^3.6.2", - "triple-beam": "^1.3.0" + "@aws-sdk/client-sso": "3.806.0", + "@aws-sdk/core": "3.806.0", + "@aws-sdk/token-providers": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">= 12.0.0" + "node": ">=18.0.0" } }, - "node_modules/winston/node_modules/async": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", - "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", - "license": "MIT" - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "tests/test-team/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.806.0.tgz", + "integrity": "sha512-XxaSY9Zd3D4ClUGENYMvi52ac5FuJPPAsvRtEfyrSdEpf6QufbMpnexWBZMYRF31h/VutgqtJwosGgNytpxMEg==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.806.0", + "@aws-sdk/nested-clients": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=0.10.0" + "node": ">=18.0.0" } }, - "node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "license": "MIT" - }, - "node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "license": "MIT", + "tests/test-team/node_modules/@aws-sdk/middleware-bucket-endpoint": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.806.0.tgz", + "integrity": "sha512-ACjuyKJw9OZl8z8HzPEaqn1o7ElVW94mowyoZvyUIDouwAPGqPGJbJ5V35qx1oDTFSAJX+N3O3AO6RyFc8nUhw==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "@aws-sdk/types": "3.804.0", + "@aws-sdk/util-arn-parser": "3.804.0", + "@smithy/node-config-provider": "^4.1.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", + "@smithy/util-config-provider": "^4.0.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=8" + "node": ">=18.0.0" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, - "node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "tests/test-team/node_modules/@aws-sdk/middleware-expect-continue": { + "version": "3.804.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.804.0.tgz", + "integrity": "sha512-YW1hySBolALMII6C8y7Z0CRG2UX1dGJjLEBNFeefhO/xP7ZuE1dvnmfJGaEuBMnvc3wkRS63VZ3aqX6sevM1CA==", "dev": true, - "license": "ISC", + "license": "Apache-2.0", "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" + "@aws-sdk/types": "3.804.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=18.0.0" } }, - "node_modules/ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", + "tests/test-team/node_modules/@aws-sdk/middleware-flexible-checksums": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.806.0.tgz", + "integrity": "sha512-YEmuU2Nr/+blhi70gS38fnCe2IoL6OVVZXMp4MbzqZRUqeBbnxZhHQrd5YOiboJz7iq+g98xwFebHY167iejcg==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/crc32": "5.2.0", + "@aws-crypto/crc32c": "5.2.0", + "@aws-crypto/util": "5.2.0", + "@aws-sdk/core": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@smithy/is-array-buffer": "^4.0.0", + "@smithy/node-config-provider": "^4.1.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", + "@smithy/util-middleware": "^4.0.2", + "@smithy/util-stream": "^4.2.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } + "engines": { + "node": ">=18.0.0" } }, - "node_modules/xml-name-validator": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", - "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "tests/test-team/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.804.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.804.0.tgz", + "integrity": "sha512-bum1hLVBrn2lJCi423Z2fMUYtsbkGI2s4N+2RI2WSjvbaVyMSv/WcejIrjkqiiMR+2Y7m5exgoKeg4/TODLDPQ==", "dev": true, "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.804.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=12" + "node": ">=18.0.0" } }, - "node_modules/xml2js": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", - "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", + "tests/test-team/node_modules/@aws-sdk/middleware-location-constraint": { + "version": "3.804.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.804.0.tgz", + "integrity": "sha512-AMtKnllIWKgoo7hiJfphLYotEwTERfjVMO2+cKAncz9w1g+bnYhHxiVhJJoR94y047c06X4PU5MsTxvdQ73Znw==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" + "@aws-sdk/types": "3.804.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=4.0.0" + "node": ">=18.0.0" } }, - "node_modules/xml2js/node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "tests/test-team/node_modules/@aws-sdk/middleware-logger": { + "version": "3.804.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.804.0.tgz", + "integrity": "sha512-w/qLwL3iq0KOPQNat0Kb7sKndl9BtceigINwBU7SpkYWX9L/Lem6f8NPEKrC9Tl4wDBht3Yztub4oRTy/horJA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.804.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=4.0" + "node": ">=18.0.0" } }, - "node_modules/xmlbuilder": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.0.0.tgz", - "integrity": "sha512-KLu/G0DoWhkncQ9eHSI6s0/w+T4TM7rQaLhtCaL6tORv8jFlJPlnGumsgTcGfYeS1qZ/IHqrvDG7zJZ4d7e+nw==", + "tests/test-team/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.804.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.804.0.tgz", + "integrity": "sha512-zqHOrvLRdsUdN/ehYfZ9Tf8svhbiLLz5VaWUz22YndFv6m9qaAcijkpAOlKexsv3nLBMJdSdJ6GUTAeIy3BZzw==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.804.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=8.0" + "node": ">=18.0.0" } }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "tests/test-team/node_modules/@aws-sdk/middleware-sdk-s3": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.806.0.tgz", + "integrity": "sha512-K1ssdovHH/kPN9EUS1LznwzoL+r89Cx8qAkp0K8MqdCQuBjZ0KRnjvo9nx69Vg5d/rg01VYTxomFUPXfcPtVXw==", "dev": true, - "license": "MIT" - }, - "node_modules/xstate": { - "version": "4.38.3", - "resolved": "https://registry.npmjs.org/xstate/-/xstate-4.38.3.tgz", - "integrity": "sha512-SH7nAaaPQx57dx6qvfcIgqKRXIh4L0A1iYEqim4s1u7c9VoCgzZc+63FY90AKU4ZzOC2cfJzTnpO4zK7fCUzzw==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/xstate" + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@aws-sdk/util-arn-parser": "3.804.0", + "@smithy/core": "^3.3.1", + "@smithy/node-config-provider": "^4.1.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/signature-v4": "^5.1.0", + "@smithy/smithy-client": "^4.2.3", + "@smithy/types": "^4.2.0", + "@smithy/util-config-provider": "^4.0.0", + "@smithy/util-middleware": "^4.0.2", + "@smithy/util-stream": "^4.2.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "license": "ISC" - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "license": "ISC" + "tests/test-team/node_modules/@aws-sdk/middleware-ssec": { + "version": "3.804.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.804.0.tgz", + "integrity": "sha512-Tk8jK0gOIUBvEPTz/wwSlP1V70zVQ3QYqsLPAjQRMO6zfOK9ax31dln3MgKvFDJxBydS2tS3wsn53v+brxDxTA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.804.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } }, - "node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "license": "MIT", + "tests/test-team/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.806.0.tgz", + "integrity": "sha512-XoIromVffgXnc+/mjlR2EVzQVIei3bPVtafIZNsHuEmUvIWJXiWsa2eJpt3BUqa0HF9YPknK7ommNEhqRb8ucg==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" + "@aws-sdk/core": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@aws-sdk/util-endpoints": "3.806.0", + "@smithy/core": "^3.3.1", + "@smithy/protocol-http": "^5.1.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=8" + "node": ">=18.0.0" } }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "tests/test-team/node_modules/@aws-sdk/nested-clients": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.806.0.tgz", + "integrity": "sha512-ua2gzpfQ9MF8Rny+tOAivowOWWvqEusez2rdcQK8jdBjA1ANd/0xzToSZjZh0ziN8Kl8jOhNnHbQJ0v6dT6+hg==", "dev": true, - "license": "ISC", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.806.0", + "@aws-sdk/middleware-host-header": "3.804.0", + "@aws-sdk/middleware-logger": "3.804.0", + "@aws-sdk/middleware-recursion-detection": "3.804.0", + "@aws-sdk/middleware-user-agent": "3.806.0", + "@aws-sdk/region-config-resolver": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@aws-sdk/util-endpoints": "3.806.0", + "@aws-sdk/util-user-agent-browser": "3.804.0", + "@aws-sdk/util-user-agent-node": "3.806.0", + "@smithy/config-resolver": "^4.1.1", + "@smithy/core": "^3.3.1", + "@smithy/fetch-http-handler": "^5.0.2", + "@smithy/hash-node": "^4.0.2", + "@smithy/invalid-dependency": "^4.0.2", + "@smithy/middleware-content-length": "^4.0.2", + "@smithy/middleware-endpoint": "^4.1.3", + "@smithy/middleware-retry": "^4.1.4", + "@smithy/middleware-serde": "^4.0.3", + "@smithy/middleware-stack": "^4.0.2", + "@smithy/node-config-provider": "^4.1.0", + "@smithy/node-http-handler": "^4.0.4", + "@smithy/protocol-http": "^5.1.0", + "@smithy/smithy-client": "^4.2.3", + "@smithy/types": "^4.2.0", + "@smithy/url-parser": "^4.0.2", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.11", + "@smithy/util-defaults-mode-node": "^4.0.11", + "@smithy/util-endpoints": "^3.0.3", + "@smithy/util-middleware": "^4.0.2", + "@smithy/util-retry": "^4.0.3", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=12" + "node": ">=18.0.0" } }, - "node_modules/yargs/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "license": "MIT", + "tests/test-team/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.806.0.tgz", + "integrity": "sha512-cuv5pX55JOlzKC/iLsB5nZ9eUyVgncim3VhhWHZA/KYPh7rLMjOEfZ+xyaE9uLJXGmzOJboFH7+YdTRdIcOgrg==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "@aws-sdk/types": "3.804.0", + "@smithy/node-config-provider": "^4.1.0", + "@smithy/types": "^4.2.0", + "@smithy/util-config-provider": "^4.0.0", + "@smithy/util-middleware": "^4.0.2", + "tslib": "^2.6.2" }, "engines": { - "node": ">=8" + "node": ">=18.0.0" } }, - "node_modules/yargs/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "license": "MIT", + "tests/test-team/node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.806.0.tgz", + "integrity": "sha512-IrbEnpKvG8d9rUWAvsF28g8qBlQ02FaOxn4cGXtTs0b0BGMK1M+cGQrYjJ7Ak08kIXDxBqsdIlZGsKYr+Ds9+w==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "p-locate": "^4.1.0" + "@aws-sdk/middleware-sdk-s3": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/signature-v4": "^5.1.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=8" + "node": ">=18.0.0" } }, - "node_modules/yargs/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "license": "MIT", + "tests/test-team/node_modules/@aws-sdk/token-providers": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.806.0.tgz", + "integrity": "sha512-I6SxcsvV7yinJZmPgGullFHS0tsTKa7K3jEc5dmyCz8X+kZPfsWNffZmtmnCvWXPqMXWBvK6hVaxwomx79yeHA==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "p-try": "^2.0.0" + "@aws-sdk/nested-clients": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@smithy/property-provider": "^4.0.2", + "@smithy/shared-ini-file-loader": "^4.0.2", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6" + "node": ">=18.0.0" + } + }, + "tests/test-team/node_modules/@aws-sdk/types": { + "version": "3.804.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.804.0.tgz", + "integrity": "sha512-A9qnsy9zQ8G89vrPPlNG9d1d8QcKRGqJKqwyGgS0dclJpwy6d1EWgQLIolKPl6vcFpLoe6avLOLxr+h8ur5wpg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=18.0.0" } }, - "node_modules/yargs/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "license": "MIT", + "tests/test-team/node_modules/@aws-sdk/util-arn-parser": { + "version": "3.804.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.804.0.tgz", + "integrity": "sha512-wmBJqn1DRXnZu3b4EkE6CWnoWMo1ZMvlfkqU5zPz67xx1GMaXlDCchFvKAXMjk4jn/L1O3tKnoFDNsoLV1kgNQ==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "p-limit": "^2.2.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=8" + "node": ">=18.0.0" } }, - "node_modules/yargs/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "license": "ISC", + "tests/test-team/node_modules/@aws-sdk/util-endpoints": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.806.0.tgz", + "integrity": "sha512-3YRRgZ+qFuWDdm5uAbxKsr65UAil4KkrFKua9f4m7Be3v24ETiFOOqhanFUIk9/WOtvzF7oFEiDjYKDGlwV2xg==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" + "@aws-sdk/types": "3.804.0", + "@smithy/types": "^4.2.0", + "@smithy/util-endpoints": "^3.0.3", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6" + "node": ">=18.0.0" } }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "tests/test-team/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.804.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.804.0.tgz", + "integrity": "sha512-KfW6T6nQHHM/vZBBdGn6fMyG/MgX5lq82TDdX4HRQRRuHKLgBWGpKXqqvBwqIaCdXwWHgDrg2VQups6GqOWW2A==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" + "@aws-sdk/types": "3.804.0", + "@smithy/types": "^4.2.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" } }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "tests/test-team/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.806.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.806.0.tgz", + "integrity": "sha512-Az2e4/gmPZ4BpB7QRj7U76I+fctXhNcxlcgsaHnMhvt+R30nvzM2EhsyBUvsWl8+r9bnLeYt9BpvEZeq2ANDzA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.806.0", + "@aws-sdk/types": "3.804.0", + "@smithy/node-config-provider": "^4.1.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=6" + "node": ">=18.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } } }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "tests/test-team/node_modules/@aws-sdk/xml-builder": { + "version": "3.804.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.804.0.tgz", + "integrity": "sha512-JbGWp36IG9dgxtvC6+YXwt5WDZYfuamWFtVfK6fQpnmL96dx+GUPOXPKRWdw67WLKf2comHY28iX2d3z35I53Q==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=18.0.0" } }, - "node_modules/zod": { - "version": "3.24.2", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz", - "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" + "tests/test-team/node_modules/@smithy/hash-blob-browser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-4.0.2.tgz", + "integrity": "sha512-3g188Z3DyhtzfBRxpZjU8R9PpOQuYsbNnyStc/ZVS+9nVX1f6XeNOa9IrAh35HwwIZg+XWk8bFVtNINVscBP+g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/chunked-blob-reader": "^5.0.0", + "@smithy/chunked-blob-reader-native": "^4.0.0", + "@smithy/types": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "tests/test-team": { - "name": "nhs-notify-iam-webauth-ui-tests", - "version": "0.1.0", - "devDependencies": { - "@aws-sdk/client-cognito-identity-provider": "^3.772.0", - "@aws-sdk/client-kms": "^3.782.0", - "@aws-sdk/client-ssm": "^3.782.0", - "@aws-sdk/types": "^3.775.0", - "@playwright/test": "^1.51.1", - "@tsconfig/node20": "^20.1.5", - "@types/uuid": "^10.0.0", - "generate-password": "^1.7.1", - "nhs-notify-iam-webauth-util-backend-config": "^0.0.1", - "winston": "^3.14.2" + "tests/test-team/node_modules/@smithy/hash-stream-node": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-4.0.2.tgz", + "integrity": "sha512-POWDuTznzbIwlEXEvvXoPMS10y0WKXK790soe57tFRfvf4zBHyzE529HpZMqmDdwG9MfFflnyzndUQ8j78ZdSg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.2.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "tests/test-team/node_modules/@aws-sdk/types": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.775.0.tgz", - "integrity": "sha512-ZoGKwa4C9fC9Av6bdfqcW6Ix5ot05F/S4VxWR2nHuMv7hzfmAjTOcUiWT7UR4hM/U0whf84VhDtXN/DWAk52KA==", + "tests/test-team/node_modules/@smithy/md5-js": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-4.0.2.tgz", + "integrity": "sha512-Hc0R8EiuVunUewCse2syVgA2AfSRco3LyAv07B/zCOMa+jpXI9ll+Q21Nc6FAlYPcpNcAXqBzMhNs1CD/pP2bA==", "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.2.0", + "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, "engines": { @@ -29604,6 +30750,20 @@ "node": ">=18.0.0" } }, + "tests/test-team/node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "tests/test-team/node_modules/@types/uuid": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", diff --git a/tests/test-team/backend-tests/jwks-key-rotation.backend.spec.ts b/tests/test-team/backend-tests/jwks-key-rotation.backend.spec.ts index ee416b4f..3496cfb3 100644 --- a/tests/test-team/backend-tests/jwks-key-rotation.backend.spec.ts +++ b/tests/test-team/backend-tests/jwks-key-rotation.backend.spec.ts @@ -1,28 +1,111 @@ -import { test, expect } from '@playwright/test'; -import { deleteAllKeysForTags } from '../helpers/kms-util'; -import { putParameter } from '../helpers/ssm-util'; +import { expect, test } from '@playwright/test'; +import { deleteAllKeysForTags, getKmsPublicKey } from '../helpers/kms-util'; +import { getParameter, putParameter } from '../helpers/ssm-util'; +import { invokeLambda } from '../helpers/lambda-util'; +import { readFile } from '../helpers/s3-util'; +import { parseJwksPublicSigningKeys } from '../helpers/jwks-key-parser'; const nameTag = process.env.NAME_TAG || 'unknown'; const groupTag = process.env.GROUP_TAG || 'unknown'; +const keyRotationLambdaName = process.env.KEY_ROTATION_LAMBDA_NAME || 'unknown'; +const publicKeysS3BucketName = + process.env.PUBLIC_KEYS_S3_BUCKET_NAME || 'unknown'; +const keyDirectorySsmParameterName = + process.env.KEY_DIRECTORY_SSM_PARAMETER_NAME || 'unknown'; const usageTag = 'CIS2-JWKS-AUTH'; test.describe('jwks-key-rotation', () => { - test('should generate first key', async () => { - // arrange - + test.beforeEach(async () => { // Delete any existing KMS key rotation keys for the environment await deleteAllKeysForTags(nameTag, groupTag, usageTag); // Clear key directory - await putParameter('[]', process.env.KEY_DIRECTORY_SSM_PARAMETER_NAME); + await putParameter('[]', keyDirectorySsmParameterName); + }); + + test.afterAll(async () => { + await deleteAllKeysForTags(nameTag, groupTag, usageTag); + }); + + for (const { keyCount, description } of [ + { keyCount: 1, description: 'first' }, + { keyCount: 2, description: 'second' }, + ]) + test(`should generate ${description} key`, async () => { + // arrange + const today = new Date().toISOString().split('T')[0]; + + // act + // Invoke the key rotation lambda + for (let i = 0; i < keyCount; i++) { + await invokeLambda(keyRotationLambdaName); + } + + // assert + const jwksFileResponse = await readFile('jwks', publicKeysS3BucketName); + const jwksFileBody = + (await jwksFileResponse.Body?.transformToString()) || ''; + const jwksPublicKeys = await parseJwksPublicSigningKeys(jwksFileBody); + const jwksKeyIds = jwksPublicKeys.map((publicKey) => publicKey.kid); + + const keyDirectoryContent = await getParameter( + keyDirectorySsmParameterName + ); + const keyDirectory = JSON.parse(keyDirectoryContent) as Array<{ + kid: string; + createdDate: string; + }>; + + // Verify the contents of the JWKS public keys file in S3 + expect(jwksFileResponse.ContentType).toEqual('application/json'); + expect(jwksPublicKeys.length).toBe(keyCount); + for (const publicKey of jwksPublicKeys) { + expect(publicKey.use).toBe('sig'); + expect(publicKey.alg).toBe('RS512'); + } + + // Verify the contents of the key directory + expect(keyDirectory.length).toEqual(jwksPublicKeys.length); + for (const keyEntry of keyDirectory) { + expect( + jwksKeyIds.filter((keyId) => keyEntry.kid === keyId).length + ).toBe(1); + expect(keyEntry.createdDate).toBe(today); + } + + // Verify the existance of the keys in KMS + const kmsPublicKeys = await Promise.all( + jwksKeyIds.map((keyId) => getKmsPublicKey(keyId)) + ); + expect(kmsPublicKeys.length).toEqual(jwksPublicKeys.length); + }); + + test('should trim out expired keys', async () => { + // arrange + + // Populate the key directory with an expired key reference + await putParameter( + '[{"kid":"00000000-0000-0000-0000-000000000000","createdDate":"2000-01-01"}]', + keyDirectorySsmParameterName + ); // act // Invoke the key rotation lambda + await invokeLambda(keyRotationLambdaName); // assert + const jwksFileResponse = await readFile('jwks', publicKeysS3BucketName); + const jwksFileBody = + (await jwksFileResponse.Body?.transformToString()) || ''; + const jwksPublicKeys = await parseJwksPublicSigningKeys(jwksFileBody); + const jwksKeyIds = jwksPublicKeys.map((publicKey) => publicKey.kid); - // Verify the contents of the JWKS public keys file in S3 - // Verify the contents of the key directory - // Verify the existance of the key in KMS + // Verify that the expired key has been removed + expect(jwksPublicKeys.length).toBe(1); + expect( + jwksKeyIds.filter( + (keyId) => keyId === '00000000-0000-0000-0000-000000000000' + ).length + ).toBe(0); }); }); diff --git a/tests/test-team/config/backend/backend.config.ts b/tests/test-team/config/backend/backend.config.ts index d11f6212..cd01dd91 100644 --- a/tests/test-team/config/backend/backend.config.ts +++ b/tests/test-team/config/backend/backend.config.ts @@ -5,16 +5,19 @@ export default defineConfig({ ...baseConfig, timeout: 10_000, + retries: 0, workers: 1, projects: [ { name: 'backend:setup', testMatch: 'backend.setup.ts', + retries: 0, }, { name: 'backend', testMatch: '*.backend.spec.ts', dependencies: ['backend:setup'], + retries: 0, }, ], }); diff --git a/tests/test-team/helpers/jwks-key-parser.ts b/tests/test-team/helpers/jwks-key-parser.ts new file mode 100644 index 00000000..d7246670 --- /dev/null +++ b/tests/test-team/helpers/jwks-key-parser.ts @@ -0,0 +1,8 @@ +import { JWK } from 'node-jose'; + +export async function parseJwksPublicSigningKeys( + rawJwks: string +): Promise> { + const jwks = JSON.parse(rawJwks) as Array; + return await Promise.all(jwks.map((jwk) => JWK.asKey(jwk))); +} diff --git a/tests/test-team/helpers/kms-util.ts b/tests/test-team/helpers/kms-util.ts index 632fa666..a98496a6 100644 --- a/tests/test-team/helpers/kms-util.ts +++ b/tests/test-team/helpers/kms-util.ts @@ -1,4 +1,5 @@ import { + GetPublicKeyCommand, KMSClient, ListKeysCommand, ListKeysCommandOutput, @@ -69,11 +70,19 @@ async function getKeyTags( async function deleteKey(keyId: string): Promise { logger.info(`Deleting key ${keyId}`); - await kmsClient.send( - new ScheduleKeyDeletionCommand({ - KeyId: keyId, - }) - ); + await kmsClient + .send( + new ScheduleKeyDeletionCommand({ + KeyId: keyId, + PendingWindowInDays: 7 + }) + ) + .catch((error) => { + if (error['__type'] === 'KMSInvalidStateException') { + return; + } + throw error; + }); } export async function deleteAllKeysForTags( @@ -84,7 +93,7 @@ export async function deleteAllKeysForTags( if (!name.endsWith('-sbx')) { throw new Error(`Should only be deleting keys from a sandbox: ${name}`); } - + logger.info( `Looking for keys to delete using tags Name: ${name}, Group: ${group}, Usage: ${usage}` ); @@ -103,3 +112,20 @@ export async function deleteAllKeysForTags( logger.info(`About to delete ${keysToDelete.length} keys`); await Promise.all(keysToDelete.map((keyId) => deleteKey(keyId))); } + +export async function getKmsPublicKey( + keyId: string +): Promise { + const keyArn = `arn:aws:kms:${process.env.REGION}:${process.env.ACCOUNT_ID}:key/${keyId}`; + + const result = await kmsClient.send( + new GetPublicKeyCommand({ + KeyId: keyArn, + }) + ); + + if (!result.PublicKey) { + logger.warn(`PublicKey not found ${keyArn}`); + } + return result.PublicKey; +} diff --git a/tests/test-team/helpers/lambda-util.ts b/tests/test-team/helpers/lambda-util.ts new file mode 100644 index 00000000..7c98462d --- /dev/null +++ b/tests/test-team/helpers/lambda-util.ts @@ -0,0 +1,20 @@ +import { InvokeCommand, LambdaClient } from '@aws-sdk/client-lambda'; +import { logger } from './logger'; + +const lambdaClient = new LambdaClient({ + region: process.env.REGION, +}); + +export async function invokeLambda(lambdaName: string): Promise { + logger.info(`Invoking lambda ${lambdaName}`); + + const response = await lambdaClient.send( + new InvokeCommand({ + FunctionName: lambdaName, + }) + ); + + if (response.StatusCode !== 200) { + throw new Error(`Unexpected lambda response ${JSON.stringify(response)}`); + } +} diff --git a/tests/test-team/helpers/s3-util.ts b/tests/test-team/helpers/s3-util.ts new file mode 100644 index 00000000..90d086c6 --- /dev/null +++ b/tests/test-team/helpers/s3-util.ts @@ -0,0 +1,23 @@ +import { + GetObjectCommand, + GetObjectCommandOutput, + S3Client, +} from '@aws-sdk/client-s3'; + +const s3Client = new S3Client({ + region: process.env.REGION, + retryMode: 'standard', + maxAttempts: 10, +}); + +export async function readFile( + path: string, + bucket: string +): Promise { + return s3Client.send( + new GetObjectCommand({ + Bucket: bucket, + Key: path, + }) + ); +} diff --git a/tests/test-team/helpers/ssm-util.ts b/tests/test-team/helpers/ssm-util.ts index fba2a1e4..938ec61e 100644 --- a/tests/test-team/helpers/ssm-util.ts +++ b/tests/test-team/helpers/ssm-util.ts @@ -1,4 +1,5 @@ import { + GetParameterCommand, PutParameterCommand, SSMClient, } from '@aws-sdk/client-ssm'; @@ -10,11 +11,7 @@ const ssmClient = new SSMClient({ maxAttempts: 10, }); -export async function putParameter(value: string, name = ''): Promise { - if (!name) { - throw new Error('Missing parameter name'); - } - +export async function putParameter(value: string, name: string): Promise { logger.info(`Updating parameter ${name}`); ssmClient.send( @@ -25,3 +22,12 @@ export async function putParameter(value: string, name = ''): Promise { }) ); } + +export async function getParameter(name: string): Promise { + const result = await ssmClient.send( + new GetParameterCommand({ + Name: name, + }) + ); + return result.Parameter?.Value || ''; +} diff --git a/tests/test-team/package.json b/tests/test-team/package.json index fca982b2..6d7e07ba 100644 --- a/tests/test-team/package.json +++ b/tests/test-team/package.json @@ -4,6 +4,7 @@ "private": true, "scripts": { "lint": "eslint .", + "lint:fix": "eslint . --fix", "test:local-ui": "playwright test --project component -c config/component/component.config.ts", "test:backend": "playwright test --project backend -c config/backend/backend.config.ts", "test:story": "echo 'Not implemented'", @@ -12,13 +13,17 @@ }, "devDependencies": { "@aws-sdk/client-cognito-identity-provider": "^3.772.0", + "@aws-sdk/client-lambda": "^3.806.0", "@aws-sdk/client-kms": "^3.782.0", + "@aws-sdk/client-s3": "^3.806.0", "@aws-sdk/client-ssm": "^3.782.0", "@aws-sdk/types": "^3.775.0", "@playwright/test": "^1.51.1", "@tsconfig/node20": "^20.1.5", + "@types/node-jose": "^1.1.13", "@types/uuid": "^10.0.0", "generate-password": "^1.7.1", + "node-jose": "^2.2.0", "nhs-notify-iam-webauth-util-backend-config": "^0.0.1", "winston": "^3.14.2" } diff --git a/utils/backend-config/src/backend-config.ts b/utils/backend-config/src/backend-config.ts index cfd0016a..dacd3fed 100644 --- a/utils/backend-config/src/backend-config.ts +++ b/utils/backend-config/src/backend-config.ts @@ -6,6 +6,10 @@ export type BackendConfig = { groupTag: string; nameTag: string; keyDirectorySsmParameterName: string; + keyRotationLambdaName: string; + publicKeysS3BucketName: string; + region: string; + accountId: string; }; export const BackendConfigHelper = { @@ -15,7 +19,11 @@ export const BackendConfigHelper = { return { groupTag: outputs.group_tag.value, nameTag: outputs.name_tag.value, - keyDirectorySsmParameterName: outputs.key_directory_ssm_parameter_name.value + keyDirectorySsmParameterName: outputs.key_directory_ssm_parameter_name.value, + keyRotationLambdaName: outputs.key_rotation_lambda_name.value, + publicKeysS3BucketName: outputs.public_keys_s3_bucket_name.value, + region: outputs.deployment.value.aws_region, + accountId: outputs.deployment.value.aws_account_id }; }, @@ -23,5 +31,9 @@ export const BackendConfigHelper = { process.env.GROUP_TAG = config.groupTag; process.env.NAME_TAG = config.nameTag; process.env.KEY_DIRECTORY_SSM_PARAMETER_NAME = config.keyDirectorySsmParameterName; + process.env.KEY_ROTATION_LAMBDA_NAME = config.keyRotationLambdaName; + process.env.PUBLIC_KEYS_S3_BUCKET_NAME = config.publicKeysS3BucketName; + process.env.ACCOUNT_ID = config.accountId; + process.env.REGION = config.region; }, }; From 6e893213b6b05d10423bcf014535dd317036911b Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Fri, 16 May 2025 10:55:22 +0100 Subject: [PATCH 38/54] CCM-9554: linting --- utils/backend-config/src/backend-config.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/utils/backend-config/src/backend-config.ts b/utils/backend-config/src/backend-config.ts index dacd3fed..03caadf2 100644 --- a/utils/backend-config/src/backend-config.ts +++ b/utils/backend-config/src/backend-config.ts @@ -15,22 +15,24 @@ export type BackendConfig = { export const BackendConfigHelper = { fromTerraformOutputsFile(filepath: string): BackendConfig { const outputs = JSON.parse(fs.readFileSync(filepath, 'utf8')); - + return { groupTag: outputs.group_tag.value, nameTag: outputs.name_tag.value, - keyDirectorySsmParameterName: outputs.key_directory_ssm_parameter_name.value, + keyDirectorySsmParameterName: + outputs.key_directory_ssm_parameter_name.value, keyRotationLambdaName: outputs.key_rotation_lambda_name.value, publicKeysS3BucketName: outputs.public_keys_s3_bucket_name.value, region: outputs.deployment.value.aws_region, - accountId: outputs.deployment.value.aws_account_id + accountId: outputs.deployment.value.aws_account_id, }; }, toEnv(config: BackendConfig): void { process.env.GROUP_TAG = config.groupTag; process.env.NAME_TAG = config.nameTag; - process.env.KEY_DIRECTORY_SSM_PARAMETER_NAME = config.keyDirectorySsmParameterName; + process.env.KEY_DIRECTORY_SSM_PARAMETER_NAME = + config.keyDirectorySsmParameterName; process.env.KEY_ROTATION_LAMBDA_NAME = config.keyRotationLambdaName; process.env.PUBLIC_KEYS_S3_BUCKET_NAME = config.publicKeysS3BucketName; process.env.ACCOUNT_ID = config.accountId; From 8ebf2efd4efc893d7c1c66145bbe5418404dbc0f Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Fri, 16 May 2025 13:07:52 +0100 Subject: [PATCH 39/54] CCM-9554: linting --- .../backend-tests/jwks-key-rotation.backend.spec.ts | 1 + tests/test-team/helpers/jwks-key-parser.ts | 2 +- tests/test-team/helpers/kms-util.ts | 9 +++++---- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/test-team/backend-tests/jwks-key-rotation.backend.spec.ts b/tests/test-team/backend-tests/jwks-key-rotation.backend.spec.ts index 3496cfb3..8b46d490 100644 --- a/tests/test-team/backend-tests/jwks-key-rotation.backend.spec.ts +++ b/tests/test-team/backend-tests/jwks-key-rotation.backend.spec.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-await-in-loop, no-plusplus */ import { expect, test } from '@playwright/test'; import { deleteAllKeysForTags, getKmsPublicKey } from '../helpers/kms-util'; import { getParameter, putParameter } from '../helpers/ssm-util'; diff --git a/tests/test-team/helpers/jwks-key-parser.ts b/tests/test-team/helpers/jwks-key-parser.ts index d7246670..3abfbf70 100644 --- a/tests/test-team/helpers/jwks-key-parser.ts +++ b/tests/test-team/helpers/jwks-key-parser.ts @@ -4,5 +4,5 @@ export async function parseJwksPublicSigningKeys( rawJwks: string ): Promise> { const jwks = JSON.parse(rawJwks) as Array; - return await Promise.all(jwks.map((jwk) => JWK.asKey(jwk))); + return Promise.all(jwks.map((jwk) => JWK.asKey(jwk))); } diff --git a/tests/test-team/helpers/kms-util.ts b/tests/test-team/helpers/kms-util.ts index a98496a6..a05e557d 100644 --- a/tests/test-team/helpers/kms-util.ts +++ b/tests/test-team/helpers/kms-util.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-await-in-loop, unicorn/no-array-for-each, unicorn/no-array-reduce, dot-notation */ import { GetPublicKeyCommand, KMSClient, @@ -74,7 +75,7 @@ async function deleteKey(keyId: string): Promise { .send( new ScheduleKeyDeletionCommand({ KeyId: keyId, - PendingWindowInDays: 7 + PendingWindowInDays: 7, }) ) .catch((error) => { @@ -104,9 +105,9 @@ export async function deleteAllKeysForTags( ); const keysToDelete = taggedKeys - .filter((keyMetadata) => keyMetadata.tags['Name'] === name) - .filter((keyMetadata) => keyMetadata.tags['Group'] === group) - .filter((keyMetadata) => keyMetadata.tags['Usage'] === usage) + .filter((keyMetadata) => keyMetadata.tags.Name === name) + .filter((keyMetadata) => keyMetadata.tags.Group === group) + .filter((keyMetadata) => keyMetadata.tags.Usage === usage) .map((keyMetadata) => keyMetadata.keyId); logger.info(`About to delete ${keysToDelete.length} keys`); From ced8e8057d0557f83a8635868b51c0349ec462f0 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Fri, 16 May 2025 13:15:12 +0100 Subject: [PATCH 40/54] CCM-9554: linting --- .../jwks-key-rotation/src/utils/aws/tag-util.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts b/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts index 18f3df3e..f7548c20 100644 --- a/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts +++ b/lambdas/jwks-key-rotation/src/utils/aws/tag-util.ts @@ -22,16 +22,16 @@ export function getKeyTags(): Array { } const tags = parameters - .map((parameter) => parameter.split('=')) - .map((keyTag) => ({ - TagKey: keyTag[0], - TagValue: keyTag[1], - })); + .map((parameter) => parameter.split('=')) + .map((keyTag) => ({ + TagKey: keyTag[0], + TagValue: keyTag[1], + })); tags.push({ TagKey: USAGE_TAG_NAME, - TagValue: USAGE_TAG_VALUE - }) + TagValue: USAGE_TAG_VALUE, + }); return tags; } From 11fa4e6ce39285a529335606a60dee17c6f81646 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Fri, 16 May 2025 13:32:14 +0100 Subject: [PATCH 41/54] CCM-9554: update tests --- .../src/__tests__/utils/aws/tag-util.test.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lambdas/jwks-key-rotation/src/__tests__/utils/aws/tag-util.test.ts b/lambdas/jwks-key-rotation/src/__tests__/utils/aws/tag-util.test.ts index d3a96a70..d9d6cb3f 100644 --- a/lambdas/jwks-key-rotation/src/__tests__/utils/aws/tag-util.test.ts +++ b/lambdas/jwks-key-rotation/src/__tests__/utils/aws/tag-util.test.ts @@ -22,6 +22,7 @@ describe('tag-util', () => { { TagKey: 'Group', TagValue: 'dev' }, { TagKey: 'Name', TagValue: 'def' }, { TagKey: 'Project', TagValue: 'NHS Notify' }, + { TagKey: 'Usage', TagValue: 'CIS2-JWKS-AUTH' }, ]); }); @@ -35,6 +36,7 @@ describe('tag-util', () => { // assert expect(result).toMatchObject([ { TagKey: 'Component', TagValue: 'abc 123' }, + { TagKey: 'Usage', TagValue: 'CIS2-JWKS-AUTH' }, ]); }); @@ -46,7 +48,9 @@ describe('tag-util', () => { const result = getKeyTags(); // assert - expect(result).toMatchObject([]); + expect(result).toMatchObject([ + { TagKey: 'Usage', TagValue: 'CIS2-JWKS-AUTH' }, + ]); }); test('should parse empty key tags', () => { @@ -57,7 +61,9 @@ describe('tag-util', () => { const result = getKeyTags(); // assert - expect(result).toMatchObject([]); + expect(result).toMatchObject([ + { TagKey: 'Usage', TagValue: 'CIS2-JWKS-AUTH' }, + ]); }); test('should ignore empty tags', () => { @@ -70,6 +76,7 @@ describe('tag-util', () => { // assert expect(result).toMatchObject([ { TagKey: 'Component', TagValue: 'abc 123' }, + { TagKey: 'Usage', TagValue: 'CIS2-JWKS-AUTH' }, ]); }); From dc62e4dbc9cbfdd2c2533a298f369d5ada0c9357 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Mon, 19 May 2025 09:28:49 +0100 Subject: [PATCH 42/54] CCM-9554: update tests --- .github/actions/acceptance-tests/action.yaml | 9 +- .gitignore | 2 + lambdas/jwks-key-rotation/src/handler.ts | 8 +- .../src/utils/aws/kms-util.ts | 19 ++++ .../src/utils/key-directory-repository.ts | 24 ++++ scripts/tests/backend.sh | 11 ++ scripts/tests/test.mk | 5 + .../jwks-key-rotation.backend.spec.ts | 2 +- .../config/backend/backend.config.ts | 14 ++- .../config/component/component.config.ts | 13 +++ tests/test-team/helpers/async-util.ts | 53 +++++++++ tests/test-team/helpers/kms-util.ts | 104 ++++++++++++++---- 12 files changed, 239 insertions(+), 25 deletions(-) create mode 100755 scripts/tests/backend.sh create mode 100644 tests/test-team/helpers/async-util.ts diff --git a/.github/actions/acceptance-tests/action.yaml b/.github/actions/acceptance-tests/action.yaml index 851433bf..3d4a1598 100644 --- a/.github/actions/acceptance-tests/action.yaml +++ b/.github/actions/acceptance-tests/action.yaml @@ -51,7 +51,14 @@ runs: uses: actions/upload-artifact@v4 with: name: UI test report - path: "tests/test-team/playwright-report" + path: "tests/test-team/playwright-report-component-tests" + + - name: Archive backend test results + if: ${{ inputs.testType == 'backend' }} + uses: actions/upload-artifact@v4 + with: + name: Backend test report + path: "tests/test-team/playwright-report-backend-tests" - name: Archive accessibility results if: ${{ inputs.testType == 'accessibility' }} diff --git a/.gitignore b/.gitignore index 4e8ebb51..ead1fbd0 100644 --- a/.gitignore +++ b/.gitignore @@ -59,6 +59,8 @@ next-env.d.ts # playwright tests/test-team/test-results/ tests/test-team/playwright-report/ +tests/test-team/playwright-report-component-tests/ +tests/test-team/playwright-report-backend-tests/ tests/test-team/blob-report/ tests/test-team/playwright/.cache/ *.webm diff --git a/lambdas/jwks-key-rotation/src/handler.ts b/lambdas/jwks-key-rotation/src/handler.ts index 48a6fde4..8ea5fb6c 100644 --- a/lambdas/jwks-key-rotation/src/handler.ts +++ b/lambdas/jwks-key-rotation/src/handler.ts @@ -1,6 +1,7 @@ /* eslint-disable unicorn/no-array-reduce, unicorn/prefer-at */ import type { ScheduledHandler } from 'aws-lambda'; import { + filterKeyDirectoryToActiveKeys, getKeyDirectory, SigningKeyDirectory, writeKeyDirectory, @@ -55,7 +56,12 @@ function buildPublicKeyMap( export const handler: ScheduledHandler = async () => { // Get the existing key directory - const keyDirectory = await getKeyDirectory(); + const unfilteredKeyDirectory = await getKeyDirectory(); + + // Filter any keys that are pending deletion + const keyDirectory = await filterKeyDirectoryToActiveKeys( + unfilteredKeyDirectory + ); // Dertermine which keys we should remove const keysToDelete = getKeysToDelete(keyDirectory); diff --git a/lambdas/jwks-key-rotation/src/utils/aws/kms-util.ts b/lambdas/jwks-key-rotation/src/utils/aws/kms-util.ts index ba306fe8..93fbfeba 100644 --- a/lambdas/jwks-key-rotation/src/utils/aws/kms-util.ts +++ b/lambdas/jwks-key-rotation/src/utils/aws/kms-util.ts @@ -1,10 +1,13 @@ import { CreateKeyCommand, + DescribeKeyCommand, GetPublicKeyCommand, + KeyState, KMSClient, ScheduleKeyDeletionCommand, } from '@aws-sdk/client-kms'; import { logger } from '@/src/utils/logger'; +import { KMS_NO_OP_ERRORS } from '../constants'; const kmsClient = new KMSClient({ region: process.env.REGION, @@ -51,3 +54,19 @@ export async function deleteKey(keyId: string): Promise { }) ); } + +export async function getKeyState( + keyId: string +): Promise<{ keyId: string; keyState: KeyState }> { + const keyState = await kmsClient + .send(new DescribeKeyCommand({ KeyId: keyId })) + .then((result) => result.KeyMetadata.KeyState) + .catch((error) => { + if (KMS_NO_OP_ERRORS.some((errorType) => error instanceof errorType)) { + logger.warn(`Key not found: ${keyId}`); + return KeyState.Unavailable; + } + throw error; + }); + return { keyId, keyState }; +} diff --git a/lambdas/jwks-key-rotation/src/utils/key-directory-repository.ts b/lambdas/jwks-key-rotation/src/utils/key-directory-repository.ts index 66882247..0f2a2878 100644 --- a/lambdas/jwks-key-rotation/src/utils/key-directory-repository.ts +++ b/lambdas/jwks-key-rotation/src/utils/key-directory-repository.ts @@ -1,6 +1,8 @@ import { z } from 'zod'; import { logger } from '@/src/utils/logger'; import { getParameter, putParameter } from '@/src/utils/aws/ssm-util'; +import { getKeyState } from './aws/kms-util'; +import { KeyState } from '@aws-sdk/client-kms'; const schemaFor = () => @@ -25,6 +27,12 @@ const $SigningKeyDirectory = schemaFor()( z.array($SigningKeyMetaData) ); +const activeKeyStates: Set = new Set([ + KeyState.Enabled, + KeyState.Creating, + KeyState.Updating, +]); + export async function getKeyDirectory(): Promise { const ssmResult = await getParameter(process.env.SSM_KEY_DIRECTORY_NAME); @@ -51,3 +59,19 @@ export async function writeKeyDirectory( process.env.SSM_KEY_DIRECTORY_NAME ); } + +export async function filterKeyDirectoryToActiveKeys( + keyDirectory: SigningKeyDirectory +): Promise { + const results = await Promise.all( + keyDirectory.map((keyMetadata) => + getKeyState(keyMetadata.kid).then((result) => ({ + ...keyMetadata, + keyState: result.keyState, + })) + ) + ); + return results + .filter((entry) => activeKeyStates.has(entry.keyState)) + .map((result) => ({ kid: result.kid, createdDate: result.createdDate })); +} diff --git a/scripts/tests/backend.sh b/scripts/tests/backend.sh new file mode 100755 index 00000000..fb2b3d0b --- /dev/null +++ b/scripts/tests/backend.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -euo pipefail + +cd "$(git rev-parse --show-toplevel)" + +npx playwright install --with-deps > /dev/null + +cd tests/test-team + +npm run test:backend diff --git a/scripts/tests/test.mk b/scripts/tests/test.mk index aab47c62..e28929b3 100644 --- a/scripts/tests/test.mk +++ b/scripts/tests/test.mk @@ -48,6 +48,9 @@ test-security: # Run your security tests from scripts/test/security @Testing test-ui: # Run your UI tests from scripts/test/ui @Testing make _test name="ui" +test-backend: # Run your backend tests from scripts/test/backend @Testing + make _test name="backend" + test-ui-performance: # Run UI render tests from scripts/test/ui-performance @Testing make _test name="ui-performance" @@ -59,6 +62,7 @@ test: # Run all the test tasks @Testing test-contract \ test-security \ test-ui \ + test-backend \ test-ui-performance \ test-integration \ test-accessibility \ @@ -87,5 +91,6 @@ ${VERBOSE}.SILENT: \ test-response-time \ test-security \ test-ui \ + test-backend \ test-ui-performance \ test-unit \ diff --git a/tests/test-team/backend-tests/jwks-key-rotation.backend.spec.ts b/tests/test-team/backend-tests/jwks-key-rotation.backend.spec.ts index 8b46d490..b1b63f46 100644 --- a/tests/test-team/backend-tests/jwks-key-rotation.backend.spec.ts +++ b/tests/test-team/backend-tests/jwks-key-rotation.backend.spec.ts @@ -102,7 +102,7 @@ test.describe('jwks-key-rotation', () => { const jwksKeyIds = jwksPublicKeys.map((publicKey) => publicKey.kid); // Verify that the expired key has been removed - expect(jwksPublicKeys.length).toBe(1); + expect(jwksPublicKeys.length, JSON.stringify(jwksPublicKeys)).toBe(1); expect( jwksKeyIds.filter( (keyId) => keyId === '00000000-0000-0000-0000-000000000000' diff --git a/tests/test-team/config/backend/backend.config.ts b/tests/test-team/config/backend/backend.config.ts index cd01dd91..59305b2a 100644 --- a/tests/test-team/config/backend/backend.config.ts +++ b/tests/test-team/config/backend/backend.config.ts @@ -1,10 +1,11 @@ +import path from 'node:path'; import { defineConfig } from '@playwright/test'; import baseConfig from '../playwright.config'; export default defineConfig({ ...baseConfig, - timeout: 10_000, + timeout: 20_000, retries: 0, workers: 1, projects: [ @@ -20,4 +21,15 @@ export default defineConfig({ retries: 0, }, ], + reporter: [ + [ + 'html', + { + outputFolder: path.resolve( + __dirname, + '../../playwright-report-backend-tests' + ), + }, + ], + ], }); diff --git a/tests/test-team/config/component/component.config.ts b/tests/test-team/config/component/component.config.ts index ebca19a2..75756f7e 100644 --- a/tests/test-team/config/component/component.config.ts +++ b/tests/test-team/config/component/component.config.ts @@ -27,6 +27,19 @@ export default defineConfig({ }, }, ], + + reporter: [ + [ + 'html', + { + outputFolder: path.resolve( + __dirname, + '../../playwright-report-component-tests' + ), + }, + ], + ], + /* Run your local dev server before starting the tests */ webServer: { command: 'npm run build && npm run start', diff --git a/tests/test-team/helpers/async-util.ts b/tests/test-team/helpers/async-util.ts new file mode 100644 index 00000000..46f6378e --- /dev/null +++ b/tests/test-team/helpers/async-util.ts @@ -0,0 +1,53 @@ +/* eslint-disable no-await-in-loop, no-plusplus, unicorn/consistent-function-scoping */ + +export function sleep(millis: number) { + return new Promise((resolve) => { + setTimeout(resolve, millis); + }); +} + +export async function poll( + durationMs: number, + operation: (attemptNumber: number) => Promise +): Promise { + const startTime = Date.now(); + let success = false; + let attemptNumber = 1; + while (!success && Date.now() < startTime + durationMs) { + success = await operation(attemptNumber); + if (!success) { + await sleep(500); + } + attemptNumber++; + } + + if (!success) { + throw new Error('Timed out polling'); + } +} + +export async function batchPromises( + asyncFunctions: Array<() => Promise>, + batchSize: number +): Promise> { + const batches = []; + + for (let i = 0; i < asyncFunctions.length; i += batchSize) { + const batch = asyncFunctions.slice(i, i + batchSize); + + const batchExecutor = async () => { + const results: Array = []; + for (const job of batch) { + const result = await job(); + results.push(result); + } + return results; + }; + batches.push(batchExecutor); + } + + const results = await Promise.all( + batches.map((batchExecutor) => batchExecutor()) + ); + return results.flat(); +} diff --git a/tests/test-team/helpers/kms-util.ts b/tests/test-team/helpers/kms-util.ts index a05e557d..98232534 100644 --- a/tests/test-team/helpers/kms-util.ts +++ b/tests/test-team/helpers/kms-util.ts @@ -1,6 +1,8 @@ /* eslint-disable no-await-in-loop, unicorn/no-array-for-each, unicorn/no-array-reduce, dot-notation */ import { + DescribeKeyCommand, GetPublicKeyCommand, + KeyState, KMSClient, ListKeysCommand, ListKeysCommandOutput, @@ -9,6 +11,7 @@ import { Tag, } from '@aws-sdk/client-kms'; import { logger } from './logger'; +import { batchPromises, poll, sleep } from './async-util'; const kmsClient = new KMSClient({ region: process.env.REGION, @@ -16,7 +19,20 @@ const kmsClient = new KMSClient({ maxAttempts: 10, }); -async function listAllKeyIds(): Promise> { +async function getKeyState( + keyId: string +): Promise<{ keyId: string; state: KeyState | undefined }> { + const keyDetails = await kmsClient + .send( + new DescribeKeyCommand({ + KeyId: keyId, + }) + ) + .catch(() => {}); + return { keyId, state: keyDetails?.KeyMetadata?.KeyState }; +} + +async function listAllEnabledKeyIds(): Promise> { let truncated = false; let marker; const allKeyIds: Array = []; @@ -36,7 +52,14 @@ async function listAllKeyIds(): Promise> { .forEach((keyId) => allKeyIds.push(keyId)); } while (truncated); - return allKeyIds; + const keyStates = await batchPromises( + allKeyIds.map((keyId) => () => getKeyState(keyId)), + 5 + ); + + return keyStates + .filter((state) => state.state === KeyState.Enabled) + .map((state) => state.keyId); } async function getKeyTags( @@ -86,6 +109,32 @@ async function deleteKey(keyId: string): Promise { }); } +export async function getKmsPublicKey( + keyId: string +): Promise { + const keyArn = `arn:aws:kms:${process.env.REGION}:${process.env.ACCOUNT_ID}:key/${keyId}`; + + const result = await kmsClient.send( + new GetPublicKeyCommand({ + KeyId: keyArn, + }) + ); + + if (!result.PublicKey) { + logger.warn(`PublicKey not found ${keyArn}`); + } + return result.PublicKey; +} + +function createPublicKeyRetriever( + keyId: string +): () => Promise<{ keyId: string; publicKey: Uint8Array | undefined }> { + return () => + getKmsPublicKey(keyId) + .then((pk) => ({ keyId, publicKey: pk })) + .catch(() => ({ keyId, publicKey: undefined })); +} + export async function deleteAllKeysForTags( name: string, group: string, @@ -99,9 +148,10 @@ export async function deleteAllKeysForTags( `Looking for keys to delete using tags Name: ${name}, Group: ${group}, Usage: ${usage}` ); - const allKeyIds = await listAllKeyIds(); - const taggedKeys = await Promise.all( - allKeyIds.map((keyId) => getKeyTags(keyId)) + const allKeyIds = await listAllEnabledKeyIds(); + const taggedKeys = await batchPromises( + allKeyIds.map((keyId) => () => getKeyTags(keyId)), + 5 ); const keysToDelete = taggedKeys @@ -111,22 +161,34 @@ export async function deleteAllKeysForTags( .map((keyMetadata) => keyMetadata.keyId); logger.info(`About to delete ${keysToDelete.length} keys`); - await Promise.all(keysToDelete.map((keyId) => deleteKey(keyId))); -} - -export async function getKmsPublicKey( - keyId: string -): Promise { - const keyArn = `arn:aws:kms:${process.env.REGION}:${process.env.ACCOUNT_ID}:key/${keyId}`; - - const result = await kmsClient.send( - new GetPublicKeyCommand({ - KeyId: keyArn, - }) + await batchPromises( + keysToDelete.map((keyId) => () => deleteKey(keyId)), + 5 ); - if (!result.PublicKey) { - logger.warn(`PublicKey not found ${keyArn}`); - } - return result.PublicKey; + // Wait until all key states have been updated + let keysRemaining = [...keysToDelete]; + + // KMS uses an eventual consistency model - wait until the public keys are no longer available + await sleep(500); + const deletedKeyCheck: (attemptNumber: number) => Promise = async ( + attemptNumber + ) => { + const publicKeys = await batchPromises( + keysRemaining.map((keyId) => createPublicKeyRetriever(keyId)), + 5 + ); + + if (attemptNumber > 1) { + logger.warn( + `attemptNumber: ${attemptNumber}, publicKeys: ${JSON.stringify(publicKeys)}` + ); + } + + keysRemaining = publicKeys + .filter((keyState) => !!keyState.publicKey) + .map((keyState) => keyState.keyId); + return keysRemaining.length === 0; + }; + await poll(2000, deletedKeyCheck); } From 53b0f5a689a6226a00bc865217662e11b67601c4 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Tue, 20 May 2025 15:45:17 +0100 Subject: [PATCH 43/54] CCM-9554: update tests --- .../src/__tests__/handler.test.ts | 38 +++++++ .../src/__tests__/utils/aws/kms-util.test.ts | 104 ++++++++++++++++++ .../utils/key-directory-repository.test.ts | 38 +++++++ .../src/utils/aws/kms-util.ts | 2 +- .../src/utils/key-directory-repository.ts | 2 +- 5 files changed, 182 insertions(+), 2 deletions(-) diff --git a/lambdas/jwks-key-rotation/src/__tests__/handler.test.ts b/lambdas/jwks-key-rotation/src/__tests__/handler.test.ts index bde015e6..4b683b90 100644 --- a/lambdas/jwks-key-rotation/src/__tests__/handler.test.ts +++ b/lambdas/jwks-key-rotation/src/__tests__/handler.test.ts @@ -1,6 +1,7 @@ import { handler } from '@/src/handler'; import { Context, EventBridgeEvent, Callback } from 'aws-lambda'; import { + filterKeyDirectoryToActiveKeys, getKeyDirectory, SigningKeyDirectory, writeKeyDirectory, @@ -12,6 +13,7 @@ import { deleteKey } from '@/src/utils/aws/kms-util'; jest.mock('@/src/utils/key-directory-repository', () => ({ ...jest.requireActual('@/src/utils/key-directory-repository'), getKeyDirectory: jest.fn(), + filterKeyDirectoryToActiveKeys: jest.fn(), writeKeyDirectory: jest.fn(), })); jest.mock('@/src/utils/key-util'); @@ -30,6 +32,9 @@ describe('handler', () => { const todayFormatted = new Date().toISOString().split('T')[0]; const mockedGetKeyDirectory = jest.mocked(getKeyDirectory); + const mockedFilterKeyDirectoryToActiveKeys = jest.mocked( + filterKeyDirectoryToActiveKeys + ); const mockedGenerateKey = jest.mocked(generateKey); const mockedGetPublicKey = jest.mocked(getPublicKey); const mockedWriteKeyDirectory = jest.mocked(writeKeyDirectory); @@ -37,6 +42,9 @@ describe('handler', () => { mockedGetKeyDirectory.mockImplementation(() => Promise.resolve(mockKeyDirectory) ); + mockedFilterKeyDirectoryToActiveKeys.mockImplementation(() => + Promise.resolve(mockKeyDirectory) + ); mockedGenerateKey.mockImplementation(() => Promise.resolve('new-test-key-id') ); @@ -48,6 +56,9 @@ describe('handler', () => { await handler(mockEvent, mockContext, mockCallback); // assert + expect(mockedFilterKeyDirectoryToActiveKeys).toHaveBeenCalledWith( + mockKeyDirectory + ); expect(mockedGenerateKey).toHaveBeenCalled(); expect(updateJwksFile).toHaveBeenCalledWith([ { keyId: 'new-test-key-id', publicKey: mockPublicKey }, @@ -78,6 +89,9 @@ describe('handler', () => { const mockPublicKey = Uint8Array.from([1, 2, 3]); const mockedGetKeyDirectory = jest.mocked(getKeyDirectory); + const mockedFilterKeyDirectoryToActiveKeys = jest.mocked( + filterKeyDirectoryToActiveKeys + ); const mockedGenerateKey = jest.mocked(generateKey); const mockedGetPublicKey = jest.mocked(getPublicKey); const mockedWriteKeyDirectory = jest.mocked(writeKeyDirectory); @@ -85,6 +99,9 @@ describe('handler', () => { mockedGetKeyDirectory.mockImplementation(() => Promise.resolve(mockKeyDirectory) ); + mockedFilterKeyDirectoryToActiveKeys.mockImplementation(() => + Promise.resolve(mockKeyDirectory) + ); mockedGenerateKey.mockImplementation(() => Promise.resolve('new-test-key-id') ); @@ -96,6 +113,9 @@ describe('handler', () => { await handler(mockEvent, mockContext, mockCallback); // assert + expect(mockedFilterKeyDirectoryToActiveKeys).toHaveBeenCalledWith( + mockKeyDirectory + ); expect(mockedGenerateKey).toHaveBeenCalled(); expect(updateJwksFile).toHaveBeenCalledWith([ { @@ -146,6 +166,9 @@ describe('handler', () => { const mockPublicKey = Uint8Array.from([1, 2, 3]); const mockedGetKeyDirectory = jest.mocked(getKeyDirectory); + const mockedFilterKeyDirectoryToActiveKeys = jest.mocked( + filterKeyDirectoryToActiveKeys + ); const mockedGenerateKey = jest.mocked(generateKey); const mockedGetPublicKey = jest.mocked(getPublicKey); const mockedWriteKeyDirectory = jest.mocked(writeKeyDirectory); @@ -153,6 +176,9 @@ describe('handler', () => { mockedGetKeyDirectory.mockImplementation(() => Promise.resolve(mockKeyDirectory) ); + mockedFilterKeyDirectoryToActiveKeys.mockImplementation(() => + Promise.resolve(mockKeyDirectory) + ); mockedGenerateKey.mockImplementation(() => Promise.resolve('new-test-key-id') ); @@ -164,6 +190,9 @@ describe('handler', () => { await handler(mockEvent, mockContext, mockCallback); // assert + expect(mockedFilterKeyDirectoryToActiveKeys).toHaveBeenCalledWith( + mockKeyDirectory + ); expect(mockedGenerateKey).toHaveBeenCalled(); expect(updateJwksFile).toHaveBeenCalledWith([ { @@ -208,6 +237,9 @@ describe('handler', () => { const mockPublicKey = Uint8Array.from([1, 2, 3]); const mockedGetKeyDirectory = jest.mocked(getKeyDirectory); + const mockedFilterKeyDirectoryToActiveKeys = jest.mocked( + filterKeyDirectoryToActiveKeys + ); const mockedGenerateKey = jest.mocked(generateKey); const mockedGetPublicKey = jest.mocked(getPublicKey); const mockedWriteKeyDirectory = jest.mocked(writeKeyDirectory); @@ -215,6 +247,9 @@ describe('handler', () => { mockedGetKeyDirectory.mockImplementation(() => Promise.resolve(mockKeyDirectory) ); + mockedFilterKeyDirectoryToActiveKeys.mockImplementation(() => + Promise.resolve(mockKeyDirectory) + ); mockedGenerateKey.mockImplementation(() => Promise.resolve('new-test-key-id') ); @@ -226,6 +261,9 @@ describe('handler', () => { await handler(mockEvent, mockContext, mockCallback); // assert + expect(mockedFilterKeyDirectoryToActiveKeys).toHaveBeenCalledWith( + mockKeyDirectory + ); expect(mockedGenerateKey).toHaveBeenCalled(); expect(updateJwksFile).toHaveBeenCalledWith([ { diff --git a/lambdas/jwks-key-rotation/src/__tests__/utils/aws/kms-util.test.ts b/lambdas/jwks-key-rotation/src/__tests__/utils/aws/kms-util.test.ts index fb261504..e6e556fb 100644 --- a/lambdas/jwks-key-rotation/src/__tests__/utils/aws/kms-util.test.ts +++ b/lambdas/jwks-key-rotation/src/__tests__/utils/aws/kms-util.test.ts @@ -1,12 +1,16 @@ import { createKmsKey, deleteKey, + getKeyState, getKmsPublicKey, } from '@/src/utils/aws/kms-util'; +import { KMS_NO_OP_ERRORS } from '@/src/utils/constants'; import { CreateKeyCommand, + DescribeKeyCommand, GetPublicKeyCommand, KeySpec, + KeyState, KeyUsageType, KMSClient, ScheduleKeyDeletionCommand, @@ -134,4 +138,104 @@ describe('kms-util', () => { ); }); }); + + describe('getKeyState', () => { + test('should get key state', async () => { + // arrange + const sendSpy = jest.spyOn(KMSClient.prototype, 'send'); + sendSpy.mockImplementation(() => + Promise.resolve({ + KeyMetadata: { + KeyState: KeyState.PendingDeletion, + }, + }) + ); + + // act + const result = await getKeyState('00000000-0000-0000-0000-000000000000'); + + // assert + expect(result).toEqual({ + keyId: '00000000-0000-0000-0000-000000000000', + keyState: KeyState.PendingDeletion, + }); + expect(sendSpy).toHaveBeenCalledWith( + expect.objectContaining({ + input: { KeyId: '00000000-0000-0000-0000-000000000000' }, + }) + ); + expect(sendSpy).toHaveBeenCalledWith(expect.any(DescribeKeyCommand)); + }); + + test('should ignore no-op errors', async () => { + // arrange + class TestError1 extends Error {} + + (jest.mocked(KMS_NO_OP_ERRORS) as Array).push(TestError1); + + const sendSpy = jest.spyOn(KMSClient.prototype, 'send'); + sendSpy.mockImplementation(() => Promise.reject(new TestError1('TEST'))); + + // act + const result = await getKeyState('00000000-0000-0000-0000-000000000000'); + + // assert + expect(result).toEqual({ + keyId: '00000000-0000-0000-0000-000000000000', + keyState: KeyState.Unavailable, + }); + }); + + test('should propagate general errors', async () => { + // arrange + const sendSpy = jest.spyOn(KMSClient.prototype, 'send'); + sendSpy.mockImplementation(() => Promise.reject(new Error('TEST'))); + + // act + let caughtError; + try { + await getKeyState('00000000-0000-0000-0000-000000000000'); + } catch (error) { + caughtError = error; + } + + // assert + expect(caughtError).toBeTruthy(); + expect((caughtError as Error).message).toBe('TEST'); + }); + + test('should handle missing state', async () => { + // arrange + const sendSpy = jest.spyOn(KMSClient.prototype, 'send'); + sendSpy.mockImplementation(() => + Promise.resolve({ + KeyMetadata: {}, + }) + ); + + // act + const result = await getKeyState('00000000-0000-0000-0000-000000000000'); + + // assert + expect(result).toEqual({ + keyId: '00000000-0000-0000-0000-000000000000', + keyState: KeyState.Unavailable, + }); + }); + + test('should handle missing metadata', async () => { + // arrange + const sendSpy = jest.spyOn(KMSClient.prototype, 'send'); + sendSpy.mockImplementation(() => Promise.resolve({})); + + // act + const result = await getKeyState('00000000-0000-0000-0000-000000000000'); + + // assert + expect(result).toEqual({ + keyId: '00000000-0000-0000-0000-000000000000', + keyState: KeyState.Unavailable, + }); + }); + }); }); diff --git a/lambdas/jwks-key-rotation/src/__tests__/utils/key-directory-repository.test.ts b/lambdas/jwks-key-rotation/src/__tests__/utils/key-directory-repository.test.ts index caf73761..825be1a5 100644 --- a/lambdas/jwks-key-rotation/src/__tests__/utils/key-directory-repository.test.ts +++ b/lambdas/jwks-key-rotation/src/__tests__/utils/key-directory-repository.test.ts @@ -1,15 +1,20 @@ import { + filterKeyDirectoryToActiveKeys, getKeyDirectory, writeKeyDirectory, } from '@/src/utils/key-directory-repository'; import { getParameter, putParameter } from '@/src/utils/aws/ssm-util'; +import { getKeyState } from '@/src/utils/aws/kms-util'; +import { KeyState } from '@aws-sdk/client-kms'; jest.mock('@/src/utils/aws/ssm-util'); jest.mock('@/src/utils/logger'); +jest.mock('@/src/utils/aws/kms-util'); const mockKeyDirectory = [ { createdDate: '2025-04-01', kid: '00000000-0000-0000-0000-000000000000' }, { createdDate: '2025-05-01', kid: '00000000-0000-0000-0000-000000000001' }, + { createdDate: '2025-06-01', kid: '00000000-0000-0000-0000-000000000002' }, ]; describe('key-directory-repository', () => { @@ -100,4 +105,37 @@ describe('key-directory-repository', () => { ); }); }); + + describe('filterKeyDirectoryToActiveKeys', () => { + test('should filter key directory to retain only active keys', async () => { + // arrange + const mockGetKeyState = jest.mocked(getKeyState); + + mockGetKeyState + .mockImplementationOnce(() => + Promise.resolve({ + keyId: mockKeyDirectory[0].kid, + keyState: KeyState.Enabled, + }) + ) + .mockImplementationOnce(() => + Promise.resolve({ + keyId: mockKeyDirectory[1].kid, + keyState: KeyState.PendingDeletion, + }) + ) + .mockImplementationOnce(() => + Promise.resolve({ + keyId: mockKeyDirectory[2].kid, + keyState: KeyState.Unavailable, + }) + ); + + // act + const result = await filterKeyDirectoryToActiveKeys(mockKeyDirectory); + + // assert + expect(result).toEqual([mockKeyDirectory[0]]); + }); + }); }); diff --git a/lambdas/jwks-key-rotation/src/utils/aws/kms-util.ts b/lambdas/jwks-key-rotation/src/utils/aws/kms-util.ts index 93fbfeba..97bb0b61 100644 --- a/lambdas/jwks-key-rotation/src/utils/aws/kms-util.ts +++ b/lambdas/jwks-key-rotation/src/utils/aws/kms-util.ts @@ -60,7 +60,7 @@ export async function getKeyState( ): Promise<{ keyId: string; keyState: KeyState }> { const keyState = await kmsClient .send(new DescribeKeyCommand({ KeyId: keyId })) - .then((result) => result.KeyMetadata.KeyState) + .then((result) => result.KeyMetadata?.KeyState ?? KeyState.Unavailable) .catch((error) => { if (KMS_NO_OP_ERRORS.some((errorType) => error instanceof errorType)) { logger.warn(`Key not found: ${keyId}`); diff --git a/lambdas/jwks-key-rotation/src/utils/key-directory-repository.ts b/lambdas/jwks-key-rotation/src/utils/key-directory-repository.ts index 0f2a2878..d6852c47 100644 --- a/lambdas/jwks-key-rotation/src/utils/key-directory-repository.ts +++ b/lambdas/jwks-key-rotation/src/utils/key-directory-repository.ts @@ -1,7 +1,7 @@ import { z } from 'zod'; import { logger } from '@/src/utils/logger'; import { getParameter, putParameter } from '@/src/utils/aws/ssm-util'; -import { getKeyState } from './aws/kms-util'; +import { getKeyState } from '@/src/utils/aws/kms-util'; import { KeyState } from '@aws-sdk/client-kms'; const schemaFor = From 2b932c892870680982254a9ae0214a74d20ed3b5 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Wed, 21 May 2025 12:53:20 +0100 Subject: [PATCH 44/54] CCM-9554: update vuln scanner --- .tool-versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.tool-versions b/.tool-versions index 0a4dfc63..8545d4f1 100644 --- a/.tool-versions +++ b/.tool-versions @@ -14,7 +14,7 @@ vale 3.6.0 # The section below is reserved for Docker image versions. # TODO: Move this section - consider using a different file for the repository template dependencies. -# docker/ghcr.io/anchore/grype v0.69.1@sha256:d41fcb371d0af59f311e72123dff46900ebd6d0482391b5a830853ee4f9d1a76 # SEE: https://github.com/anchore/grype/pkgs/container/grype +# docker/ghcr.io/anchore/grype v0.92.2@sha256:651e558f9ba84f2a790b3449c8a57cbbf4f34e004f7d3f14ae8f8cbeede4cd33 # SEE: https://github.com/anchore/grype/pkgs/container/grype # docker/ghcr.io/anchore/syft v0.92.0@sha256:63c60f0a21efb13e80aa1359ab243e49213b6cc2d7e0f8179da38e6913b997e0 # SEE: https://github.com/anchore/syft/pkgs/container/syft # docker/ghcr.io/gitleaks/gitleaks:v8.24.0@sha256:b8e9bf46893c2f20e10bfb4b2e783adaef519dea981b01ca6221ac325e836040 # SEE: https://github.com/gitleaks/gitleaks/pkgs/container/gitleaks # docker/ghcr.io/igorshubovych/markdownlint-cli v0.37.0@sha256:fb3e79946fce78e1cde84d6798c6c2a55f2de11fc16606a40d49411e281d950d # SEE: https://github.com/igorshubovych/markdownlint-cli/pkgs/container/markdownlint-cli From 3f937854875e799db8829e709cc9d88789a087a5 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Thu, 22 May 2025 08:50:49 +0100 Subject: [PATCH 45/54] CCM-9554: support internal repo override --- .github/workflows/dispatch_internal_repo_workflow.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/dispatch_internal_repo_workflow.yaml b/.github/workflows/dispatch_internal_repo_workflow.yaml index ef98e6eb..3ad1fae0 100644 --- a/.github/workflows/dispatch_internal_repo_workflow.yaml +++ b/.github/workflows/dispatch_internal_repo_workflow.yaml @@ -35,6 +35,10 @@ on: type: string description: The Terraform action to run default: "" + internalRef: + type: string + description: Internal repo reference (branch or tag) + default: "main" concurrency: group: ${{ inputs.targetEnvironment }}-${{ inputs.targetAccountGroup }}-${{ inputs.targetComponent }}-${{ inputs.terraformAction }} @@ -62,7 +66,7 @@ jobs: --arg targetComponent ${{ inputs.targetComponent }} \ --arg terraformAction "${{ inputs.terraformAction }}" \ '{ - "ref": "main", + "ref": "${{ inputs.internalRef }}", "inputs": ( (if $infraRepoName != "" then { "infraRepoName": $infraRepoName } else {} end) + (if $terraformAction != "" then { "terraformAction": $terraformAction } else {} end) + From c853a102cf244ec873f5f08148f50bc6418ce514 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Thu, 22 May 2025 10:28:50 +0100 Subject: [PATCH 46/54] CCM-9554: test internal repo changes --- .github/workflows/dispatch_internal_repo_workflow.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dispatch_internal_repo_workflow.yaml b/.github/workflows/dispatch_internal_repo_workflow.yaml index 3ad1fae0..dad683cd 100644 --- a/.github/workflows/dispatch_internal_repo_workflow.yaml +++ b/.github/workflows/dispatch_internal_repo_workflow.yaml @@ -38,7 +38,7 @@ on: internalRef: type: string description: Internal repo reference (branch or tag) - default: "main" + default: "feature/CCM-9554_key-rotation-tests" concurrency: group: ${{ inputs.targetEnvironment }}-${{ inputs.targetAccountGroup }}-${{ inputs.targetComponent }}-${{ inputs.terraformAction }} From fc233d6e8e643c8fc44f6e062e1597e3ba0601ef Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Thu, 22 May 2025 12:04:22 +0100 Subject: [PATCH 47/54] CCM-9554: revert test internal repo changes --- .github/workflows/dispatch_internal_repo_workflow.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dispatch_internal_repo_workflow.yaml b/.github/workflows/dispatch_internal_repo_workflow.yaml index dad683cd..3ad1fae0 100644 --- a/.github/workflows/dispatch_internal_repo_workflow.yaml +++ b/.github/workflows/dispatch_internal_repo_workflow.yaml @@ -38,7 +38,7 @@ on: internalRef: type: string description: Internal repo reference (branch or tag) - default: "feature/CCM-9554_key-rotation-tests" + default: "main" concurrency: group: ${{ inputs.targetEnvironment }}-${{ inputs.targetAccountGroup }}-${{ inputs.targetComponent }}-${{ inputs.terraformAction }} From 4dc345394c5a7fcda6b954adde5a82e64c44275a Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Fri, 23 May 2025 13:43:54 +0100 Subject: [PATCH 48/54] CCM-9554: dynamic tests WIP --- .github/actions/test-types.json | 5 +++++ .github/workflows/dispatch_internal_repo_workflow.yaml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .github/actions/test-types.json diff --git a/.github/actions/test-types.json b/.github/actions/test-types.json new file mode 100644 index 00000000..75a579b8 --- /dev/null +++ b/.github/actions/test-types.json @@ -0,0 +1,5 @@ +[ + { + "test": "backend" + } +] \ No newline at end of file diff --git a/.github/workflows/dispatch_internal_repo_workflow.yaml b/.github/workflows/dispatch_internal_repo_workflow.yaml index 3ad1fae0..6ce9ae65 100644 --- a/.github/workflows/dispatch_internal_repo_workflow.yaml +++ b/.github/workflows/dispatch_internal_repo_workflow.yaml @@ -38,7 +38,7 @@ on: internalRef: type: string description: Internal repo reference (branch or tag) - default: "main" + default: "feature/CCM-9554_optional-backend-tests" concurrency: group: ${{ inputs.targetEnvironment }}-${{ inputs.targetAccountGroup }}-${{ inputs.targetComponent }}-${{ inputs.terraformAction }} From 1947e8eba4edfb4c936fdebe46d7a890cdc2b923 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Fri, 23 May 2025 13:45:44 +0100 Subject: [PATCH 49/54] CCM-9554: dynamic tests WIP --- .github/actions/test-types.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/test-types.json b/.github/actions/test-types.json index 75a579b8..f502c81c 100644 --- a/.github/actions/test-types.json +++ b/.github/actions/test-types.json @@ -2,4 +2,4 @@ { "test": "backend" } -] \ No newline at end of file +] From c083ce9dd2b56cf1dd428e05a931d6c2293be96e Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Fri, 23 May 2025 14:55:14 +0100 Subject: [PATCH 50/54] CCM-9554: dynamic tests WIP --- .github/actions/test-types.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/actions/test-types.json b/.github/actions/test-types.json index f502c81c..f2e4c9dc 100644 --- a/.github/actions/test-types.json +++ b/.github/actions/test-types.json @@ -1,5 +1,3 @@ [ - { - "test": "backend" - } + "backend" ] From 0bec5bb715003aa267c479f128587841da5a9082 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Fri, 23 May 2025 14:55:14 +0100 Subject: [PATCH 51/54] CCM-9554: dynamic tests WIP --- .github/actions/test-types.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/actions/test-types.json b/.github/actions/test-types.json index f502c81c..fec12214 100644 --- a/.github/actions/test-types.json +++ b/.github/actions/test-types.json @@ -1,5 +1,4 @@ [ - { - "test": "backend" - } + "backend", + "ui" ] From a2a3714c32aef7cb38e2ae65cef6565997326047 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Tue, 27 May 2025 09:28:41 +0100 Subject: [PATCH 52/54] CCM-9554: merge --- .github/actions/test-types.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/actions/test-types.json b/.github/actions/test-types.json index 98e0048e..fec12214 100644 --- a/.github/actions/test-types.json +++ b/.github/actions/test-types.json @@ -1,8 +1,4 @@ [ -<<<<<<< HEAD "backend", "ui" -======= - "backend" ->>>>>>> c083ce9dd2b56cf1dd428e05a931d6c2293be96e ] From accd020c6e7e2e66d955b8699045b716140b6592 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Tue, 27 May 2025 10:21:14 +0100 Subject: [PATCH 53/54] CCM-9554: dynamic tests WIP --- .github/actions/test-types.json | 4 ---- .github/actions/zz-test-types.json | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) delete mode 100644 .github/actions/test-types.json create mode 100644 .github/actions/zz-test-types.json diff --git a/.github/actions/test-types.json b/.github/actions/test-types.json deleted file mode 100644 index fec12214..00000000 --- a/.github/actions/test-types.json +++ /dev/null @@ -1,4 +0,0 @@ -[ - "backend", - "ui" -] diff --git a/.github/actions/zz-test-types.json b/.github/actions/zz-test-types.json new file mode 100644 index 00000000..f2e4c9dc --- /dev/null +++ b/.github/actions/zz-test-types.json @@ -0,0 +1,3 @@ +[ + "backend" +] From 69e52975d6224652e90fd90ee97995a04fbe8bb2 Mon Sep 17 00:00:00 2001 From: Mark Ramsden Date: Tue, 27 May 2025 11:31:24 +0100 Subject: [PATCH 54/54] CCM-9554: dynamic tests --- .github/actions/{zz-test-types.json => test-types.json} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/actions/{zz-test-types.json => test-types.json} (100%) diff --git a/.github/actions/zz-test-types.json b/.github/actions/test-types.json similarity index 100% rename from .github/actions/zz-test-types.json rename to .github/actions/test-types.json