From cbc35a8d59044263fd56ef621e08566948fe36b7 Mon Sep 17 00:00:00 2001 From: Chris Wilton-Magras Date: Tue, 20 Feb 2024 13:01:10 +0000 Subject: [PATCH] 385: Put APIGateway in front of private loadbalancer (#834) --- backend/src/server/app.ts | 5 +- backend/src/server/proxySetup.ts | 65 +++++++ backend/src/server/sessionRoutes.ts | 13 +- cloud/bin/cloud.ts | 17 +- cloud/cdk.context.json | 7 + cloud/lib/api-stack.ts | 104 ++++++++++-- cloud/lib/ui-stack.ts | 6 +- cloud/package-lock.json | 255 +++++++++++++++------------- cloud/package.json | 24 +-- 9 files changed, 347 insertions(+), 149 deletions(-) create mode 100644 backend/src/server/proxySetup.ts create mode 100644 cloud/cdk.context.json diff --git a/backend/src/server/app.ts b/backend/src/server/app.ts index 4a45be2a8..d6d0019f6 100644 --- a/backend/src/server/app.ts +++ b/backend/src/server/app.ts @@ -7,10 +7,13 @@ import queryTypes from 'query-types'; import { importMetaUrl } from './importMetaUtils'; import nonSessionRoutes from './nonSessionRoutes'; +import { usingForwardedHeader } from './proxySetup'; import sessionRoutes from './sessionRoutes'; import uiRoutes from './uiRoutes'; -const app = express().use(express.json()).use(queryTypes.middleware()); +const app = usingForwardedHeader(express()) + .use(express.json()) + .use(queryTypes.middleware()); const isDevelopment = env.NODE_ENV === 'development'; const isServingUI = env.NODE_ENV === 'prodlite'; diff --git a/backend/src/server/proxySetup.ts b/backend/src/server/proxySetup.ts new file mode 100644 index 000000000..57fe0be98 --- /dev/null +++ b/backend/src/server/proxySetup.ts @@ -0,0 +1,65 @@ +import { Express, Request } from 'express'; + +declare module 'node:net' { + interface Socket { + encrypted?: boolean; + } +} +/** + * Unfortunately, "trust proxy" is by default broken when Express is behind an + * AWS HTTP API Gateway: + * - https://github.com/expressjs/express/issues/5459 + * - https://repost.aws/en/questions/QUtBHMaz7IQ6aM4RCBMnJvgw/why-does-apigw-http-api-use-forwarded-header-while-other-services-still-use-x-forwarded-headers + * + * Therefore we use Express API overrides to modify our Request IP and Protocol properties: + * - https://expressjs.com/en/guide/overriding-express-api.html + */ +export function usingForwardedHeader(app: Express): Express { + Object.defineProperties(app.request, { + ip: { + configurable: true, + enumerable: true, + get() { + const proxies = parseForwardedHeader(this as Request); + return proxies?.for ?? (this as Request).socket.remoteAddress; + }, + }, + protocol: { + configurable: true, + enumerable: true, + get() { + const proxies = parseForwardedHeader(this as Request); + return proxies?.proto ?? (this as Request).socket.encrypted + ? 'https' + : 'http'; + }, + }, + }); + return app; +} + +/** + * Forwarded header looks like this: + * + * ``` + * for=12.345.67.89;proto=https;host=somehost.org,for=98.76.54.321;proto=http;host=someproxy.net + * ``` + * + * Note we only need the first entry, as that is the client. + * + * @param request incoming express Request object + */ +function parseForwardedHeader(request: Request) { + return request + .header('Forwarded') + ?.split(',') + .at(0) + ?.split(';') + .reduce((result, proxyProps) => { + const [key, value] = proxyProps.split('='); + if (key && value) { + result[key] = value; + } + return result; + }, {} as Record); +} diff --git a/backend/src/server/sessionRoutes.ts b/backend/src/server/sessionRoutes.ts index 3e2edb4d3..db269cd86 100644 --- a/backend/src/server/sessionRoutes.ts +++ b/backend/src/server/sessionRoutes.ts @@ -86,6 +86,17 @@ router.use((req, _res, next) => { next(); }); +// TODO: Remove this debug logging! +if (isProduction) { + router.use('/openai', (req, res, next) => { + console.log('Request:', req.path, `secure=${req.secure}`, req.headers); + res.on('finish', () => { + console.log('Response:', req.path, res.getHeaders()); + }); + next(); + }); +} + // handshake router.get('/start', handleStart); @@ -109,7 +120,7 @@ router.post('/openai/model/configure', handleConfigureModel); router.post('/reset/all', handleResetProgress); router.post('/reset/:level', handleResetLevel); -// Testing endpoints +// Load testing endpoints router.post('/test/load', handleTest); export default router; diff --git a/cloud/bin/cloud.ts b/cloud/bin/cloud.ts index 3903f9dd9..a3bce11d4 100644 --- a/cloud/bin/cloud.ts +++ b/cloud/bin/cloud.ts @@ -1,5 +1,5 @@ #!/usr/bin/env node -import { App } from 'aws-cdk-lib'; +import { App, Environment } from 'aws-cdk-lib'; import 'source-map-support/register'; import { @@ -12,6 +12,12 @@ import { } from '../lib'; const app = new App(); + +const env: Environment = { + account: process.env.CDK_DEFAULT_ACCOUNT, + region: process.env.CDK_DEFAULT_REGION, +}; + const tags = { owner: appName, classification: 'unrestricted', @@ -24,22 +30,25 @@ const generateStackName = stackName(app); const generateDescription = resourceDescription(app); const uiStack = new UiStack(app, generateStackName('ui'), { - tags, description: generateDescription('UI stack'), + env, + tags, }); // Don't need this stack yet. /* const authStack = new AuthStack(app, generateStackName('auth'), { - tags, description: generateDescription('Auth stack'), + env, + tags, webappUrl: uiStack.cloudfrontUrl, }); */ new ApiStack(app, generateStackName('api'), { - tags, description: generateDescription('API stack'), + env, + tags, // userPool: authStack.userPool, // userPoolClient: authStack.userPoolClient, // userPoolDomain: authStack.userPoolDomain, diff --git a/cloud/cdk.context.json b/cloud/cdk.context.json new file mode 100644 index 000000000..7280e8b1b --- /dev/null +++ b/cloud/cdk.context.json @@ -0,0 +1,7 @@ +{ + "availability-zones:account=600982866784:region=eu-west-1": [ + "eu-west-1a", + "eu-west-1b", + "eu-west-1c" + ] +} diff --git a/cloud/lib/api-stack.ts b/cloud/lib/api-stack.ts index ecae28be2..6c73a2af9 100644 --- a/cloud/lib/api-stack.ts +++ b/cloud/lib/api-stack.ts @@ -1,20 +1,34 @@ +import { CorsHttpMethod, HttpApi, VpcLink } from 'aws-cdk-lib/aws-apigatewayv2'; +import { HttpAlbIntegration } from 'aws-cdk-lib/aws-apigatewayv2-integrations'; //import { UserPool, UserPoolClient, UserPoolDomain } from 'aws-cdk-lib/aws-cognito'; -import { Vpc } from 'aws-cdk-lib/aws-ec2'; +import { Port, SecurityGroup, Vpc } from 'aws-cdk-lib/aws-ec2'; import { DockerImageAsset } from 'aws-cdk-lib/aws-ecr-assets'; import { Cluster, ContainerImage, + PropagatedTagSource, Secret as EnvSecret, } from 'aws-cdk-lib/aws-ecs'; import { ApplicationLoadBalancedFargateService } from 'aws-cdk-lib/aws-ecs-patterns'; //import { ListenerAction } from 'aws-cdk-lib/aws-elasticloadbalancingv2'; //import { AuthenticateCognitoAction } from 'aws-cdk-lib/aws-elasticloadbalancingv2-actions'; +import { Bucket } from 'aws-cdk-lib/aws-s3'; import { Secret } from 'aws-cdk-lib/aws-secretsmanager'; -import { Stack, StackProps } from 'aws-cdk-lib/core'; +import { + CfnOutput, + RemovalPolicy, + Stack, + StackProps, + Tags, +} from 'aws-cdk-lib/core'; import { Construct } from 'constructs'; import { join } from 'node:path'; -import { resourceName } from './resourceNamingUtils'; +import { + appName, + resourceDescription, + resourceName, +} from './resourceNamingUtils'; type ApiStackProps = StackProps & { // userPool: UserPool; @@ -26,10 +40,11 @@ type ApiStackProps = StackProps & { export class ApiStack extends Stack { constructor(scope: Construct, id: string, props: ApiStackProps) { super(scope, id, props); - // TODO Enable cognito auth + // TODO Enable cognito/JWT authorization const { /*userPool, userPoolClient, userPoolDomain,*/ webappUrl } = props; const generateResourceName = resourceName(scope); + const generateResourceDescription = resourceDescription(scope); const dockerImageAsset = new DockerImageAsset( this, @@ -51,15 +66,16 @@ export class ApiStack extends Stack { 'dev/SpyLogic/ApiKey' ); - // Create a load-balanced Fargate service and make it public + // Create a private, application-load-balanced Fargate service const containerPort = 3001; - const serviceName = generateResourceName('fargate'); - const loadBalancerName = generateResourceName('alb'); + const fargateServiceName = generateResourceName('fargate'); + const loadBalancerName = generateResourceName('loadbalancer'); + const loadBalancerLogName = generateResourceName('loadbalancer-logs'); const fargateService = new ApplicationLoadBalancedFargateService( this, - serviceName, + fargateServiceName, { - serviceName, + serviceName: fargateServiceName, cluster, cpu: 256, // Default is 256 desiredCount: 1, // Bump this up for prod! @@ -70,6 +86,7 @@ export class ApiStack extends Stack { NODE_ENV: 'production', PORT: `${containerPort}`, CORS_ALLOW_ORIGIN: webappUrl, + COOKIE_NAME: `${appName}.sid`, }, secrets: { OPENAI_API_KEY: EnvSecret.fromSecretsManager( @@ -84,13 +101,25 @@ export class ApiStack extends Stack { }, memoryLimitMiB: 512, // Default is 512 loadBalancerName, - publicLoadBalancer: true, // Default is true + openListener: false, + publicLoadBalancer: false, + propagateTags: PropagatedTagSource.SERVICE, } ); + fargateService.targetGroup.configureHealthCheck({ + path: '/health', + }); + fargateService.loadBalancer.logAccessLogs( + new Bucket(this, loadBalancerLogName, { + bucketName: loadBalancerLogName, + autoDeleteObjects: true, + removalPolicy: RemovalPolicy.DESTROY, + }) + ); // Hook up Cognito to load balancer // https://stackoverflow.com/q/71124324 - // TODO This needs HTTPS and a Route53 domain, so in meantime try VPCLink: + // TODO Needs HTTPS and a Route53 domain, so for now we're using APIGateway and VPCLink: // https://repost.aws/knowledge-center/api-gateway-alb-integration /* const authActionName = generateResourceName('alb-auth'); @@ -104,6 +133,57 @@ export class ApiStack extends Stack { }); */ - fargateService.targetGroup.configureHealthCheck({ path: '/health' }); + // Create an HTTP APIGateway with a VPCLink integrated with our load balancer + const securityGroupName = generateResourceName('vpclink-sg'); + const vpcLinkSecurityGroup = new SecurityGroup(this, securityGroupName, { + vpc, + securityGroupName, + allowAllOutbound: false, + }); + vpcLinkSecurityGroup.connections.allowFromAnyIpv4( + Port.tcp(80), + 'APIGW to VPCLink' + ); + vpcLinkSecurityGroup.connections.allowTo( + fargateService.loadBalancer, + Port.tcp(80), + 'VPCLink to ALB' + ); + + const vpcLinkName = generateResourceName('vpclink'); + const vpcLink = new VpcLink(this, vpcLinkName, { + vpc, + vpcLinkName, + securityGroups: [vpcLinkSecurityGroup], + }); + Object.entries(props.tags ?? {}).forEach(([key, value]) => { + Tags.of(vpcLink).add(key, value); + }); + + const apiName = generateResourceName('api'); + const api = new HttpApi(this, apiName, { + apiName, + description: generateResourceDescription('API'), + corsPreflight: { + allowOrigins: [webappUrl], + allowMethods: [CorsHttpMethod.ANY], + allowHeaders: ['Content-Type', 'Authorization'], + allowCredentials: true, + }, + }); + api.addRoutes({ + path: '/{proxy+}', + integration: new HttpAlbIntegration( + generateResourceName('api-integration'), + fargateService.loadBalancer.listeners[0], + { vpcLink } + ), + }); + + new CfnOutput(this, 'APIGatewayURL', { + value: + api.defaultStage?.url ?? + 'FATAL ERROR: Gateway does not have a default stage', + }); } } diff --git a/cloud/lib/ui-stack.ts b/cloud/lib/ui-stack.ts index 1a7667d61..6f44ed0bc 100644 --- a/cloud/lib/ui-stack.ts +++ b/cloud/lib/ui-stack.ts @@ -23,7 +23,7 @@ import { } from 'aws-cdk-lib/aws-s3'; import { Construct } from 'constructs'; -import { resourceName } from './resourceNamingUtils'; +import { appName, resourceName } from './resourceNamingUtils'; export class UiStack extends Stack { public readonly cloudfrontUrl: string; @@ -83,9 +83,7 @@ export class UiStack extends Stack { }), cachePolicy: new CachePolicy(this, cachePolicyName, { cachePolicyName, - cookieBehavior: CacheCookieBehavior.allowList( - 'prompt-injection.sid' - ), + cookieBehavior: CacheCookieBehavior.allowList(`${appName}.sid`), }), compress: true, allowedMethods: AllowedMethods.ALLOW_GET_HEAD_OPTIONS, diff --git a/cloud/package-lock.json b/cloud/package-lock.json index fe3850df4..e7a749163 100644 --- a/cloud/package-lock.json +++ b/cloud/package-lock.json @@ -8,25 +8,25 @@ "name": "cloud", "version": "0.1.0", "dependencies": { - "aws-cdk-lib": "^2.104.0", + "aws-cdk-lib": "^2.127.0", "constructs": "^10.3.0", - "dotenv": "^16.3.1", + "dotenv": "^16.4.4", "source-map-support": "^0.5.21" }, "bin": { "cloud": "bin/cloud.js" }, "devDependencies": { - "@types/node": "^20.8.9", - "@types/source-map-support": "^0.5.9", - "@typescript-eslint/eslint-plugin": "^6.9.0", - "@typescript-eslint/parser": "^6.9.0", - "aws-cdk": "^2.104.0", + "@types/node": "^18.19.15", + "@types/source-map-support": "^0.5.10", + "@typescript-eslint/eslint-plugin": "^6.21.0", + "@typescript-eslint/parser": "^6.21.0", + "aws-cdk": "^2.127.0", "concurrently": "^8.2.2", - "eslint": "^8.52.0", - "prettier": "^3.0.3", - "ts-node": "^10.9.1", - "typescript": "^5.2.2" + "eslint": "^8.56.0", + "prettier": "^3.2.5", + "ts-node": "^10.9.2", + "typescript": "^5.3.3" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -39,9 +39,9 @@ } }, "node_modules/@aws-cdk/asset-awscli-v1": { - "version": "2.2.201", - "resolved": "https://registry.npmjs.org/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.201.tgz", - "integrity": "sha512-INZqcwDinNaIdb5CtW3ez5s943nX5stGBQS6VOP2JDlOFP81hM3fds/9NDknipqfUkZM43dx+HgVvkXYXXARCQ==" + "version": "2.2.202", + "resolved": "https://registry.npmjs.org/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.202.tgz", + "integrity": "sha512-JqlF0D4+EVugnG5dAsNZMqhu3HW7ehOXm5SDMxMbXNDMdsF0pxtQKNHRl52z1U9igsHmaFpUgSGjbhAJ+0JONg==" }, "node_modules/@aws-cdk/asset-kubectl-v20": { "version": "2.1.2", @@ -112,9 +112,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", - "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -135,9 +135,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.52.0.tgz", - "integrity": "sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", + "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -251,46 +251,46 @@ "dev": true }, "node_modules/@types/json-schema": { - "version": "7.0.14", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz", - "integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "node_modules/@types/node": { - "version": "20.8.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.9.tgz", - "integrity": "sha512-UzykFsT3FhHb1h7yD4CA4YhBHq545JC0YnEz41xkipN88eKQtL6rSgocL5tbAP6Ola9Izm/Aw4Ora8He4x0BHg==", + "version": "18.19.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.15.tgz", + "integrity": "sha512-AMZ2UWx+woHNfM11PyAEQmfSxi05jm9OlkxczuHeEqmvwPkYj6MWv44gbzDPefYOLysTOFyI3ziiy2ONmUZfpA==", "dev": true, "dependencies": { "undici-types": "~5.26.4" } }, "node_modules/@types/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.7.tgz", + "integrity": "sha512-/wdoPq1QqkSj9/QOeKkFquEuPzQbHTWAMPH/PaUMB+JuR31lXhlWXRZ52IpfDYVlDOUBvX09uBrPwxGT1hjNBg==", "dev": true }, "node_modules/@types/source-map-support": { - "version": "0.5.9", - "resolved": "https://registry.npmjs.org/@types/source-map-support/-/source-map-support-0.5.9.tgz", - "integrity": "sha512-91Jf4LyPAObBTFbpW3bSDK1ncdwXohvlBmzffSj7/44SY+1mD/HhesdfspCMxPIJwllgN2G4eVFatGs4Zw/lnw==", + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@types/source-map-support/-/source-map-support-0.5.10.tgz", + "integrity": "sha512-tgVP2H469x9zq34Z0m/fgPewGhg/MLClalNOiPIzQlXrSS2YrKu/xCdSCKnEDwkFha51VKEKB6A9wW26/ZNwzA==", "dev": true, "dependencies": { "source-map": "^0.6.0" } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.9.0.tgz", - "integrity": "sha512-lgX7F0azQwRPB7t7WAyeHWVfW1YJ9NIgd9mvGhfQpRY56X6AVf8mwM8Wol+0z4liE7XX3QOt8MN1rUKCfSjRIA==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", + "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.9.0", - "@typescript-eslint/type-utils": "6.9.0", - "@typescript-eslint/utils": "6.9.0", - "@typescript-eslint/visitor-keys": "6.9.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -316,15 +316,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.9.0.tgz", - "integrity": "sha512-GZmjMh4AJ/5gaH4XF2eXA8tMnHWP+Pm1mjQR2QN4Iz+j/zO04b9TOvJYOX2sCNIQHtRStKTxRY1FX7LhpJT4Gw==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.9.0", - "@typescript-eslint/types": "6.9.0", - "@typescript-eslint/typescript-estree": "6.9.0", - "@typescript-eslint/visitor-keys": "6.9.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4" }, "engines": { @@ -344,13 +344,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.9.0.tgz", - "integrity": "sha512-1R8A9Mc39n4pCCz9o79qRO31HGNDvC7UhPhv26TovDsWPBDx+Sg3rOZdCELIA3ZmNoWAuxaMOT7aWtGRSYkQxw==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.0", - "@typescript-eslint/visitor-keys": "6.9.0" + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -361,13 +361,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.9.0.tgz", - "integrity": "sha512-XXeahmfbpuhVbhSOROIzJ+b13krFmgtc4GlEuu1WBT+RpyGPIA4Y/eGnXzjbDj5gZLzpAXO/sj+IF/x2GtTMjQ==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", + "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.9.0", - "@typescript-eslint/utils": "6.9.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -388,9 +388,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.9.0.tgz", - "integrity": "sha512-+KB0lbkpxBkBSiVCuQvduqMJy+I1FyDbdwSpM3IoBS7APl4Bu15lStPjgBIdykdRqQNYqYNMa8Kuidax6phaEw==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -401,16 +401,17 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.0.tgz", - "integrity": "sha512-NJM2BnJFZBEAbCfBP00zONKXvMqihZCrmwCaik0UhLr0vAgb6oguXxLX1k00oQyD+vZZ+CJn3kocvv2yxm4awQ==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.0", - "@typescript-eslint/visitor-keys": "6.9.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", + "minimatch": "9.0.3", "semver": "^7.5.4", "ts-api-utils": "^1.0.1" }, @@ -427,18 +428,42 @@ } } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@typescript-eslint/utils": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.9.0.tgz", - "integrity": "sha512-5Wf+Jsqya7WcCO8me504FBigeQKVLAMPmUzYgDbWchINNh1KJbxCgVya3EQ2MjvJMVeXl3pofRmprqX6mfQkjQ==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.9.0", - "@typescript-eslint/types": "6.9.0", - "@typescript-eslint/typescript-estree": "6.9.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", "semver": "^7.5.4" }, "engines": { @@ -453,12 +478,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.0.tgz", - "integrity": "sha512-dGtAfqjV6RFOtIP8I0B4ZTBRrlTT8NHHlZZSchQx3qReaoDeXhYM++M4So2AgFK9ZB0emRPA6JI1HkafzA2Ibg==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/types": "6.21.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -567,9 +592,9 @@ } }, "node_modules/aws-cdk": { - "version": "2.104.0", - "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.104.0.tgz", - "integrity": "sha512-JuCafR5D1lnMKA88JUYhvRYeguozAWneC/n6kR1FUG+kXtXxpEqOxP91118dfJZYRw7FMIkHW8ewddvLwaCy5g==", + "version": "2.127.0", + "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.127.0.tgz", + "integrity": "sha512-0yPiN+/VFVc/NpOryO+1S7b4DBgRSs4JdQ64jhV4QbwaoWZo7KISxdN2cK4pmcVH67BSNCJCjjlf10cYhmMvwA==", "dev": true, "bin": { "cdk": "bin/cdk" @@ -582,9 +607,9 @@ } }, "node_modules/aws-cdk-lib": { - "version": "2.104.0", - "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.104.0.tgz", - "integrity": "sha512-gD5KD2j8C5ff7j4RTA5ajFDNnpw4EvVhWMgWWrOyIEa9OkndEXwzhvCvwbEpwmgSUvnmsmbiHTBaLg8KVP+yKA==", + "version": "2.127.0", + "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.127.0.tgz", + "integrity": "sha512-pEdp2TqgNLYY+kAo68oVzMDEHJevYoRArZJoH+bjM9YTwqRJJiwF1k6tc78e3jca4sCNDZAgX2ytOgqW6lVTWQ==", "bundleDependencies": [ "@balena/dockerignore", "case", @@ -598,16 +623,16 @@ "yaml" ], "dependencies": { - "@aws-cdk/asset-awscli-v1": "^2.2.200", + "@aws-cdk/asset-awscli-v1": "^2.2.202", "@aws-cdk/asset-kubectl-v20": "^2.1.2", "@aws-cdk/asset-node-proxy-agent-v6": "^2.0.1", "@balena/dockerignore": "^1.0.2", "case": "1.6.3", - "fs-extra": "^11.1.1", - "ignore": "^5.2.4", + "fs-extra": "^11.2.0", + "ignore": "^5.3.1", "jsonschema": "^1.4.1", "minimatch": "^3.1.2", - "punycode": "^2.3.0", + "punycode": "^2.3.1", "semver": "^7.5.4", "table": "^6.8.1", "yaml": "1.10.2" @@ -723,7 +748,7 @@ "license": "MIT" }, "node_modules/aws-cdk-lib/node_modules/fs-extra": { - "version": "11.1.1", + "version": "11.2.0", "inBundle": true, "license": "MIT", "dependencies": { @@ -741,7 +766,7 @@ "license": "ISC" }, "node_modules/aws-cdk-lib/node_modules/ignore": { - "version": "5.2.4", + "version": "5.3.1", "inBundle": true, "license": "MIT", "engines": { @@ -808,7 +833,7 @@ } }, "node_modules/aws-cdk-lib/node_modules/punycode": { - "version": "2.3.0", + "version": "2.3.1", "inBundle": true, "license": "MIT", "engines": { @@ -893,7 +918,7 @@ } }, "node_modules/aws-cdk-lib/node_modules/universalify": { - "version": "2.0.0", + "version": "2.0.1", "inBundle": true, "license": "MIT", "engines": { @@ -1160,14 +1185,14 @@ } }, "node_modules/dotenv": { - "version": "16.3.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", - "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "version": "16.4.4", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.4.tgz", + "integrity": "sha512-XvPXc8XAQThSjAbY6cQ/9PcBXmFoWuw1sQ3b8HqUCR6ziGXjkTi//kB9SWa2UwqlgdAIuRqAa/9hVljzPehbYg==", "engines": { "node": ">=12" }, "funding": { - "url": "https://github.com/motdotla/dotenv?sponsor=1" + "url": "https://dotenvx.com" } }, "node_modules/emoji-regex": { @@ -1198,15 +1223,15 @@ } }, "node_modules/eslint": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz", - "integrity": "sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.52.0", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.56.0", "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -1346,9 +1371,9 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -1516,9 +1541,9 @@ } }, "node_modules/globals": { - "version": "13.23.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", - "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -1938,9 +1963,9 @@ } }, "node_modules/prettier": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", - "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -1953,9 +1978,9 @@ } }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "engines": { "node": ">=6" @@ -2229,9 +2254,9 @@ } }, "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -2302,9 +2327,9 @@ } }, "node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "dev": true, "bin": { "tsc": "bin/tsc", diff --git a/cloud/package.json b/cloud/package.json index 871a4dd4e..d2f2c33ff 100644 --- a/cloud/package.json +++ b/cloud/package.json @@ -6,7 +6,7 @@ }, "scripts": { "cdk:synth": "cdk synth -q \"*\"", - "cdk:deploy": "cdk deploy --all", + "cdk:deploy": "cdk deploy --app cdk.out --all", "cdk:destroy": "cdk destroy --all", "codecheck": "concurrently \"npm run lint:check\" \"npm run format:check\"", "format": "prettier . --write", @@ -15,21 +15,21 @@ "lint:check": "eslint . --ext .ts" }, "devDependencies": { - "@types/node": "^20.8.9", - "@types/source-map-support": "^0.5.9", - "@typescript-eslint/eslint-plugin": "^6.9.0", - "@typescript-eslint/parser": "^6.9.0", + "@types/node": "^18.19.15", + "@types/source-map-support": "^0.5.10", + "@typescript-eslint/eslint-plugin": "^6.21.0", + "@typescript-eslint/parser": "^6.21.0", "concurrently": "^8.2.2", - "eslint": "^8.52.0", - "aws-cdk": "^2.104.0", - "prettier": "^3.0.3", - "ts-node": "^10.9.1", - "typescript": "^5.2.2" + "eslint": "^8.56.0", + "aws-cdk": "^2.127.0", + "prettier": "^3.2.5", + "ts-node": "^10.9.2", + "typescript": "^5.3.3" }, "dependencies": { - "aws-cdk-lib": "^2.104.0", + "aws-cdk-lib": "^2.127.0", "constructs": "^10.3.0", - "dotenv": "^16.3.1", + "dotenv": "^16.4.4", "source-map-support": "^0.5.21" } }