@digitraffic/common 2024.1.24-3 → 2024.3.11-1

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 (212) hide show
  1. package/dist/__test__/api/handler-factory.test.d.mts +1 -0
  2. package/dist/__test__/api/handler-factory.test.mjs +43 -0
  3. package/dist/__test__/api/response.test.d.mts +1 -0
  4. package/dist/__test__/api/response.test.mjs +86 -0
  5. package/dist/__test__/imports.test.d.mts +1 -0
  6. package/dist/__test__/imports.test.mjs +332 -0
  7. package/dist/__test__/marine/id_utils.test.d.mts +1 -0
  8. package/dist/__test__/marine/id_utils.test.mjs +44 -0
  9. package/dist/__test__/promise/promise.test.d.mts +1 -0
  10. package/dist/__test__/promise/promise.test.mjs +130 -0
  11. package/dist/__test__/runtime/dt-logger.test.d.mts +1 -0
  12. package/dist/__test__/runtime/dt-logger.test.mjs +108 -0
  13. package/dist/__test__/secrets/secret-holder.test.d.mts +1 -0
  14. package/dist/__test__/secrets/secret-holder.test.mjs +86 -0
  15. package/dist/__test__/secrets/secret.test.d.mts +1 -0
  16. package/dist/__test__/secrets/secret.test.mjs +38 -0
  17. package/dist/__test__/test/httpserver.test.d.mts +1 -0
  18. package/dist/__test__/test/httpserver.test.mjs +154 -0
  19. package/dist/__test__/test/mock-ky.test.d.mts +1 -0
  20. package/dist/__test__/test/mock-ky.test.mjs +46 -0
  21. package/dist/__test__/types/lambda-response.test.d.mts +1 -0
  22. package/dist/__test__/types/lambda-response.test.mjs +58 -0
  23. package/dist/__test__/utils/date-utils.test.d.mts +1 -0
  24. package/dist/__test__/utils/date-utils.test.mjs +27 -0
  25. package/dist/__test__/utils/geometry.test.d.mts +1 -0
  26. package/dist/__test__/utils/geometry.test.mjs +24 -0
  27. package/dist/__test__/utils/logging.test.d.mts +1 -0
  28. package/dist/__test__/utils/logging.test.mjs +78 -0
  29. package/dist/__test__/utils/utils.test.d.mts +1 -0
  30. package/dist/__test__/utils/utils.test.mjs +43 -0
  31. package/dist/aws/infra/api/handler-factory.mjs +4 -0
  32. package/dist/aws/infra/api/integration.d.mts +2 -2
  33. package/dist/aws/infra/api/integration.mjs +4 -1
  34. package/dist/aws/infra/api/response.d.mts +1 -1
  35. package/dist/aws/infra/api/responses.d.mts +1 -1
  36. package/dist/aws/infra/api/responses.mjs +2 -0
  37. package/dist/aws/infra/api/static-integration.mjs +1 -1
  38. package/dist/aws/infra/canaries/canary-alarm.d.mts +1 -1
  39. package/dist/aws/infra/canaries/canary-alarm.mjs +2 -0
  40. package/dist/aws/infra/canaries/canary-parameters.mjs +1 -1
  41. package/dist/aws/infra/canaries/canary-role.mjs +1 -0
  42. package/dist/aws/infra/canaries/canary.d.mts +2 -2
  43. package/dist/aws/infra/canaries/canary.mjs +2 -0
  44. package/dist/aws/infra/canaries/database-canary.d.mts +2 -2
  45. package/dist/aws/infra/canaries/database-canary.mjs +2 -0
  46. package/dist/aws/infra/canaries/database-checker.d.mts +1 -1
  47. package/dist/aws/infra/canaries/database-checker.mjs +7 -1
  48. package/dist/aws/infra/canaries/url-canary.d.mts +2 -2
  49. package/dist/aws/infra/canaries/url-canary.mjs +3 -0
  50. package/dist/aws/infra/canaries/url-checker.d.mts +1 -1
  51. package/dist/aws/infra/canaries/url-checker.mjs +4 -1
  52. package/dist/aws/infra/documentation.mjs +5 -1
  53. package/dist/aws/infra/import-util.d.mts +1 -1
  54. package/dist/aws/infra/import-util.mjs +4 -3
  55. package/dist/aws/infra/scheduler.mjs +2 -0
  56. package/dist/aws/infra/security-rule.d.mts +1 -1
  57. package/dist/aws/infra/security-rule.mjs +1 -0
  58. package/dist/aws/infra/sqs-integration.d.mts +1 -1
  59. package/dist/aws/infra/sqs-integration.mjs +3 -1
  60. package/dist/aws/infra/sqs-queue.d.mts +1 -1
  61. package/dist/aws/infra/sqs-queue.mjs +2 -1
  62. package/dist/aws/infra/stack/lambda-configs.d.mts +4 -4
  63. package/dist/aws/infra/stack/lambda-configs.mjs +4 -2
  64. package/dist/aws/infra/stack/monitoredfunction.d.mts +3 -3
  65. package/dist/aws/infra/stack/monitoredfunction.mjs +23 -18
  66. package/dist/aws/infra/stack/parameters.mjs +1 -0
  67. package/dist/aws/infra/stack/rest_apis.d.mts +2 -2
  68. package/dist/aws/infra/stack/rest_apis.mjs +6 -1
  69. package/dist/aws/infra/stack/stack-checking-aspect.d.mts +2 -2
  70. package/dist/aws/infra/stack/stack-checking-aspect.mjs +6 -1
  71. package/dist/aws/infra/stack/stack.d.mts +5 -5
  72. package/dist/aws/infra/stack/stack.mjs +9 -0
  73. package/dist/aws/infra/stack/subscription.mjs +4 -0
  74. package/dist/aws/infra/stacks/db-dns-stack.d.mts +1 -1
  75. package/dist/aws/infra/stacks/db-dns-stack.mjs +1 -0
  76. package/dist/aws/infra/stacks/db-proxy-stack.d.mts +3 -3
  77. package/dist/aws/infra/stacks/db-proxy-stack.mjs +4 -2
  78. package/dist/aws/infra/stacks/db-stack.d.mts +3 -3
  79. package/dist/aws/infra/stacks/db-stack.mjs +11 -7
  80. package/dist/aws/infra/stacks/intra-stack-configuration.d.mts +1 -1
  81. package/dist/aws/infra/stacks/network-stack.d.mts +2 -2
  82. package/dist/aws/infra/stacks/network-stack.mjs +8 -0
  83. package/dist/aws/infra/usage-plans.d.mts +1 -1
  84. package/dist/aws/infra/usage-plans.mjs +1 -0
  85. package/dist/aws/runtime/apikey.d.mts +2 -2
  86. package/dist/aws/runtime/apikey.mjs +2 -2
  87. package/dist/aws/runtime/digitraffic-integration-response.d.mts +1 -1
  88. package/dist/aws/runtime/dt-logger.mjs +6 -2
  89. package/dist/aws/runtime/messaging.d.mts +2 -2
  90. package/dist/aws/runtime/messaging.mjs +5 -4
  91. package/dist/aws/runtime/s3.d.mts +4 -2
  92. package/dist/aws/runtime/s3.mjs +15 -10
  93. package/dist/aws/runtime/secrets/dbsecret.d.mts +1 -1
  94. package/dist/aws/runtime/secrets/proxy-holder.mjs +1 -0
  95. package/dist/aws/runtime/secrets/rds-holder.mjs +1 -0
  96. package/dist/aws/runtime/secrets/secret-holder.d.mts +1 -1
  97. package/dist/aws/runtime/secrets/secret-holder.mjs +6 -1
  98. package/dist/aws/runtime/secrets/secret.mjs +5 -6
  99. package/dist/aws/types/errors.mjs +1 -0
  100. package/dist/aws/types/lambda-response.mjs +5 -0
  101. package/dist/aws/types/model-with-reference.mjs +1 -1
  102. package/dist/database/cached.d.mts +1 -1
  103. package/dist/database/database.mjs +1 -0
  104. package/dist/database/last-updated.d.mts +1 -1
  105. package/dist/test/db-testutils.d.mts +1 -1
  106. package/dist/test/db-testutils.mjs +1 -1
  107. package/dist/test/httpserver.mjs +7 -3
  108. package/dist/test/mock-ky.d.mts +2 -0
  109. package/dist/test/mock-ky.mjs +15 -0
  110. package/dist/test/secrets-manager.d.mts +3 -2
  111. package/dist/test/secrets-manager.mjs +14 -16
  112. package/dist/test/testutils.mjs +1 -1
  113. package/dist/types/http-error.mjs +1 -0
  114. package/dist/types/nullable.d.mts +1 -1
  115. package/dist/utils/api-model.d.mts +2 -2
  116. package/dist/utils/api-model.mjs +1 -1
  117. package/dist/utils/geojson-types.d.mts +1 -1
  118. package/dist/utils/geojson-types.mjs +4 -2
  119. package/dist/utils/geometry.d.mts +1 -1
  120. package/dist/utils/geometry.mjs +3 -0
  121. package/dist/utils/logging.mjs +2 -2
  122. package/dist/utils/retry.d.mts +2 -2
  123. package/dist/utils/retry.mjs +2 -2
  124. package/dist/utils/slack.mjs +4 -3
  125. package/dist/utils/utils.d.mts +2 -2
  126. package/package.json +25 -15
  127. package/src/@types/geojson-validation/index.d.mts +0 -4
  128. package/src/aws/infra/api/handler-factory.mts +0 -86
  129. package/src/aws/infra/api/integration.mts +0 -147
  130. package/src/aws/infra/api/response.mts +0 -165
  131. package/src/aws/infra/api/responses.mts +0 -127
  132. package/src/aws/infra/api/static-integration.mts +0 -108
  133. package/src/aws/infra/canaries/Synthetics.d.mts +0 -21
  134. package/src/aws/infra/canaries/canary-alarm.mts +0 -33
  135. package/src/aws/infra/canaries/canary-keys.mts +0 -3
  136. package/src/aws/infra/canaries/canary-parameters.mts +0 -19
  137. package/src/aws/infra/canaries/canary-role.mts +0 -73
  138. package/src/aws/infra/canaries/canary.mts +0 -44
  139. package/src/aws/infra/canaries/database-canary.mts +0 -98
  140. package/src/aws/infra/canaries/database-checker.mts +0 -163
  141. package/src/aws/infra/canaries/url-canary.mts +0 -98
  142. package/src/aws/infra/canaries/url-checker.mts +0 -388
  143. package/src/aws/infra/documentation.mts +0 -142
  144. package/src/aws/infra/import-util.mts +0 -57
  145. package/src/aws/infra/scheduler.mts +0 -59
  146. package/src/aws/infra/security-rule.mts +0 -38
  147. package/src/aws/infra/sqs-integration.mts +0 -106
  148. package/src/aws/infra/sqs-queue.mts +0 -162
  149. package/src/aws/infra/stack/lambda-configs.mts +0 -135
  150. package/src/aws/infra/stack/monitoredfunction.mts +0 -352
  151. package/src/aws/infra/stack/parameters.mts +0 -74
  152. package/src/aws/infra/stack/rest_apis.mts +0 -322
  153. package/src/aws/infra/stack/stack-checking-aspect.mts +0 -233
  154. package/src/aws/infra/stack/stack.mts +0 -144
  155. package/src/aws/infra/stack/subscription.mts +0 -58
  156. package/src/aws/infra/stacks/db-dns-stack.mts +0 -77
  157. package/src/aws/infra/stacks/db-proxy-stack.mts +0 -134
  158. package/src/aws/infra/stacks/db-stack.mts +0 -292
  159. package/src/aws/infra/stacks/intra-stack-configuration.mts +0 -6
  160. package/src/aws/infra/stacks/network-stack.mts +0 -76
  161. package/src/aws/infra/usage-plans.mts +0 -50
  162. package/src/aws/runtime/apikey.mts +0 -9
  163. package/src/aws/runtime/digitraffic-integration-response.mts +0 -35
  164. package/src/aws/runtime/dt-logger-default.mts +0 -11
  165. package/src/aws/runtime/dt-logger.mts +0 -184
  166. package/src/aws/runtime/environment.mts +0 -22
  167. package/src/aws/runtime/messaging.mts +0 -26
  168. package/src/aws/runtime/s3.mts +0 -44
  169. package/src/aws/runtime/secrets/dbsecret.mts +0 -31
  170. package/src/aws/runtime/secrets/node-ttl.d.mts +0 -12
  171. package/src/aws/runtime/secrets/proxy-holder.mts +0 -34
  172. package/src/aws/runtime/secrets/rds-holder.mts +0 -34
  173. package/src/aws/runtime/secrets/secret-holder.mts +0 -106
  174. package/src/aws/runtime/secrets/secret.mts +0 -58
  175. package/src/aws/types/errors.mts +0 -14
  176. package/src/aws/types/lambda-response.mts +0 -100
  177. package/src/aws/types/mediatypes.mts +0 -12
  178. package/src/aws/types/model-with-reference.mts +0 -8
  179. package/src/aws/types/proxytypes.mts +0 -27
  180. package/src/aws/types/tags.mts +0 -3
  181. package/src/database/cached.mts +0 -64
  182. package/src/database/database.mts +0 -107
  183. package/src/database/last-updated.mts +0 -103
  184. package/src/database/models.mts +0 -7
  185. package/src/index.mts +0 -2
  186. package/src/marine/id_utils.mts +0 -30
  187. package/src/marine/rtz.mts +0 -57
  188. package/src/test/asserter.mts +0 -58
  189. package/src/test/db-testutils.mts +0 -52
  190. package/src/test/httpserver.mts +0 -111
  191. package/src/test/secrets-manager.mts +0 -37
  192. package/src/test/testutils.mts +0 -39
  193. package/src/types/async-timeout-error.mts +0 -5
  194. package/src/types/aws-env.mts +0 -3
  195. package/src/types/either.mts +0 -9
  196. package/src/types/http-error.mts +0 -8
  197. package/src/types/input-error.mts +0 -2
  198. package/src/types/language.mts +0 -3
  199. package/src/types/nullable.mts +0 -21
  200. package/src/types/traffictype.mts +0 -8
  201. package/src/types/urn.mts +0 -1
  202. package/src/types/util-types.mts +0 -10
  203. package/src/types/validator.mts +0 -10
  204. package/src/utils/api-model.mts +0 -133
  205. package/src/utils/base64.mts +0 -16
  206. package/src/utils/date-utils.mts +0 -53
  207. package/src/utils/geojson-types.mts +0 -22
  208. package/src/utils/geometry.mts +0 -171
  209. package/src/utils/logging.mts +0 -75
  210. package/src/utils/retry.mts +0 -200
  211. package/src/utils/slack.mts +0 -26
  212. package/src/utils/utils.mts +0 -184
@@ -1,322 +0,0 @@
1
- import {
2
- CfnDocumentationPart,
3
- EndpointType,
4
- GatewayResponse,
5
- IResource,
6
- JsonSchema,
7
- MethodLoggingLevel,
8
- MockIntegration,
9
- Model,
10
- Resource,
11
- ResponseType,
12
- RestApi,
13
- RestApiProps,
14
- } from "aws-cdk-lib/aws-apigateway";
15
- import {
16
- AnyPrincipal,
17
- Effect,
18
- PolicyDocument,
19
- PolicyStatement,
20
- } from "aws-cdk-lib/aws-iam";
21
- import { Construct } from "constructs";
22
- import { getModelReference } from "../../../utils/api-model.mjs";
23
- import { MediaType } from "../../types/mediatypes.mjs";
24
- import { ModelWithReference } from "../../types/model-with-reference.mjs";
25
- import { DocumentationPart, DocumentationProperties } from "../documentation.mjs";
26
- import { createDefaultUsagePlan, createUsagePlan } from "../usage-plans.mjs";
27
- import { DigitrafficStack } from "./stack.mjs";
28
-
29
- import _ from "lodash";
30
-
31
- export class DigitrafficRestApi extends RestApi {
32
- readonly apiKeyIds: string[];
33
- readonly enableDocumentation: boolean;
34
-
35
- constructor(
36
- stack: DigitrafficStack,
37
- apiId: string,
38
- apiName: string,
39
- allowFromIpAddresses?: string[] | undefined,
40
- config?: Partial<RestApiProps>
41
- ) {
42
- const policyDocument =
43
- allowFromIpAddresses == null
44
- ? createDefaultPolicyDocument()
45
- : createIpRestrictionPolicyDocument(allowFromIpAddresses);
46
-
47
- // override default config with given extra config
48
- const apiConfig = {
49
- ...{
50
- deployOptions: {
51
- loggingLevel: MethodLoggingLevel.ERROR,
52
- },
53
- restApiName: apiName,
54
- endpointTypes: [EndpointType.REGIONAL],
55
- policy: policyDocument,
56
- },
57
- ...config,
58
- };
59
-
60
- super(stack, apiId, apiConfig);
61
-
62
- this.apiKeyIds = [];
63
- this.enableDocumentation =
64
- stack.configuration.stackFeatures?.enableDocumentation ?? true;
65
-
66
- add404Support(this, stack);
67
- }
68
-
69
- hostname(): string {
70
- return `${this.restApiId}.execute-api.${
71
- (this.stack as DigitrafficStack).region
72
- }.amazonaws.com`;
73
- }
74
-
75
- createUsagePlan(apiKeyId: string, apiKeyName: string): string {
76
- const newKeyId = createUsagePlan(this, apiKeyId, apiKeyName).keyId;
77
-
78
- this.apiKeyIds.push(newKeyId);
79
-
80
- return newKeyId;
81
- }
82
-
83
- createUsagePlanV2(apiName: string, apiKey?: string): string {
84
- const newKeyId = createDefaultUsagePlan(this, apiName, apiKey).keyId;
85
-
86
- this.apiKeyIds.push(newKeyId);
87
-
88
- return newKeyId;
89
- }
90
-
91
- addJsonModel(modelName: string, schema: JsonSchema) {
92
- return this.getModelWithReference(
93
- this.addModel(modelName, {
94
- contentType: MediaType.APPLICATION_JSON,
95
- modelName,
96
- schema,
97
- })
98
- );
99
- }
100
-
101
- addCSVModel(modelName: string) {
102
- return this.getModelWithReference(
103
- this.addModel(modelName, {
104
- contentType: MediaType.TEXT_CSV,
105
- modelName,
106
- schema: {},
107
- })
108
- );
109
- }
110
-
111
- private getModelWithReference(model: Model): ModelWithReference {
112
- return _.set(
113
- model,
114
- "modelReference",
115
- getModelReference(model.modelId, this.restApiId)
116
- ) as ModelWithReference;
117
- }
118
-
119
- private addDocumentationPart(
120
- resource: Resource,
121
- parameterName: string,
122
- resourceName: string,
123
- type: string,
124
- properties: DocumentationProperties
125
- ) {
126
- const location: CfnDocumentationPart.LocationProperty = {
127
- type,
128
- path: resource.path,
129
- name: type !== "METHOD" ? parameterName : undefined,
130
- };
131
-
132
- new CfnDocumentationPart(this.stack, resourceName, {
133
- restApiId: resource.api.restApiId,
134
- location,
135
- properties: JSON.stringify(properties),
136
- });
137
- }
138
-
139
- documentResource(
140
- resource: Resource,
141
- ...documentationPart: DocumentationPart[]
142
- ) {
143
- if (this.enableDocumentation) {
144
- documentationPart.forEach((dp) =>
145
- this.addDocumentationPart(
146
- resource,
147
- dp.parameterName,
148
- `${resource.path}.${dp.parameterName}.Documentation`,
149
- dp.type,
150
- dp.documentationProperties
151
- )
152
- );
153
- } else {
154
- console.info("Skipping documentation for %s", resource.path);
155
- }
156
- }
157
-
158
- /**
159
- * Add support for HTTP OPTIONS to an API GW resource,
160
- * this is required for preflight CORS requests made by browsers.
161
- * @param apiResource
162
- */
163
- addCorsOptions(apiResource: IResource): void {
164
- apiResource.addMethod(
165
- "OPTIONS",
166
- new MockIntegration({
167
- integrationResponses: [
168
- {
169
- statusCode: "200",
170
- responseParameters: {
171
- "method.response.header.Access-Control-Allow-Headers":
172
- "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,Digitraffic-User'",
173
- "method.response.header.Access-Control-Allow-Origin":
174
- "'*'",
175
- "method.response.header.Access-Control-Allow-Methods":
176
- "'OPTIONS,GET,HEAD'",
177
- },
178
- },
179
- ],
180
- requestTemplates: {
181
- "application/json": '{"statusCode": 200}',
182
- },
183
- }),
184
- {
185
- methodResponses: [
186
- {
187
- statusCode: "200",
188
- responseParameters: {
189
- "method.response.header.Access-Control-Allow-Headers":
190
- true,
191
- "method.response.header.Access-Control-Allow-Methods":
192
- true,
193
- "method.response.header.Access-Control-Allow-Origin":
194
- true,
195
- },
196
- },
197
- ],
198
- }
199
- );
200
- }
201
- }
202
-
203
- /**
204
- * Due to AWS API design API Gateway will always return 403 'Missing Authentication Token' for requests
205
- * with a non-existent endpoint. This function translates this response to a 404.
206
- * Requests with an invalid or missing API key are not affected (still return 403 'Forbidden').
207
- * @param restApi RestApi
208
- * @param stack Construct
209
- */
210
- export function add404Support(restApi: RestApi, stack: Construct) {
211
- new GatewayResponse(
212
- stack,
213
- `MissingAuthenticationTokenResponse-${restApi.restApiName}`,
214
- {
215
- restApi,
216
- type: ResponseType.MISSING_AUTHENTICATION_TOKEN,
217
- statusCode: "404",
218
- templates: {
219
- [MediaType.APPLICATION_JSON]: '{"message": "Not found"}',
220
- },
221
- }
222
- );
223
- }
224
-
225
- export function add401Support(restApi: RestApi, stack: Construct) {
226
- new GatewayResponse(
227
- stack,
228
- `AuthenticationFailedResponse-${restApi.restApiName}`,
229
- {
230
- restApi,
231
- type: ResponseType.UNAUTHORIZED,
232
- statusCode: "401",
233
- responseHeaders: {
234
- "WWW-Authenticate": "'Basic'",
235
- },
236
- }
237
- );
238
- }
239
-
240
- /**
241
- * Due to AWS API design API Gateway will always return 403 'Missing Authentication Token' for requests
242
- * with a non-existent endpoint. This function converts this response to a custom one.
243
- * Requests with an invalid or missing API key are not affected (still return 403 'Forbidden').
244
- * @param returnCode
245
- * @param message
246
- * @param restApi RestApi
247
- * @param stack Construct
248
- */
249
- export function setReturnCodeForMissingAuthenticationToken(
250
- returnCode: number,
251
- message: string,
252
- restApi: RestApi,
253
- stack: Construct
254
- ) {
255
- new GatewayResponse(
256
- stack,
257
- `MissingAuthenticationTokenResponse-${restApi.restApiName}`,
258
- {
259
- restApi,
260
- type: ResponseType.MISSING_AUTHENTICATION_TOKEN,
261
- statusCode: `${returnCode}`,
262
- templates: {
263
- [MediaType.APPLICATION_JSON]: `{"message": ${message}}`,
264
- },
265
- }
266
- );
267
- }
268
-
269
- export function createRestApi(
270
- stack: Construct,
271
- apiId: string,
272
- apiName: string,
273
- allowFromIpAddresses?: string[] | undefined
274
- ): RestApi {
275
- const policyDocument =
276
- allowFromIpAddresses == null
277
- ? createDefaultPolicyDocument()
278
- : createIpRestrictionPolicyDocument(allowFromIpAddresses);
279
- const restApi = new RestApi(stack, apiId, {
280
- deployOptions: {
281
- loggingLevel: MethodLoggingLevel.ERROR,
282
- },
283
- restApiName: apiName,
284
- endpointTypes: [EndpointType.REGIONAL],
285
- policy: policyDocument,
286
- });
287
- add404Support(restApi, stack);
288
- return restApi;
289
- }
290
-
291
- export function createDefaultPolicyDocument() {
292
- return new PolicyDocument({
293
- statements: [
294
- new PolicyStatement({
295
- effect: Effect.ALLOW,
296
- actions: ["execute-api:Invoke"],
297
- resources: ["*"],
298
- principals: [new AnyPrincipal()],
299
- }),
300
- ],
301
- });
302
- }
303
-
304
- export function createIpRestrictionPolicyDocument(
305
- allowFromIpAddresses: string[]
306
- ): PolicyDocument {
307
- return new PolicyDocument({
308
- statements: [
309
- new PolicyStatement({
310
- effect: Effect.ALLOW,
311
- conditions: {
312
- IpAddress: {
313
- "aws:SourceIp": allowFromIpAddresses,
314
- },
315
- },
316
- actions: ["execute-api:Invoke"],
317
- resources: ["*"],
318
- principals: [new AnyPrincipal()],
319
- }),
320
- ],
321
- });
322
- }
@@ -1,233 +0,0 @@
1
- import { Annotations, IAspect, Stack } from "aws-cdk-lib";
2
- import { CfnFunction, Runtime } from "aws-cdk-lib/aws-lambda";
3
- import { CfnBucket } from "aws-cdk-lib/aws-s3";
4
- import { DigitrafficStack, SOLUTION_KEY } from "./stack.mjs";
5
- import { IConstruct } from "constructs";
6
- import { CfnMethod, CfnResource } from "aws-cdk-lib/aws-apigateway";
7
- import { CfnQueue } from "aws-cdk-lib/aws-sqs";
8
- import { LogRetention } from "aws-cdk-lib/aws-logs";
9
- import { kebabCase } from "change-case";
10
- import _ from "lodash";
11
- import IntegrationProperty = CfnMethod.IntegrationProperty;
12
-
13
- const MAX_CONCURRENCY_LIMIT = 100;
14
- const NODE_RUNTIMES = [Runtime.NODEJS_20_X.name, Runtime.NODEJS_18_X.name];
15
-
16
- enum ResourceType {
17
- stackName = "STACK_NAME",
18
- reservedConcurrentConcurrency = "RESERVED_CONCURRENT_CONCURRENCY",
19
- functionTimeout = "FUNCTION_TIMEOUT",
20
- functionMemorySize = "FUNCTION_MEMORY_SIZE",
21
- functionRuntime = "FUNCTION_RUNTIME",
22
- functionName = "FUNCTION_NAME",
23
- tagSolution = "TAG_SOLUTION",
24
- bucketPublicity = "BUCKET_PUBLICITY",
25
- resourcePath = "RESOURCE_PATH",
26
- queueEncryption = "QUEUE_ENCRYPTION",
27
- logGroupRetention = "LOG_GROUP_RETENTION",
28
- }
29
-
30
- export class StackCheckingAspect implements IAspect {
31
- private readonly stackShortName?: string;
32
- private readonly whitelistedResources?: string[];
33
-
34
- constructor(stackShortName?: string, whitelistedResources?: string[]) {
35
- this.stackShortName = stackShortName;
36
- this.whitelistedResources = whitelistedResources;
37
- }
38
-
39
- static create(stack: DigitrafficStack) {
40
- return new StackCheckingAspect(
41
- stack.configuration.shortName,
42
- stack.configuration.whitelistedResources
43
- );
44
- }
45
-
46
- public visit(node: IConstruct): void {
47
- //console.info("visiting class " + node.constructor.name);
48
-
49
- this.checkStack(node);
50
- this.checkFunction(node);
51
- this.checkTags(node);
52
- this.checkBucket(node);
53
- this.checkResourceCasing(node);
54
- this.checkQueueEncryption(node);
55
- this.checkLogGroupRetention(node);
56
- }
57
-
58
- private isWhitelisted(key: string) {
59
- return this.whitelistedResources?.some((wl) => {
60
- return key.matchAll(new RegExp(wl, "g"));
61
- });
62
- }
63
-
64
- private addAnnotation(node: IConstruct, key: ResourceType | string, message: string, isError = true) {
65
- const resourceKey = `${node.node.path}/${key}`;
66
- const isWhiteListed = this.isWhitelisted(resourceKey);
67
- const annotationMessage = `${resourceKey}:${message}`;
68
-
69
- // error && whitelisted -> warning
70
- // warning && whitelisted -> nothing
71
- if (isError && !isWhiteListed) {
72
- Annotations.of(node).addError(annotationMessage);
73
- } else if ((!isError && !isWhiteListed) || (isError && isWhiteListed)) {
74
- Annotations.of(node).addWarning(annotationMessage);
75
- }
76
- }
77
-
78
- private checkStack(node: IConstruct) {
79
- if (node instanceof DigitrafficStack) {
80
- if (
81
- (node.stackName.includes("Test") || node.stackName.includes("Tst")) &&
82
- node.configuration.production
83
- ) {
84
- this.addAnnotation(node, ResourceType.stackName, "Production is set for Test-stack");
85
- }
86
-
87
- if (
88
- (node.stackName.includes("Prod") || node.stackName.includes("Prd")) &&
89
- !node.configuration.production
90
- ) {
91
- this.addAnnotation(
92
- node,
93
- ResourceType.stackName,
94
- "Production is not set for Production-stack"
95
- );
96
- }
97
- }
98
- }
99
-
100
- private checkFunction(node: IConstruct) {
101
- if (node instanceof CfnFunction) {
102
- if (!node.reservedConcurrentExecutions) {
103
- this.addAnnotation(
104
- node,
105
- ResourceType.reservedConcurrentConcurrency,
106
- "Function must have reservedConcurrentConcurrency"
107
- );
108
- } else if (node.reservedConcurrentExecutions > MAX_CONCURRENCY_LIMIT) {
109
- this.addAnnotation(
110
- node,
111
- ResourceType.reservedConcurrentConcurrency,
112
- "Function reservedConcurrentConcurrency too high!"
113
- );
114
- }
115
-
116
- if (!node.timeout) {
117
- this.addAnnotation(node, ResourceType.functionTimeout, "Function must have timeout");
118
- }
119
-
120
- if (!node.memorySize) {
121
- this.addAnnotation(node, ResourceType.functionMemorySize, "Function must have memorySize");
122
- }
123
-
124
- if (node.runtime !== undefined && !NODE_RUNTIMES.includes(node.runtime)) {
125
- this.addAnnotation(
126
- node,
127
- ResourceType.functionRuntime,
128
- `Function has wrong runtime ${node.runtime}!`
129
- );
130
- }
131
-
132
- if (
133
- this.stackShortName &&
134
- node.functionName &&
135
- !node.functionName.startsWith(this.stackShortName)
136
- ) {
137
- this.addAnnotation(
138
- node,
139
- ResourceType.functionName,
140
- `Function name does not begin with ${this.stackShortName}`
141
- );
142
- }
143
- }
144
- }
145
-
146
- private checkTags(node: IConstruct) {
147
- if (node instanceof Stack) {
148
- if (!node.tags.tagValues()[SOLUTION_KEY]) {
149
- this.addAnnotation(node, ResourceType.tagSolution, "Solution tag is missing");
150
- }
151
- }
152
- }
153
-
154
- private checkBucket(node: IConstruct) {
155
- if (node instanceof CfnBucket) {
156
- const c = node.publicAccessBlockConfiguration as
157
- | CfnBucket.PublicAccessBlockConfigurationProperty
158
- | undefined;
159
-
160
- if (
161
- c &&
162
- (!c.blockPublicAcls ||
163
- !c.blockPublicPolicy ||
164
- !c.ignorePublicAcls ||
165
- !c.restrictPublicBuckets)
166
- ) {
167
- this.addAnnotation(node, ResourceType.bucketPublicity, "Check bucket publicity");
168
- }
169
- }
170
- }
171
-
172
- private static isValidPath(path: string): boolean {
173
- // if path includes . or { check only the trailing part of path
174
- if (path.includes(".")) {
175
- return this.isValidPath(path.split(".")[0]);
176
- }
177
-
178
- if (path.includes("{")) {
179
- return this.isValidPath(path.split("{")[0]);
180
- }
181
-
182
- return kebabCase(path) === path;
183
- }
184
-
185
- private static isValidQueryString(name: string) {
186
- return _.snakeCase(name) === name;
187
- }
188
-
189
- private checkResourceCasing(node: IConstruct) {
190
- if (node instanceof CfnResource) {
191
- if (!StackCheckingAspect.isValidPath(node.pathPart)) {
192
- this.addAnnotation(node, ResourceType.resourcePath, "Path part should be in kebab-case");
193
- }
194
- } else if (node instanceof CfnMethod) {
195
- const integration = node.integration as IntegrationProperty | undefined;
196
-
197
- if (integration?.requestParameters) {
198
- Object.keys(integration.requestParameters).forEach((key) => {
199
- const split = key.split(".");
200
- const type = split[2];
201
- const name = split[3];
202
-
203
- if (type === "querystring" && !StackCheckingAspect.isValidQueryString(name)) {
204
- this.addAnnotation(node, name, "Querystring should be in snake_case");
205
- }
206
- });
207
- }
208
- }
209
- }
210
-
211
- private checkQueueEncryption(node: IConstruct) {
212
- if (node instanceof CfnQueue) {
213
- if (!node.kmsMasterKeyId) {
214
- this.addAnnotation(node, ResourceType.queueEncryption, "Queue must have encryption enabled");
215
- }
216
- }
217
- }
218
-
219
- private checkLogGroupRetention(node: IConstruct) {
220
- if (node instanceof LogRetention) {
221
- const child = node.node.defaultChild as unknown as Record<string, Record<string, string>>;
222
- const retention = child._cfnProperties.RetentionInDays;
223
-
224
- if (!retention) {
225
- this.addAnnotation(
226
- node,
227
- ResourceType.logGroupRetention,
228
- "Log group must define log group retention"
229
- );
230
- }
231
- }
232
- }
233
- }
@@ -1,144 +0,0 @@
1
- import { Aspects, Stack, StackProps } from "aws-cdk-lib";
2
- import { type ISecurityGroup, IVpc, SecurityGroup, Vpc } from "aws-cdk-lib/aws-ec2";
3
- import { ITopic, Topic } from "aws-cdk-lib/aws-sns";
4
- import { StringParameter } from "aws-cdk-lib/aws-ssm";
5
- import { ISecret, Secret } from "aws-cdk-lib/aws-secretsmanager";
6
- import { Function as AWSFunction } from "aws-cdk-lib/aws-lambda";
7
-
8
- import { StackCheckingAspect } from "./stack-checking-aspect.mjs";
9
- import { Construct } from "constructs";
10
- import { TrafficType } from "../../../types/traffictype.mjs";
11
- import { DBLambdaEnvironment } from "./lambda-configs.mjs";
12
-
13
- const SSM_ROOT = "/digitraffic";
14
- export const SOLUTION_KEY = "Solution";
15
- const MONITORING_ROOT = "/monitoring";
16
-
17
- export const SSM_KEY_WARNING_TOPIC = `${SSM_ROOT}${MONITORING_ROOT}/warning-topic`;
18
- export const SSM_KEY_ALARM_TOPIC = `${SSM_ROOT}${MONITORING_ROOT}/alarm-topic`;
19
-
20
- export interface StackConfiguration {
21
- readonly shortName: string;
22
- readonly secretId?: string;
23
- readonly alarmTopicArn: string;
24
- readonly warningTopicArn: string;
25
- readonly logsDestinationArn?: string;
26
-
27
- readonly vpcId?: string;
28
- readonly lambdaDbSgId?: string;
29
- readonly privateSubnetIds?: string[];
30
- readonly availabilityZones?: string[];
31
-
32
- readonly trafficType: TrafficType;
33
- readonly production: boolean;
34
- readonly stackProps: StackProps;
35
-
36
- readonly stackFeatures?: {
37
- readonly enableCanaries?: boolean;
38
- readonly enableDocumentation?: boolean;
39
- };
40
-
41
- /// whitelist resources for StackCheckingAspect
42
- readonly whitelistedResources?: string[];
43
- }
44
-
45
- export class DigitrafficStack extends Stack {
46
- readonly vpc?: IVpc;
47
- readonly lambdaDbSg?: ISecurityGroup;
48
- readonly alarmTopic: ITopic;
49
- readonly warningTopic: ITopic;
50
- readonly secret?: ISecret;
51
-
52
- readonly configuration: StackConfiguration;
53
-
54
- constructor(
55
- scope: Construct,
56
- id: string,
57
- configuration: StackConfiguration
58
- ) {
59
- super(scope, id, configuration.stackProps);
60
-
61
- this.configuration = configuration;
62
-
63
- if (configuration.secretId) {
64
- this.secret = Secret.fromSecretNameV2(
65
- this,
66
- "Secret",
67
- configuration.secretId
68
- );
69
- }
70
-
71
- // VPC reference construction requires vpcId and availability zones
72
- // private subnets are used in Lambda configuration
73
- if (configuration.vpcId) {
74
- this.vpc = Vpc.fromVpcAttributes(this, "vpc", {
75
- vpcId: configuration.vpcId,
76
- privateSubnetIds: configuration.privateSubnetIds,
77
- availabilityZones: configuration.availabilityZones ?? [],
78
- });
79
- }
80
-
81
- // security group that allows Lambda database access
82
- if (configuration.lambdaDbSgId) {
83
- this.lambdaDbSg = SecurityGroup.fromSecurityGroupId(
84
- this,
85
- "LambdaDbSG",
86
- configuration.lambdaDbSgId
87
- );
88
- }
89
-
90
- this.alarmTopic = Topic.fromTopicArn(
91
- this,
92
- "AlarmTopic",
93
- StringParameter.fromStringParameterName(
94
- this,
95
- "AlarmTopicParam",
96
- SSM_KEY_ALARM_TOPIC
97
- ).stringValue
98
- );
99
- this.warningTopic = Topic.fromTopicArn(
100
- this,
101
- "WarningTopic",
102
- StringParameter.fromStringParameterName(
103
- this,
104
- "WarningTopicParam",
105
- SSM_KEY_WARNING_TOPIC
106
- ).stringValue
107
- );
108
-
109
- this.addAspects();
110
- }
111
-
112
- addAspects() {
113
- Aspects.of(this).add(StackCheckingAspect.create(this));
114
- }
115
-
116
- createLambdaEnvironment(): DBLambdaEnvironment {
117
- return this.createDefaultLambdaEnvironment(
118
- this.configuration.shortName
119
- );
120
- }
121
-
122
- createDefaultLambdaEnvironment(dbApplication: string): DBLambdaEnvironment {
123
- return this.configuration.secretId
124
- ? {
125
- SECRET_ID: this.configuration.secretId,
126
- DB_APPLICATION: dbApplication,
127
- }
128
- : {
129
- DB_APPLICATION: dbApplication,
130
- };
131
- }
132
-
133
- getSecret(): ISecret {
134
- if (this.secret === undefined) {
135
- throw new Error("Secret is undefined");
136
- }
137
- return this.secret;
138
- }
139
-
140
- grantSecret(...lambdas: AWSFunction[]) {
141
- const secret = this.getSecret();
142
- lambdas.forEach((l: AWSFunction) => secret.grantRead(l));
143
- }
144
- }