@aws-solutions-constructs/aws-lambda-kinesisstreams 2.30.0
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.
- package/.eslintignore +5 -0
- package/.jsii +3655 -0
- package/README.md +121 -0
- package/architecture.png +0 -0
- package/lib/index.d.ts +90 -0
- package/lib/index.js +64 -0
- package/package.json +92 -0
- package/test/integ.existingLambda.d.ts +13 -0
- package/test/integ.existingLambda.expected.json +232 -0
- package/test/integ.existingLambda.js +31 -0
- package/test/integ.existingStream.d.ts +13 -0
- package/test/integ.existingStream.expected.json +231 -0
- package/test/integ.existingStream.js +37 -0
- package/test/integ.existingStreamWithCmk.d.ts +13 -0
- package/test/integ.existingStreamWithCmk.expected.json +300 -0
- package/test/integ.existingStreamWithCmk.js +39 -0
- package/test/integ.existingVpc.d.ts +13 -0
- package/test/integ.existingVpc.expected.json +1068 -0
- package/test/integ.existingVpc.js +34 -0
- package/test/integ.newStreamFromProps.d.ts +13 -0
- package/test/integ.newStreamFromProps.expected.json +231 -0
- package/test/integ.newStreamFromProps.js +34 -0
- package/test/integ.newVpc.d.ts +13 -0
- package/test/integ.newVpc.expected.json +674 -0
- package/test/integ.newVpc.js +31 -0
- package/test/integ.newVpcFromProps.d.ts +13 -0
- package/test/integ.newVpcFromProps.expected.json +560 -0
- package/test/integ.newVpcFromProps.js +34 -0
- package/test/integ.noArguments.d.ts +13 -0
- package/test/integ.noArguments.expected.json +232 -0
- package/test/integ.noArguments.js +30 -0
- package/test/lambda/index.mjs +15 -0
- package/test/lambda-kinesisstream.test.d.ts +13 -0
- package/test/lambda-kinesisstream.test.js +472 -0
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance
|
|
6
|
+
* with the License. A copy of the License is located at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES
|
|
11
|
+
* OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions
|
|
12
|
+
* and limitations under the License.
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const lib_1 = require("../lib");
|
|
16
|
+
const lambda = require("aws-cdk-lib/aws-lambda");
|
|
17
|
+
const cdk = require("aws-cdk-lib");
|
|
18
|
+
const ec2 = require("aws-cdk-lib/aws-ec2");
|
|
19
|
+
const kinesis = require("aws-cdk-lib/aws-kinesis");
|
|
20
|
+
const kms = require("aws-cdk-lib/aws-kms");
|
|
21
|
+
require("@aws-cdk/assert/jest");
|
|
22
|
+
const assertions_1 = require("aws-cdk-lib/assertions");
|
|
23
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
24
|
+
test('Default construct has all expected properties', () => {
|
|
25
|
+
const stack = new cdk.Stack();
|
|
26
|
+
const construct = new lib_1.LambdaToKinesisStreams(stack, 'test-lambda-kinesisstreams', {
|
|
27
|
+
lambdaFunctionProps: {
|
|
28
|
+
code: lambda.Code.fromAsset(`${__dirname}/lambda`),
|
|
29
|
+
runtime: lambda.Runtime.NODEJS_18_X,
|
|
30
|
+
handler: 'index.handler'
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
expect(construct.lambdaFunction).toBeDefined();
|
|
34
|
+
expect(construct.kinesisStream).toBeDefined();
|
|
35
|
+
expect(construct.cloudwatchAlarms).toBeDefined();
|
|
36
|
+
// By default, we don't create a VPC
|
|
37
|
+
expect(construct.vpc).toBeUndefined();
|
|
38
|
+
});
|
|
39
|
+
test('New VPC is created when deployVpc flag is true', () => {
|
|
40
|
+
const stack = new cdk.Stack();
|
|
41
|
+
new lib_1.LambdaToKinesisStreams(stack, 'test-lambda-kinesisstreams', {
|
|
42
|
+
lambdaFunctionProps: {
|
|
43
|
+
code: lambda.Code.fromAsset(`${__dirname}/lambda`),
|
|
44
|
+
runtime: lambda.Runtime.NODEJS_18_X,
|
|
45
|
+
handler: 'index.handler'
|
|
46
|
+
},
|
|
47
|
+
deployVpc: true
|
|
48
|
+
});
|
|
49
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
50
|
+
// Get the VPC created by the construct
|
|
51
|
+
const vpcResource = template.findResources('AWS::EC2::VPC');
|
|
52
|
+
const [vpcId] = Object.keys(vpcResource);
|
|
53
|
+
verifyLambdaFunctionVpcProps(stack, template, vpcId);
|
|
54
|
+
});
|
|
55
|
+
test('Existing VPC is used when specified', () => {
|
|
56
|
+
const stack = new cdk.Stack();
|
|
57
|
+
const existingVpc = new ec2.Vpc(stack, 'test-vpc', {
|
|
58
|
+
vpcName: 'my-vpc-name'
|
|
59
|
+
});
|
|
60
|
+
new lib_1.LambdaToKinesisStreams(stack, 'test-lambda-kinesisstreams', {
|
|
61
|
+
lambdaFunctionProps: {
|
|
62
|
+
code: lambda.Code.fromAsset(`${__dirname}/lambda`),
|
|
63
|
+
runtime: lambda.Runtime.NODEJS_18_X,
|
|
64
|
+
handler: 'index.handler'
|
|
65
|
+
},
|
|
66
|
+
existingVpc
|
|
67
|
+
});
|
|
68
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
69
|
+
// Get the VPC by its name
|
|
70
|
+
const vpcResource = template.findResources('AWS::EC2::VPC', {
|
|
71
|
+
Properties: {
|
|
72
|
+
Name: 'my-vpc-name'
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
const [vpcId] = Object.keys(vpcResource);
|
|
76
|
+
verifyLambdaFunctionVpcProps(stack, template, vpcId);
|
|
77
|
+
});
|
|
78
|
+
test('New VPC is created from user-provided vpcProps', () => {
|
|
79
|
+
const stack = new cdk.Stack();
|
|
80
|
+
new lib_1.LambdaToKinesisStreams(stack, 'test-lambda-kinesisstreams', {
|
|
81
|
+
lambdaFunctionProps: {
|
|
82
|
+
code: lambda.Code.fromAsset(`${__dirname}/lambda`),
|
|
83
|
+
runtime: lambda.Runtime.NODEJS_18_X,
|
|
84
|
+
handler: 'index.handler'
|
|
85
|
+
},
|
|
86
|
+
vpcProps: {
|
|
87
|
+
vpcName: 'my-vpc-name'
|
|
88
|
+
},
|
|
89
|
+
deployVpc: true
|
|
90
|
+
});
|
|
91
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
92
|
+
// Get the VPC by its name
|
|
93
|
+
const vpcResource = template.findResources('AWS::EC2::VPC', {
|
|
94
|
+
Properties: {
|
|
95
|
+
Name: 'my-vpc-name'
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
const [vpcId] = Object.keys(vpcResource);
|
|
99
|
+
verifyLambdaFunctionVpcProps(stack, template, vpcId);
|
|
100
|
+
});
|
|
101
|
+
test('Lambda Function has default stream environment variable', () => {
|
|
102
|
+
const stack = new cdk.Stack();
|
|
103
|
+
new lib_1.LambdaToKinesisStreams(stack, 'test-lambda-kinesisstreams', {
|
|
104
|
+
lambdaFunctionProps: {
|
|
105
|
+
code: lambda.Code.fromAsset(`${__dirname}/lambda`),
|
|
106
|
+
runtime: lambda.Runtime.NODEJS_18_X,
|
|
107
|
+
handler: 'index.handler'
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
111
|
+
// Get Kinesis Data Stream created by the construct
|
|
112
|
+
const kinesisStream = template.findResources('AWS::Kinesis::Stream');
|
|
113
|
+
const [kinesisStreamId] = Object.keys(kinesisStream);
|
|
114
|
+
expect(stack).toHaveResourceLike('AWS::Lambda::Function', {
|
|
115
|
+
Environment: {
|
|
116
|
+
Variables: {
|
|
117
|
+
KINESIS_DATASTREAM_NAME: {
|
|
118
|
+
Ref: kinesisStreamId
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
test('Lambda Function stream name environment variable can be overridden', () => {
|
|
125
|
+
const stack = new cdk.Stack();
|
|
126
|
+
new lib_1.LambdaToKinesisStreams(stack, 'test-lambda-kinesisstreams', {
|
|
127
|
+
lambdaFunctionProps: {
|
|
128
|
+
code: lambda.Code.fromAsset(`${__dirname}/lambda`),
|
|
129
|
+
runtime: lambda.Runtime.NODEJS_18_X,
|
|
130
|
+
handler: 'index.handler'
|
|
131
|
+
},
|
|
132
|
+
streamEnvironmentVariableName: 'CUSTOM_ENV_VAR_NAME'
|
|
133
|
+
});
|
|
134
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
135
|
+
// Get Kinesis Data Stream created by the construct
|
|
136
|
+
const kinesisStream = template.findResources('AWS::Kinesis::Stream');
|
|
137
|
+
const [kinesisStreamId] = Object.keys(kinesisStream);
|
|
138
|
+
expect(stack).toHaveResourceLike('AWS::Lambda::Function', {
|
|
139
|
+
Environment: {
|
|
140
|
+
Variables: {
|
|
141
|
+
CUSTOM_ENV_VAR_NAME: {
|
|
142
|
+
Ref: kinesisStreamId
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
test('Kinesis Stream is encrypted with AWS-managed CMK by default', () => {
|
|
149
|
+
const stack = new cdk.Stack();
|
|
150
|
+
new lib_1.LambdaToKinesisStreams(stack, 'test-lambda-kinesisstreams', {
|
|
151
|
+
lambdaFunctionProps: {
|
|
152
|
+
code: lambda.Code.fromAsset(`${__dirname}/lambda`),
|
|
153
|
+
runtime: lambda.Runtime.NODEJS_18_X,
|
|
154
|
+
handler: 'index.handler'
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
expect(stack).toHaveResourceLike('AWS::Kinesis::Stream', {
|
|
158
|
+
StreamEncryption: {
|
|
159
|
+
EncryptionType: 'KMS',
|
|
160
|
+
KeyId: 'alias/aws/kinesis'
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
test('CloudWatch Alarms are created for Kinesis Stream by default', () => {
|
|
165
|
+
const stack = new cdk.Stack();
|
|
166
|
+
new lib_1.LambdaToKinesisStreams(stack, 'test-lambda-kinesisstreams', {
|
|
167
|
+
lambdaFunctionProps: {
|
|
168
|
+
code: lambda.Code.fromAsset(`${__dirname}/lambda`),
|
|
169
|
+
runtime: lambda.Runtime.NODEJS_18_X,
|
|
170
|
+
handler: 'index.handler'
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
expect(stack).toHaveResourceLike('AWS::CloudWatch::Alarm', {
|
|
174
|
+
Namespace: 'AWS/Kinesis',
|
|
175
|
+
MetricName: 'GetRecords.IteratorAgeMilliseconds'
|
|
176
|
+
});
|
|
177
|
+
expect(stack).toHaveResourceLike('AWS::CloudWatch::Alarm', {
|
|
178
|
+
Namespace: 'AWS/Kinesis',
|
|
179
|
+
MetricName: 'ReadProvisionedThroughputExceeded'
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
test('CloudWatch Alarms are not created when createCloudWatchAlarms property is set to false', () => {
|
|
183
|
+
const stack = new cdk.Stack();
|
|
184
|
+
new lib_1.LambdaToKinesisStreams(stack, 'test-lambda-kinesisstreams', {
|
|
185
|
+
lambdaFunctionProps: {
|
|
186
|
+
code: lambda.Code.fromAsset(`${__dirname}/lambda`),
|
|
187
|
+
runtime: lambda.Runtime.NODEJS_18_X,
|
|
188
|
+
handler: 'index.handler'
|
|
189
|
+
},
|
|
190
|
+
createCloudWatchAlarms: false
|
|
191
|
+
});
|
|
192
|
+
expect(stack).toCountResources('AWS::CloudWatch::Alarm', 0);
|
|
193
|
+
});
|
|
194
|
+
test('Error is thrown when vpc is specified and existing lambda function is not associated with it', () => {
|
|
195
|
+
const stack = new aws_cdk_lib_1.Stack();
|
|
196
|
+
const existingLambdaObj = new lambda.Function(stack, 'test-lamba', {
|
|
197
|
+
code: lambda.Code.fromAsset(`${__dirname}/lambda`),
|
|
198
|
+
runtime: lambda.Runtime.NODEJS_18_X,
|
|
199
|
+
handler: 'index.handler'
|
|
200
|
+
});
|
|
201
|
+
const existingVpc = new ec2.Vpc(stack, 'test-vpc', {});
|
|
202
|
+
const app = () => {
|
|
203
|
+
new lib_1.LambdaToKinesisStreams(stack, 'lambda-to-sqs-stack', {
|
|
204
|
+
existingLambdaObj,
|
|
205
|
+
existingVpc
|
|
206
|
+
});
|
|
207
|
+
};
|
|
208
|
+
expect(app).toThrowError();
|
|
209
|
+
});
|
|
210
|
+
test('Construct uses existing Lambda Function', () => {
|
|
211
|
+
const stack = new aws_cdk_lib_1.Stack();
|
|
212
|
+
const existingLambdaObj = new lambda.Function(stack, 'test-lamba', {
|
|
213
|
+
code: lambda.Code.fromAsset(`${__dirname}/lambda`),
|
|
214
|
+
runtime: lambda.Runtime.NODEJS_18_X,
|
|
215
|
+
handler: 'index.handler',
|
|
216
|
+
functionName: 'my-lambda-function'
|
|
217
|
+
});
|
|
218
|
+
new lib_1.LambdaToKinesisStreams(stack, 'lambda-to-sqs-stack', {
|
|
219
|
+
existingLambdaObj
|
|
220
|
+
});
|
|
221
|
+
expect(stack).toHaveResourceLike('AWS::Lambda::Function', {
|
|
222
|
+
FunctionName: 'my-lambda-function'
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
test('Construct uses existing Kinesis Stream', () => {
|
|
226
|
+
const stack = new aws_cdk_lib_1.Stack();
|
|
227
|
+
const existingStreamObj = new kinesis.Stream(stack, 'test-stream', {
|
|
228
|
+
streamName: 'my-stream',
|
|
229
|
+
});
|
|
230
|
+
new lib_1.LambdaToKinesisStreams(stack, 'test-lambda-kinesisstreams', {
|
|
231
|
+
lambdaFunctionProps: {
|
|
232
|
+
code: lambda.Code.fromAsset(`${__dirname}/lambda`),
|
|
233
|
+
runtime: lambda.Runtime.NODEJS_18_X,
|
|
234
|
+
handler: 'index.handler'
|
|
235
|
+
},
|
|
236
|
+
existingStreamObj
|
|
237
|
+
});
|
|
238
|
+
expect(stack).toHaveResourceLike('AWS::Kinesis::Stream', {
|
|
239
|
+
Name: 'my-stream'
|
|
240
|
+
});
|
|
241
|
+
expect(stack).toCountResources('AWS::Kinesis::Stream', 1);
|
|
242
|
+
});
|
|
243
|
+
test('Construct uses unencrypted existing stream', () => {
|
|
244
|
+
const stack = new aws_cdk_lib_1.Stack();
|
|
245
|
+
const existingStreamObj = new kinesis.Stream(stack, 'test-stream', {
|
|
246
|
+
streamName: 'my-stream',
|
|
247
|
+
encryption: kinesis.StreamEncryption.UNENCRYPTED
|
|
248
|
+
});
|
|
249
|
+
new lib_1.LambdaToKinesisStreams(stack, 'test-lambda-kinesisstreams', {
|
|
250
|
+
lambdaFunctionProps: {
|
|
251
|
+
code: lambda.Code.fromAsset(`${__dirname}/lambda`),
|
|
252
|
+
runtime: lambda.Runtime.NODEJS_18_X,
|
|
253
|
+
handler: 'index.handler'
|
|
254
|
+
},
|
|
255
|
+
existingStreamObj
|
|
256
|
+
});
|
|
257
|
+
expect(stack).not.toHaveResourceLike('AWS::Kinesis::Stream', {
|
|
258
|
+
StreamEncryption: {
|
|
259
|
+
EncryptionType: 'KMS',
|
|
260
|
+
KeyId: 'alias/aws/kinesis'
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
expect(stack).toCountResources('AWS::Kinesis::Stream', 1);
|
|
264
|
+
});
|
|
265
|
+
test('Construct uses unencrypted streams from stream props', () => {
|
|
266
|
+
const stack = new aws_cdk_lib_1.Stack();
|
|
267
|
+
new lib_1.LambdaToKinesisStreams(stack, 'test-lambda-kinesisstreams', {
|
|
268
|
+
lambdaFunctionProps: {
|
|
269
|
+
code: lambda.Code.fromAsset(`${__dirname}/lambda`),
|
|
270
|
+
runtime: lambda.Runtime.NODEJS_18_X,
|
|
271
|
+
handler: 'index.handler'
|
|
272
|
+
},
|
|
273
|
+
kinesisStreamProps: {
|
|
274
|
+
streamName: 'my-stream',
|
|
275
|
+
encryption: kinesis.StreamEncryption.UNENCRYPTED
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
expect(stack).not.toHaveResourceLike('AWS::Kinesis::Stream', {
|
|
279
|
+
StreamEncryption: {
|
|
280
|
+
EncryptionType: 'KMS',
|
|
281
|
+
KeyId: 'alias/aws/kinesis'
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
expect(stack).toCountResources('AWS::Kinesis::Stream', 1);
|
|
285
|
+
});
|
|
286
|
+
test('Construct grants PutRecord permission for the Lambda Function to write to the Kinesis Stream', () => {
|
|
287
|
+
const stack = new aws_cdk_lib_1.Stack();
|
|
288
|
+
new lib_1.LambdaToKinesisStreams(stack, 'test-lambda-kinesisstreams', {
|
|
289
|
+
lambdaFunctionProps: {
|
|
290
|
+
code: lambda.Code.fromAsset(`${__dirname}/lambda`),
|
|
291
|
+
runtime: lambda.Runtime.NODEJS_18_X,
|
|
292
|
+
handler: 'index.handler'
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
296
|
+
// Get Kinesis Data Stream created by the construct
|
|
297
|
+
const kinesisStream = template.findResources('AWS::Kinesis::Stream');
|
|
298
|
+
const [kinesisStreamId] = Object.keys(kinesisStream);
|
|
299
|
+
expect(stack).toHaveResourceLike('AWS::IAM::Policy', {
|
|
300
|
+
PolicyDocument: {
|
|
301
|
+
Statement: [
|
|
302
|
+
{
|
|
303
|
+
Action: [
|
|
304
|
+
'xray:PutTraceSegments',
|
|
305
|
+
'xray:PutTelemetryRecords'
|
|
306
|
+
],
|
|
307
|
+
Effect: 'Allow',
|
|
308
|
+
Resource: '*'
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
Action: [
|
|
312
|
+
'kinesis:ListShards',
|
|
313
|
+
'kinesis:PutRecord',
|
|
314
|
+
'kinesis:PutRecords'
|
|
315
|
+
],
|
|
316
|
+
Effect: 'Allow',
|
|
317
|
+
Resource: {
|
|
318
|
+
'Fn::GetAtt': [
|
|
319
|
+
kinesisStreamId,
|
|
320
|
+
'Arn'
|
|
321
|
+
]
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
]
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
});
|
|
328
|
+
test('When a Customer-manged CMK is used on an existing stream, construct grants the Lambda Function permission to use the encryption key so it can publish messages to it', () => {
|
|
329
|
+
const stack = new aws_cdk_lib_1.Stack();
|
|
330
|
+
const encryptionKey = new kms.Key(stack, 'Key', {
|
|
331
|
+
description: 'my-key-description'
|
|
332
|
+
});
|
|
333
|
+
const existingStreamObj = new kinesis.Stream(stack, 'test-stream', {
|
|
334
|
+
streamName: 'my-stream',
|
|
335
|
+
encryptionKey
|
|
336
|
+
});
|
|
337
|
+
new lib_1.LambdaToKinesisStreams(stack, 'test-lambda-kinesisstreams', {
|
|
338
|
+
lambdaFunctionProps: {
|
|
339
|
+
code: lambda.Code.fromAsset(`${__dirname}/lambda`),
|
|
340
|
+
runtime: lambda.Runtime.NODEJS_18_X,
|
|
341
|
+
handler: 'index.handler'
|
|
342
|
+
},
|
|
343
|
+
existingStreamObj
|
|
344
|
+
});
|
|
345
|
+
const template = assertions_1.Template.fromStack(stack);
|
|
346
|
+
const resource = template.findResources('AWS::KMS::Key', {
|
|
347
|
+
Properties: {
|
|
348
|
+
Description: assertions_1.Match.exact('my-key-description')
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
const [kmsKey] = Object.keys(resource);
|
|
352
|
+
expect(stack).toHaveResourceLike('AWS::IAM::Policy', {
|
|
353
|
+
PolicyDocument: {
|
|
354
|
+
Statement: [
|
|
355
|
+
{
|
|
356
|
+
Action: [
|
|
357
|
+
'xray:PutTraceSegments',
|
|
358
|
+
'xray:PutTelemetryRecords'
|
|
359
|
+
],
|
|
360
|
+
Effect: 'Allow',
|
|
361
|
+
Resource: '*'
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
Action: [
|
|
365
|
+
'kinesis:ListShards',
|
|
366
|
+
'kinesis:PutRecord',
|
|
367
|
+
'kinesis:PutRecords'
|
|
368
|
+
],
|
|
369
|
+
Effect: 'Allow',
|
|
370
|
+
Resource: {
|
|
371
|
+
'Fn::GetAtt': [
|
|
372
|
+
'teststream04374A09',
|
|
373
|
+
'Arn'
|
|
374
|
+
]
|
|
375
|
+
}
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
Action: [
|
|
379
|
+
'kms:Encrypt',
|
|
380
|
+
'kms:ReEncrypt*',
|
|
381
|
+
'kms:GenerateDataKey*'
|
|
382
|
+
],
|
|
383
|
+
Effect: 'Allow',
|
|
384
|
+
Resource: {
|
|
385
|
+
'Fn::GetAtt': [
|
|
386
|
+
kmsKey,
|
|
387
|
+
'Arn'
|
|
388
|
+
]
|
|
389
|
+
}
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
Action: [
|
|
393
|
+
'kms:Decrypt',
|
|
394
|
+
'kms:GenerateDataKey*'
|
|
395
|
+
],
|
|
396
|
+
Effect: 'Allow',
|
|
397
|
+
Resource: {
|
|
398
|
+
'Fn::GetAtt': [
|
|
399
|
+
kmsKey,
|
|
400
|
+
'Arn'
|
|
401
|
+
]
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
]
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
});
|
|
408
|
+
function verifyLambdaFunctionVpcProps(stack, template, vpcId) {
|
|
409
|
+
// Get the Security Group associated with the VPC
|
|
410
|
+
const securityGroupResource = template.findResources('AWS::EC2::SecurityGroup', {
|
|
411
|
+
Properties: {
|
|
412
|
+
VpcId: {
|
|
413
|
+
Ref: assertions_1.Match.exact(vpcId)
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
const [securityGroupId] = Object.keys(securityGroupResource);
|
|
418
|
+
// Get the Subnets associated with the VPC
|
|
419
|
+
const subnetResources = template.findResources('AWS::EC2::Subnet', {
|
|
420
|
+
Properties: {
|
|
421
|
+
VpcId: {
|
|
422
|
+
Ref: assertions_1.Match.exact(vpcId)
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
const [subnet1, subnet2] = Object.keys(subnetResources);
|
|
427
|
+
// Verify the Lambda Function has the same Security Group
|
|
428
|
+
expect(stack).toHaveResourceLike('AWS::Lambda::Function', {
|
|
429
|
+
VpcConfig: {
|
|
430
|
+
SecurityGroupIds: [
|
|
431
|
+
{
|
|
432
|
+
'Fn::GetAtt': [
|
|
433
|
+
securityGroupId,
|
|
434
|
+
'GroupId'
|
|
435
|
+
]
|
|
436
|
+
}
|
|
437
|
+
],
|
|
438
|
+
SubnetIds: [
|
|
439
|
+
{
|
|
440
|
+
Ref: subnet1
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
Ref: subnet2
|
|
444
|
+
}
|
|
445
|
+
]
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
// Verify the VPC has an interface endpoint for Kinesis Streams
|
|
449
|
+
expect(stack).toHaveResourceLike('AWS::EC2::VPCEndpoint', {
|
|
450
|
+
ServiceName: {
|
|
451
|
+
'Fn::Join': [
|
|
452
|
+
'',
|
|
453
|
+
[
|
|
454
|
+
'com.amazonaws.',
|
|
455
|
+
{
|
|
456
|
+
Ref: 'AWS::Region'
|
|
457
|
+
},
|
|
458
|
+
'.kinesis-streams'
|
|
459
|
+
]
|
|
460
|
+
]
|
|
461
|
+
},
|
|
462
|
+
VpcId: {
|
|
463
|
+
Ref: vpcId
|
|
464
|
+
},
|
|
465
|
+
});
|
|
466
|
+
// Verify the VPC has dns hostnames and support enabled
|
|
467
|
+
expect(stack).toHaveResource('AWS::EC2::VPC', {
|
|
468
|
+
EnableDnsHostnames: true,
|
|
469
|
+
EnableDnsSupport: true,
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGFtYmRhLWtpbmVzaXNzdHJlYW0udGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImxhbWJkYS1raW5lc2lzc3RyZWFtLnRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7Ozs7OztHQVdHOztBQUVILGdDQUFnRDtBQUNoRCxpREFBaUQ7QUFDakQsbUNBQW1DO0FBQ25DLDJDQUEyQztBQUMzQyxtREFBbUQ7QUFDbkQsMkNBQTJDO0FBQzNDLGdDQUE4QjtBQUM5Qix1REFBeUQ7QUFDekQsNkNBQW9DO0FBRXBDLElBQUksQ0FBQywrQ0FBK0MsRUFBRSxHQUFHLEVBQUU7SUFDekQsTUFBTSxLQUFLLEdBQUcsSUFBSSxHQUFHLENBQUMsS0FBSyxFQUFFLENBQUM7SUFFOUIsTUFBTSxTQUFTLEdBQUcsSUFBSSw0QkFBc0IsQ0FBQyxLQUFLLEVBQUUsNEJBQTRCLEVBQUU7UUFDaEYsbUJBQW1CLEVBQUU7WUFDbkIsSUFBSSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsU0FBUyxTQUFTLENBQUM7WUFDbEQsT0FBTyxFQUFFLE1BQU0sQ0FBQyxPQUFPLENBQUMsV0FBVztZQUNuQyxPQUFPLEVBQUUsZUFBZTtTQUN6QjtLQUNGLENBQUMsQ0FBQztJQUVILE1BQU0sQ0FBQyxTQUFTLENBQUMsY0FBYyxDQUFDLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDL0MsTUFBTSxDQUFDLFNBQVMsQ0FBQyxhQUFhLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUM5QyxNQUFNLENBQUMsU0FBUyxDQUFDLGdCQUFnQixDQUFDLENBQUMsV0FBVyxFQUFFLENBQUM7SUFFakQsb0NBQW9DO0lBQ3BDLE1BQU0sQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUMsYUFBYSxFQUFFLENBQUM7QUFDeEMsQ0FBQyxDQUFDLENBQUM7QUFFSCxJQUFJLENBQUMsZ0RBQWdELEVBQUUsR0FBRyxFQUFFO0lBQzFELE1BQU0sS0FBSyxH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QUNFLEdBQUcsRUFBRSxPQUFPO2lCQUNiO2FBQ0Y7U0FDRjtLQUNGLENBQUMsQ0FBQztJQUVILCtEQUErRDtJQUMvRCxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsa0JBQWtCLENBQUMsdUJBQXVCLEVBQUU7UUFDeEQsV0FBVyxFQUFFO1lBQ1gsVUFBVSxFQUFFO2dCQUNWLEVBQUU7Z0JBQ0Y7b0JBQ0UsZ0JBQWdCO29CQUNoQjt3QkFDRSxHQUFHLEVBQUUsYUFBYTtxQkFDbkI7b0JBQ0Qsa0JBQWtCO2lCQUNuQjthQUNGO1NBQ0Y7UUFDRCxLQUFLLEVBQUU7WUFDTCxHQUFHLEVBQUUsS0FBSztTQUNYO0tBQ0YsQ0FBQyxDQUFDO0lBRUgsdURBQXVEO0lBQ3ZELE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxjQUFjLENBQUMsZUFBZSxFQUFFO1FBQzVDLGtCQUFrQixFQUFFLElBQUk7UUFDeEIsZ0JBQWdCLEVBQUUsSUFBSTtLQUN2QixDQUFDLENBQUM7QUFDTCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiAgQ29weXJpZ2h0IEFtYXpvbi5jb20sIEluYy4gb3IgaXRzIGFmZmlsaWF0ZXMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIikuIFlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2VcbiAqICB3aXRoIHRoZSBMaWNlbnNlLiBBIGNvcHkgb2YgdGhlIExpY2Vuc2UgaXMgbG9jYXRlZCBhdFxuICpcbiAqICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogIG9yIGluIHRoZSAnbGljZW5zZScgZmlsZSBhY2NvbXBhbnlpbmcgdGhpcyBmaWxlLiBUaGlzIGZpbGUgaXMgZGlzdHJpYnV0ZWQgb24gYW4gJ0FTIElTJyBCQVNJUywgV0lUSE9VVCBXQVJSQU5USUVTXG4gKiAgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZXhwcmVzcyBvciBpbXBsaWVkLiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnNcbiAqICBhbmQgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKi9cblxuaW1wb3J0IHsgTGFtYmRhVG9LaW5lc2lzU3RyZWFtcyB9IGZyb20gXCIuLi9saWJcIjtcbmltcG9ydCAqIGFzIGxhbWJkYSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtbGFtYmRhJztcbmltcG9ydCAqIGFzIGNkayBmcm9tIFwiYXdzLWNkay1saWJcIjtcbmltcG9ydCAqIGFzIGVjMiBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWVjMlwiO1xuaW1wb3J0ICogYXMga2luZXNpcyBmcm9tICdhd3MtY2RrLWxpYi9hd3Mta2luZXNpcyc7XG5pbXBvcnQgKiBhcyBrbXMgZnJvbSAnYXdzLWNkay1saWIvYXdzLWttcyc7XG5pbXBvcnQgJ0Bhd3MtY2RrL2Fzc2VydC9qZXN0JztcbmltcG9ydCB7IE1hdGNoLCBUZW1wbGF0ZSB9IGZyb20gXCJhd3MtY2RrLWxpYi9hc3NlcnRpb25zXCI7XG5pbXBvcnQgeyBTdGFjayB9IGZyb20gXCJhd3MtY2RrLWxpYlwiO1xuXG50ZXN0KCdEZWZhdWx0IGNvbnN0cnVjdCBoYXMgYWxsIGV4cGVjdGVkIHByb3BlcnRpZXMnLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIGNvbnN0IGNvbnN0cnVjdCA9IG5ldyBMYW1iZGFUb0tpbmVzaXNTdHJlYW1zKHN0YWNrLCAndGVzdC1sYW1iZGEta2luZXNpc3N0cmVhbXMnLCB7XG4gICAgbGFtYmRhRnVuY3Rpb25Qcm9wczoge1xuICAgICAgY29kZTogbGFtYmRhLkNvZGUuZnJvbUFzc2V0KGAke19fZGlybmFtZX0vbGFtYmRhYCksXG4gICAgICBydW50aW1lOiBsYW1iZGEuUnVudGltZS5OT0RFSlNfMThfWCxcbiAgICAgIGhhbmRsZXI6ICdpbmRleC5oYW5kbGVyJ1xuICAgIH1cbiAgfSk7XG5cbiAgZXhwZWN0KGNvbnN0cnVjdC5sYW1iZGFGdW5jdGlvbikudG9CZURlZmluZWQoKTtcbiAgZXhwZWN0KGNvbnN0cnVjdC5raW5lc2lzU3RyZWFtKS50b0JlRGVmaW5lZCgpO1xuICBleHBlY3QoY29uc3RydWN0LmNsb3Vkd2F0Y2hBbGFybXMpLnRvQmVEZWZpbmVkKCk7XG5cbiAgLy8gQnkgZGVmYXVsdCwgd2UgZG9uJ3QgY3JlYXRlIGEgVlBDXG4gIGV4cGVjdChjb25zdHJ1Y3QudnBjKS50b0JlVW5kZWZpbmVkKCk7XG59KTtcblxudGVzdCgnTmV3IFZQQyBpcyBjcmVhdGVkIHdoZW4gZGVwbG95VnBjIGZsYWcgaXMgdHJ1ZScsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG5cbiAgbmV3IExhbWJkYVRvS2luZXNpc1N0cmVhbXMoc3RhY2ssICd0ZXN0LWxhbWJkYS1raW5lc2lzc3RyZWFtcycsIHtcbiAgICBsYW1iZGFGdW5jdGlvblByb3BzOiB7XG4gICAgICBjb2RlOiBsYW1iZGEuQ29kZS5mcm9tQXNzZXQoYCR7X19kaXJuYW1lfS9sYW1iZGFgKSxcbiAgICAgIHJ1bnRpbWU6IGxhbWJkYS5SdW50aW1lLk5PREVKU18xOF9YLFxuICAgICAgaGFuZGxlcjogJ2luZGV4LmhhbmRsZXInXG4gICAgfSxcbiAgICBkZXBsb3lWcGM6IHRydWVcbiAgfSk7XG5cbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuXG4gIC8vIEdldCB0aGUgVlBDIGNyZWF0ZWQgYnkgdGhlIGNvbnN0cnVjdFxuICBjb25zdCB2cGNSZXNvdXJjZSA9IHRlbXBsYXRlLmZpbmRSZXNvdXJjZXMoJ0FXUzo6RUMyOjpWUEMnKTtcbiAgY29uc3QgWyB2cGNJZCBdID0gT2JqZWN0LmtleXModnBjUmVzb3VyY2UpO1xuXG4gIHZlcmlmeUxhbWJkYUZ1bmN0aW9uVnBjUHJvcHMoc3RhY2ssIHRlbXBsYXRlLCB2cGNJZCk7XG59KTtcblxudGVzdCgnRXhpc3RpbmcgVlBDIGlzIHVzZWQgd2hlbiBzcGVjaWZpZWQnLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIGNvbnN0IGV4aXN0aW5nVnBjID0gbmV3IGVjMi5WcGMoc3RhY2ssICd0ZXN0LXZwYycsIHtcbiAgICB2cGNOYW1lOiAnbXktdnBjLW5hbWUnXG4gIH0pO1xuXG4gIG5ldyBMYW1iZGFUb0tpbmVzaXNTdHJlYW1zKHN0YWNrLCAndGVzdC1sYW1iZGEta2luZXNpc3N0cmVhbXMnLCB7XG4gICAgbGFtYmRhRnVuY3Rpb25Qcm9wczoge1xuICAgICAgY29kZTogbGFtYmRhLkNvZGUuZnJvbUFzc2V0KGAke19fZGlybmFtZX0vbGFtYmRhYCksXG4gICAgICBydW50aW1lOiBsYW1iZGEuUnVudGltZS5OT0RFSlNfMThfWCxcbiAgICAgIGhhbmRsZXI6ICdpbmRleC5oYW5kbGVyJ1xuICAgIH0sXG4gICAgZXhpc3RpbmdWcGNcbiAgfSk7XG5cbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuXG4gIC8vIEdldCB0aGUgVlBDIGJ5IGl0cyBuYW1lXG4gIGNvbnN0IHZwY1Jlc291cmNlID0gdGVtcGxhdGUuZmluZFJlc291cmNlcygnQVdTOjpFQzI6OlZQQycsIHtcbiAgICBQcm9wZXJ0aWVzOiB7XG4gICAgICBOYW1lOiAnbXktdnBjLW5hbWUnXG4gICAgfVxuICB9KTtcbiAgY29uc3QgWyB2cGNJZCBdID0gT2JqZWN0LmtleXModnBjUmVzb3VyY2UpO1xuXG4gIHZlcmlmeUxhbWJkYUZ1bmN0aW9uVnBjUHJvcHMoc3RhY2ssIHRlbXBsYXRlLCB2cGNJZCk7XG59KTtcblxudGVzdCgnTmV3IFZQQyBpcyBjcmVhdGVkIGZyb20gdXNlci1wcm92aWRlZCB2cGNQcm9wcycsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG5cbiAgbmV3IExhbWJkYVRvS2luZXNpc1N0cmVhbXMoc3RhY2ssICd0ZXN0LWxhbWJkYS1raW5lc2lzc3RyZWFtcycsIHtcbiAgICBsYW1iZGFGdW5jdGlvblByb3BzOiB7XG4gICAgICBjb2RlOiBsYW1iZGEuQ29kZS5mcm9tQXNzZXQoYCR7X19kaXJuYW1lfS9sYW1iZGFgKSxcbiAgICAgIHJ1bnRpbWU6IGxhbWJkYS5SdW50aW1lLk5PREVKU18xOF9YLFxuICAgICAgaGFuZGxlcjogJ2luZGV4LmhhbmRsZXInXG4gICAgfSxcbiAgICB2cGNQcm9wczoge1xuICAgICAgdnBjTmFtZTogJ215LXZwYy1uYW1lJ1xuICAgIH0sXG4gICAgZGVwbG95VnBjOiB0cnVlXG4gIH0pO1xuXG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcblxuICAvLyBHZXQgdGhlIFZQQyBieSBpdHMgbmFtZVxuICBjb25zdCB2cGNSZXNvdXJjZSA9IHRlbXBsYXRlLmZpbmRSZXNvdXJjZXMoJ0FXUzo6RUMyOjpWUEMnLCB7XG4gICAgUHJvcGVydGllczoge1xuICAgICAgTmFtZTogJ215LXZwYy1uYW1lJ1xuICAgIH1cbiAgfSk7XG4gIGNvbnN0IFsgdnBjSWQgXSA9IE9iamVjdC5rZXlzKHZwY1Jlc291cmNlKTtcblxuICB2ZXJpZnlMYW1iZGFGdW5jdGlvblZwY1Byb3BzKHN0YWNrLCB0ZW1wbGF0ZSwgdnBjSWQpO1xufSk7XG5cbnRlc3QoJ0xhbWJkYSBGdW5jdGlvbiBoYXMgZGVmYXVsdCBzdHJlYW0gZW52aXJvbm1lbnQgdmFyaWFibGUnLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIG5ldyBMYW1iZGFUb0tpbmVzaXNTdHJlYW1zKHN0YWNrLCAndGVzdC1sYW1iZGEta2luZXNpc3N0cmVhbXMnLCB7XG4gICAgbGFtYmRhRnVuY3Rpb25Qcm9wczoge1xuICAgICAgY29kZTogbGFtYmRhLkNvZGUuZnJvbUFzc2V0KGAke19fZGlybmFtZX0vbGFtYmRhYCksXG4gICAgICBydW50aW1lOiBsYW1iZGEuUnVudGltZS5OT0RFSlNfMThfWCxcbiAgICAgIGhhbmRsZXI6ICdpbmRleC5oYW5kbGVyJ1xuICAgIH1cbiAgfSk7XG5cbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuXG4gIC8vIEdldCBLaW5lc2lzIERhdGEgU3RyZWFtIGNyZWF0ZWQgYnkgdGhlIGNvbnN0cnVjdFxuICBjb25zdCBraW5lc2lzU3RyZWFtID0gdGVtcGxhdGUuZmluZFJlc291cmNlcygnQVdTOjpLaW5lc2lzOjpTdHJlYW0nKTtcbiAgY29uc3QgWyBraW5lc2lzU3RyZWFtSWQgXSA9IE9iamVjdC5rZXlzKGtpbmVzaXNTdHJlYW0pO1xuXG4gIGV4cGVjdChzdGFjaykudG9IYXZlUmVzb3VyY2VMaWtlKCdBV1M6OkxhbWJkYTo6RnVuY3Rpb24nLCB7XG4gICAgRW52aXJvbm1lbnQ6IHtcbiAgICAgIFZhcmlhYmxlczoge1xuICAgICAgICBLSU5FU0lTX0RBVEFTVFJFQU1fTkFNRToge1xuICAgICAgICAgIFJlZjoga2luZXNpc1N0cmVhbUlkXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH0pO1xufSk7XG5cbnRlc3QoJ0xhbWJkYSBGdW5jdGlvbiBzdHJlYW0gbmFtZSBlbnZpcm9ubWVudCB2YXJpYWJsZSBjYW4gYmUgb3ZlcnJpZGRlbicsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgY2RrLlN0YWNrKCk7XG5cbiAgbmV3IExhbWJkYVRvS2luZXNpc1N0cmVhbXMoc3RhY2ssICd0ZXN0LWxhbWJkYS1raW5lc2lzc3RyZWFtcycsIHtcbiAgICBsYW1iZGFGdW5jdGlvblByb3BzOiB7XG4gICAgICBjb2RlOiBsYW1iZGEuQ29kZS5mcm9tQXNzZXQoYCR7X19kaXJuYW1lfS9sYW1iZGFgKSxcbiAgICAgIHJ1bnRpbWU6IGxhbWJkYS5SdW50aW1lLk5PREVKU18xOF9YLFxuICAgICAgaGFuZGxlcjogJ2luZGV4LmhhbmRsZXInXG4gICAgfSxcbiAgICBzdHJlYW1FbnZpcm9ubWVudFZhcmlhYmxlTmFtZTogJ0NVU1RPTV9FTlZfVkFSX05BTUUnXG4gIH0pO1xuXG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcblxuICAvLyBHZXQgS2luZXNpcyBEYXRhIFN0cmVhbSBjcmVhdGVkIGJ5IHRoZSBjb25zdHJ1Y3RcbiAgY29uc3Qga2luZXNpc1N0cmVhbSA9IHRlbXBsYXRlLmZpbmRSZXNvdXJjZXMoJ0FXUzo6S2luZXNpczo6U3RyZWFtJyk7XG4gIGNvbnN0IFsga2luZXNpc1N0cmVhbUlkIF0gPSBPYmplY3Qua2V5cyhraW5lc2lzU3RyZWFtKTtcblxuICBleHBlY3Qoc3RhY2spLnRvSGF2ZVJlc291cmNlTGlrZSgnQVdTOjpMYW1iZGE6OkZ1bmN0aW9uJywge1xuICAgIEVudmlyb25tZW50OiB7XG4gICAgICBWYXJpYWJsZXM6IHtcbiAgICAgICAgQ1VTVE9NX0VOVl9WQVJfTkFNRToge1xuICAgICAgICAgIFJlZjoga2luZXNpc1N0cmVhbUlkXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH0pO1xufSk7XG5cbnRlc3QoJ0tpbmVzaXMgU3RyZWFtIGlzIGVuY3J5cHRlZCB3aXRoIEFXUy1tYW5hZ2VkIENNSyBieSBkZWZhdWx0JywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBjZGsuU3RhY2soKTtcblxuICBuZXcgTGFtYmRhVG9LaW5lc2lzU3RyZWFtcyhzdGFjaywgJ3Rlc3QtbGFtYmRhLWtpbmVzaXNzdHJlYW1zJywge1xuICAgIGxhbWJkYUZ1bmN0aW9uUHJvcHM6IHtcbiAgICAgIGNvZGU6IGxhbWJkYS5Db2RlLmZyb21Bc3NldChgJHtfX2Rpcm5hbWV9L2xhbWJkYWApLFxuICAgICAgcnVudGltZTogbGFtYmRhLlJ1bnRpbWUuTk9ERUpTXzE4X1gsXG4gICAgICBoYW5kbGVyOiAnaW5kZXguaGFuZGxlcidcbiAgICB9XG4gIH0pO1xuXG4gIGV4cGVjdChzdGFjaykudG9IYXZlUmVzb3VyY2VMaWtlKCdBV1M6OktpbmVzaXM6OlN0cmVhbScsIHtcbiAgICBTdHJlYW1FbmNyeXB0aW9uOiB7XG4gICAgICBFbmNyeXB0aW9uVHlwZTogJ0tNUycsXG4gICAgICBLZXlJZDogJ2FsaWFzL2F3cy9raW5lc2lzJ1xuICAgIH1cbiAgfSk7XG59KTtcblxudGVzdCgnQ2xvdWRXYXRjaCBBbGFybXMgYXJlIGNyZWF0ZWQgZm9yIEtpbmVzaXMgU3RyZWFtIGJ5IGRlZmF1bHQnLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIG5ldyBMYW1iZGFUb0tpbmVzaXNTdHJlYW1zKHN0YWNrLCAndGVzdC1sYW1iZGEta2luZXNpc3N0cmVhbXMnLCB7XG4gICAgbGFtYmRhRnVuY3Rpb25Qcm9wczoge1xuICAgICAgY29kZTogbGFtYmRhLkNvZGUuZnJvbUFzc2V0KGAke19fZGlybmFtZX0vbGFtYmRhYCksXG4gICAgICBydW50aW1lOiBsYW1iZGEuUnVudGltZS5OT0RFSlNfMThfWCxcbiAgICAgIGhhbmRsZXI6ICdpbmRleC5oYW5kbGVyJ1xuICAgIH1cbiAgfSk7XG5cbiAgZXhwZWN0KHN0YWNrKS50b0hhdmVSZXNvdXJjZUxpa2UoJ0FXUzo6Q2xvdWRXYXRjaDo6QWxhcm0nLCB7XG4gICAgTmFtZXNwYWNlOiAnQVdTL0tpbmVzaXMnLFxuICAgIE1ldHJpY05hbWU6ICdHZXRSZWNvcmRzLkl0ZXJhdG9yQWdlTWlsbGlzZWNvbmRzJ1xuICB9KTtcblxuICBleHBlY3Qoc3RhY2spLnRvSGF2ZVJlc291cmNlTGlrZSgnQVdTOjpDbG91ZFdhdGNoOjpBbGFybScsIHtcbiAgICBOYW1lc3BhY2U6ICdBV1MvS2luZXNpcycsXG4gICAgTWV0cmljTmFtZTogJ1JlYWRQcm92aXNpb25lZFRocm91Z2hwdXRFeGNlZWRlZCdcbiAgfSk7XG59KTtcblxudGVzdCgnQ2xvdWRXYXRjaCBBbGFybXMgYXJlIG5vdCBjcmVhdGVkIHdoZW4gY3JlYXRlQ2xvdWRXYXRjaEFsYXJtcyBwcm9wZXJ0eSBpcyBzZXQgdG8gZmFsc2UnLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IGNkay5TdGFjaygpO1xuXG4gIG5ldyBMYW1iZGFUb0tpbmVzaXNTdHJlYW1zKHN0YWNrLCAndGVzdC1sYW1iZGEta2luZXNpc3N0cmVhbXMnLCB7XG4gICAgbGFtYmRhRnVuY3Rpb25Qcm9wczoge1xuICAgICAgY29kZTogbGFtYmRhLkNvZGUuZnJvbUFzc2V0KGAke19fZGlybmFtZX0vbGFtYmRhYCksXG4gICAgICBydW50aW1lOiBsYW1iZGEuUnVudGltZS5OT0RFSlNfMThfWCxcbiAgICAgIGhhbmRsZXI6ICdpbmRleC5oYW5kbGVyJ1xuICAgIH0sXG4gICAgY3JlYXRlQ2xvdWRXYXRjaEFsYXJtczogZmFsc2VcbiAgfSk7XG5cbiAgZXhwZWN0KHN0YWNrKS50b0NvdW50UmVzb3VyY2VzKCdBV1M6OkNsb3VkV2F0Y2g6OkFsYXJtJywgMCk7XG59KTtcblxudGVzdCgnRXJyb3IgaXMgdGhyb3duIHdoZW4gdnBjIGlzIHNwZWNpZmllZCBhbmQgZXhpc3RpbmcgbGFtYmRhIGZ1bmN0aW9uIGlzIG5vdCBhc3NvY2lhdGVkIHdpdGggaXQnLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IFN0YWNrKCk7XG5cbiAgY29uc3QgZXhpc3RpbmdMYW1iZGFPYmogPSBuZXcgbGFtYmRhLkZ1bmN0aW9uKHN0YWNrLCAndGVzdC1sYW1iYScsIHtcbiAgICBjb2RlOiBsYW1iZGEuQ29kZS5mcm9tQXNzZXQoYCR7X19kaXJuYW1lfS9sYW1iZGFgKSxcbiAgICBydW50aW1lOiBsYW1iZGEuUnVudGltZS5OT0RFSlNfMThfWCxcbiAgICBoYW5kbGVyOiAnaW5kZXguaGFuZGxlcidcbiAgfSk7XG5cbiAgY29uc3QgZXhpc3RpbmdWcGMgPSBuZXcgZWMyLlZwYyhzdGFjaywgJ3Rlc3QtdnBjJywge30pO1xuXG4gIGNvbnN0IGFwcCA9ICgpID0+IHtcbiAgICBuZXcgTGFtYmRhVG9LaW5lc2lzU3RyZWFtcyhzdGFjaywgJ2xhbWJkYS10by1zcXMtc3RhY2snLCB7XG4gICAgICBleGlzdGluZ0xhbWJkYU9iaixcbiAgICAgIGV4aXN0aW5nVnBjXG4gICAgfSk7XG4gIH07XG5cbiAgZXhwZWN0KGFwcCkudG9UaHJvd0Vycm9yKCk7XG59KTtcblxudGVzdCgnQ29uc3RydWN0IHVzZXMgZXhpc3RpbmcgTGFtYmRhIEZ1bmN0aW9uJywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBTdGFjaygpO1xuXG4gIGNvbnN0IGV4aXN0aW5nTGFtYmRhT2JqID0gbmV3IGxhbWJkYS5GdW5jdGlvbihzdGFjaywgJ3Rlc3QtbGFtYmEnLCB7XG4gICAgY29kZTogbGFtYmRhLkNvZGUuZnJvbUFzc2V0KGAke19fZGlybmFtZX0vbGFtYmRhYCksXG4gICAgcnVudGltZTogbGFtYmRhLlJ1bnRpbWUuTk9ERUpTXzE4X1gsXG4gICAgaGFuZGxlcjogJ2luZGV4LmhhbmRsZXInLFxuICAgIGZ1bmN0aW9uTmFtZTogJ215LWxhbWJkYS1mdW5jdGlvbidcbiAgfSk7XG5cbiAgbmV3IExhbWJkYVRvS2luZXNpc1N0cmVhbXMoc3RhY2ssICdsYW1iZGEtdG8tc3FzLXN0YWNrJywge1xuICAgIGV4aXN0aW5nTGFtYmRhT2JqXG4gIH0pO1xuXG4gIGV4cGVjdChzdGFjaykudG9IYXZlUmVzb3VyY2VMaWtlKCdBV1M6OkxhbWJkYTo6RnVuY3Rpb24nLCB7XG4gICAgRnVuY3Rpb25OYW1lOiAnbXktbGFtYmRhLWZ1bmN0aW9uJ1xuICB9KTtcbn0pO1xuXG50ZXN0KCdDb25zdHJ1Y3QgdXNlcyBleGlzdGluZyBLaW5lc2lzIFN0cmVhbScsICgpID0+IHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgU3RhY2soKTtcblxuICBjb25zdCBleGlzdGluZ1N0cmVhbU9iaiA9IG5ldyBraW5lc2lzLlN0cmVhbShzdGFjaywgJ3Rlc3Qtc3RyZWFtJywge1xuICAgIHN0cmVhbU5hbWU6ICdteS1zdHJlYW0nLFxuICB9KTtcblxuICBuZXcgTGFtYmRhVG9LaW5lc2lzU3RyZWFtcyhzdGFjaywgJ3Rlc3QtbGFtYmRhLWtpbmVzaXNzdHJlYW1zJywge1xuICAgIGxhbWJkYUZ1bmN0aW9uUHJvcHM6IHtcbiAgICAgIGNvZGU6IGxhbWJkYS5Db2RlLmZyb21Bc3NldChgJHtfX2Rpcm5hbWV9L2xhbWJkYWApLFxuICAgICAgcnVudGltZTogbGFtYmRhLlJ1bnRpbWUuTk9ERUpTXzE4X1gsXG4gICAgICBoYW5kbGVyOiAnaW5kZXguaGFuZGxlcidcbiAgICB9LFxuICAgIGV4aXN0aW5nU3RyZWFtT2JqXG4gIH0pO1xuXG4gIGV4cGVjdChzdGFjaykudG9IYXZlUmVzb3VyY2VMaWtlKCdBV1M6OktpbmVzaXM6OlN0cmVhbScsIHtcbiAgICBOYW1lOiAnbXktc3RyZWFtJ1xuICB9KTtcblxuICBleHBlY3Qoc3RhY2spLnRvQ291bnRSZXNvdXJjZXMoJ0FXUzo6S2luZXNpczo6U3RyZWFtJywgMSk7XG59KTtcblxudGVzdCgnQ29uc3RydWN0IHVzZXMgdW5lbmNyeXB0ZWQgZXhpc3Rpbmcgc3RyZWFtJywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBTdGFjaygpO1xuXG4gIGNvbnN0IGV4aXN0aW5nU3RyZWFtT2JqID0gbmV3IGtpbmVzaXMuU3RyZWFtKHN0YWNrLCAndGVzdC1zdHJlYW0nLCB7XG4gICAgc3RyZWFtTmFtZTogJ215LXN0cmVhbScsXG4gICAgZW5jcnlwdGlvbjoga2luZXNpcy5TdHJlYW1FbmNyeXB0aW9uLlVORU5DUllQVEVEXG4gIH0pO1xuXG4gIG5ldyBMYW1iZGFUb0tpbmVzaXNTdHJlYW1zKHN0YWNrLCAndGVzdC1sYW1iZGEta2luZXNpc3N0cmVhbXMnLCB7XG4gICAgbGFtYmRhRnVuY3Rpb25Qcm9wczoge1xuICAgICAgY29kZTogbGFtYmRhLkNvZGUuZnJvbUFzc2V0KGAke19fZGlybmFtZX0vbGFtYmRhYCksXG4gICAgICBydW50aW1lOiBsYW1iZGEuUnVudGltZS5OT0RFSlNfMThfWCxcbiAgICAgIGhhbmRsZXI6ICdpbmRleC5oYW5kbGVyJ1xuICAgIH0sXG4gICAgZXhpc3RpbmdTdHJlYW1PYmpcbiAgfSk7XG5cbiAgZXhwZWN0KHN0YWNrKS5ub3QudG9IYXZlUmVzb3VyY2VMaWtlKCdBV1M6OktpbmVzaXM6OlN0cmVhbScsIHtcbiAgICBTdHJlYW1FbmNyeXB0aW9uOiB7XG4gICAgICBFbmNyeXB0aW9uVHlwZTogJ0tNUycsXG4gICAgICBLZXlJZDogJ2FsaWFzL2F3cy9raW5lc2lzJ1xuICAgIH1cbiAgfSk7XG5cbiAgZXhwZWN0KHN0YWNrKS50b0NvdW50UmVzb3VyY2VzKCdBV1M6OktpbmVzaXM6OlN0cmVhbScsIDEpO1xufSk7XG5cbnRlc3QoJ0NvbnN0cnVjdCB1c2VzIHVuZW5jcnlwdGVkIHN0cmVhbXMgZnJvbSBzdHJlYW0gcHJvcHMnLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IFN0YWNrKCk7XG5cbiAgbmV3IExhbWJkYVRvS2luZXNpc1N0cmVhbXMoc3RhY2ssICd0ZXN0LWxhbWJkYS1raW5lc2lzc3RyZWFtcycsIHtcbiAgICBsYW1iZGFGdW5jdGlvblByb3BzOiB7XG4gICAgICBjb2RlOiBsYW1iZGEuQ29kZS5mcm9tQXNzZXQoYCR7X19kaXJuYW1lfS9sYW1iZGFgKSxcbiAgICAgIHJ1bnRpbWU6IGxhbWJkYS5SdW50aW1lLk5PREVKU18xOF9YLFxuICAgICAgaGFuZGxlcjogJ2luZGV4LmhhbmRsZXInXG4gICAgfSxcbiAgICBraW5lc2lzU3RyZWFtUHJvcHM6IHtcbiAgICAgIHN0cmVhbU5hbWU6ICdteS1zdHJlYW0nLFxuICAgICAgZW5jcnlwdGlvbjoga2luZXNpcy5TdHJlYW1FbmNyeXB0aW9uLlVORU5DUllQVEVEXG4gICAgfVxuICB9KTtcblxuICBleHBlY3Qoc3RhY2spLm5vdC50b0hhdmVSZXNvdXJjZUxpa2UoJ0FXUzo6S2luZXNpczo6U3RyZWFtJywge1xuICAgIFN0cmVhbUVuY3J5cHRpb246IHtcbiAgICAgIEVuY3J5cHRpb25UeXBlOiAnS01TJyxcbiAgICAgIEtleUlkOiAnYWxpYXMvYXdzL2tpbmVzaXMnXG4gICAgfVxuICB9KTtcblxuICBleHBlY3Qoc3RhY2spLnRvQ291bnRSZXNvdXJjZXMoJ0FXUzo6S2luZXNpczo6U3RyZWFtJywgMSk7XG59KTtcblxudGVzdCgnQ29uc3RydWN0IGdyYW50cyBQdXRSZWNvcmQgcGVybWlzc2lvbiBmb3IgdGhlIExhbWJkYSBGdW5jdGlvbiB0byB3cml0ZSB0byB0aGUgS2luZXNpcyBTdHJlYW0nLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IFN0YWNrKCk7XG5cbiAgbmV3IExhbWJkYVRvS2luZXNpc1N0cmVhbXMoc3RhY2ssICd0ZXN0LWxhbWJkYS1raW5lc2lzc3RyZWFtcycsIHtcbiAgICBsYW1iZGFGdW5jdGlvblByb3BzOiB7XG4gICAgICBjb2RlOiBsYW1iZGEuQ29kZS5mcm9tQXNzZXQoYCR7X19kaXJuYW1lfS9sYW1iZGFgKSxcbiAgICAgIHJ1bnRpbWU6IGxhbWJkYS5SdW50aW1lLk5PREVKU18xOF9YLFxuICAgICAgaGFuZGxlcjogJ2luZGV4LmhhbmRsZXInXG4gICAgfVxuICB9KTtcblxuICBjb25zdCB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG5cbiAgLy8gR2V0IEtpbmVzaXMgRGF0YSBTdHJlYW0gY3JlYXRlZCBieSB0aGUgY29uc3RydWN0XG4gIGNvbnN0IGtpbmVzaXNTdHJlYW0gPSB0ZW1wbGF0ZS5maW5kUmVzb3VyY2VzKCdBV1M6OktpbmVzaXM6OlN0cmVhbScpO1xuICBjb25zdCBbIGtpbmVzaXNTdHJlYW1JZCBdID0gT2JqZWN0LmtleXMoa2luZXNpc1N0cmVhbSk7XG5cbiAgZXhwZWN0KHN0YWNrKS50b0hhdmVSZXNvdXJjZUxpa2UoJ0FXUzo6SUFNOjpQb2xpY3knLCB7XG4gICAgUG9saWN5RG9jdW1lbnQ6IHtcbiAgICAgIFN0YXRlbWVudDogW1xuICAgICAgICB7XG4gICAgICAgICAgQWN0aW9uOiBbXG4gICAgICAgICAgICAneHJheTpQdXRUcmFjZVNlZ21lbnRzJyxcbiAgICAgICAgICAgICd4cmF5OlB1dFRlbGVtZXRyeVJlY29yZHMnXG4gICAgICAgICAgXSxcbiAgICAgICAgICBFZmZlY3Q6ICdBbGxvdycsXG4gICAgICAgICAgUmVzb3VyY2U6ICcqJ1xuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgQWN0aW9uOiBbXG4gICAgICAgICAgICAna2luZXNpczpMaXN0U2hhcmRzJyxcbiAgICAgICAgICAgICdraW5lc2lzOlB1dFJlY29yZCcsXG4gICAgICAgICAgICAna2luZXNpczpQdXRSZWNvcmRzJ1xuICAgICAgICAgIF0sXG4gICAgICAgICAgRWZmZWN0OiAnQWxsb3cnLFxuICAgICAgICAgIFJlc291cmNlOiB7XG4gICAgICAgICAgICAnRm46OkdldEF0dCc6IFtcbiAgICAgICAgICAgICAga2luZXNpc1N0cmVhbUlkLFxuICAgICAgICAgICAgICAnQXJuJ1xuICAgICAgICAgICAgXVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgXVxuICAgIH1cbiAgfSk7XG59KTtcblxudGVzdCgnV2hlbiBhIEN1c3RvbWVyLW1hbmdlZCBDTUsgaXMgdXNlZCBvbiBhbiBleGlzdGluZyBzdHJlYW0sIGNvbnN0cnVjdCBncmFudHMgdGhlIExhbWJkYSBGdW5jdGlvbiBwZXJtaXNzaW9uIHRvIHVzZSB0aGUgZW5jcnlwdGlvbiBrZXkgc28gaXQgY2FuIHB1Ymxpc2ggbWVzc2FnZXMgdG8gaXQnLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IFN0YWNrKCk7XG5cbiAgY29uc3QgZW5jcnlwdGlvbktleSA9IG5ldyBrbXMuS2V5KHN0YWNrLCAnS2V5Jywge1xuICAgIGRlc2NyaXB0aW9uOiAnbXkta2V5LWRlc2NyaXB0aW9uJ1xuICB9KTtcblxuICBjb25zdCBleGlzdGluZ1N0cmVhbU9iaiA9IG5ldyBraW5lc2lzLlN0cmVhbShzdGFjaywgJ3Rlc3Qtc3RyZWFtJywge1xuICAgIHN0cmVhbU5hbWU6ICdteS1zdHJlYW0nLFxuICAgIGVuY3J5cHRpb25LZXlcbiAgfSk7XG5cbiAgbmV3IExhbWJkYVRvS2luZXNpc1N0cmVhbXMoc3RhY2ssICd0ZXN0LWxhbWJkYS1raW5lc2lzc3RyZWFtcycsIHtcbiAgICBsYW1iZGFGdW5jdGlvblByb3BzOiB7XG4gICAgICBjb2RlOiBsYW1iZGEuQ29kZS5mcm9tQXNzZXQoYCR7X19kaXJuYW1lfS9sYW1iZGFgKSxcbiAgICAgIHJ1bnRpbWU6IGxhbWJkYS5SdW50aW1lLk5PREVKU18xOF9YLFxuICAgICAgaGFuZGxlcjogJ2luZGV4LmhhbmRsZXInXG4gICAgfSxcbiAgICBleGlzdGluZ1N0cmVhbU9ialxuICB9KTtcblxuICBjb25zdCB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG4gIGNvbnN0IHJlc291cmNlID0gdGVtcGxhdGUuZmluZFJlc291cmNlcygnQVdTOjpLTVM6OktleScsIHtcbiAgICBQcm9wZXJ0aWVzOiB7XG4gICAgICBEZXNjcmlwdGlvbjogTWF0Y2guZXhhY3QoJ215LWtleS1kZXNjcmlwdGlvbicpXG4gICAgfVxuICB9KTtcbiAgY29uc3QgWyBrbXNLZXkgXSA9IE9iamVjdC5rZXlzKHJlc291cmNlKTtcblxuICBleHBlY3Qoc3RhY2spLnRvSGF2ZVJlc291cmNlTGlrZSgnQVdTOjpJQU06OlBvbGljeScsIHtcbiAgICBQb2xpY3lEb2N1bWVudDoge1xuICAgICAgU3RhdGVtZW50OiBbXG4gICAgICAgIHtcbiAgICAgICAgICBBY3Rpb246IFtcbiAgICAgICAgICAgICd4cmF5OlB1dFRyYWNlU2VnbWVudHMnLFxuICAgICAgICAgICAgJ3hyYXk6UHV0VGVsZW1ldHJ5UmVjb3JkcydcbiAgICAgICAgICBdLFxuICAgICAgICAgIEVmZmVjdDogJ0FsbG93JyxcbiAgICAgICAgICBSZXNvdXJjZTogJyonXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBBY3Rpb246IFtcbiAgICAgICAgICAgICdraW5lc2lzOkxpc3RTaGFyZHMnLFxuICAgICAgICAgICAgJ2tpbmVzaXM6UHV0UmVjb3JkJyxcbiAgICAgICAgICAgICdraW5lc2lzOlB1dFJlY29yZHMnXG4gICAgICAgICAgXSxcbiAgICAgICAgICBFZmZlY3Q6ICdBbGxvdycsXG4gICAgICAgICAgUmVzb3VyY2U6IHtcbiAgICAgICAgICAgICdGbjo6R2V0QXR0JzogW1xuICAgICAgICAgICAgICAndGVzdHN0cmVhbTA0Mzc0QTA5JyxcbiAgICAgICAgICAgICAgJ0FybidcbiAgICAgICAgICAgIF1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBBY3Rpb246IFtcbiAgICAgICAgICAgICdrbXM6RW5jcnlwdCcsXG4gICAgICAgICAgICAna21zOlJlRW5jcnlwdConLFxuICAgICAgICAgICAgJ2ttczpHZW5lcmF0ZURhdGFLZXkqJ1xuICAgICAgICAgIF0sXG4gICAgICAgICAgRWZmZWN0OiAnQWxsb3cnLFxuICAgICAgICAgIFJlc291cmNlOiB7XG4gICAgICAgICAgICAnRm46OkdldEF0dCc6IFtcbiAgICAgICAgICAgICAga21zS2V5LFxuICAgICAgICAgICAgICAnQXJuJ1xuICAgICAgICAgICAgXVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIEFjdGlvbjogW1xuICAgICAgICAgICAgJ2ttczpEZWNyeXB0JyxcbiAgICAgICAgICAgICdrbXM6R2VuZXJhdGVEYXRhS2V5KidcbiAgICAgICAgICBdLFxuICAgICAgICAgIEVmZmVjdDogJ0FsbG93JyxcbiAgICAgICAgICBSZXNvdXJjZToge1xuICAgICAgICAgICAgJ0ZuOjpHZXRBdHQnOiBbXG4gICAgICAgICAgICAgIGttc0tleSxcbiAgICAgICAgICAgICAgJ0FybidcbiAgICAgICAgICAgIF1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIF1cbiAgICB9XG4gIH0pO1xufSk7XG5cbmZ1bmN0aW9uIHZlcmlmeUxhbWJkYUZ1bmN0aW9uVnBjUHJvcHMoc3RhY2s6IFN0YWNrLCB0ZW1wbGF0ZTogVGVtcGxhdGUsIHZwY0lkOiBzdHJpbmcpIHtcbiAgLy8gR2V0IHRoZSBTZWN1cml0eSBHcm91cCBhc3NvY2lhdGVkIHdpdGggdGhlIFZQQ1xuICBjb25zdCBzZWN1cml0eUdyb3VwUmVzb3VyY2UgPSB0ZW1wbGF0ZS5maW5kUmVzb3VyY2VzKCdBV1M6OkVDMjo6U2VjdXJpdHlHcm91cCcsIHtcbiAgICBQcm9wZXJ0aWVzOiB7XG4gICAgICBWcGNJZDoge1xuICAgICAgICBSZWY6IE1hdGNoLmV4YWN0KHZwY0lkKVxuICAgICAgfVxuICAgIH1cbiAgfSk7XG4gIGNvbnN0IFsgc2VjdXJpdHlHcm91cElkIF0gPSBPYmplY3Qua2V5cyhzZWN1cml0eUdyb3VwUmVzb3VyY2UpO1xuXG4gIC8vIEdldCB0aGUgU3VibmV0cyBhc3NvY2lhdGVkIHdpdGggdGhlIFZQQ1xuICBjb25zdCBzdWJuZXRSZXNvdXJjZXMgPSB0ZW1wbGF0ZS5maW5kUmVzb3VyY2VzKCdBV1M6OkVDMjo6U3VibmV0Jywge1xuICAgIFByb3BlcnRpZXM6IHtcbiAgICAgIFZwY0lkOiB7XG4gICAgICAgIFJlZjogTWF0Y2guZXhhY3QodnBjSWQpXG4gICAgICB9XG4gICAgfVxuICB9KTtcbiAgY29uc3QgW3N1Ym5ldDEsIHN1Ym5ldDJdID0gT2JqZWN0LmtleXMoc3VibmV0UmVzb3VyY2VzKTtcblxuICAvLyBWZXJpZnkgdGhlIExhbWJkYSBGdW5jdGlvbiBoYXMgdGhlIHNhbWUgU2VjdXJpdHkgR3JvdXBcbiAgZXhwZWN0KHN0YWNrKS50b0hhdmVSZXNvdXJjZUxpa2UoJ0FXUzo6TGFtYmRhOjpGdW5jdGlvbicsIHtcbiAgICBWcGNDb25maWc6IHtcbiAgICAgIFNlY3VyaXR5R3JvdXBJZHM6IFtcbiAgICAgICAge1xuICAgICAgICAgICdGbjo6R2V0QXR0JzogW1xuICAgICAgICAgICAgc2VjdXJpdHlHcm91cElkLFxuICAgICAgICAgICAgJ0dyb3VwSWQnXG4gICAgICAgICAgXVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgU3VibmV0SWRzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBSZWY6IHN1Ym5ldDFcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFJlZjogc3VibmV0MlxuICAgICAgICB9XG4gICAgICBdXG4gICAgfVxuICB9KTtcblxuICAvLyBWZXJpZnkgdGhlIFZQQyBoYXMgYW4gaW50ZXJmYWNlIGVuZHBvaW50IGZvciBLaW5lc2lzIFN0cmVhbXNcbiAgZXhwZWN0KHN0YWNrKS50b0hhdmVSZXNvdXJjZUxpa2UoJ0FXUzo6RUMyOjpWUENFbmRwb2ludCcsIHtcbiAgICBTZXJ2aWNlTmFtZToge1xuICAgICAgJ0ZuOjpKb2luJzogW1xuICAgICAgICAnJyxcbiAgICAgICAgW1xuICAgICAgICAgICdjb20uYW1hem9uYXdzLicsXG4gICAgICAgICAge1xuICAgICAgICAgICAgUmVmOiAnQVdTOjpSZWdpb24nXG4gICAgICAgICAgfSxcbiAgICAgICAgICAnLmtpbmVzaXMtc3RyZWFtcydcbiAgICAgICAgXVxuICAgICAgXVxuICAgIH0sXG4gICAgVnBjSWQ6IHtcbiAgICAgIFJlZjogdnBjSWRcbiAgICB9LFxuICB9KTtcblxuICAvLyBWZXJpZnkgdGhlIFZQQyBoYXMgZG5zIGhvc3RuYW1lcyBhbmQgc3VwcG9ydCBlbmFibGVkXG4gIGV4cGVjdChzdGFjaykudG9IYXZlUmVzb3VyY2UoJ0FXUzo6RUMyOjpWUEMnLCB7XG4gICAgRW5hYmxlRG5zSG9zdG5hbWVzOiB0cnVlLFxuICAgIEVuYWJsZURuc1N1cHBvcnQ6IHRydWUsXG4gIH0pO1xufSJdfQ==
|