From 9c30a7fce09e207d3b8ab971474d53cec5d8039d Mon Sep 17 00:00:00 2001 From: Finlay Birnie Date: Wed, 11 Dec 2024 15:22:56 +0000 Subject: [PATCH 1/8] serverless devdependency packaging issue has been fixed --- api/serverless-config-default.yml | 46 ------------------------------- 1 file changed, 46 deletions(-) diff --git a/api/serverless-config-default.yml b/api/serverless-config-default.yml index e2f040a3c..a2ea024ac 100644 --- a/api/serverless-config-default.yml +++ b/api/serverless-config-default.yml @@ -540,29 +540,6 @@ package: - '!serverless*' - '!src/**' - '!tsconfig*' - # From devdependencies - due to an issue serverless's automatic devDependency exclusion doesn't work. - # https://github.com/serverless/serverless/issues/12911 - # Please remove these rules when it's fixed. - - '!node_modules/.bin/esbuild' - - '!node_modules/@aws-crypto/**' - - '!node_modules/@babel/**' - - '!node_modules/@esbuild/**' - - '!node_modules/@eslint/**' - - '!node_modules/@hapi/**' - - '!node_modules/@types/**' - - '!node_modules/@typescript-eslint/**' - - '!node_modules/devtools-protocol/**' - - '!node_modules/es-abstract/**' - - '!node_modules/esbuild/**' - - '!node_modules/eslint/**' - - '!node_modules/eslint-plugin-import/**' - - '!node_modules/java-invoke-local/**' - - '!node_modules/prettier/**' - - '!node_modules/rxjs/**' - - '!node_modules/serverless/**' - - '!node_modules/terser/**' - - '!node_modules/web-streams-polyfill/**' - - '!node_modules/webpack/**' # Inclusions. - 'node_modules/.prisma/client/libquery_engine-linux-arm64-*' @@ -600,29 +577,6 @@ package: - '!serverless*' - '!src/**' - '!tsconfig*' - # From devdependencies - due to an issue serverless's automatic devDependency exclusion doesn't work. - # https://github.com/serverless/serverless/issues/12911 - # Please remove these rules when it's fixed. - - '!node_modules/.bin/esbuild' - - '!node_modules/@aws-crypto/**' - - '!node_modules/@babel/**' - - '!node_modules/@esbuild/**' - - '!node_modules/@eslint/**' - - '!node_modules/@hapi/**' - - '!node_modules/@types/**' - - '!node_modules/@typescript-eslint/**' - - '!node_modules/devtools-protocol/**' - - '!node_modules/es-abstract/**' - - '!node_modules/esbuild/**' - - '!node_modules/eslint/**' - - '!node_modules/eslint-plugin-import/**' - - '!node_modules/java-invoke-local/**' - - '!node_modules/prettier/**' - - '!node_modules/rxjs/**' - - '!node_modules/serverless/**' - - '!node_modules/terser/**' - - '!node_modules/web-streams-polyfill/**' - - '!node_modules/webpack/**' # Inclusions. - 'node_modules/@sparticuz/chromium/**' - 'node_modules/.prisma/client/libquery_engine-rhel-*' From f5e7f9d61e943ecfcf187f778054002a9a122766 Mon Sep 17 00:00:00 2001 From: Finlay Birnie Date: Wed, 11 Dec 2024 15:25:50 +0000 Subject: [PATCH 2/8] remove ecs service and add SSM params needed for lambda to trigger task --- infra/modules/ecs/ecs.tf | 6 ++++++ infra/modules/ecs/services.tf | 37 ----------------------------------- infra/modules/ecs/tasks.tf | 30 ++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 37 deletions(-) delete mode 100644 infra/modules/ecs/services.tf diff --git a/infra/modules/ecs/ecs.tf b/infra/modules/ecs/ecs.tf index 5a761056c..5c41debdf 100644 --- a/infra/modules/ecs/ecs.tf +++ b/infra/modules/ecs/ecs.tf @@ -48,3 +48,9 @@ resource "aws_ecs_cluster" "ecs" { namespace = aws_service_discovery_private_dns_namespace.namespace.arn } } + +resource "aws_ssm_parameter" "ecs-cluster-arn" { + name = "ecs_cluster_arn_${var.environment}_${var.project_name}" + type = "String" + value = aws_ecs_cluster.ecs.arn +} diff --git a/infra/modules/ecs/services.tf b/infra/modules/ecs/services.tf deleted file mode 100644 index afbec365d..000000000 --- a/infra/modules/ecs/services.tf +++ /dev/null @@ -1,37 +0,0 @@ -resource "aws_security_group" "hello-world-task-sg" { - name = "${var.project_name}-hello-world-task-sg-${var.environment}" - description = "Security group for hello world ecs service" - vpc_id = var.vpc_id - revoke_rules_on_delete = true - - egress { - from_port = 0 - to_port = 0 - protocol = -1 - cidr_blocks = ["0.0.0.0/0"] - } - - tags = { - Name = "${var.project_name}-hello-world-task-sg-${var.environment}" - } -} - -resource "aws_ecs_service" "hello-world" { - name = "${var.project_name}-hello-world-${var.environment}" - cluster = aws_ecs_cluster.ecs.id - task_definition = "${aws_ecs_task_definition.hello-world.id}:${aws_ecs_task_definition.hello-world.revision}" - enable_execute_command = true - launch_type = "FARGATE" - desired_count = 1 - - network_configuration { - assign_public_ip = true - subnets = var.private_subnet_ids - security_groups = [aws_security_group.hello-world-task-sg.id] - } - - deployment_circuit_breaker { - enable = true - rollback = true - } -} diff --git a/infra/modules/ecs/tasks.tf b/infra/modules/ecs/tasks.tf index f38c28aed..74012ee51 100644 --- a/infra/modules/ecs/tasks.tf +++ b/infra/modules/ecs/tasks.tf @@ -45,3 +45,33 @@ resource "aws_ecs_task_definition" "hello-world" { } ]) } + +resource "aws_security_group" "hello-world-task-sg" { + name = "${var.project_name}-hello-world-task-sg-${var.environment}" + description = "Security group for hello world ecs service" + vpc_id = var.vpc_id + revoke_rules_on_delete = true + + egress { + from_port = 0 + to_port = 0 + protocol = -1 + cidr_blocks = ["0.0.0.0/0"] + } + + tags = { + Name = "${var.project_name}-hello-world-task-sg-${var.environment}" + } +} + +resource "aws_ssm_parameter" "ecs-security-group-id" { + name = "ecs_task_security_group_id_${var.environment}_${var.project_name}" + type = "String" + value = aws_security_group.hello-world-task-sg.id +} + +resource "aws_ssm_parameter" "ecs-task-definition-id" { + name = "ecs_task_definition_id_${var.environment}_${var.project_name}" + type = "String" + value = "${aws_ecs_task_definition.hello-world.id}:${aws_ecs_task_definition.hello-world.revision}" +} From a8d82e545feee58e28dedb40f9f4cc2395eb2d22 Mon Sep 17 00:00:00 2001 From: Finlay Birnie Date: Wed, 11 Dec 2024 15:26:13 +0000 Subject: [PATCH 3/8] add lambda function that triggers ecs task --- api/package-lock.json | 1395 +++++++++++++++++- api/package.json | 1 + api/serverless-config-deploy.yml | 9 +- api/serverless.yml | 13 + api/src/components/integration/controller.ts | 13 + api/src/components/integration/routes.ts | 4 + api/src/components/integration/service.ts | 13 + api/src/lib/ecs.ts | 25 + 8 files changed, 1403 insertions(+), 70 deletions(-) create mode 100644 api/src/lib/ecs.ts diff --git a/api/package-lock.json b/api/package-lock.json index d64d099cd..97ceb8c8d 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -31,6 +31,7 @@ "supertest": "^6.3.3" }, "devDependencies": { + "@aws-sdk/client-ecs": "^3.709.0", "@aws-sdk/client-s3": "^3.413.0", "@aws-sdk/client-ses": "^3.413.0", "@aws-sdk/client-sqs": "^3.413.0", @@ -256,6 +257,1255 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, + "node_modules/@aws-sdk/client-ecs": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-ecs/-/client-ecs-3.709.0.tgz", + "integrity": "sha512-oyjd3rIxENb176NVp5+sttHC3uIIPCVbSefDPF5Qv/cToc3IJ78CdCWIBJTW2C3pMZmN3CIQ4zYORI7wAKpDDw==", + "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.709.0", + "@aws-sdk/client-sts": "3.709.0", + "@aws-sdk/core": "3.709.0", + "@aws-sdk/credential-provider-node": "3.709.0", + "@aws-sdk/middleware-host-header": "3.709.0", + "@aws-sdk/middleware-logger": "3.709.0", + "@aws-sdk/middleware-recursion-detection": "3.709.0", + "@aws-sdk/middleware-user-agent": "3.709.0", + "@aws-sdk/region-config-resolver": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@aws-sdk/util-endpoints": "3.709.0", + "@aws-sdk/util-user-agent-browser": "3.709.0", + "@aws-sdk/util-user-agent-node": "3.709.0", + "@smithy/config-resolver": "^3.0.13", + "@smithy/core": "^2.5.5", + "@smithy/fetch-http-handler": "^4.1.2", + "@smithy/hash-node": "^3.0.11", + "@smithy/invalid-dependency": "^3.0.11", + "@smithy/middleware-content-length": "^3.0.13", + "@smithy/middleware-endpoint": "^3.2.5", + "@smithy/middleware-retry": "^3.0.30", + "@smithy/middleware-serde": "^3.0.11", + "@smithy/middleware-stack": "^3.0.11", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/node-http-handler": "^3.3.2", + "@smithy/protocol-http": "^4.1.8", + "@smithy/smithy-client": "^3.5.0", + "@smithy/types": "^3.7.2", + "@smithy/url-parser": "^3.0.11", + "@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.30", + "@smithy/util-defaults-mode-node": "^3.0.30", + "@smithy/util-endpoints": "^2.1.7", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-retry": "^3.0.11", + "@smithy/util-utf8": "^3.0.0", + "@smithy/util-waiter": "^3.2.0", + "@types/uuid": "^9.0.1", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@aws-sdk/client-sso": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.709.0.tgz", + "integrity": "sha512-Qxeo8cN0jNy6Wnbqq4wucffAGJM6sJjofoTgNtPA6cC7sPYx7aYC6OAAAo6NaMRY+WywOKdS9Wgjx2QYRxKx7w==", + "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.709.0", + "@aws-sdk/middleware-host-header": "3.709.0", + "@aws-sdk/middleware-logger": "3.709.0", + "@aws-sdk/middleware-recursion-detection": "3.709.0", + "@aws-sdk/middleware-user-agent": "3.709.0", + "@aws-sdk/region-config-resolver": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@aws-sdk/util-endpoints": "3.709.0", + "@aws-sdk/util-user-agent-browser": "3.709.0", + "@aws-sdk/util-user-agent-node": "3.709.0", + "@smithy/config-resolver": "^3.0.13", + "@smithy/core": "^2.5.5", + "@smithy/fetch-http-handler": "^4.1.2", + "@smithy/hash-node": "^3.0.11", + "@smithy/invalid-dependency": "^3.0.11", + "@smithy/middleware-content-length": "^3.0.13", + "@smithy/middleware-endpoint": "^3.2.5", + "@smithy/middleware-retry": "^3.0.30", + "@smithy/middleware-serde": "^3.0.11", + "@smithy/middleware-stack": "^3.0.11", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/node-http-handler": "^3.3.2", + "@smithy/protocol-http": "^4.1.8", + "@smithy/smithy-client": "^3.5.0", + "@smithy/types": "^3.7.2", + "@smithy/url-parser": "^3.0.11", + "@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.30", + "@smithy/util-defaults-mode-node": "^3.0.30", + "@smithy/util-endpoints": "^2.1.7", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-retry": "^3.0.11", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@aws-sdk/client-sso-oidc": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.709.0.tgz", + "integrity": "sha512-1w6egz17QQy661lNCRmZZlqIANEbD6g2VFAQIJbVwSiu7brg+GUns+mT1eLLLHAMQc1sL0Ds8/ybSK2SrgGgIA==", + "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.709.0", + "@aws-sdk/credential-provider-node": "3.709.0", + "@aws-sdk/middleware-host-header": "3.709.0", + "@aws-sdk/middleware-logger": "3.709.0", + "@aws-sdk/middleware-recursion-detection": "3.709.0", + "@aws-sdk/middleware-user-agent": "3.709.0", + "@aws-sdk/region-config-resolver": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@aws-sdk/util-endpoints": "3.709.0", + "@aws-sdk/util-user-agent-browser": "3.709.0", + "@aws-sdk/util-user-agent-node": "3.709.0", + "@smithy/config-resolver": "^3.0.13", + "@smithy/core": "^2.5.5", + "@smithy/fetch-http-handler": "^4.1.2", + "@smithy/hash-node": "^3.0.11", + "@smithy/invalid-dependency": "^3.0.11", + "@smithy/middleware-content-length": "^3.0.13", + "@smithy/middleware-endpoint": "^3.2.5", + "@smithy/middleware-retry": "^3.0.30", + "@smithy/middleware-serde": "^3.0.11", + "@smithy/middleware-stack": "^3.0.11", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/node-http-handler": "^3.3.2", + "@smithy/protocol-http": "^4.1.8", + "@smithy/smithy-client": "^3.5.0", + "@smithy/types": "^3.7.2", + "@smithy/url-parser": "^3.0.11", + "@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.30", + "@smithy/util-defaults-mode-node": "^3.0.30", + "@smithy/util-endpoints": "^2.1.7", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-retry": "^3.0.11", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.709.0" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@aws-sdk/client-sts": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.709.0.tgz", + "integrity": "sha512-cBAvlPg6yslXNL385UUGFPw+XY+lA9BzioNdIFkMo3fEUlTShogTtiWz4LsyLHoN6LhKojssP9DSmmWKWjCZIw==", + "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.709.0", + "@aws-sdk/core": "3.709.0", + "@aws-sdk/credential-provider-node": "3.709.0", + "@aws-sdk/middleware-host-header": "3.709.0", + "@aws-sdk/middleware-logger": "3.709.0", + "@aws-sdk/middleware-recursion-detection": "3.709.0", + "@aws-sdk/middleware-user-agent": "3.709.0", + "@aws-sdk/region-config-resolver": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@aws-sdk/util-endpoints": "3.709.0", + "@aws-sdk/util-user-agent-browser": "3.709.0", + "@aws-sdk/util-user-agent-node": "3.709.0", + "@smithy/config-resolver": "^3.0.13", + "@smithy/core": "^2.5.5", + "@smithy/fetch-http-handler": "^4.1.2", + "@smithy/hash-node": "^3.0.11", + "@smithy/invalid-dependency": "^3.0.11", + "@smithy/middleware-content-length": "^3.0.13", + "@smithy/middleware-endpoint": "^3.2.5", + "@smithy/middleware-retry": "^3.0.30", + "@smithy/middleware-serde": "^3.0.11", + "@smithy/middleware-stack": "^3.0.11", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/node-http-handler": "^3.3.2", + "@smithy/protocol-http": "^4.1.8", + "@smithy/smithy-client": "^3.5.0", + "@smithy/types": "^3.7.2", + "@smithy/url-parser": "^3.0.11", + "@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.30", + "@smithy/util-defaults-mode-node": "^3.0.30", + "@smithy/util-endpoints": "^2.1.7", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-retry": "^3.0.11", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@aws-sdk/core": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.709.0.tgz", + "integrity": "sha512-7kuSpzdOTAE026j85wq/fN9UDZ70n0OHw81vFqMWwlEFtm5IQ/MRCLKcC4HkXxTdfy1PqFlmoXxWqeBa15tujw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/core": "^2.5.5", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/property-provider": "^3.1.11", + "@smithy/protocol-http": "^4.1.8", + "@smithy/signature-v4": "^4.2.4", + "@smithy/smithy-client": "^3.5.0", + "@smithy/types": "^3.7.2", + "@smithy/util-middleware": "^3.0.11", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.709.0.tgz", + "integrity": "sha512-ZMAp9LSikvHDFVa84dKpQmow6wsg956Um20cKuioPpX2GGreJFur7oduD+tRJT6FtIOHn+64YH+0MwiXLhsaIQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/property-provider": "^3.1.11", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.709.0.tgz", + "integrity": "sha512-lIS7XLwCOyJnLD70f+VIRr8DNV1HPQe9oN6aguYrhoczqz7vDiVZLe3lh714cJqq9rdxzFypK5DqKHmcscMEPQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/fetch-http-handler": "^4.1.2", + "@smithy/node-http-handler": "^3.3.2", + "@smithy/property-provider": "^3.1.11", + "@smithy/protocol-http": "^4.1.8", + "@smithy/smithy-client": "^3.5.0", + "@smithy/types": "^3.7.2", + "@smithy/util-stream": "^3.3.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.709.0.tgz", + "integrity": "sha512-qCF8IIGcPoUp+Ib3ANhbF5gElxFd+kIrtv2/1tKdvhudMANstQbMiWV0LTH47ZZR6c3as4iSrm09NZnpEoD/pA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.709.0", + "@aws-sdk/credential-provider-env": "3.709.0", + "@aws-sdk/credential-provider-http": "3.709.0", + "@aws-sdk/credential-provider-process": "3.709.0", + "@aws-sdk/credential-provider-sso": "3.709.0", + "@aws-sdk/credential-provider-web-identity": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/credential-provider-imds": "^3.2.8", + "@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" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.709.0" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.709.0.tgz", + "integrity": "sha512-4HRX9KYWPSjO5O/Vg03YAsebKpvTjTvpK1n7zHYBmlLMBLxUrVsL1nNKKC5p2/7OW3RL8XR1ki3QkoV7kGRxUQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.709.0", + "@aws-sdk/credential-provider-http": "3.709.0", + "@aws-sdk/credential-provider-ini": "3.709.0", + "@aws-sdk/credential-provider-process": "3.709.0", + "@aws-sdk/credential-provider-sso": "3.709.0", + "@aws-sdk/credential-provider-web-identity": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/credential-provider-imds": "^3.2.8", + "@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-ecs/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.709.0.tgz", + "integrity": "sha512-IAC+jPlGQII6jhIylHOwh3RgSobqlgL59nw2qYTURr8hMCI0Z1p5y2ee646HTVt4WeCYyzUAXfxr6YI/Vitv+Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@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-ecs/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.709.0.tgz", + "integrity": "sha512-rYdTDOxazS2GdGScelsRK5CAkktRLCCdRjlwXaxrcW57j749hEqxcF5uTv9RD6WBwInfedcSywErNZB+hylQlg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.709.0", + "@aws-sdk/core": "3.709.0", + "@aws-sdk/token-providers": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@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-ecs/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.709.0.tgz", + "integrity": "sha512-2lbDfE0IQ6gma/7BB2JpkjW5G0wGe4AS0x80oybYAYYviJmUtIR3Cn2pXun6bnAWElt4wYKl4su7oC36rs5rNA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/property-provider": "^3.1.11", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.709.0" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.709.0.tgz", + "integrity": "sha512-8gQYCYAaIw4lOCd5WYdf15Y/61MgRsAnrb2eiTl+icMlUOOzl8aOl5iDwm/Idp0oHZTflwxM4XSvGXO83PRWcw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@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-ecs/node_modules/@aws-sdk/middleware-logger": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.709.0.tgz", + "integrity": "sha512-jDoGSccXv9zebnpUoisjWd5u5ZPIalrmm6TjvPzZ8UqzQt3Beiz0tnQwmxQD6KRc7ADweWP5Ntiqzbw9xpVajg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.709.0.tgz", + "integrity": "sha512-PObL/wLr4lkfbQ0yXUWaoCWu/jcwfwZzCjsUiXW/H6hW9b/00enZxmx7OhtJYaR6xmh/Lcx5wbhIoDCbzdv0tw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@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-ecs/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.709.0.tgz", + "integrity": "sha512-ooc9ZJvgkjPhi9q05XwSfNTXkEBEIfL4hleo5rQBKwHG3aTHvwOM7LLzhdX56QZVa6sorPBp6fwULuRDSqiQHw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@aws-sdk/util-endpoints": "3.709.0", + "@smithy/core": "^2.5.5", + "@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-ecs/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.709.0.tgz", + "integrity": "sha512-/NoCAMEVKAg3kBKOrNtgOfL+ECt6nrl+L7q2SyYmrcY4tVCmwuECVqewQaHc03fTnJijfKLccw0Fj+6wOCnB6w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@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-ecs/node_modules/@aws-sdk/token-providers": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.709.0.tgz", + "integrity": "sha512-q5Ar6k71nci43IbULFgC8a89d/3EHpmd7HvBzqVGRcHnoPwh8eZDBfbBXKH83NGwcS1qPSRYiDbVfeWPm4/1jA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@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" + }, + "peerDependencies": { + "@aws-sdk/client-sso-oidc": "^3.709.0" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@aws-sdk/types": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.709.0.tgz", + "integrity": "sha512-ArtLTMxgjf13Kfu3gWH3Ez9Q5TkDdcRZUofpKH3pMGB/C6KAbeSCtIIDKfoRTUABzyGlPyCrZdnFjKyH+ypIpg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@aws-sdk/util-endpoints": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.709.0.tgz", + "integrity": "sha512-Mbc7AtL5WGCTKC16IGeUTz+sjpC3ptBda2t0CcK0kMVw3THDdcSq6ZlNKO747cNqdbwUvW34oHteUiHv4/z88Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/types": "^3.7.2", + "@smithy/util-endpoints": "^2.1.7", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.709.0.tgz", + "integrity": "sha512-/rL2GasJzdTWUURCQKFldw2wqBtY4k4kCiA2tVZSKg3y4Ey7zO34SW8ebaeCE2/xoWOyLR2/etdKyphoo4Zrtg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.709.0", + "@smithy/types": "^3.7.2", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.709.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.709.0.tgz", + "integrity": "sha512-trBfzSCVWy7ILgqhEXgiuM7hfRCw4F4a8IK90tjk9YL0jgoJ6eJuOp7+DfCtHJaygoBxD3cdMFkOu+lluFmGBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.709.0", + "@aws-sdk/types": "3.709.0", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/types": "^3.7.2", + "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-ecs/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==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/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==", + "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", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/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==", + "dev": true, + "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-ecs/node_modules/@smithy/fetch-http-handler": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-4.1.2.tgz", + "integrity": "sha512-R7rU7Ae3ItU4rC0c5mB2sP5mJNbCfoDc8I5XlYjIZnquyUwec7fEo78F6DA3SmgJgkU1qTMcZJuGblxZsl10ZA==", + "dev": true, + "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-ecs/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==", + "dev": true, + "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-ecs/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==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-ecs/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==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/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==", + "dev": true, + "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-ecs/node_modules/@smithy/middleware-endpoint": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.2.5.tgz", + "integrity": "sha512-VhJNs/s/lyx4weiZdXSloBgoLoS8osV0dKIain8nGmx7of3QFKu5BSdEuk1z/U8x9iwes1i+XCiNusEvuK1ijg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^2.5.5", + "@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", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@smithy/middleware-retry": { + "version": "3.0.30", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.30.tgz", + "integrity": "sha512-6323RL2BvAR3VQpTjHpa52kH/iSHyxd/G9ohb2MkBk2Ucu+oMtRXT8yi7KTSIS9nb58aupG6nO0OlXnQOAcvmQ==", + "dev": true, + "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.5.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-ecs/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==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/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==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/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==", + "dev": true, + "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-ecs/node_modules/@smithy/node-http-handler": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.3.2.tgz", + "integrity": "sha512-t4ng1DAd527vlxvOfKFYEe6/QFBcsj7WpNlWTyjorwXXcKw3XlltBGbyHfSJ24QT84nF+agDha9tNYpzmSRZPA==", + "dev": true, + "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" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/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==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/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==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.7.2", + "@smithy/util-uri-escape": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/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==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/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==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.7.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/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==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/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==", + "dev": true, + "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", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@smithy/smithy-client": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.5.0.tgz", + "integrity": "sha512-Y8FeOa7gbDfCWf7njrkoRATPa5eNLUEjlJS5z5rXatYuGkCb80LbHcu8AQR8qgAZZaNHCLyo2N+pxPsV7l+ivg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^2.5.5", + "@smithy/middleware-endpoint": "^3.2.5", + "@smithy/middleware-stack": "^3.0.11", + "@smithy/protocol-http": "^4.1.8", + "@smithy/types": "^3.7.2", + "@smithy/util-stream": "^3.3.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/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==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/querystring-parser": "^3.0.11", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-ecs/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==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@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-ecs/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==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-ecs/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==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/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==", + "dev": true, + "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-ecs/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==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@smithy/util-defaults-mode-browser": { + "version": "3.0.30", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.30.tgz", + "integrity": "sha512-nLuGmgfcr0gzm64pqF2UT4SGWVG8UGviAdayDlVzJPNa6Z4lqvpDzdRXmLxtOdEjVlTOEdpZ9dd3ZMMu488mzg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^3.1.11", + "@smithy/smithy-client": "^3.5.0", + "@smithy/types": "^3.7.2", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@smithy/util-defaults-mode-node": { + "version": "3.0.30", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.30.tgz", + "integrity": "sha512-OD63eWoH68vp75mYcfYyuVH+p7Li/mY4sYOROnauDrtObo1cS4uWfsy/zhOTW8F8ZPxQC1ZXZKVxoxvMGUv2Ow==", + "dev": true, + "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/smithy-client": "^3.5.0", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/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==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/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==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/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==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/service-error-classification": "^3.0.11", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/@smithy/util-stream": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.3.2.tgz", + "integrity": "sha512-sInAqdiVeisUGYAv/FrXpmJ0b4WTFmciTRqzhb7wVuem9BHvhIG7tpiYHLDWrl2stOokNZpTTGqz3mzB2qFwXg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/fetch-http-handler": "^4.1.2", + "@smithy/node-http-handler": "^3.3.2", + "@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-ecs/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==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/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==", + "dev": true, + "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-ecs/node_modules/@smithy/util-waiter": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-3.2.0.tgz", + "integrity": "sha512-PpjSboaDUE6yl+1qlg3Si57++e84oXdWGbuFUSAciXsVfEZJJJupR2Nb0QuXHiunt2vGR+1PTizOMvnUPaG2Qg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/abort-controller": "^3.1.9", + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ecs/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/@aws-sdk/client-lambda": { "version": "3.691.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.691.0.tgz", @@ -10367,18 +11617,18 @@ } }, "node_modules/@smithy/core": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.5.1.tgz", - "integrity": "sha512-DujtuDA7BGEKExJ05W5OdxCoyekcKT3Rhg1ZGeiUWaz2BJIWXjZmsG/DIP4W48GHno7AQwRsaCb8NcBgH3QZpg==", + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.5.5.tgz", + "integrity": "sha512-G8G/sDDhXA7o0bOvkc7bgai6POuSld/+XhNnWAbpQTpLv2OZPvyqQ58tLPPlz0bSNsXktldDDREIv1LczFeNEw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@smithy/middleware-serde": "^3.0.8", - "@smithy/protocol-http": "^4.1.5", - "@smithy/types": "^3.6.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.8", - "@smithy/util-stream": "^3.2.1", + "@smithy/util-middleware": "^3.0.11", + "@smithy/util-stream": "^3.3.2", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, @@ -10387,13 +11637,13 @@ } }, "node_modules/@smithy/core/node_modules/@smithy/abort-controller": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.6.tgz", - "integrity": "sha512-0XuhuHQlEqbNQZp7QxxrFTdVWdwxch4vjxYgfInF91hZFkPxf9QDrdQka0KfxFMPqLNzSw0b95uGTrLliQUavQ==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.9.tgz", + "integrity": "sha512-yiW0WI30zj8ZKoSYNx90no7ugVn3khlyH/z5W8qtKBtVE6awRALbhSG+2SAHA1r6bO/6M9utxYKVZ3PCJ1rWxw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.6.0", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { @@ -10401,15 +11651,15 @@ } }, "node_modules/@smithy/core/node_modules/@smithy/fetch-http-handler": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-4.0.0.tgz", - "integrity": "sha512-MLb1f5tbBO2X6K4lMEKJvxeLooyg7guq48C2zKr4qM7F2Gpkz4dc+hdSgu77pCJ76jVqFBjZczHYAs6dp15N+g==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-4.1.2.tgz", + "integrity": "sha512-R7rU7Ae3ItU4rC0c5mB2sP5mJNbCfoDc8I5XlYjIZnquyUwec7fEo78F6DA3SmgJgkU1qTMcZJuGblxZsl10ZA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^4.1.5", - "@smithy/querystring-builder": "^3.0.8", - "@smithy/types": "^3.6.0", + "@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" } @@ -10428,13 +11678,13 @@ } }, "node_modules/@smithy/core/node_modules/@smithy/middleware-serde": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.8.tgz", - "integrity": "sha512-Xg2jK9Wc/1g/MBMP/EUn2DLspN8LNt+GMe7cgF+Ty3vl+Zvu+VeZU5nmhveU+H8pxyTsjrAkci8NqY6OuvZnjA==", + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.11.tgz", + "integrity": "sha512-KzPAeySp/fOoQA82TpnwItvX8BBURecpx6ZMu75EZDkAcnPtO6vf7q4aH5QHs/F1s3/snQaSFbbUMcFFZ086Mw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.6.0", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { @@ -10442,16 +11692,16 @@ } }, "node_modules/@smithy/core/node_modules/@smithy/node-http-handler": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.2.5.tgz", - "integrity": "sha512-PkOwPNeKdvX/jCpn0A8n9/TyoxjGZB8WVoJmm9YzsnAgggTj4CrjpRHlTQw7dlLZ320n1mY1y+nTRUDViKi/3w==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.3.2.tgz", + "integrity": "sha512-t4ng1DAd527vlxvOfKFYEe6/QFBcsj7WpNlWTyjorwXXcKw3XlltBGbyHfSJ24QT84nF+agDha9tNYpzmSRZPA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@smithy/abort-controller": "^3.1.6", - "@smithy/protocol-http": "^4.1.5", - "@smithy/querystring-builder": "^3.0.8", - "@smithy/types": "^3.6.0", + "@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" }, "engines": { @@ -10459,13 +11709,13 @@ } }, "node_modules/@smithy/core/node_modules/@smithy/querystring-builder": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.8.tgz", - "integrity": "sha512-btYxGVqFUARbUrN6VhL9c3dnSviIwBYD9Rz1jHuN1hgh28Fpv2xjU1HeCeDJX68xctz7r4l1PBnFhGg1WBBPuA==", + "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==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.6.0", + "@smithy/types": "^3.7.2", "@smithy/util-uri-escape": "^3.0.0", "tslib": "^2.6.2" }, @@ -10525,13 +11775,13 @@ } }, "node_modules/@smithy/core/node_modules/@smithy/util-middleware": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.8.tgz", - "integrity": "sha512-p7iYAPaQjoeM+AKABpYWeDdtwQNxasr4aXQEA/OmbOaug9V0odRVDy3Wx4ci8soljE/JXQo+abV0qZpW8NX0yA==", + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.11.tgz", + "integrity": "sha512-dWpyc1e1R6VoXrwLoLDd57U1z6CwNSdkM69Ie4+6uYh2GC7Vg51Qtan7ITzczuVpqezdDTKJGJB95fFvvjU/ow==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.6.0", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { @@ -10539,15 +11789,15 @@ } }, "node_modules/@smithy/core/node_modules/@smithy/util-stream": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.2.1.tgz", - "integrity": "sha512-R3ufuzJRxSJbE58K9AEnL/uSZyVdHzud9wLS8tIbXclxKzoe09CRohj2xV8wpx5tj7ZbiJaKYcutMm1eYgz/0A==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.3.2.tgz", + "integrity": "sha512-sInAqdiVeisUGYAv/FrXpmJ0b4WTFmciTRqzhb7wVuem9BHvhIG7tpiYHLDWrl2stOokNZpTTGqz3mzB2qFwXg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@smithy/fetch-http-handler": "^4.0.0", - "@smithy/node-http-handler": "^3.2.5", - "@smithy/types": "^3.6.0", + "@smithy/fetch-http-handler": "^4.1.2", + "@smithy/node-http-handler": "^3.3.2", + "@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", @@ -11177,13 +12427,13 @@ } }, "node_modules/@smithy/protocol-http": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.5.tgz", - "integrity": "sha512-hsjtwpIemmCkm3ZV5fd/T0bPIugW1gJXwZ/hpuVubt2hEUApIoUTrf6qIdh9MAWlw0vjMrA1ztJLAwtNaZogvg==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.8.tgz", + "integrity": "sha512-hmgIAVyxw1LySOwkgMIUN0kjN8TG9Nc85LJeEmEE/cNEe2rkHDUWhnJf2gxcSRFLWsyqWsrZGw40ROjUogg+Iw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.6.0", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { @@ -11334,9 +12584,9 @@ } }, "node_modules/@smithy/types": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.6.0.tgz", - "integrity": "sha512-8VXK/KzOHefoC65yRgCn5vG1cysPJjHnOVt9d0ybFQSmJgQj152vMn4EkYhGuaOmnnZvCPav/KnYyE6/KsNZ2w==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.7.2.tgz", + "integrity": "sha512-bNwBYYmN8Eh9RyjS1p2gW6MIhSO2rl7X9QeLM8iTdcGRP+eDiIWDt66c9IysCc22gefKszZv+ubV9qZc7hdESg==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -11485,14 +12735,14 @@ } }, "node_modules/@smithy/util-endpoints": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.1.4.tgz", - "integrity": "sha512-kPt8j4emm7rdMWQyL0F89o92q10gvCUa6sBkBtDJ7nV2+P7wpXczzOfoDJ49CKXe5CCqb8dc1W+ZdLlrKzSAnQ==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.1.7.tgz", + "integrity": "sha512-tSfcqKcN/Oo2STEYCABVuKgJ76nyyr6skGl9t15hs+YaiU06sgMkN7QYjo0BbVw+KT26zok3IzbdSOksQ4YzVw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^3.1.9", - "@smithy/types": "^3.6.0", + "@smithy/node-config-provider": "^3.1.12", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { @@ -11500,15 +12750,15 @@ } }, "node_modules/@smithy/util-endpoints/node_modules/@smithy/node-config-provider": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.9.tgz", - "integrity": "sha512-qRHoah49QJ71eemjuS/WhUXB+mpNtwHRWQr77J/m40ewBVVwvo52kYAmb7iuaECgGTTcYxHS4Wmewfwy++ueew==", + "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==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@smithy/property-provider": "^3.1.8", - "@smithy/shared-ini-file-loader": "^3.1.9", - "@smithy/types": "^3.6.0", + "@smithy/property-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.12", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { @@ -11516,13 +12766,13 @@ } }, "node_modules/@smithy/util-endpoints/node_modules/@smithy/property-provider": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.8.tgz", - "integrity": "sha512-ukNUyo6rHmusG64lmkjFeXemwYuKge1BJ8CtpVKmrxQxc6rhUX0vebcptFA9MmrGsnLhwnnqeH83VTU9hwOpjA==", + "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==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.6.0", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { @@ -11530,13 +12780,13 @@ } }, "node_modules/@smithy/util-endpoints/node_modules/@smithy/shared-ini-file-loader": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.9.tgz", - "integrity": "sha512-/+OsJRNtoRbtsX0UpSgWVxFZLsJHo/4sTr+kBg/J78sr7iC+tHeOvOJrS5hCpVQ6sWBbhWLp1UNiuMyZhE6pmA==", + "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==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^3.6.0", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { @@ -12316,6 +13566,13 @@ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==" }, + "node_modules/@types/uuid": { + "version": "9.0.8", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", + "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/yargs": { "version": "17.0.24", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", diff --git a/api/package.json b/api/package.json index 3fbdfcae1..7b006195e 100644 --- a/api/package.json +++ b/api/package.json @@ -63,6 +63,7 @@ "supertest": "^6.3.3" }, "devDependencies": { + "@aws-sdk/client-ecs": "^3.709.0", "@aws-sdk/client-s3": "^3.413.0", "@aws-sdk/client-ses": "^3.413.0", "@aws-sdk/client-sqs": "^3.413.0", diff --git a/api/serverless-config-deploy.yml b/api/serverless-config-deploy.yml index 9d247ce22..2e51e9e49 100644 --- a/api/serverless-config-deploy.yml +++ b/api/serverless-config-deploy.yml @@ -3,4 +3,11 @@ functions: generatePDFsFromQueue: handler: dist/src/components/sqs/handler.generatePDFs events: - - sqs: 'arn:aws:sqs:${aws:region}:${aws:accountId}:science-octopus-pdf-queue-${self:provider.stage}' \ No newline at end of file + - sqs: 'arn:aws:sqs:${aws:region}:${aws:accountId}:science-octopus-pdf-queue-${self:provider.stage}' + triggerECSTask: + handler: dist/src/components/integration/routes.triggerECSTask + events: + - http: + path: ${self:custom.versions.v1}/integrations/simple-ecs-task + method: POST + cors: true \ No newline at end of file diff --git a/api/serverless.yml b/api/serverless.yml index fe9122995..fb3c78889 100644 --- a/api/serverless.yml +++ b/api/serverless.yml @@ -50,6 +50,10 @@ provider: TRIGGER_ARI_INGEST_API_KEY: ${ssm:/trigger_ari_ingest_api_key_${self:provider.stage}_octopus} INGEST_REPORT_RECIPIENTS: ${ssm:/ingest_report_recipients_${self:provider.stage}_octopus} PARTICIPATING_ARI_USER_IDS: ${ssm:/participating_ari_user_ids_${self:provider.stage}_octopus} + ECS_CLUSTER_ARN: ${ssm:/ecs_cluster_arn_${self:provider.stage}_octopus} + ECS_TASK_DEFINITION_ID: ${ssm:/ecs_task_definition_id_${self:provider.stage}_octopus} + ECS_TASK_SECURITY_GROUP_ID: ${ssm:/ecs_task_security_group_id_${self:provider.stage}_octopus} + PRIVATE_SUBNET_IDS: ${ssm:/${self:provider.stage}_octopus_private_subnet_az1},${ssm:/${self:provider.stage}_octopus_private_subnet_az2},${ssm:/${self:provider.stage}_octopus_private_subnet_az3} deploymentBucket: tags: Project: Octopus @@ -84,6 +88,15 @@ provider: - 'sqs:GetQueueAttributes' - 'sqs:ReceiveMessage' - 'sqs:SendMessage' + # Required to trigger ECS tasks + - Effect: 'Allow' + Resource: "arn:aws:ecs:${aws:region}:${aws:accountId}:task-definition/${ssm:/ecs_task_definition_id_${self:provider.stage}_octopus}" + Action: 'ecs:RunTask' + - Effect: 'Allow' + Resource: + - 'arn:aws:iam::${aws:accountId}:role/octopus-ecs-task-role-${self:provider.stage}' + - 'arn:aws:iam::${aws:accountId}:role/octopus-ecs-task-exec-role-${self:provider.stage}' + Action: 'iam:PassRole' custom: splitStacks: perFunction: true diff --git a/api/src/components/integration/controller.ts b/api/src/components/integration/controller.ts index 3c8de9254..0a83b7c5b 100644 --- a/api/src/components/integration/controller.ts +++ b/api/src/components/integration/controller.ts @@ -48,3 +48,16 @@ export const incrementalAriIngest = async ( return response.json(500, { message: 'Unknown server error.' }); } }; + +export const triggerECSTask = async (event: I.APIRequest): Promise => { + const apiKey = event.queryStringParameters?.apiKey; + + // While this is a proof of concept just use the same API key as the ARI ingest. + if (apiKey !== process.env.TRIGGER_ARI_INGEST_API_KEY) { + return response.json(401, { message: "Please provide a valid 'apiKey'." }); + } + + const triggerTaskOutput = await integrationService.triggerECSTask(); + + return response.json(200, { message: triggerTaskOutput }); +}; diff --git a/api/src/components/integration/routes.ts b/api/src/components/integration/routes.ts index 89e9dde43..1db662c73 100644 --- a/api/src/components/integration/routes.ts +++ b/api/src/components/integration/routes.ts @@ -7,3 +7,7 @@ import * as middleware from 'middleware'; export const incrementalAriIngest = middy(integrationController.incrementalAriIngest) .use(middleware.doNotWaitForEmptyEventLoop({ runOnError: true, runOnBefore: true, runOnAfter: true })) .use(middleware.validator(integrationSchema.incrementalAriIngestHttp, 'queryStringParameters')); + +export const triggerECSTask = middy(integrationController.triggerECSTask).use( + middleware.doNotWaitForEmptyEventLoop({ runOnError: true, runOnBefore: true, runOnAfter: true }) +); diff --git a/api/src/components/integration/service.ts b/api/src/components/integration/service.ts index 6e88de4f4..b7b897787 100644 --- a/api/src/components/integration/service.ts +++ b/api/src/components/integration/service.ts @@ -1,6 +1,8 @@ import axios from 'axios'; import * as ariUtils from 'integration/ariUtils'; +import * as ecs from 'lib/ecs'; import * as ingestLogService from 'ingestLog/service'; +import * as Helpers from 'lib/helpers'; /** * Incremental ARI ingest. @@ -151,3 +153,14 @@ export const incrementalAriIngest = async (dryRun: boolean, reportFormat: 'email return `${preamble} ${writeCount} publication${writeCount !== 1 ? 's' : ''}.`; }; + +export const triggerECSTask = async (): Promise => { + await ecs.runFargateTask({ + clusterArn: Helpers.checkEnvVariable('ECS_CLUSTER_ARN'), + securityGroups: [Helpers.checkEnvVariable('ECS_TASK_SECURITY_GROUP_ID')], + subnetIds: Helpers.checkEnvVariable('PRIVATE_SUBNET_IDS').split(','), + taskDefinitionId: Helpers.checkEnvVariable('ECS_TASK_DEFINITION_ID') + }); + + return 'Done'; +}; diff --git a/api/src/lib/ecs.ts b/api/src/lib/ecs.ts new file mode 100644 index 000000000..8edc29118 --- /dev/null +++ b/api/src/lib/ecs.ts @@ -0,0 +1,25 @@ +import { ECSClient, RunTaskCommand, RunTaskCommandInput } from '@aws-sdk/client-ecs'; + +const client = new ECSClient(); + +export const runFargateTask = async (config: { + clusterArn: string; + securityGroups: string[]; + subnetIds: string[]; + taskDefinitionId: string; +}): Promise => { + const input: RunTaskCommandInput = { + cluster: config.clusterArn, + launchType: 'FARGATE', + networkConfiguration: { + awsvpcConfiguration: { + securityGroups: config.securityGroups, + subnets: config.subnetIds + } + }, + taskDefinition: config.taskDefinitionId + }; + const command = new RunTaskCommand(input); + const response = await client.send(command); + console.log(response); +}; From 331c8061be46aba0d5a55d8b0b24df50cf2b14df Mon Sep 17 00:00:00 2001 From: Finlay Birnie Date: Wed, 11 Dec 2024 09:31:46 +0000 Subject: [PATCH 4/8] forward ref to search input --- ui/src/components/SearchPage/index.tsx | 405 +++++++++++---------- ui/src/pages/search/publications/index.tsx | 1 + 2 files changed, 205 insertions(+), 201 deletions(-) diff --git a/ui/src/components/SearchPage/index.tsx b/ui/src/components/SearchPage/index.tsx index 67ce52444..0d8295440 100644 --- a/ui/src/components/SearchPage/index.tsx +++ b/ui/src/components/SearchPage/index.tsx @@ -33,217 +33,220 @@ type Props = { } ); -const SearchPage: React.FC = (props: Props): React.ReactElement => { - const router = Router.useRouter(); +const SearchPage = React.forwardRef( + (props: Props, searchInputRef: React.ForwardedRef): React.ReactElement => { + const router = Router.useRouter(); - const upperPageBound = props.limit + props.offset > props.total ? props.total : props.limit + props.offset; + const upperPageBound = props.limit + props.offset > props.total ? props.total : props.limit + props.offset; - return ( - <> -
- -
-
-
-
- Search options + return ( + <> +
+ +
+
+
+
+ Search options - + - -
-
- -
-
- {props.filters && ( - - )} -
-
- {props.error ? props.error : `${props.total} result${props.total !== 1 ? 's' : ''}`} -
- {props.error ? ( - - ) : ( - - {!props.error && !props.results.length && !props.isValidating && ( - + + Showing + + + +
+
+ +
+
+ {props.filters && ( + + )} +
+
+ {props.error ? props.error : `${props.total} result${props.total !== 1 ? 's' : ''}`} +
+ {props.error ? ( + + ) : ( + + {!props.error && !props.results.length && !props.isValidating && ( + + )} - {props.results.length && ( - <> -
- {props.results.map((result, index: number) => { - let classes = ''; + {props.results.length && ( + <> +
+ {props.results.map((result, index: number) => { + let classes = ''; - if (index === 0) { - classes += 'rounded-t'; - } + if (index === 0) { + classes += 'rounded-t'; + } - if (index === props.results.length - 1) { - classes += '!border-b-transparent !rounded-b'; - } + if (index === props.results.length - 1) { + classes += '!border-b-transparent !rounded-b'; + } - return props.searchType === 'publication-versions' ? ( - - ) : props.searchType === 'authors' || - props.searchType === 'organisations' ? ( - - ) : props.searchType == 'topics' ? ( - - ) : ( - <> - ); - })} -
+ return props.searchType === 'publication-versions' ? ( + + ) : props.searchType === 'authors' || + props.searchType === 'organisations' ? ( + + ) : props.searchType == 'topics' ? ( + + ) : ( + <> + ); + })} +
- {!props.isValidating && !!props.results.length && ( - -
- { - props.setOffset(props.offset - props.limit); - Helpers.scrollTopSmooth(); - }} - disabled={props.offset === 0} - title="Previous" - /> - { - props.setOffset(props.offset + props.limit); - Helpers.scrollTopSmooth(); - }} - disabled={props.limit + props.offset >= props.total} - title="Next" - /> -
- - Showing {props.offset + 1} - {upperPageBound} of {props.total} - -
- )} - - )} -
- )} -
-
- - ); -}; +
+ { + props.setOffset(props.offset - props.limit); + Helpers.scrollTopSmooth(); + }} + disabled={props.offset === 0} + title="Previous" + /> + { + props.setOffset(props.offset + props.limit); + Helpers.scrollTopSmooth(); + }} + disabled={props.limit + props.offset >= props.total} + title="Next" + /> +
+ + Showing {props.offset + 1} - {upperPageBound} of {props.total} + + + )} + + )} + + )} + + + + ); + } +); export default SearchPage; diff --git a/ui/src/pages/search/publications/index.tsx b/ui/src/pages/search/publications/index.tsx index c6be78d0a..66afb2093 100644 --- a/ui/src/pages/search/publications/index.tsx +++ b/ui/src/pages/search/publications/index.tsx @@ -462,6 +462,7 @@ const Publications: Types.NextPage = (props): React.ReactElement => { limit={limit} offset={offset} query={query} + ref={searchInputRef} resetFilters={resetFilters} results={response?.data || []} searchType="publication-versions" From 8388d518478f69eccad44ee516f4c26cbd254d6e Mon Sep 17 00:00:00 2001 From: Finlay Birnie Date: Wed, 11 Dec 2024 09:41:37 +0000 Subject: [PATCH 5/8] SearchPage component now needs a displayname --- ui/src/components/SearchPage/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/src/components/SearchPage/index.tsx b/ui/src/components/SearchPage/index.tsx index 0d8295440..a288a0b35 100644 --- a/ui/src/components/SearchPage/index.tsx +++ b/ui/src/components/SearchPage/index.tsx @@ -248,5 +248,6 @@ const SearchPage = React.forwardRef( ); } ); +SearchPage.displayName = 'SearchPage'; export default SearchPage; From 3ecefccc67f7c5c4ad7d133e8b9fabe2a54a752f Mon Sep 17 00:00:00 2001 From: Finlay Birnie Date: Thu, 12 Dec 2024 15:59:19 +0000 Subject: [PATCH 6/8] do api key check in middleware --- .../integration/__tests__/ari.test.ts | 11 +--- api/src/components/integration/controller.ts | 22 +------- api/src/components/integration/routes.ts | 10 ++-- api/src/components/user/controller.ts | 8 +-- api/src/components/user/routes.ts | 5 +- api/src/middleware/authentication.ts | 51 +++++++++++-------- 6 files changed, 47 insertions(+), 60 deletions(-) diff --git a/api/src/components/integration/__tests__/ari.test.ts b/api/src/components/integration/__tests__/ari.test.ts index eec55feba..9ea03a463 100644 --- a/api/src/components/integration/__tests__/ari.test.ts +++ b/api/src/components/integration/__tests__/ari.test.ts @@ -415,16 +415,9 @@ describe('ARI import processes', () => { test('Incremental import endpoint requires API key', async () => { const triggerImport = await testUtils.agent.post('/integrations/ari/incremental'); - expect(triggerImport.status).toEqual(400); + expect(triggerImport.status).toEqual(401); expect(triggerImport.body).toMatchObject({ - message: [ - { - keyword: 'required', - params: { - missingProperty: 'apiKey' - } - } - ] + message: "Please provide a valid 'apiKey'." }); }); diff --git a/api/src/components/integration/controller.ts b/api/src/components/integration/controller.ts index 0a83b7c5b..43a56d4ee 100644 --- a/api/src/components/integration/controller.ts +++ b/api/src/components/integration/controller.ts @@ -6,20 +6,9 @@ import * as response from 'lib/response'; export const incrementalAriIngest = async ( event: I.APIRequest | I.EventBridgeEvent<'Scheduled Event', string> ): Promise => { - const triggeredByHttp = event && 'headers' in event; - - // This can also be triggered on a schedule, in which case we don't need to check for an API key, - // so only check for the API key if the event is an API request. - if (triggeredByHttp) { - const apiKey = event.queryStringParameters?.apiKey; - - if (apiKey !== process.env.TRIGGER_ARI_INGEST_API_KEY) { - return response.json(401, { message: "Please provide a valid 'apiKey'." }); - } - } - // Check if a process is currently running. const lastLog = await ingestLogService.getMostRecentLog('ARI', true); + const triggeredByHttp = event && 'headers' in event; const dryRun = triggeredByHttp ? !!event.queryStringParameters?.dryRun : false; const dryRunMessages: string[] = []; @@ -49,14 +38,7 @@ export const incrementalAriIngest = async ( } }; -export const triggerECSTask = async (event: I.APIRequest): Promise => { - const apiKey = event.queryStringParameters?.apiKey; - - // While this is a proof of concept just use the same API key as the ARI ingest. - if (apiKey !== process.env.TRIGGER_ARI_INGEST_API_KEY) { - return response.json(401, { message: "Please provide a valid 'apiKey'." }); - } - +export const triggerECSTask = async (): Promise => { const triggerTaskOutput = await integrationService.triggerECSTask(); return response.json(200, { message: triggerTaskOutput }); diff --git a/api/src/components/integration/routes.ts b/api/src/components/integration/routes.ts index 1db662c73..47a299064 100644 --- a/api/src/components/integration/routes.ts +++ b/api/src/components/integration/routes.ts @@ -1,13 +1,17 @@ import middy from '@middy/core'; +import * as Helpers from 'lib/helpers'; import * as integrationController from 'integration/controller'; import * as integrationSchema from 'integration/schema'; import * as middleware from 'middleware'; +const triggerAriIngestApiKey = Helpers.checkEnvVariable('TRIGGER_ARI_INGEST_API_KEY'); + export const incrementalAriIngest = middy(integrationController.incrementalAriIngest) .use(middleware.doNotWaitForEmptyEventLoop({ runOnError: true, runOnBefore: true, runOnAfter: true })) + .use(middleware.authentication(false, false, triggerAriIngestApiKey)) .use(middleware.validator(integrationSchema.incrementalAriIngestHttp, 'queryStringParameters')); -export const triggerECSTask = middy(integrationController.triggerECSTask).use( - middleware.doNotWaitForEmptyEventLoop({ runOnError: true, runOnBefore: true, runOnAfter: true }) -); +export const triggerECSTask = middy(integrationController.triggerECSTask) + .use(middleware.doNotWaitForEmptyEventLoop({ runOnError: true, runOnBefore: true, runOnAfter: true })) + .use(middleware.authentication(false, false, triggerAriIngestApiKey)); diff --git a/api/src/components/user/controller.ts b/api/src/components/user/controller.ts index d52a2fa46..2a2aca1ce 100644 --- a/api/src/components/user/controller.ts +++ b/api/src/components/user/controller.ts @@ -77,13 +77,7 @@ export const getPublications = async ( } }; -export const getUserList = async (event: I.APIRequest): Promise => { - const apiKey = event.queryStringParameters?.apiKey; - - if (apiKey !== process.env.LIST_USERS_API_KEY) { - return response.json(401, { message: "Please provide a valid 'apiKey'." }); - } - +export const getUserList = async (): Promise => { try { const userList = await userService.getUserList(); diff --git a/api/src/components/user/routes.ts b/api/src/components/user/routes.ts index 66c241809..4836143dc 100644 --- a/api/src/components/user/routes.ts +++ b/api/src/components/user/routes.ts @@ -1,5 +1,6 @@ import middy from '@middy/core'; +import * as Helpers from 'lib/helpers'; import * as middleware from 'middleware'; import * as userController from 'user/controller'; import * as userSchema from 'user/schema'; @@ -20,7 +21,9 @@ export const getPublications = middy(userController.getPublications) .use(middleware.authentication(true)) .use(middleware.validator(userSchema.getPublications, 'queryStringParameters')); -export const getUserList = userController.getUserList; +export const getUserList = middy(userController.getUserList) + .use(middleware.doNotWaitForEmptyEventLoop({ runOnError: true, runOnBefore: true, runOnAfter: true })) + .use(middleware.authentication(false, false, Helpers.checkEnvVariable('LIST_USERS_API_KEY'))); export const getUserControlRequests = middy(userController.getUserControlRequests) .use(middleware.doNotWaitForEmptyEventLoop({ runOnError: true, runOnBefore: true, runOnAfter: true })) diff --git a/api/src/middleware/authentication.ts b/api/src/middleware/authentication.ts index 76d373636..be0d3d936 100644 --- a/api/src/middleware/authentication.ts +++ b/api/src/middleware/authentication.ts @@ -5,36 +5,47 @@ import * as response from 'lib/response'; import * as userService from 'user/service'; import * as authorizationService from 'authorization/service'; -const authentication = (optional = false, requiresName = true): middy.MiddlewareObj => { +const authentication = (optional = false, requiresName = true, endpointSpecificKey?: string): middy.MiddlewareObj => { const before: middy.MiddlewareFn = async (request): Promise => { try { let user: null | I.User = null; const apiKey = request.event.queryStringParameters?.apiKey; - const bearerToken = request.event.headers.Authorization; - if (apiKey) { - user = await userService.getByApiKey(apiKey); - } else if (bearerToken) { - user = authorizationService.validateJWT(bearerToken.split(' ')[1]); - } - - if (!optional) { - // If there's no user account, and authentication is *not* optional, then the request is blocked. - if (!user) { - return response.json(401, { message: 'Please enter either a valid apiKey or bearer token.' }); + if (endpointSpecificKey) { + // The function only accepts one specific api key.) + if (apiKey !== endpointSpecificKey) { + return response.json(401, { message: "Please provide a valid 'apiKey'." }); + } + } else { + // The function attempts to authenticate an existing user, + // looking them up either by their api key or JWT, + // and then adds the user details to the request event. + const bearerToken = request.event.headers.Authorization; + + if (apiKey) { + user = await userService.getByApiKey(apiKey); + } else if (bearerToken) { + user = authorizationService.validateJWT(bearerToken.split(' ')[1]); } - // If the user hasn't made their name visible in ORCiD, we want to disallow them from doing most actions. - if (!user?.firstName && !user?.lastName && requiresName) { - return response.json(403, { - message: - 'No name detected. Please ensure your name visibility is set to "Everyone" or "Trusted parties" on your ORCiD account, then re-authorize at /authorization.' - }); + if (!optional) { + // If there's no user account, and authentication is *not* optional, then the request is blocked. + if (!user) { + return response.json(401, { message: 'Please enter either a valid apiKey or bearer token.' }); + } + + // If the user hasn't made their name visible in ORCiD, we want to disallow them from doing most actions. + if (!user?.firstName && !user?.lastName && requiresName) { + return response.json(403, { + message: + 'No name detected. Please ensure your name visibility is set to "Everyone" or "Trusted parties" on your ORCiD account, then re-authorize at /authorization.' + }); + } } - } - Object.assign(request.event, { user }); + Object.assign(request.event, { user }); + } } catch (err) { console.log(err); From 89d42711afa0c8490d985b1af6d7dd2faaffc1f4 Mon Sep 17 00:00:00 2001 From: Finlay Birnie Date: Thu, 12 Dec 2024 16:02:43 +0000 Subject: [PATCH 7/8] correct description --- infra/modules/ecs/tasks.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infra/modules/ecs/tasks.tf b/infra/modules/ecs/tasks.tf index 74012ee51..8f3968376 100644 --- a/infra/modules/ecs/tasks.tf +++ b/infra/modules/ecs/tasks.tf @@ -48,7 +48,7 @@ resource "aws_ecs_task_definition" "hello-world" { resource "aws_security_group" "hello-world-task-sg" { name = "${var.project_name}-hello-world-task-sg-${var.environment}" - description = "Security group for hello world ecs service" + description = "Security group for hello world ecs task" vpc_id = var.vpc_id revoke_rules_on_delete = true From 1309efb8fe2ad099d929b5a0437ca640461c3a9d Mon Sep 17 00:00:00 2001 From: Finlay Birnie Date: Wed, 18 Dec 2024 16:26:47 +0000 Subject: [PATCH 8/8] early return for anonymous access to optionally authenticated endpoint --- api/src/middleware/authentication.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/api/src/middleware/authentication.ts b/api/src/middleware/authentication.ts index be0d3d936..5d88f90e8 100644 --- a/api/src/middleware/authentication.ts +++ b/api/src/middleware/authentication.ts @@ -23,6 +23,11 @@ const authentication = (optional = false, requiresName = true, endpointSpecificK // and then adds the user details to the request event. const bearerToken = request.event.headers.Authorization; + // If unauthenticated user is accessing an optional endpoint, just skip. + if (optional && !apiKey && !bearerToken) { + return; + } + if (apiKey) { user = await userService.getByApiKey(apiKey); } else if (bearerToken) {