@digitraffic/common 2023.1.18-2 → 2023.1.23-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/aws/infra/api/integration.d.ts +2 -1
  2. package/dist/aws/infra/api/integration.js +3 -2
  3. package/dist/aws/infra/api/response.d.ts +2 -1
  4. package/dist/aws/infra/api/response.js +13 -7
  5. package/dist/aws/infra/canaries/canary-alarm.js +11 -13
  6. package/dist/aws/infra/canaries/canary.js +2 -4
  7. package/dist/aws/infra/canaries/database-checker.js +4 -1
  8. package/dist/aws/infra/canaries/url-canary.js +1 -0
  9. package/dist/aws/infra/canaries/url-checker.d.ts +2 -2
  10. package/dist/aws/infra/canaries/url-checker.js +24 -5
  11. package/dist/aws/infra/sqs-integration.d.ts +1 -3
  12. package/dist/aws/infra/sqs-integration.js +28 -32
  13. package/dist/aws/infra/sqs-queue.d.ts +0 -2
  14. package/dist/aws/infra/sqs-queue.js +31 -24
  15. package/dist/aws/infra/stack/lambda-configs.d.ts +2 -31
  16. package/dist/aws/infra/stack/lambda-configs.js +5 -38
  17. package/dist/aws/infra/stack/monitoredfunction.js +3 -1
  18. package/dist/aws/infra/stacks/db-stack.js +1 -1
  19. package/dist/aws/infra/stacks/network-stack.d.ts +2 -1
  20. package/dist/aws/infra/stacks/network-stack.js +4 -2
  21. package/dist/aws/runtime/digitraffic-integration-response.d.ts +2 -2
  22. package/dist/aws/runtime/digitraffic-integration-response.js +6 -4
  23. package/dist/aws/runtime/secrets/dbsecret.d.ts +0 -39
  24. package/dist/aws/runtime/secrets/dbsecret.js +1 -71
  25. package/dist/aws/runtime/secrets/proxy-holder.js +5 -4
  26. package/dist/aws/runtime/secrets/rds-holder.js +5 -4
  27. package/dist/aws/runtime/secrets/secret-holder.d.ts +0 -4
  28. package/dist/aws/runtime/secrets/secret-holder.js +6 -12
  29. package/dist/aws/runtime/secrets/secret.d.ts +0 -6
  30. package/dist/aws/runtime/secrets/secret.js +8 -17
  31. package/dist/database/database.d.ts +7 -0
  32. package/dist/database/database.js +19 -8
  33. package/dist/test/db-testutils.js +4 -5
  34. package/package.json +1 -1
  35. package/src/aws/infra/api/integration.ts +8 -3
  36. package/src/aws/infra/api/response.ts +16 -16
  37. package/src/aws/infra/canaries/canary-alarm.ts +26 -24
  38. package/src/aws/infra/canaries/canary.ts +2 -4
  39. package/src/aws/infra/canaries/database-checker.ts +4 -1
  40. package/src/aws/infra/canaries/url-canary.ts +2 -1
  41. package/src/aws/infra/canaries/url-checker.ts +28 -11
  42. package/src/aws/infra/sqs-integration.ts +51 -47
  43. package/src/aws/infra/sqs-queue.ts +85 -53
  44. package/src/aws/infra/stack/lambda-configs.ts +6 -69
  45. package/src/aws/infra/stack/monitoredfunction.ts +2 -1
  46. package/src/aws/infra/stacks/db-stack.ts +1 -1
  47. package/src/aws/infra/stacks/network-stack.ts +7 -3
  48. package/src/aws/runtime/digitraffic-integration-response.ts +16 -9
  49. package/src/aws/runtime/secrets/dbsecret.ts +1 -117
  50. package/src/aws/runtime/secrets/proxy-holder.ts +2 -5
  51. package/src/aws/runtime/secrets/rds-holder.ts +2 -1
  52. package/src/aws/runtime/secrets/secret-holder.ts +8 -20
  53. package/src/aws/runtime/secrets/secret.ts +17 -22
  54. package/src/database/database.ts +14 -3
  55. package/src/test/db-testutils.ts +5 -2
  56. package/dist/test/secret.d.ts +0 -3
  57. package/dist/test/secret.js +0 -25
  58. package/src/test/secret.ts +0 -23
@@ -1,18 +1,20 @@
1
- import {Queue, QueueEncryption, QueueProps} from "aws-cdk-lib/aws-sqs";
2
- import {Duration} from "aws-cdk-lib";
3
- import {BlockPublicAccess, Bucket} from "aws-cdk-lib/aws-s3";
4
- import {PolicyStatement} from "aws-cdk-lib/aws-iam";
5
- import {InlineCode, Runtime} from "aws-cdk-lib/aws-lambda";
6
- import {RetentionDays} from "aws-cdk-lib/aws-logs";
7
- import {SqsEventSource} from "aws-cdk-lib/aws-lambda-event-sources";
8
- import {ComparisonOperator, TreatMissingData} from "aws-cdk-lib/aws-cloudwatch";
9
- import {SnsAction} from "aws-cdk-lib/aws-cloudwatch-actions";
10
- import {ManagedUpload} from "aws-sdk/clients/s3";
11
- import {S3} from "aws-sdk";
12
- import {SQSEvent, SQSHandler, SQSRecord} from "aws-lambda";
13
- import {Construct} from "constructs";
14
- import {DigitrafficStack} from "./stack/stack";
15
- import {MonitoredFunction} from "./stack/monitoredfunction";
1
+ import { Queue, QueueEncryption, QueueProps } from "aws-cdk-lib/aws-sqs";
2
+ import { Duration } from "aws-cdk-lib";
3
+ import { BlockPublicAccess, Bucket } from "aws-cdk-lib/aws-s3";
4
+ import { PolicyStatement } from "aws-cdk-lib/aws-iam";
5
+ import { InlineCode, Runtime } from "aws-cdk-lib/aws-lambda";
6
+ import { RetentionDays } from "aws-cdk-lib/aws-logs";
7
+ import { SqsEventSource } from "aws-cdk-lib/aws-lambda-event-sources";
8
+ import {
9
+ ComparisonOperator,
10
+ TreatMissingData,
11
+ } from "aws-cdk-lib/aws-cloudwatch";
12
+ import { SnsAction } from "aws-cdk-lib/aws-cloudwatch-actions";
13
+ import { ManagedUpload } from "aws-sdk/clients/s3";
14
+ import { S3 } from "aws-sdk";
15
+ import { SQSEvent, SQSHandler, SQSRecord } from "aws-lambda";
16
+ import { DigitrafficStack } from "./stack/stack";
17
+ import { MonitoredFunction } from "./stack/monitoredfunction";
16
18
 
17
19
  /**
18
20
  * Construct for creating SQS-queues.
@@ -21,20 +23,23 @@ import {MonitoredFunction} from "./stack/monitoredfunction";
21
23
  * and an alarm for the queue. Anything that goes to the dlq will be written into the bucket and the alarm is activated.
22
24
  */
23
25
  export class DigitrafficSqsQueue extends Queue {
24
- constructor(scope: Construct, name: string, props: QueueProps) {
25
- super(scope, name, props);
26
- }
27
-
28
- static create(stack: DigitrafficStack, name: string, props: QueueProps): DigitrafficSqsQueue {
26
+ static create(
27
+ stack: DigitrafficStack,
28
+ name: string,
29
+ props: QueueProps
30
+ ): DigitrafficSqsQueue {
29
31
  const queueName = `${stack.configuration.shortName}-${name}-Queue`;
30
- const queueProps = {...props, ...{
31
- encryption: QueueEncryption.KMS_MANAGED,
32
- queueName,
33
- deadLetterQueue: props.deadLetterQueue || {
34
- maxReceiveCount: 2,
35
- queue: DigitrafficDLQueue.create(stack, name),
32
+ const queueProps = {
33
+ ...props,
34
+ ...{
35
+ encryption: QueueEncryption.KMS_MANAGED,
36
+ queueName,
37
+ deadLetterQueue: props.deadLetterQueue ?? {
38
+ maxReceiveCount: 2,
39
+ queue: DigitrafficDLQueue.create(stack, name),
40
+ },
36
41
  },
37
- }};
42
+ };
38
43
 
39
44
  return new DigitrafficSqsQueue(stack, queueName, queueProps);
40
45
  }
@@ -61,15 +66,15 @@ export class DigitrafficDLQueue {
61
66
  functionName: dlqFunctionName,
62
67
  code: getDlqCode(dlqBucket.bucketName),
63
68
  timeout: Duration.seconds(10),
64
- handler: 'index.handler',
69
+ handler: "index.handler",
65
70
  memorySize: 128,
66
71
  reservedConcurrentExecutions: 1,
67
72
  });
68
73
 
69
74
  const statement = new PolicyStatement();
70
- statement.addActions('s3:PutObject');
71
- statement.addActions('s3:PutObjectAcl');
72
- statement.addResources(dlqBucket.bucketArn + '/*');
75
+ statement.addActions("s3:PutObject");
76
+ statement.addActions("s3:PutObjectAcl");
77
+ statement.addResources(dlqBucket.bucketArn + "/*");
73
78
 
74
79
  lambda.addToRolePolicy(statement);
75
80
  lambda.addEventSource(new SqsEventSource(dlq));
@@ -84,18 +89,19 @@ function addDLQAlarm(stack: DigitrafficStack, dlqName: string, dlq: Queue) {
84
89
  const alarmName = `${dlqName}-Alarm`;
85
90
  dlq.metricNumberOfMessagesReceived({
86
91
  period: Duration.minutes(5),
87
- }).createAlarm(stack, alarmName, {
88
- alarmName,
89
- threshold: 0,
90
- evaluationPeriods: 1,
91
- treatMissingData: TreatMissingData.NOT_BREACHING,
92
- comparisonOperator: ComparisonOperator.GREATER_THAN_THRESHOLD,
93
- }).addAlarmAction(new SnsAction(stack.warningTopic));
92
+ })
93
+ .createAlarm(stack, alarmName, {
94
+ alarmName,
95
+ threshold: 0,
96
+ evaluationPeriods: 1,
97
+ treatMissingData: TreatMissingData.NOT_BREACHING,
98
+ comparisonOperator: ComparisonOperator.GREATER_THAN_THRESHOLD,
99
+ })
100
+ .addAlarmAction(new SnsAction(stack.warningTopic));
94
101
  }
95
102
 
96
103
  function getDlqCode(bName: string): InlineCode {
97
- const functionBody = DLQ_LAMBDA_CODE
98
- .replace("__bucketName__", bName)
104
+ const functionBody = DLQ_LAMBDA_CODE.replace("__bucketName__", bName)
99
105
  .replace("__upload__", uploadToS3.toString())
100
106
  .replace("__doUpload__", doUpload.toString())
101
107
  .replace("__handler__", createHandler().toString().substring(23)); // remove function handler() from signature
@@ -103,38 +109,64 @@ function getDlqCode(bName: string): InlineCode {
103
109
  return new InlineCode(functionBody);
104
110
  }
105
111
 
106
- async function uploadToS3(s3: S3, bName: string, body: string, objectName: string): Promise<void> {
112
+ async function uploadToS3(
113
+ s3: S3,
114
+ bName: string,
115
+ body: string,
116
+ objectName: string
117
+ ): Promise<void> {
107
118
  try {
108
- console.info('writing %s to %s', objectName, bName);
119
+ console.info("writing %s to %s", objectName, bName);
109
120
  await doUpload(s3, bName, body, objectName);
110
121
  } catch (error) {
111
122
  console.warn(error);
112
- console.warn('method=uploadToS3 retrying upload to bucket %s', bName);
123
+ console.warn("method=uploadToS3 retrying upload to bucket %s", bName);
113
124
  try {
114
125
  await doUpload(s3, bName, body, objectName);
115
126
  } catch (e2) {
116
- console.error('method=uploadToS3 failed retrying upload to bucket %s', bName);
127
+ console.error(
128
+ "method=uploadToS3 failed retrying upload to bucket %s",
129
+ bName
130
+ );
117
131
  }
118
132
  }
119
133
  }
120
134
 
121
- function doUpload(s3: S3, bName: string, Body: string, Key: string): Promise<ManagedUpload.SendData> {
122
- return s3.upload({
123
- Bucket: bName, Body, Key,
124
- }).promise();
135
+ function doUpload(
136
+ s3: S3,
137
+ bName: string,
138
+ Body: string,
139
+ Key: string
140
+ ): Promise<ManagedUpload.SendData> {
141
+ return s3
142
+ .upload({
143
+ Bucket: bName,
144
+ Body,
145
+ Key,
146
+ })
147
+ .promise();
125
148
  }
126
149
 
127
150
  // bucketName is unused, will be overridden in the actual lambda code below
128
- const bucketName = '';
151
+ const bucketName = "";
129
152
 
130
153
  function createHandler(): SQSHandler {
131
154
  return async function handler(event: SQSEvent): Promise<void> {
132
- // eslint-disable-next-line @typescript-eslint/no-var-requires
133
- const AWS = require('aws-sdk');
155
+ // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-assignment
156
+ const AWS = require("aws-sdk");
134
157
 
135
158
  const millis = new Date().getTime();
136
- await Promise.all(event.Records.map((e: SQSRecord, idx: number) =>
137
- uploadToS3(new AWS.S3(), bucketName, e.body, `dlq-${millis}-${idx}.json`)));
159
+ await Promise.all(
160
+ event.Records.map((e: SQSRecord, idx: number) =>
161
+ uploadToS3(
162
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
163
+ new AWS.S3(),
164
+ bucketName,
165
+ e.body,
166
+ `dlq-${millis}-${idx}.json`
167
+ )
168
+ )
169
+ );
138
170
  };
139
171
  }
140
172
 
@@ -6,7 +6,7 @@ import {
6
6
  Runtime,
7
7
  } from "aws-cdk-lib/aws-lambda";
8
8
  import { Duration } from "aws-cdk-lib";
9
- import { ISecurityGroup, IVpc, SubnetSelection } from "aws-cdk-lib/aws-ec2";
9
+ import { IVpc, SubnetSelection } from "aws-cdk-lib/aws-ec2";
10
10
  import { RetentionDays } from "aws-cdk-lib/aws-logs";
11
11
  import { Role } from "aws-cdk-lib/aws-iam";
12
12
  import { DigitrafficStack } from "./stack";
@@ -19,26 +19,6 @@ export type DBLambdaEnvironment = LambdaEnvironment & {
19
19
  DB_APPLICATION: string;
20
20
  };
21
21
 
22
- export interface LambdaConfiguration {
23
- vpcId: string;
24
- allowFromIpAddresses?: string[];
25
- privateSubnetIds: string[];
26
- availabilityZones: string[];
27
- lambdaDbSgId: string;
28
- dbProps?: DbProps;
29
- defaultLambdaDurationSeconds?: number;
30
- logsDestinationArn: string;
31
- memorySize?: number;
32
- runtime?: Runtime;
33
- }
34
-
35
- declare interface DbProps {
36
- username: string;
37
- password: string;
38
- uri?: string;
39
- ro_uri?: string;
40
- }
41
-
42
22
  export function databaseFunctionProps(
43
23
  stack: DigitrafficStack,
44
24
  environment: LambdaEnvironment,
@@ -61,9 +41,9 @@ export function databaseFunctionProps(
61
41
  config
62
42
  ),
63
43
  ...{
64
- vpc: stack.vpc || undefined,
44
+ vpc: stack.vpc ?? undefined,
65
45
  vpcSubnets,
66
- securityGroup: stack.lambdaDbSg || undefined,
46
+ securityGroup: stack.lambdaDbSg ?? undefined,
67
47
  },
68
48
  };
69
49
  }
@@ -101,47 +81,6 @@ function getAssetCode(
101
81
  return new AssetCode(lambdaPath);
102
82
  }
103
83
 
104
- /**
105
- * Creates a base configuration for a Lambda that uses an RDS database
106
- * @param vpc "Private" Lambdas are associated with a VPC
107
- * @param lambdaDbSg Security Group shared by Lambda and RDS
108
- * @param props Database connection properties for the Lambda
109
- * @param config Lambda configuration
110
- */
111
- export function dbLambdaConfiguration(
112
- vpc: IVpc,
113
- lambdaDbSg: ISecurityGroup,
114
- props: LambdaConfiguration,
115
- config: FunctionParameters
116
- ): FunctionProps {
117
- return {
118
- runtime: props.runtime ?? Runtime.NODEJS_16_X,
119
- memorySize: props.memorySize ?? config.memorySize ?? 1024,
120
- functionName: config.functionName,
121
- code: config.code,
122
- role: config.role,
123
- handler: config.handler,
124
- timeout: Duration.seconds(
125
- config.timeout ?? props.defaultLambdaDurationSeconds ?? 60
126
- ),
127
- environment: config.environment ?? {
128
- DB_USER: props.dbProps?.username ?? "",
129
- DB_PASS: props.dbProps?.password ?? "",
130
- DB_URI:
131
- (config.readOnly
132
- ? props.dbProps?.ro_uri
133
- : props.dbProps?.uri) ?? "",
134
- },
135
- logRetention: RetentionDays.ONE_YEAR,
136
- vpc: vpc,
137
- vpcSubnets: {
138
- subnets: vpc.privateSubnets,
139
- },
140
- securityGroups: [lambdaDbSg],
141
- reservedConcurrentExecutions: config.reservedConcurrentExecutions ?? 3,
142
- };
143
- }
144
-
145
84
  export function defaultLambdaConfiguration(
146
85
  config: FunctionParameters
147
86
  ): FunctionProps {
@@ -155,7 +94,7 @@ export function defaultLambdaConfiguration(
155
94
  reservedConcurrentExecutions: config.reservedConcurrentExecutions,
156
95
  code: config.code,
157
96
  role: config.role,
158
- timeout: Duration.seconds(config.timeout || 10),
97
+ timeout: Duration.seconds(config.timeout ?? 10),
159
98
  };
160
99
  if (config.vpc) {
161
100
  return {
@@ -163,7 +102,7 @@ export function defaultLambdaConfiguration(
163
102
  ...{
164
103
  vpc: config.vpc,
165
104
  vpcSubnets: {
166
- subnets: config.vpc?.privateSubnets,
105
+ subnets: config.vpc.privateSubnets,
167
106
  },
168
107
  },
169
108
  };
@@ -178,9 +117,7 @@ export interface FunctionParameters {
178
117
  code: Code;
179
118
  handler: string;
180
119
  readOnly?: boolean;
181
- environment?: {
182
- [key: string]: string;
183
- };
120
+ environment?: Record<string, string>;
184
121
  reservedConcurrentExecutions?: number;
185
122
  role?: Role;
186
123
  vpc?: IVpc;
@@ -82,7 +82,8 @@ export class MonitoredFunction extends Function {
82
82
  stack.configuration.production
83
83
  ) {
84
84
  throw new Error(
85
- `Function ${functionProps.functionName} has DISABLE_ALARMS. Remove before installing to production or define your own properties!`
85
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
86
+ `Function ${functionProps.functionName!} has DISABLE_ALARMS. Remove before installing to production or define your own properties!`
86
87
  );
87
88
  }
88
89
 
@@ -139,7 +139,7 @@ export class DbStack extends Stack {
139
139
  vpc,
140
140
  securityGroups: [securityGroup],
141
141
  vpcSubnets: {
142
- subnetType: SubnetType.PRIVATE_WITH_NAT,
142
+ subnetType: SubnetType.PRIVATE_WITH_EGRESS,
143
143
  },
144
144
  instanceType: configuration.dbInstanceType,
145
145
  parameterGroup,
@@ -1,7 +1,8 @@
1
1
  import { Stack } from "aws-cdk-lib";
2
2
  import { Construct } from "constructs";
3
- import { SubnetType, Vpc } from "aws-cdk-lib/aws-ec2";
3
+ import { IVpc, SubnetType, Vpc } from "aws-cdk-lib/aws-ec2";
4
4
  import { InfraStackConfiguration } from "./intra-stack-configuration";
5
+ import { exportValue } from "../import-util";
5
6
 
6
7
  export interface NetworkConfiguration {
7
8
  readonly vpcName: string;
@@ -9,6 +10,8 @@ export interface NetworkConfiguration {
9
10
  }
10
11
 
11
12
  export class NetworkStack extends Stack {
13
+ readonly vpc: IVpc;
14
+
12
15
  constructor(
13
16
  scope: Construct,
14
17
  id: string,
@@ -19,7 +22,8 @@ export class NetworkStack extends Stack {
19
22
  env: isc.env,
20
23
  });
21
24
 
22
- this.createVpc(configuration);
25
+ this.vpc = this.createVpc(configuration);
26
+ exportValue(this, isc.environmentName, "VPCID", this.vpc.vpcId);
23
27
  }
24
28
 
25
29
  createVpc(configuration: NetworkConfiguration): Vpc {
@@ -38,7 +42,7 @@ export class NetworkStack extends Stack {
38
42
  {
39
43
  name: "private",
40
44
  cidrMask: 24,
41
- subnetType: SubnetType.PRIVATE_WITH_NAT,
45
+ subnetType: SubnetType.PRIVATE_WITH_EGRESS,
42
46
  },
43
47
  ],
44
48
  });
@@ -1,11 +1,13 @@
1
- import {IntegrationResponse} from "aws-cdk-lib/aws-apigateway";
2
- import {MediaType} from "../types/mediatypes";
3
- import {RESPONSE_DEFAULT_LAMBDA} from "../infra/api/response";
1
+ import { IntegrationResponse } from "aws-cdk-lib/aws-apigateway";
2
+ import { MediaType } from "../types/mediatypes";
3
+ import {
4
+ getDeprecatedDefaultLambdaResponse,
5
+ RESPONSE_DEFAULT_LAMBDA,
6
+ } from "../infra/api/response";
4
7
 
5
8
  export abstract class DigitrafficIntegrationResponse {
6
-
7
- static ok(mediaType: MediaType): IntegrationResponse {
8
- return this.create("200", mediaType);
9
+ static ok(mediaType: MediaType, sunset?: string): IntegrationResponse {
10
+ return this.create("200", mediaType, sunset);
9
11
  }
10
12
 
11
13
  static badRequest(mediaType?: MediaType): IntegrationResponse {
@@ -16,13 +18,18 @@ export abstract class DigitrafficIntegrationResponse {
16
18
  return this.create("501", mediaType ?? MediaType.TEXT_PLAIN);
17
19
  }
18
20
 
19
- static create(statusCode: string, mediaType: MediaType): IntegrationResponse {
21
+ static create(
22
+ statusCode: string,
23
+ mediaType: MediaType,
24
+ sunset?: string
25
+ ): IntegrationResponse {
20
26
  return {
21
27
  statusCode,
22
28
  responseTemplates: {
23
- [mediaType]: RESPONSE_DEFAULT_LAMBDA,
29
+ [mediaType]: sunset
30
+ ? getDeprecatedDefaultLambdaResponse(sunset)
31
+ : RESPONSE_DEFAULT_LAMBDA,
24
32
  },
25
33
  };
26
34
  }
27
35
  }
28
-
@@ -1,11 +1,4 @@
1
- import { GenericSecret, withSecret, withSecretAndPrefix } from "./secret";
2
-
3
- export interface DbSecret {
4
- readonly username: string;
5
- readonly password: string;
6
- readonly host: string;
7
- readonly ro_host: string;
8
- }
1
+ import { GenericSecret } from "./secret";
9
2
 
10
3
  export enum RdsProxySecretKey {
11
4
  username = "username",
@@ -24,115 +17,6 @@ export enum RdsSecretKey {
24
17
  export type RdsProxySecret = Record<RdsProxySecretKey, string>;
25
18
  export type RdsSecret = Record<RdsSecretKey, string>;
26
19
 
27
- export enum DatabaseEnvironmentKeys {
28
- DB_USER = "DB_USER",
29
- DB_PASS = "DB_PASS",
30
- DB_URI = "DB_URI",
31
- DB_RO_URI = "DB_RO_URI",
32
- DB_APPLICATION = "DB_APPLICATION",
33
- }
34
-
35
- function setDbSecret(secret: DbSecret) {
36
- process.env[DatabaseEnvironmentKeys.DB_USER] = secret.username;
37
- process.env[DatabaseEnvironmentKeys.DB_PASS] = secret.password;
38
- process.env[DatabaseEnvironmentKeys.DB_URI] = secret.host;
39
- process.env[DatabaseEnvironmentKeys.DB_RO_URI] = secret.ro_host;
40
- }
41
-
42
- // cached at Lambda container level
43
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
- let cachedSecret: any;
45
-
46
- const missingSecretErrorText = "Missing or empty secretId";
47
-
48
- /**
49
- * You can give the following options for retrieving a secret:
50
- *
51
- * expectedKeys: the list of keys the secret must include. If not, an error will be thrown.
52
- * prefix: a prefix that's included in retrieved secret's keys. Only keys begining with the prefix will be included.
53
- * The secret that is passed to the given function will not include the prefix in it's keys.
54
-
55
- */
56
- export interface SecretOptions {
57
- readonly expectedKeys?: string[];
58
- readonly prefix?: string;
59
- }
60
-
61
- export type SecretToPromiseFunction<Secret, Response = void> = (
62
- secret: Secret
63
- ) => Promise<Response> | void;
64
- export type SecretFunction<Secret, Response = void> = (
65
- secretId: string,
66
- fn: SecretToPromiseFunction<Secret, Response>,
67
- options?: SecretOptions
68
- ) => Promise<Response | void>;
69
- export type EmptySecretFunction<Response = void> = SecretFunction<
70
- DbSecret,
71
- Response
72
- >;
73
-
74
- /**
75
- * Run the given function with secret retrieved from Secrets Manager. Also injects database-credentials into environment.
76
- *
77
- * @deprecated use SecretHolder & ProxyHolder
78
- * @see SecretOptions
79
- *
80
- * @param {string} secretId
81
- * @param {function} fn
82
- * @param {SecretOptions} options
83
- */
84
- export async function withDbSecret<Secret, Response>(
85
- secretId: string,
86
- fn: SecretToPromiseFunction<Secret, Response>,
87
- options?: SecretOptions
88
- ): Promise<Response | void> {
89
- if (!secretId) {
90
- console.error(missingSecretErrorText);
91
- return Promise.reject(missingSecretErrorText);
92
- }
93
-
94
- if (!cachedSecret) {
95
- // if prefix is given, first set db values and then fetch secret
96
- if (options?.prefix) {
97
- // first set db values
98
- await withSecret(secretId, (fetchedSecret: DbSecret) => {
99
- setDbSecret(fetchedSecret);
100
- });
101
-
102
- // then actual secret
103
- await withSecretAndPrefix(
104
- secretId,
105
- options.prefix,
106
- (fetchedSecret: Secret) => {
107
- cachedSecret = fetchedSecret;
108
- }
109
- );
110
- } else {
111
- await withSecret(secretId, (fetchedSecret: DbSecret) => {
112
- setDbSecret(fetchedSecret);
113
- cachedSecret = fetchedSecret;
114
- });
115
- }
116
- }
117
- try {
118
- if (options?.expectedKeys?.length) {
119
- checkExpectedSecretKeys(options.expectedKeys, cachedSecret);
120
- }
121
- return fn(cachedSecret);
122
- } catch (error) {
123
- console.error(
124
- "method=withDbSecret Caught an error, refreshing secret",
125
- error
126
- );
127
- // try to refetch secret in case it has changed
128
- await withSecret(secretId, (fetchedSecret: DbSecret) => {
129
- setDbSecret(fetchedSecret);
130
- cachedSecret = fetchedSecret;
131
- });
132
- return fn(cachedSecret);
133
- }
134
- }
135
-
136
20
  export function checkExpectedSecretKeys<Secret extends GenericSecret>(
137
21
  keys: string[],
138
22
  secret: Secret
@@ -1,10 +1,7 @@
1
1
  import { SecretHolder } from "./secret-holder";
2
- import {
3
- DatabaseEnvironmentKeys,
4
- RdsProxySecretKey,
5
- RdsProxySecret,
6
- } from "./dbsecret";
2
+ import { RdsProxySecretKey, RdsProxySecret } from "./dbsecret";
7
3
  import { getEnvVariable } from "../../../utils/utils";
4
+ import { DatabaseEnvironmentKeys } from "../../../database/database";
8
5
 
9
6
  const RDS_PROXY_SECRET_KEYS = Object.values(RdsProxySecretKey);
10
7
 
@@ -1,6 +1,7 @@
1
1
  import { SecretHolder } from "./secret-holder";
2
- import { DatabaseEnvironmentKeys, RdsSecret, RdsSecretKey } from "./dbsecret";
2
+ import { RdsSecret, RdsSecretKey } from "./dbsecret";
3
3
  import { getEnvVariable } from "../../../utils/utils";
4
+ import { DatabaseEnvironmentKeys } from "../../../database/database";
4
5
 
5
6
  const RDS_SECRET_KEYS = Object.values(RdsSecretKey);
6
7
 
@@ -1,12 +1,8 @@
1
1
  import { GenericSecret, getSecret } from "./secret";
2
- import {
3
- checkExpectedSecretKeys,
4
- DatabaseEnvironmentKeys,
5
- DbSecret,
6
- } from "./dbsecret";
2
+ import { checkExpectedSecretKeys } from "./dbsecret";
7
3
  import { getEnvVariable } from "../../../utils/utils";
8
4
 
9
- // eslint-disable-next-line @typescript-eslint/no-var-requires
5
+ // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-assignment
10
6
  const NodeTtl = require("node-ttl");
11
7
 
12
8
  const DEFAULT_PREFIX = "";
@@ -40,6 +36,7 @@ export class SecretHolder<Secret extends GenericSecret> {
40
36
  this.prefix = prefix;
41
37
  this.expectedKeys = expectedKeys;
42
38
 
39
+ // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
43
40
  this.secretCache = new NodeTtl(configuration);
44
41
  }
45
42
 
@@ -48,6 +45,7 @@ export class SecretHolder<Secret extends GenericSecret> {
48
45
 
49
46
  console.info("refreshing secret " + this.secretId);
50
47
 
48
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
51
49
  this.secretCache.push(DEFAULT_SECRET_KEY, secretValue);
52
50
  }
53
51
 
@@ -90,24 +88,14 @@ export class SecretHolder<Secret extends GenericSecret> {
90
88
  }
91
89
 
92
90
  private async getSecret<S>(): Promise<S> {
93
- const secret = this.secretCache.get(DEFAULT_SECRET_KEY);
91
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
92
+ const secret: S | undefined = this.secretCache.get(DEFAULT_SECRET_KEY);
94
93
 
95
94
  if (!secret) {
96
95
  await this.initSecret();
97
96
  }
98
97
 
99
- return secret || this.secretCache.get(DEFAULT_SECRET_KEY);
100
- }
101
-
102
- /**
103
- * @deprecated Use ProxyHolder
104
- */
105
- public async setDatabaseCredentials() {
106
- const secret = await this.getSecret<DbSecret>();
107
-
108
- process.env[DatabaseEnvironmentKeys.DB_USER] = secret.username;
109
- process.env[DatabaseEnvironmentKeys.DB_PASS] = secret.password;
110
- process.env[DatabaseEnvironmentKeys.DB_URI] = secret.host;
111
- process.env[DatabaseEnvironmentKeys.DB_RO_URI] = secret.ro_host;
98
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
99
+ return secret ?? (this.secretCache.get(DEFAULT_SECRET_KEY) as S);
112
100
  }
113
101
  }