@cdklabs/cdk-appmod-catalog-blueprints 1.4.1 → 1.6.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/.jsii +2579 -194
- package/lib/document-processing/adapter/adapter.d.ts +4 -2
- package/lib/document-processing/adapter/adapter.js +1 -1
- package/lib/document-processing/adapter/queued-s3-adapter.d.ts +9 -2
- package/lib/document-processing/adapter/queued-s3-adapter.js +29 -15
- package/lib/document-processing/agentic-document-processing.d.ts +4 -0
- package/lib/document-processing/agentic-document-processing.js +20 -10
- package/lib/document-processing/base-document-processing.d.ts +54 -2
- package/lib/document-processing/base-document-processing.js +136 -82
- package/lib/document-processing/bedrock-document-processing.d.ts +202 -2
- package/lib/document-processing/bedrock-document-processing.js +717 -77
- package/lib/document-processing/chunking-config.d.ts +614 -0
- package/lib/document-processing/chunking-config.js +5 -0
- package/lib/document-processing/default-document-processing-config.js +1 -1
- package/lib/document-processing/index.d.ts +1 -0
- package/lib/document-processing/index.js +2 -1
- package/lib/document-processing/resources/aggregation/handler.py +567 -0
- package/lib/document-processing/resources/aggregation/requirements.txt +7 -0
- package/lib/document-processing/resources/aggregation/test_handler.py +362 -0
- package/lib/document-processing/resources/cleanup/handler.py +276 -0
- package/lib/document-processing/resources/cleanup/requirements.txt +5 -0
- package/lib/document-processing/resources/cleanup/test_handler.py +436 -0
- package/lib/document-processing/resources/default-bedrock-invoke/index.py +85 -3
- package/lib/document-processing/resources/default-bedrock-invoke/test_index.py +622 -0
- package/lib/document-processing/resources/pdf-chunking/README.md +313 -0
- package/lib/document-processing/resources/pdf-chunking/chunking_strategies.py +460 -0
- package/lib/document-processing/resources/pdf-chunking/error_handling.py +491 -0
- package/lib/document-processing/resources/pdf-chunking/handler.py +958 -0
- package/lib/document-processing/resources/pdf-chunking/metrics.py +435 -0
- package/lib/document-processing/resources/pdf-chunking/requirements.txt +3 -0
- package/lib/document-processing/resources/pdf-chunking/strategy_selection.py +420 -0
- package/lib/document-processing/resources/pdf-chunking/structured_logging.py +457 -0
- package/lib/document-processing/resources/pdf-chunking/test_chunking_strategies.py +353 -0
- package/lib/document-processing/resources/pdf-chunking/test_error_handling.py +487 -0
- package/lib/document-processing/resources/pdf-chunking/test_handler.py +609 -0
- package/lib/document-processing/resources/pdf-chunking/test_integration.py +694 -0
- package/lib/document-processing/resources/pdf-chunking/test_metrics.py +532 -0
- package/lib/document-processing/resources/pdf-chunking/test_strategy_selection.py +471 -0
- package/lib/document-processing/resources/pdf-chunking/test_structured_logging.py +449 -0
- package/lib/document-processing/resources/pdf-chunking/test_token_estimation.py +374 -0
- package/lib/document-processing/resources/pdf-chunking/token_estimation.py +189 -0
- package/lib/document-processing/tests/agentic-document-processing-nag.test.js +4 -3
- package/lib/document-processing/tests/agentic-document-processing.test.js +488 -4
- package/lib/document-processing/tests/base-document-processing-nag.test.js +9 -2
- package/lib/document-processing/tests/base-document-processing-schema.test.d.ts +1 -0
- package/lib/document-processing/tests/base-document-processing-schema.test.js +337 -0
- package/lib/document-processing/tests/base-document-processing.test.js +114 -8
- package/lib/document-processing/tests/bedrock-document-processing-chunking-nag.test.d.ts +1 -0
- package/lib/document-processing/tests/bedrock-document-processing-chunking-nag.test.js +382 -0
- package/lib/document-processing/tests/bedrock-document-processing-nag.test.js +4 -3
- package/lib/document-processing/tests/bedrock-document-processing-security.test.d.ts +1 -0
- package/lib/document-processing/tests/bedrock-document-processing-security.test.js +389 -0
- package/lib/document-processing/tests/bedrock-document-processing.test.js +808 -8
- package/lib/document-processing/tests/chunking-config.test.d.ts +1 -0
- package/lib/document-processing/tests/chunking-config.test.js +238 -0
- package/lib/document-processing/tests/queued-s3-adapter-nag.test.js +9 -2
- package/lib/document-processing/tests/queued-s3-adapter.test.js +17 -6
- package/lib/framework/agents/base-agent.js +1 -1
- package/lib/framework/agents/batch-agent.js +1 -1
- package/lib/framework/agents/default-agent-config.js +1 -1
- package/lib/framework/bedrock/bedrock.js +1 -1
- package/lib/framework/custom-resource/default-runtimes.js +1 -1
- package/lib/framework/foundation/access-log.js +1 -1
- package/lib/framework/foundation/eventbridge-broker.js +1 -1
- package/lib/framework/foundation/network.d.ts +4 -2
- package/lib/framework/foundation/network.js +52 -41
- package/lib/framework/tests/access-log.test.js +5 -2
- package/lib/framework/tests/batch-agent.test.js +5 -2
- package/lib/framework/tests/bedrock.test.js +5 -2
- package/lib/framework/tests/eventbridge-broker.test.js +5 -2
- package/lib/framework/tests/framework-nag.test.js +26 -7
- package/lib/framework/tests/network.test.js +30 -2
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/utilities/data-loader.js +1 -1
- package/lib/utilities/lambda-iam-utils.js +1 -1
- package/lib/utilities/observability/cloudfront-distribution-observability-property-injector.js +1 -1
- package/lib/utilities/observability/default-observability-config.js +1 -1
- package/lib/utilities/observability/lambda-observability-property-injector.js +1 -1
- package/lib/utilities/observability/log-group-data-protection-utils.js +1 -1
- package/lib/utilities/observability/powertools-config.d.ts +10 -1
- package/lib/utilities/observability/powertools-config.js +19 -3
- package/lib/utilities/observability/state-machine-observability-property-injector.js +1 -1
- package/lib/utilities/test-utils.d.ts +43 -0
- package/lib/utilities/test-utils.js +56 -0
- package/lib/utilities/tests/data-loader-nag.test.js +3 -2
- package/lib/utilities/tests/data-loader.test.js +3 -2
- package/lib/webapp/frontend-construct.js +1 -1
- package/lib/webapp/tests/frontend-construct-nag.test.js +3 -2
- package/lib/webapp/tests/frontend-construct.test.js +3 -2
- package/package.json +6 -5
- package/lib/document-processing/resources/default-error-handler/index.js +0 -46
- package/lib/document-processing/resources/default-pdf-processor/index.js +0 -46
- package/lib/document-processing/resources/default-pdf-validator/index.js +0 -36
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
4
|
+
const assertions_1 = require("aws-cdk-lib/assertions");
|
|
5
|
+
const aws_s3_1 = require("aws-cdk-lib/aws-s3");
|
|
6
|
+
const framework_1 = require("../../framework");
|
|
7
|
+
const test_utils_1 = require("../../utilities/test-utils");
|
|
8
|
+
const adapter_1 = require("../adapter");
|
|
9
|
+
const bedrock_document_processing_1 = require("../bedrock-document-processing");
|
|
10
|
+
/**
|
|
11
|
+
* Security tests for BedrockDocumentProcessing with chunking enabled.
|
|
12
|
+
*
|
|
13
|
+
* These tests verify that:
|
|
14
|
+
* 1. Lambda functions have minimum required IAM permissions (least privilege)
|
|
15
|
+
* 2. Lambda functions cannot access unauthorized resources
|
|
16
|
+
* 3. Encryption is enforced for all resources
|
|
17
|
+
*
|
|
18
|
+
* ## Security Controls Tested
|
|
19
|
+
*
|
|
20
|
+
* ### Least Privilege IAM Permissions
|
|
21
|
+
* - Classification Lambda: s3:GetObject only (read-only)
|
|
22
|
+
* - Processing Lambda: s3:GetObject only (read-only)
|
|
23
|
+
* - Chunking Lambda: s3:GetObject, s3:PutObject (read/write for chunks)
|
|
24
|
+
* - Cleanup Lambda: s3:DeleteObject only (delete-only)
|
|
25
|
+
* - Aggregation Lambda: dynamodb:GetItem, dynamodb:Query (read-only)
|
|
26
|
+
*
|
|
27
|
+
* ### Encryption at Rest
|
|
28
|
+
* - S3 bucket uses KMS encryption
|
|
29
|
+
* - DynamoDB table uses KMS encryption
|
|
30
|
+
* - SQS queues use KMS encryption
|
|
31
|
+
* - Lambda environment variables use KMS encryption
|
|
32
|
+
* - Step Functions state machine uses KMS encryption
|
|
33
|
+
*
|
|
34
|
+
* ### Encryption in Transit
|
|
35
|
+
* - S3 bucket enforces SSL
|
|
36
|
+
* - SQS queues enforce SSL
|
|
37
|
+
*/
|
|
38
|
+
describe('BedrockDocumentProcessing Security Tests', () => {
|
|
39
|
+
let app;
|
|
40
|
+
let stack;
|
|
41
|
+
let template;
|
|
42
|
+
beforeAll(() => {
|
|
43
|
+
app = (0, test_utils_1.createTestApp)();
|
|
44
|
+
stack = new aws_cdk_lib_1.Stack(app, 'SecurityTestStack', {
|
|
45
|
+
env: {
|
|
46
|
+
account: '123456789012',
|
|
47
|
+
region: 'us-east-1',
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
const accessLog = new framework_1.AccessLog(stack, 'AccessLog');
|
|
51
|
+
const bucket = new aws_s3_1.Bucket(stack, 'DocumentBucket', {
|
|
52
|
+
serverAccessLogsBucket: accessLog.bucket,
|
|
53
|
+
serverAccessLogsPrefix: accessLog.bucketPrefix,
|
|
54
|
+
enforceSSL: true,
|
|
55
|
+
});
|
|
56
|
+
const adapter = new adapter_1.QueuedS3Adapter({ bucket });
|
|
57
|
+
new bedrock_document_processing_1.BedrockDocumentProcessing(stack, 'BedrockDocumentProcessing', {
|
|
58
|
+
ingressAdapter: adapter,
|
|
59
|
+
enableChunking: true,
|
|
60
|
+
chunkingConfig: {
|
|
61
|
+
strategy: 'hybrid',
|
|
62
|
+
pageThreshold: 100,
|
|
63
|
+
tokenThreshold: 150000,
|
|
64
|
+
processingMode: 'parallel',
|
|
65
|
+
maxConcurrency: 10,
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
template = assertions_1.Template.fromStack(stack);
|
|
69
|
+
});
|
|
70
|
+
describe('Least Privilege IAM Permissions', () => {
|
|
71
|
+
describe('Classification Lambda', () => {
|
|
72
|
+
test('has only s3:GetObject permission for S3 access', () => {
|
|
73
|
+
// Find IAM policies that grant S3 access to classification Lambda
|
|
74
|
+
const policies = template.findResources('AWS::IAM::Policy');
|
|
75
|
+
// Verify that classification Lambda role has s3:GetObject
|
|
76
|
+
// and does NOT have s3:PutObject, s3:DeleteObject, or s3:*
|
|
77
|
+
const s3Policies = Object.values(policies).filter((policy) => {
|
|
78
|
+
const statements = policy.Properties?.PolicyDocument?.Statement || [];
|
|
79
|
+
return statements.some((stmt) => {
|
|
80
|
+
const actions = Array.isArray(stmt.Action) ? stmt.Action : [stmt.Action];
|
|
81
|
+
return actions.some((action) => action.startsWith('s3:'));
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
// Should have S3 policies
|
|
85
|
+
expect(s3Policies.length).toBeGreaterThan(0);
|
|
86
|
+
// Verify no wildcard s3:* permissions
|
|
87
|
+
s3Policies.forEach((policy) => {
|
|
88
|
+
const statements = policy.Properties?.PolicyDocument?.Statement || [];
|
|
89
|
+
statements.forEach((stmt) => {
|
|
90
|
+
const actions = Array.isArray(stmt.Action) ? stmt.Action : [stmt.Action];
|
|
91
|
+
actions.forEach((action) => {
|
|
92
|
+
if (action.startsWith('s3:')) {
|
|
93
|
+
expect(action).not.toBe('s3:*');
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
test('has Bedrock InvokeModel permission', () => {
|
|
100
|
+
template.hasResourceProperties('AWS::IAM::Role', {
|
|
101
|
+
Policies: assertions_1.Match.arrayWith([
|
|
102
|
+
assertions_1.Match.objectLike({
|
|
103
|
+
PolicyDocument: {
|
|
104
|
+
Statement: assertions_1.Match.arrayWith([
|
|
105
|
+
assertions_1.Match.objectLike({
|
|
106
|
+
Action: assertions_1.Match.arrayWith(['bedrock:InvokeModel']),
|
|
107
|
+
Effect: 'Allow',
|
|
108
|
+
}),
|
|
109
|
+
]),
|
|
110
|
+
},
|
|
111
|
+
}),
|
|
112
|
+
]),
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
describe('Chunking Lambda', () => {
|
|
117
|
+
test('has s3:GetObject and s3:PutObject permissions', () => {
|
|
118
|
+
// Chunking Lambda needs to read PDFs and write chunks
|
|
119
|
+
// Verify the chunking Lambda role policy exists
|
|
120
|
+
const policies = template.findResources('AWS::IAM::Policy');
|
|
121
|
+
// Find the chunking Lambda policy by name pattern
|
|
122
|
+
const chunkingPolicyKey = Object.keys(policies).find(key => key.includes('ChunkingLambdaRole'));
|
|
123
|
+
expect(chunkingPolicyKey).toBeDefined();
|
|
124
|
+
// Verify no s3:* wildcard in any policy
|
|
125
|
+
Object.values(policies).forEach((policy) => {
|
|
126
|
+
const statements = policy.Properties?.PolicyDocument?.Statement || [];
|
|
127
|
+
statements.forEach((stmt) => {
|
|
128
|
+
const actions = Array.isArray(stmt.Action) ? stmt.Action : [stmt.Action];
|
|
129
|
+
actions.forEach((action) => {
|
|
130
|
+
expect(action).not.toBe('s3:*');
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
describe('Cleanup Lambda', () => {
|
|
137
|
+
test('has s3:DeleteObject permission', () => {
|
|
138
|
+
// Cleanup Lambda should have delete permission
|
|
139
|
+
const policies = template.findResources('AWS::IAM::Policy');
|
|
140
|
+
// Find the cleanup Lambda policy by name pattern
|
|
141
|
+
const cleanupPolicyKey = Object.keys(policies).find(key => key.includes('CleanupLambdaRole'));
|
|
142
|
+
expect(cleanupPolicyKey).toBeDefined();
|
|
143
|
+
// Verify no s3:* wildcard in any policy
|
|
144
|
+
Object.values(policies).forEach((policy) => {
|
|
145
|
+
const statements = policy.Properties?.PolicyDocument?.Statement || [];
|
|
146
|
+
statements.forEach((stmt) => {
|
|
147
|
+
const actions = Array.isArray(stmt.Action) ? stmt.Action : [stmt.Action];
|
|
148
|
+
actions.forEach((action) => {
|
|
149
|
+
expect(action).not.toBe('s3:*');
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
describe('Aggregation Lambda', () => {
|
|
156
|
+
test('has DynamoDB permissions', () => {
|
|
157
|
+
// Aggregation Lambda should have DynamoDB permissions
|
|
158
|
+
const policies = template.findResources('AWS::IAM::Policy');
|
|
159
|
+
// Find the aggregation Lambda policy by name pattern
|
|
160
|
+
const aggregationPolicyKey = Object.keys(policies).find(key => key.includes('AggregationLambdaRole'));
|
|
161
|
+
expect(aggregationPolicyKey).toBeDefined();
|
|
162
|
+
// Verify no dynamodb:* wildcard in any policy
|
|
163
|
+
Object.values(policies).forEach((policy) => {
|
|
164
|
+
const statements = policy.Properties?.PolicyDocument?.Statement || [];
|
|
165
|
+
statements.forEach((stmt) => {
|
|
166
|
+
const actions = Array.isArray(stmt.Action) ? stmt.Action : [stmt.Action];
|
|
167
|
+
actions.forEach((action) => {
|
|
168
|
+
expect(action).not.toBe('dynamodb:*');
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
describe('No Wildcard Permissions', () => {
|
|
175
|
+
test('no Lambda role has s3:* permission', () => {
|
|
176
|
+
const policies = template.findResources('AWS::IAM::Policy');
|
|
177
|
+
Object.values(policies).forEach((policy) => {
|
|
178
|
+
const statements = policy.Properties?.PolicyDocument?.Statement || [];
|
|
179
|
+
statements.forEach((stmt) => {
|
|
180
|
+
const actions = Array.isArray(stmt.Action) ? stmt.Action : [stmt.Action];
|
|
181
|
+
actions.forEach((action) => {
|
|
182
|
+
expect(action).not.toBe('s3:*');
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
test('no Lambda role has dynamodb:* permission', () => {
|
|
188
|
+
const policies = template.findResources('AWS::IAM::Policy');
|
|
189
|
+
Object.values(policies).forEach((policy) => {
|
|
190
|
+
const statements = policy.Properties?.PolicyDocument?.Statement || [];
|
|
191
|
+
statements.forEach((stmt) => {
|
|
192
|
+
const actions = Array.isArray(stmt.Action) ? stmt.Action : [stmt.Action];
|
|
193
|
+
actions.forEach((action) => {
|
|
194
|
+
expect(action).not.toBe('dynamodb:*');
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
test('no Lambda role has bedrock:* permission', () => {
|
|
200
|
+
const policies = template.findResources('AWS::IAM::Policy');
|
|
201
|
+
Object.values(policies).forEach((policy) => {
|
|
202
|
+
const statements = policy.Properties?.PolicyDocument?.Statement || [];
|
|
203
|
+
statements.forEach((stmt) => {
|
|
204
|
+
const actions = Array.isArray(stmt.Action) ? stmt.Action : [stmt.Action];
|
|
205
|
+
actions.forEach((action) => {
|
|
206
|
+
expect(action).not.toBe('bedrock:*');
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
describe('Encryption at Rest', () => {
|
|
214
|
+
test('S3 bucket uses encryption', () => {
|
|
215
|
+
// S3 bucket should use encryption (AWS-managed KMS or customer-managed)
|
|
216
|
+
// The bucket provided by the user may use different encryption settings
|
|
217
|
+
template.hasResourceProperties('AWS::S3::Bucket', {
|
|
218
|
+
BucketEncryption: assertions_1.Match.anyValue(),
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
test('DynamoDB table uses KMS encryption', () => {
|
|
222
|
+
template.hasResourceProperties('AWS::DynamoDB::Table', {
|
|
223
|
+
SSESpecification: {
|
|
224
|
+
SSEEnabled: true,
|
|
225
|
+
SSEType: 'KMS',
|
|
226
|
+
},
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
test('SQS queues use KMS encryption', () => {
|
|
230
|
+
template.hasResourceProperties('AWS::SQS::Queue', {
|
|
231
|
+
KmsMasterKeyId: assertions_1.Match.anyValue(),
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
test('Step Functions state machine uses KMS encryption', () => {
|
|
235
|
+
template.hasResourceProperties('AWS::StepFunctions::StateMachine', {
|
|
236
|
+
EncryptionConfiguration: {
|
|
237
|
+
Type: 'CUSTOMER_MANAGED_KMS_KEY',
|
|
238
|
+
KmsKeyId: assertions_1.Match.anyValue(),
|
|
239
|
+
},
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
test('Lambda environment variables use KMS encryption', () => {
|
|
243
|
+
// Find Lambda functions with environment variables
|
|
244
|
+
const lambdas = template.findResources('AWS::Lambda::Function');
|
|
245
|
+
// All Lambda functions should have KmsKeyArn set for environment encryption
|
|
246
|
+
const lambdasWithEnvVars = Object.values(lambdas).filter((lambda) => lambda.Properties?.Environment?.Variables);
|
|
247
|
+
// Should have Lambda functions with environment variables
|
|
248
|
+
expect(lambdasWithEnvVars.length).toBeGreaterThan(0);
|
|
249
|
+
// Each Lambda with env vars should have KmsKeyArn
|
|
250
|
+
lambdasWithEnvVars.forEach((lambda) => {
|
|
251
|
+
expect(lambda.Properties.KmsKeyArn).toBeDefined();
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
describe('Encryption in Transit', () => {
|
|
256
|
+
test('S3 bucket enforces SSL', () => {
|
|
257
|
+
template.hasResourceProperties('AWS::S3::BucketPolicy', {
|
|
258
|
+
PolicyDocument: {
|
|
259
|
+
Statement: assertions_1.Match.arrayWith([
|
|
260
|
+
assertions_1.Match.objectLike({
|
|
261
|
+
Condition: {
|
|
262
|
+
Bool: {
|
|
263
|
+
'aws:SecureTransport': 'false',
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
Effect: 'Deny',
|
|
267
|
+
}),
|
|
268
|
+
]),
|
|
269
|
+
},
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
describe('Resource Isolation', () => {
|
|
274
|
+
test('Lambda functions have specific resource ARNs, not wildcards', () => {
|
|
275
|
+
const policies = template.findResources('AWS::IAM::Policy');
|
|
276
|
+
// Check that S3 permissions are scoped to specific bucket ARNs
|
|
277
|
+
Object.values(policies).forEach((policy) => {
|
|
278
|
+
const statements = policy.Properties?.PolicyDocument?.Statement || [];
|
|
279
|
+
statements.forEach((stmt) => {
|
|
280
|
+
const actions = Array.isArray(stmt.Action) ? stmt.Action : [stmt.Action];
|
|
281
|
+
const resources = Array.isArray(stmt.Resource) ? stmt.Resource : [stmt.Resource];
|
|
282
|
+
// If this is an S3 action, verify resources are not just '*'
|
|
283
|
+
if (actions.some((a) => a.startsWith('s3:'))) {
|
|
284
|
+
resources.forEach((resource) => {
|
|
285
|
+
// Resource should be a Ref, GetAtt, or Fn::Join, not just '*'
|
|
286
|
+
if (typeof resource === 'string') {
|
|
287
|
+
expect(resource).not.toBe('*');
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
test('DynamoDB permissions are scoped to specific table', () => {
|
|
295
|
+
const policies = template.findResources('AWS::IAM::Policy');
|
|
296
|
+
Object.values(policies).forEach((policy) => {
|
|
297
|
+
const statements = policy.Properties?.PolicyDocument?.Statement || [];
|
|
298
|
+
statements.forEach((stmt) => {
|
|
299
|
+
const actions = Array.isArray(stmt.Action) ? stmt.Action : [stmt.Action];
|
|
300
|
+
const resources = Array.isArray(stmt.Resource) ? stmt.Resource : [stmt.Resource];
|
|
301
|
+
// If this is a DynamoDB action, verify resources are not just '*'
|
|
302
|
+
if (actions.some((a) => a.startsWith('dynamodb:'))) {
|
|
303
|
+
resources.forEach((resource) => {
|
|
304
|
+
if (typeof resource === 'string') {
|
|
305
|
+
expect(resource).not.toBe('*');
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
});
|
|
313
|
+
});
|
|
314
|
+
describe('BedrockDocumentProcessing Security - Without Chunking', () => {
|
|
315
|
+
let app;
|
|
316
|
+
let stack;
|
|
317
|
+
let template;
|
|
318
|
+
beforeAll(() => {
|
|
319
|
+
app = (0, test_utils_1.createTestApp)();
|
|
320
|
+
stack = new aws_cdk_lib_1.Stack(app, 'SecurityNoChunkingStack', {
|
|
321
|
+
env: {
|
|
322
|
+
account: '123456789012',
|
|
323
|
+
region: 'us-east-1',
|
|
324
|
+
},
|
|
325
|
+
});
|
|
326
|
+
new bedrock_document_processing_1.BedrockDocumentProcessing(stack, 'BedrockDocumentProcessing', {
|
|
327
|
+
enableChunking: false,
|
|
328
|
+
});
|
|
329
|
+
template = assertions_1.Template.fromStack(stack);
|
|
330
|
+
});
|
|
331
|
+
describe('Encryption at Rest (without chunking)', () => {
|
|
332
|
+
test('S3 bucket uses KMS encryption', () => {
|
|
333
|
+
template.hasResourceProperties('AWS::S3::Bucket', {
|
|
334
|
+
BucketEncryption: {
|
|
335
|
+
ServerSideEncryptionConfiguration: assertions_1.Match.arrayWith([
|
|
336
|
+
assertions_1.Match.objectLike({
|
|
337
|
+
ServerSideEncryptionByDefault: {
|
|
338
|
+
SSEAlgorithm: 'aws:kms',
|
|
339
|
+
},
|
|
340
|
+
}),
|
|
341
|
+
]),
|
|
342
|
+
},
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
test('DynamoDB table uses KMS encryption', () => {
|
|
346
|
+
template.hasResourceProperties('AWS::DynamoDB::Table', {
|
|
347
|
+
SSESpecification: {
|
|
348
|
+
SSEEnabled: true,
|
|
349
|
+
SSEType: 'KMS',
|
|
350
|
+
},
|
|
351
|
+
});
|
|
352
|
+
});
|
|
353
|
+
test('Step Functions state machine uses KMS encryption', () => {
|
|
354
|
+
template.hasResourceProperties('AWS::StepFunctions::StateMachine', {
|
|
355
|
+
EncryptionConfiguration: {
|
|
356
|
+
Type: 'CUSTOMER_MANAGED_KMS_KEY',
|
|
357
|
+
KmsKeyId: assertions_1.Match.anyValue(),
|
|
358
|
+
},
|
|
359
|
+
});
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
describe('Least Privilege (without chunking)', () => {
|
|
363
|
+
test('no wildcard s3:* permissions', () => {
|
|
364
|
+
const policies = template.findResources('AWS::IAM::Policy');
|
|
365
|
+
Object.values(policies).forEach((policy) => {
|
|
366
|
+
const statements = policy.Properties?.PolicyDocument?.Statement || [];
|
|
367
|
+
statements.forEach((stmt) => {
|
|
368
|
+
const actions = Array.isArray(stmt.Action) ? stmt.Action : [stmt.Action];
|
|
369
|
+
actions.forEach((action) => {
|
|
370
|
+
expect(action).not.toBe('s3:*');
|
|
371
|
+
});
|
|
372
|
+
});
|
|
373
|
+
});
|
|
374
|
+
});
|
|
375
|
+
test('no wildcard dynamodb:* permissions', () => {
|
|
376
|
+
const policies = template.findResources('AWS::IAM::Policy');
|
|
377
|
+
Object.values(policies).forEach((policy) => {
|
|
378
|
+
const statements = policy.Properties?.PolicyDocument?.Statement || [];
|
|
379
|
+
statements.forEach((stmt) => {
|
|
380
|
+
const actions = Array.isArray(stmt.Action) ? stmt.Action : [stmt.Action];
|
|
381
|
+
actions.forEach((action) => {
|
|
382
|
+
expect(action).not.toBe('dynamodb:*');
|
|
383
|
+
});
|
|
384
|
+
});
|
|
385
|
+
});
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
});
|
|
389
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmVkcm9jay1kb2N1bWVudC1wcm9jZXNzaW5nLXNlY3VyaXR5LnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi91c2UtY2FzZXMvZG9jdW1lbnQtcHJvY2Vzc2luZy90ZXN0cy9iZWRyb2NrLWRvY3VtZW50LXByb2Nlc3Npbmctc2VjdXJpdHkudGVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLDZDQUFvQztBQUNwQyx1REFBeUQ7QUFDekQsK0NBQTRDO0FBQzVDLCtDQUE0QztBQUM1QywyREFBMkQ7QUFDM0Qsd0NBQTZDO0FBQzdDLGdGQUEyRTtBQUUzRTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBMkJHO0FBRUgsUUFBUSxDQUFDLDBDQUEwQyxFQUFFLEdBQUcsRUFBRTtJQUN4RCxJQUFJLEdBQXFDLENBQUM7SUFDMUMsSUFBSSxLQUFZLENBQUM7SUFDakIsSUFBSSxRQUFrQixDQUFDO0lBRXZCLFNBQVMsQ0FBQyxHQUFHLEVBQUU7UUFDYixHQUFHLEdBQUcsSUFBQSwwQkFBYSxHQUFFLENBQUM7UUFDdEIsS0FBSyxHQUFHLElBQUksbUJBQUssQ0FBQyxHQUFHLEVBQUUsbUJBQW1CLEVBQUU7WUFDMUMsR0FBRyxFQUFFO2dCQUNILE9BQU8sRUFBRSxjQUFjO2dCQUN2QixNQUFNLEVBQUUsV0FBVzthQUNwQjtTQUNGLENBQUMsQ0FBQztRQUVILE1BQU0sU0FBUyxHQUFHLElBQUkscUJBQVMsQ0FBQyxLQUFLLEVBQUUsV0FBVyxDQUFDLENBQUM7UUFDcEQsTUFBTSxNQUFNLEdBQUcsSUFBSSxlQUFNLENBQUMsS0FBSyxFQUFFLGdCQUFnQixFQUFFO1lBQ2pELHNCQUFzQixFQUFFLFNBQVMsQ0FBQyxNQUFNO1lBQ3hDLHNCQUFzQixFQUFFLFNBQVMsQ0FBQyxZQUFZO1lBQzlDLFVBQVUsRUFBRSxJQUFJO1NBQ2pCLENBQUMsQ0FBQztRQUVILE1BQU0sT0FBTyxHQUFHLElBQUkseUJBQWUsQ0FBQyxFQUFF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QUFDLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO29CQUN6RSxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUMsTUFBYyxFQUFFLEVBQUU7d0JBQ2pDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDO29CQUN4QyxDQUFDLENBQUMsQ0FBQztnQkFDTCxDQUFDLENBQUMsQ0FBQztZQUNMLENBQUMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgU3RhY2sgfSBmcm9tICdhd3MtY2RrLWxpYic7XG5pbXBvcnQgeyBNYXRjaCwgVGVtcGxhdGUgfSBmcm9tICdhd3MtY2RrLWxpYi9hc3NlcnRpb25zJztcbmltcG9ydCB7IEJ1Y2tldCB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1zMyc7XG5pbXBvcnQgeyBBY2Nlc3NMb2cgfSBmcm9tICcuLi8uLi9mcmFtZXdvcmsnO1xuaW1wb3J0IHsgY3JlYXRlVGVzdEFwcCB9IGZyb20gJy4uLy4uL3V0aWxpdGllcy90ZXN0LXV0aWxzJztcbmltcG9ydCB7IFF1ZXVlZFMzQWRhcHRlciB9IGZyb20gJy4uL2FkYXB0ZXInO1xuaW1wb3J0IHsgQmVkcm9ja0RvY3VtZW50UHJvY2Vzc2luZyB9IGZyb20gJy4uL2JlZHJvY2stZG9jdW1lbnQtcHJvY2Vzc2luZyc7XG5cbi8qKlxuICogU2VjdXJpdHkgdGVzdHMgZm9yIEJlZHJvY2tEb2N1bWVudFByb2Nlc3Npbmcgd2l0aCBjaHVua2luZyBlbmFibGVkLlxuICpcbiAqIFRoZXNlIHRlc3RzIHZlcmlmeSB0aGF0OlxuICogMS4gTGFtYmRhIGZ1bmN0aW9ucyBoYXZlIG1pbmltdW0gcmVxdWlyZWQgSUFNIHBlcm1pc3Npb25zIChsZWFzdCBwcml2aWxlZ2UpXG4gKiAyLiBMYW1iZGEgZnVuY3Rpb25zIGNhbm5vdCBhY2Nlc3MgdW5hdXRob3JpemVkIHJlc291cmNlc1xuICogMy4gRW5jcnlwdGlvbiBpcyBlbmZvcmNlZCBmb3IgYWxsIHJlc291cmNlc1xuICpcbiAqICMjIFNlY3VyaXR5IENvbnRyb2xzIFRlc3RlZFxuICpcbiAqICMjIyBMZWFzdCBQcml2aWxlZ2UgSUFNIFBlcm1pc3Npb25zXG4gKiAtIENsYXNzaWZpY2F0aW9uIExhbWJkYTogczM6R2V0T2JqZWN0IG9ubHkgKHJlYWQtb25seSlcbiAqIC0gUHJvY2Vzc2luZyBMYW1iZGE6IHMzOkdldE9iamVjdCBvbmx5IChyZWFkLW9ubHkpXG4gKiAtIENodW5raW5nIExhbWJkYTogczM6R2V0T2JqZWN0LCBzMzpQdXRPYmplY3QgKHJlYWQvd3JpdGUgZm9yIGNodW5rcylcbiAqIC0gQ2xlYW51cCBMYW1iZGE6IHMzOkRlbGV0ZU9iamVjdCBvbmx5IChkZWxldGUtb25seSlcbiAqIC0gQWdncmVnYXRpb24gTGFtYmRhOiBkeW5hbW9kYjpHZXRJdGVtLCBkeW5hbW9kYjpRdWVyeSAocmVhZC1vbmx5KVxuICpcbiAqICMjIyBFbmNyeXB0aW9uIGF0IFJlc3RcbiAqIC0gUzMgYnVja2V0IHVzZXMgS01TIGVuY3J5cHRpb25cbiAqIC0gRHluYW1vREIgdGFibGUgdXNlcyBLTVMgZW5jcnlwdGlvblxuICogLSBTUVMgcXVldWVzIHVzZSBLTVMgZW5jcnlwdGlvblxuICogLSBMYW1iZGEgZW52aXJvbm1lbnQgdmFyaWFibGVzIHVzZSBLTVMgZW5jcnlwdGlvblxuICogLSBTdGVwIEZ1bmN0aW9ucyBzdGF0ZSBtYWNoaW5lIHVzZXMgS01TIGVuY3J5cHRpb25cbiAqXG4gKiAjIyMgRW5jcnlwdGlvbiBpbiBUcmFuc2l0XG4gKiAtIFMzIGJ1Y2tldCBlbmZvcmNlcyBTU0xcbiAqIC0gU1FTIHF1ZXVlcyBlbmZvcmNlIFNTTFxuICovXG5cbmRlc2NyaWJlKCdCZWRyb2NrRG9jdW1lbnRQcm9jZXNzaW5nIFNlY3VyaXR5IFRlc3RzJywgKCkgPT4ge1xuICBsZXQgYXBwOiBSZXR1cm5UeXBlPHR5cGVvZiBjcmVhdGVUZXN0QXBwPjtcbiAgbGV0IHN0YWNrOiBTdGFjaztcbiAgbGV0IHRlbXBsYXRlOiBUZW1wbGF0ZTtcblxuICBiZWZvcmVBbGwoKCkgPT4ge1xuICAgIGFwcCA9IGNyZWF0ZVRlc3RBcHAoKTtcbiAgICBzdGFjayA9IG5ldyBTdGFjayhhcHAsICdTZWN1cml0eVRlc3RTdGFjaycsIHtcbiAgICAgIGVudjoge1xuICAgICAgICBhY2NvdW50OiAnMTIzNDU2Nzg5MDEyJyxcbiAgICAgICAgcmVnaW9uOiAndXMtZWFzdC0xJyxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICBjb25zdCBhY2Nlc3NMb2cgPSBuZXcgQWNjZXNzTG9nKHN0YWNrLCAnQWNjZXNzTG9nJyk7XG4gICAgY29uc3QgYnVja2V0ID0gbmV3IEJ1Y2tldChzdGFjaywgJ0RvY3VtZW50QnVja2V0Jywge1xuICAgICAgc2VydmVyQWNjZXNzTG9nc0J1Y2tldDogYWNjZXNzTG9nLmJ1Y2tldCxcbiAgICAgIHNlcnZlckFjY2Vzc0xvZ3NQcmVmaXg6IGFjY2Vzc0xvZy5idWNrZXRQcmVmaXgsXG4gICAgICBlbmZvcmNlU1NMOiB0cnVlLFxuICAgIH0pO1xuXG4gICAgY29uc3QgYWRhcHRlciA9IG5ldyBRdWV1ZWRTM0FkYXB0ZXIoeyBidWNrZXQgfSk7XG5cbiAgICBuZXcgQmVkcm9ja0RvY3VtZW50UHJvY2Vzc2luZyhzdGFjaywgJ0JlZHJvY2tEb2N1bWVudFByb2Nlc3NpbmcnLCB7XG4gICAgICBpbmdyZXNzQWRhcHRlcjogYWRhcHRlcixcbiAgICAgIGVuYWJsZUNodW5raW5nOiB0cnVlLFxuICAgICAgY2h1bmtpbmdDb25maWc6IHtcbiAgICAgICAgc3RyYXRlZ3k6ICdoeWJyaWQnLFxuICAgICAgICBwYWdlVGhyZXNob2xkOiAxMDAsXG4gICAgICAgIHRva2VuVGhyZXNob2xkOiAxNTAwMDAsXG4gICAgICAgIHByb2Nlc3NpbmdNb2RlOiAncGFyYWxsZWwnLFxuICAgICAgICBtYXhDb25jdXJyZW5jeTogMTAsXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuICB9KTtcblxuICBkZXNjcmliZSgnTGVhc3QgUHJpdmlsZWdlIElBTSBQZXJtaXNzaW9ucycsICgpID0+IHtcbiAgICBkZXNjcmliZSgnQ2xhc3NpZmljYXRpb24gTGFtYmRhJywgKCkgPT4ge1xuICAgICAgdGVzdCgnaGFzIG9ubHkgczM6R2V0T2JqZWN0IHBlcm1pc3Npb24gZm9yIFMzIGFjY2VzcycsICgpID0+IHtcbiAgICAgICAgLy8gRmluZCBJQU0gcG9saWNpZXMgdGhhdCBncmFudCBTMyBhY2Nlc3MgdG8gY2xhc3NpZmljYXRpb24gTGFtYmRhXG4gICAgICAgIGNvbnN0IHBvbGljaWVzID0gdGVtcGxhdGUuZmluZFJlc291cmNlcygnQVdTOjpJQU06OlBvbGljeScpO1xuXG4gICAgICAgIC8vIFZlcmlmeSB0aGF0IGNsYXNzaWZpY2F0aW9uIExhbWJkYSByb2xlIGhhcyBzMzpHZXRPYmplY3RcbiAgICAgICAgLy8gYW5kIGRvZXMgTk9UIGhhdmUgczM6UHV0T2JqZWN0LCBzMzpEZWxldGVPYmplY3QsIG9yIHMzOipcbiAgICAgICAgY29uc3QgczNQb2xpY2llcyA9IE9iamVjdC52YWx1ZXMocG9saWNpZXMpLmZpbHRlcigocG9saWN5OiBhbnkpID0+IHtcbiAgICAgICAgICBjb25zdCBzdGF0ZW1lbnRzID0gcG9saWN5LlByb3BlcnRpZXM/LlBvbGljeURvY3VtZW50Py5TdGF0ZW1lbnQgfHwgW107XG4gICAgICAgICAgcmV0dXJuIHN0YXRlbWVudHMuc29tZSgoc3RtdDogYW55KSA9PiB7XG4gICAgICAgICAgICBjb25zdCBhY3Rpb25zID0gQXJyYXkuaXNBcnJheShzdG10LkFjdGlvbikgPyBzdG10LkFjdGlvbiA6IFtzdG10LkFjdGlvbl07XG4gICAgICAgICAgICByZXR1cm4gYWN0aW9ucy5zb21lKChhY3Rpb246IHN0cmluZykgPT4gYWN0aW9uLnN0YXJ0c1dpdGgoJ3MzOicpKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gU2hvdWxkIGhhdmUgUzMgcG9saWNpZXNcbiAgICAgICAgZXhwZWN0KHMzUG9saWNpZXMubGVuZ3RoKS50b0JlR3JlYXRlclRoYW4oMCk7XG5cbiAgICAgICAgLy8gVmVyaWZ5IG5vIHdpbGRjYXJkIHMzOiogcGVybWlzc2lvbnNcbiAgICAgICAgczNQb2xpY2llcy5mb3JFYWNoKChwb2xpY3k6IGFueSkgPT4ge1xuICAgICAgICAgIGNvbnN0IHN0YXRlbWVudHMgPSBwb2xpY3kuUHJvcGVydGllcz8uUG9saWN5RG9jdW1lbnQ/LlN0YXRlbWVudCB8fCBbXTtcbiAgICAgICAgICBzdGF0ZW1lbnRzLmZvckVhY2goKHN0bXQ6IGFueSkgPT4ge1xuICAgICAgICAgICAgY29uc3QgYWN0aW9ucyA9IEFycmF5LmlzQXJyYXkoc3RtdC5BY3Rpb24pID8gc3RtdC5BY3Rpb24gOiBbc3RtdC5BY3Rpb25dO1xuICAgICAgICAgICAgYWN0aW9ucy5mb3JFYWNoKChhY3Rpb246IHN0cmluZykgPT4ge1xuICAgICAgICAgICAgICBpZiAoYWN0aW9uLnN0YXJ0c1dpdGgoJ3MzOicpKSB7XG4gICAgICAgICAgICAgICAgZXhwZWN0KGFjdGlvbikubm90LnRvQmUoJ3MzOionKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIHRlc3QoJ2hhcyBCZWRyb2NrIEludm9rZU1vZGVsIHBlcm1pc3Npb24nLCAoKSA9PiB7XG4gICAgICAgIHRlbXBsYXRlLmhhc1Jlc291cmNlUHJvcGVydGllcygnQVdTOjpJQU06OlJvbGUnLCB7XG4gICAgICAgICAgUG9saWNpZXM6IE1hdGNoLmFycmF5V2l0aChbXG4gICAgICAgICAgICBNYXRjaC5vYmplY3RMaWtlKHtcbiAgICAgICAgICAgICAgUG9saWN5RG9jdW1lbnQ6IHtcbiAgICAgICAgICAgICAgICBTdGF0ZW1lbnQ6IE1hdGNoLmFycmF5V2l0aChbXG4gICAgICAgICAgICAgICAgICBNYXRjaC5vYmplY3RMaWtlKHtcbiAgICAgICAgICAgICAgICAgICAgQWN0aW9uOiBNYXRjaC5hcnJheVdpdGgoWydiZWRyb2NrOkludm9rZU1vZGVsJ10pLFxuICAgICAgICAgICAgICAgICAgICBFZmZlY3Q6ICdBbGxvdycsXG4gICAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICAgICBdKSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgIF0pLFxuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgZGVzY3JpYmUoJ0NodW5raW5nIExhbWJkYScsICgpID0+IHtcbiAgICAgIHRlc3QoJ2hhcyBzMzpHZXRPYmplY3QgYW5kIHMzOlB1dE9iamVjdCBwZXJtaXNzaW9ucycsICgpID0+IHtcbiAgICAgICAgLy8gQ2h1bmtpbmcgTGFtYmRhIG5lZWRzIHRvIHJlYWQgUERGcyBhbmQgd3JpdGUgY2h1bmtzXG4gICAgICAgIC8vIFZlcmlmeSB0aGUgY2h1bmtpbmcgTGFtYmRhIHJvbGUgcG9saWN5IGV4aXN0c1xuICAgICAgICBjb25zdCBwb2xpY2llcyA9IHRlbXBsYXRlLmZpbmRSZXNvdXJjZXMoJ0FXUzo6SUFNOjpQb2xpY3knKTtcblxuICAgICAgICAvLyBGaW5kIHRoZSBjaHVua2luZyBMYW1iZGEgcG9saWN5IGJ5IG5hbWUgcGF0dGVyblxuICAgICAgICBjb25zdCBjaHVua2luZ1BvbGljeUtleSA9IE9iamVjdC5rZXlzKHBvbGljaWVzKS5maW5kKGtleSA9PlxuICAgICAgICAgIGtleS5pbmNsdWRlcygnQ2h1bmtpbmdMYW1iZGFSb2xlJyksXG4gICAgICAgICk7XG5cbiAgICAgICAgZXhwZWN0KGNodW5raW5nUG9saWN5S2V5KS50b0JlRGVmaW5lZCgpO1xuXG4gICAgICAgIC8vIFZlcmlmeSBubyBzMzoqIHdpbGRjYXJkIGluIGFueSBwb2xpY3lcbiAgICAgICAgT2JqZWN0LnZhbHVlcyhwb2xpY2llcykuZm9yRWFjaCgocG9saWN5OiBhbnkpID0+IHtcbiAgICAgICAgICBjb25zdCBzdGF0ZW1lbnRzID0gcG9saWN5LlByb3BlcnRpZXM/LlBvbGljeURvY3VtZW50Py5TdGF0ZW1lbnQgfHwgW107XG4gICAgICAgICAgc3RhdGVtZW50cy5mb3JFYWNoKChzdG10OiBhbnkpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGFjdGlvbnMgPSBBcnJheS5pc0FycmF5KHN0bXQuQWN0aW9uKSA/IHN0bXQuQWN0aW9uIDogW3N0bXQuQWN0aW9uXTtcbiAgICAgICAgICAgIGFjdGlvbnMuZm9yRWFjaCgoYWN0aW9uOiBzdHJpbmcpID0+IHtcbiAgICAgICAgICAgICAgZXhwZWN0KGFjdGlvbikubm90LnRvQmUoJ3MzOionKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgZGVzY3JpYmUoJ0NsZWFudXAgTGFtYmRhJywgKCkgPT4ge1xuICAgICAgdGVzdCgnaGFzIHMzOkRlbGV0ZU9iamVjdCBwZXJtaXNzaW9uJywgKCkgPT4ge1xuICAgICAgICAvLyBDbGVhbnVwIExhbWJkYSBzaG91bGQgaGF2ZSBkZWxldGUgcGVybWlzc2lvblxuICAgICAgICBjb25zdCBwb2xpY2llcyA9IHRlbXBsYXRlLmZpbmRSZXNvdXJjZXMoJ0FXUzo6SUFNOjpQb2xpY3knKTtcblxuICAgICAgICAvLyBGaW5kIHRoZSBjbGVhbnVwIExhbWJkYSBwb2xpY3kgYnkgbmFtZSBwYXR0ZXJuXG4gICAgICAgIGNvbnN0IGNsZWFudXBQb2xpY3lLZXkgPSBPYmplY3Qua2V5cyhwb2xpY2llcykuZmluZChrZXkgPT5cbiAgICAgICAgICBrZXkuaW5jbHVkZXMoJ0NsZWFudXBMYW1iZGFSb2xlJyksXG4gICAgICAgICk7XG5cbiAgICAgICAgZXhwZWN0KGNsZWFudXBQb2xpY3lLZXkpLnRvQmVEZWZpbmVkKCk7XG5cbiAgICAgICAgLy8gVmVyaWZ5IG5vIHMzOiogd2lsZGNhcmQgaW4gYW55IHBvbGljeVxuICAgICAgICBPYmplY3QudmFsdWVzKHBvbGljaWVzKS5mb3JFYWNoKChwb2xpY3k6IGFueSkgPT4ge1xuICAgICAgICAgIGNvbnN0IHN0YXRlbWVudHMgPSBwb2xpY3kuUHJvcGVydGllcz8uUG9saWN5RG9jdW1lbnQ/LlN0YXRlbWVudCB8fCBbXTtcbiAgICAgICAgICBzdGF0ZW1lbnRzLmZvckVhY2goKHN0bXQ6IGFueSkgPT4ge1xuICAgICAgICAgICAgY29uc3QgYWN0aW9ucyA9IEFycmF5LmlzQXJyYXkoc3RtdC5BY3Rpb24pID8gc3RtdC5BY3Rpb24gOiBbc3RtdC5BY3Rpb25dO1xuICAgICAgICAgICAgYWN0aW9ucy5mb3JFYWNoKChhY3Rpb246IHN0cmluZykgPT4ge1xuICAgICAgICAgICAgICBleHBlY3QoYWN0aW9uKS5ub3QudG9CZSgnczM6KicpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBkZXNjcmliZSgnQWdncmVnYXRpb24gTGFtYmRhJywgKCkgPT4ge1xuICAgICAgdGVzdCgnaGFzIER5bmFtb0RCIHBlcm1pc3Npb25zJywgKCkgPT4ge1xuICAgICAgICAvLyBBZ2dyZWdhdGlvbiBMYW1iZGEgc2hvdWxkIGhhdmUgRHluYW1vREIgcGVybWlzc2lvbnNcbiAgICAgICAgY29uc3QgcG9saWNpZXMgPSB0ZW1wbGF0ZS5maW5kUmVzb3VyY2VzKCdBV1M6OklBTTo6UG9saWN5Jyk7XG5cbiAgICAgICAgLy8gRmluZCB0aGUgYWdncmVnYXRpb24gTGFtYmRhIHBvbGljeSBieSBuYW1lIHBhdHRlcm5cbiAgICAgICAgY29uc3QgYWdncmVnYXRpb25Qb2xpY3lLZXkgPSBPYmplY3Qua2V5cyhwb2xpY2llcykuZmluZChrZXkgPT5cbiAgICAgICAgICBrZXkuaW5jbHVkZXMoJ0FnZ3JlZ2F0aW9uTGFtYmRhUm9sZScpLFxuICAgICAgICApO1xuXG4gICAgICAgIGV4cGVjdChhZ2dyZWdhdGlvblBvbGljeUtleSkudG9CZURlZmluZWQoKTtcblxuICAgICAgICAvLyBWZXJpZnkgbm8gZHluYW1vZGI6KiB3aWxkY2FyZCBpbiBhbnkgcG9saWN5XG4gICAgICAgIE9iamVjdC52YWx1ZXMocG9saWNpZXMpLmZvckVhY2goKHBvbGljeTogYW55KSA9PiB7XG4gICAgICAgICAgY29uc3Qgc3RhdGVtZW50cyA9IHBvbGljeS5Qcm9wZXJ0aWVzPy5Qb2xpY3lEb2N1bWVudD8uU3RhdGVtZW50IHx8IFtdO1xuICAgICAgICAgIHN0YXRlbWVudHMuZm9yRWFjaCgoc3RtdDogYW55KSA9PiB7XG4gICAgICAgICAgICBjb25zdCBhY3Rpb25zID0gQXJyYXkuaXNBcnJheShzdG10LkFjdGlvbikgPyBzdG10LkFjdGlvbiA6IFtzdG10LkFjdGlvbl07XG4gICAgICAgICAgICBhY3Rpb25zLmZvckVhY2goKGFjdGlvbjogc3RyaW5nKSA9PiB7XG4gICAgICAgICAgICAgIGV4cGVjdChhY3Rpb24pLm5vdC50b0JlKCdkeW5hbW9kYjoqJyk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGRlc2NyaWJlKCdObyBXaWxkY2FyZCBQZXJtaXNzaW9ucycsICgpID0+IHtcbiAgICAgIHRlc3QoJ25vIExhbWJkYSByb2xlIGhhcyBzMzoqIHBlcm1pc3Npb24nLCAoKSA9PiB7XG4gICAgICAgIGNvbnN0IHBvbGljaWVzID0gdGVtcGxhdGUuZmluZFJlc291cmNlcygnQVdTOjpJQU06OlBvbGljeScpO1xuXG4gICAgICAgIE9iamVjdC52YWx1ZXMocG9saWNpZXMpLmZvckVhY2goKHBvbGljeTogYW55KSA9PiB7XG4gICAgICAgICAgY29uc3Qgc3RhdGVtZW50cyA9IHBvbGljeS5Qcm9wZXJ0aWVzPy5Qb2xpY3lEb2N1bWVudD8uU3RhdGVtZW50IHx8IFtdO1xuICAgICAgICAgIHN0YXRlbWVudHMuZm9yRWFjaCgoc3RtdDogYW55KSA9PiB7XG4gICAgICAgICAgICBjb25zdCBhY3Rpb25zID0gQXJyYXkuaXNBcnJheShzdG10LkFjdGlvbikgPyBzdG10LkFjdGlvbiA6IFtzdG10LkFjdGlvbl07XG4gICAgICAgICAgICBhY3Rpb25zLmZvckVhY2goKGFjdGlvbjogc3RyaW5nKSA9PiB7XG4gICAgICAgICAgICAgIGV4cGVjdChhY3Rpb24pLm5vdC50b0JlKCdzMzoqJyk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgICAgdGVzdCgnbm8gTGFtYmRhIHJvbGUgaGFzIGR5bmFtb2RiOiogcGVybWlzc2lvbicsICgpID0+IHtcbiAgICAgICAgY29uc3QgcG9saWNpZXMgPSB0ZW1wbGF0ZS5maW5kUmVzb3VyY2VzKCdBV1M6OklBTTo6UG9saWN5Jyk7XG5cbiAgICAgICAgT2JqZWN0LnZhbHVlcyhwb2xpY2llcykuZm9yRWFjaCgocG9saWN5OiBhbnkpID0+IHtcbiAgICAgICAgICBjb25zdCBzdGF0ZW1lbnRzID0gcG9saWN5LlByb3BlcnRpZXM/LlBvbGljeURvY3VtZW50Py5TdGF0ZW1lbnQgfHwgW107XG4gICAgICAgICAgc3RhdGVtZW50cy5mb3JFYWNoKChzdG10OiBhbnkpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGFjdGlvbnMgPSBBcnJheS5pc0FycmF5KHN0bXQuQWN0aW9uKSA/IHN0bXQuQWN0aW9uIDogW3N0bXQuQWN0aW9uXTtcbiAgICAgICAgICAgIGFjdGlvbnMuZm9yRWFjaCgoYWN0aW9uOiBzdHJpbmcpID0+IHtcbiAgICAgICAgICAgICAgZXhwZWN0KGFjdGlvbikubm90LnRvQmUoJ2R5bmFtb2RiOionKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgICB0ZXN0KCdubyBMYW1iZGEgcm9sZSBoYXMgYmVkcm9jazoqIHBlcm1pc3Npb24nLCAoKSA9PiB7XG4gICAgICAgIGNvbnN0IHBvbGljaWVzID0gdGVtcGxhdGUuZmluZFJlc291cmNlcygnQVdTOjpJQU06OlBvbGljeScpO1xuXG4gICAgICAgIE9iamVjdC52YWx1ZXMocG9saWNpZXMpLmZvckVhY2goKHBvbGljeTogYW55KSA9PiB7XG4gICAgICAgICAgY29uc3Qgc3RhdGVtZW50cyA9IHBvbGljeS5Qcm9wZXJ0aWVzPy5Qb2xpY3lEb2N1bWVudD8uU3RhdGVtZW50IHx8IFtdO1xuICAgICAgICAgIHN0YXRlbWVudHMuZm9yRWFjaCgoc3RtdDogYW55KSA9PiB7XG4gICAgICAgICAgICBjb25zdCBhY3Rpb25zID0gQXJyYXkuaXNBcnJheShzdG10LkFjdGlvbikgPyBzdG10LkFjdGlvbiA6IFtzdG10LkFjdGlvbl07XG4gICAgICAgICAgICBhY3Rpb25zLmZvckVhY2goKGFjdGlvbjogc3RyaW5nKSA9PiB7XG4gICAgICAgICAgICAgIGV4cGVjdChhY3Rpb24pLm5vdC50b0JlKCdiZWRyb2NrOionKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnRW5jcnlwdGlvbiBhdCBSZXN0JywgKCkgPT4ge1xuICAgIHRlc3QoJ1MzIGJ1Y2tldCB1c2VzIGVuY3J5cHRpb24nLCAoKSA9PiB7XG4gICAgICAvLyBTMyBidWNrZXQgc2hvdWxkIHVzZSBlbmNyeXB0aW9uIChBV1MtbWFuYWdlZCBLTVMgb3IgY3VzdG9tZXItbWFuYWdlZClcbiAgICAgIC8vIFRoZSBidWNrZXQgcHJvdmlkZWQgYnkgdGhlIHVzZXIgbWF5IHVzZSBkaWZmZXJlbnQgZW5jcnlwdGlvbiBzZXR0aW5nc1xuICAgICAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKCdBV1M6OlMzOjpCdWNrZXQnLCB7XG4gICAgICAgIEJ1Y2tldEVuY3J5cHRpb246IE1hdGNoLmFueVZhbHVlKCksXG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIHRlc3QoJ0R5bmFtb0RCIHRhYmxlIHVzZXMgS01TIGVuY3J5cHRpb24nLCAoKSA9PiB7XG4gICAgICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoJ0FXUzo6RHluYW1vREI6OlRhYmxlJywge1xuICAgICAgICBTU0VTcGVjaWZpY2F0aW9uOiB7XG4gICAgICAgICAgU1NFRW5hYmxlZDogdHJ1ZSxcbiAgICAgICAgICBTU0VUeXBlOiAnS01TJyxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgdGVzdCgnU1FTIHF1ZXVlcyB1c2UgS01TIGVuY3J5cHRpb24nLCAoKSA9PiB7XG4gICAgICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoJ0FXUzo6U1FTOjpRdWV1ZScsIHtcbiAgICAgICAgS21zTWFzdGVyS2V5SWQ6IE1hdGNoLmFueVZhbHVlKCksXG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIHRlc3QoJ1N0ZXAgRnVuY3Rpb25zIHN0YXRlIG1hY2hpbmUgdXNlcyBLTVMgZW5jcnlwdGlvbicsICgpID0+IHtcbiAgICAgIHRlbXBsYXRlLmhhc1Jlc291cmNlUHJvcGVydGllcygnQVdTOjpTdGVwRnVuY3Rpb25zOjpTdGF0ZU1hY2hpbmUnLCB7XG4gICAgICAgIEVuY3J5cHRpb25Db25maWd1cmF0aW9uOiB7XG4gICAgICAgICAgVHlwZTogJ0NVU1RPTUVSX01BTkFHRURfS01TX0tFWScsXG4gICAgICAgICAgS21zS2V5SWQ6IE1hdGNoLmFueVZhbHVlKCksXG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIHRlc3QoJ0xhbWJkYSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgdXNlIEtNUyBlbmNyeXB0aW9uJywgKCkgPT4ge1xuICAgICAgLy8gRmluZCBMYW1iZGEgZnVuY3Rpb25zIHdpdGggZW52aXJvbm1lbnQgdmFyaWFibGVzXG4gICAgICBjb25zdCBsYW1iZGFzID0gdGVtcGxhdGUuZmluZFJlc291cmNlcygnQVdTOjpMYW1iZGE6OkZ1bmN0aW9uJyk7XG5cbiAgICAgIC8vIEFsbCBMYW1iZGEgZnVuY3Rpb25zIHNob3VsZCBoYXZlIEttc0tleUFybiBzZXQgZm9yIGVudmlyb25tZW50IGVuY3J5cHRpb25cbiAgICAgIGNvbnN0IGxhbWJkYXNXaXRoRW52VmFycyA9IE9iamVjdC52YWx1ZXMobGFtYmRhcykuZmlsdGVyKChsYW1iZGE6IGFueSkgPT5cbiAgICAgICAgbGFtYmRhLlByb3BlcnRpZXM/LkVudmlyb25tZW50Py5WYXJpYWJsZXMsXG4gICAgICApO1xuXG4gICAgICAvLyBTaG91bGQgaGF2ZSBMYW1iZGEgZnVuY3Rpb25zIHdpdGggZW52aXJvbm1lbnQgdmFyaWFibGVzXG4gICAgICBleHBlY3QobGFtYmRhc1dpdGhFbnZWYXJzLmxlbmd0aCkudG9CZUdyZWF0ZXJUaGFuKDApO1xuXG4gICAgICAvLyBFYWNoIExhbWJkYSB3aXRoIGVudiB2YXJzIHNob3VsZCBoYXZlIEttc0tleUFyblxuICAgICAgbGFtYmRhc1dpdGhFbnZWYXJzLmZvckVhY2goKGxhbWJkYTogYW55KSA9PiB7XG4gICAgICAgIGV4cGVjdChsYW1iZGEuUHJvcGVydGllcy5LbXNLZXlBcm4pLnRvQmVEZWZpbmVkKCk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ0VuY3J5cHRpb24gaW4gVHJhbnNpdCcsICgpID0+IHtcbiAgICB0ZXN0KCdTMyBidWNrZXQgZW5mb3JjZXMgU1NMJywgKCkgPT4ge1xuICAgICAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKCdBV1M6OlMzOjpCdWNrZXRQb2xpY3knLCB7XG4gICAgICAgIFBvbGljeURvY3VtZW50OiB7XG4gICAgICAgICAgU3RhdGVtZW50OiBNYXRjaC5hcnJheVdpdGgoW1xuICAgICAgICAgICAgTWF0Y2gub2JqZWN0TGlrZSh7XG4gICAgICAgICAgICAgIENvbmRpdGlvbjoge1xuICAgICAgICAgICAgICAgIEJvb2w6IHtcbiAgICAgICAgICAgICAgICAgICdhd3M6U2VjdXJlVHJhbnNwb3J0JzogJ2ZhbHNlJyxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICBFZmZlY3Q6ICdEZW55JyxcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgIF0pLFxuICAgICAgICB9LFxuICAgICAgfSk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdSZXNvdXJjZSBJc29sYXRpb24nLCAoKSA9PiB7XG4gICAgdGVzdCgnTGFtYmRhIGZ1bmN0aW9ucyBoYXZlIHNwZWNpZmljIHJlc291cmNlIEFSTnMsIG5vdCB3aWxkY2FyZHMnLCAoKSA9PiB7XG4gICAgICBjb25zdCBwb2xpY2llcyA9IHRlbXBsYXRlLmZpbmRSZXNvdXJjZXMoJ0FXUzo6SUFNOjpQb2xpY3knKTtcblxuICAgICAgLy8gQ2hlY2sgdGhhdCBTMyBwZXJtaXNzaW9ucyBhcmUgc2NvcGVkIHRvIHNwZWNpZmljIGJ1Y2tldCBBUk5zXG4gICAgICBPYmplY3QudmFsdWVzKHBvbGljaWVzKS5mb3JFYWNoKChwb2xpY3k6IGFueSkgPT4ge1xuICAgICAgICBjb25zdCBzdGF0ZW1lbnRzID0gcG9saWN5LlByb3BlcnRpZXM/LlBvbGljeURvY3VtZW50Py5TdGF0ZW1lbnQgfHwgW107XG4gICAgICAgIHN0YXRlbWVudHMuZm9yRWFjaCgoc3RtdDogYW55KSA9PiB7XG4gICAgICAgICAgY29uc3QgYWN0aW9ucyA9IEFycmF5LmlzQXJyYXkoc3RtdC5BY3Rpb24pID8gc3RtdC5BY3Rpb24gOiBbc3RtdC5BY3Rpb25dO1xuICAgICAgICAgIGNvbnN0IHJlc291cmNlcyA9IEFycmF5LmlzQXJyYXkoc3RtdC5SZXNvdXJjZSkgPyBzdG10LlJlc291cmNlIDogW3N0bXQuUmVzb3VyY2VdO1xuXG4gICAgICAgICAgLy8gSWYgdGhpcyBpcyBhbiBTMyBhY3Rpb24sIHZlcmlmeSByZXNvdXJjZXMgYXJlIG5vdCBqdXN0ICcqJ1xuICAgICAgICAgIGlmIChhY3Rpb25zLnNvbWUoKGE6IHN0cmluZykgPT4gYS5zdGFydHNXaXRoKCdzMzonKSkpIHtcbiAgICAgICAgICAgIHJlc291cmNlcy5mb3JFYWNoKChyZXNvdXJjZTogYW55KSA9PiB7XG4gICAgICAgICAgICAgIC8vIFJlc291cmNlIHNob3VsZCBiZSBhIFJlZiwgR2V0QXR0LCBvciBGbjo6Sm9pbiwgbm90IGp1c3QgJyonXG4gICAgICAgICAgICAgIGlmICh0eXBlb2YgcmVzb3VyY2UgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgZXhwZWN0KHJlc291cmNlKS5ub3QudG9CZSgnKicpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdEeW5hbW9EQiBwZXJtaXNzaW9ucyBhcmUgc2NvcGVkIHRvIHNwZWNpZmljIHRhYmxlJywgKCkgPT4ge1xuICAgICAgY29uc3QgcG9saWNpZXMgPSB0ZW1wbGF0ZS5maW5kUmVzb3VyY2VzKCdBV1M6OklBTTo6UG9saWN5Jyk7XG5cbiAgICAgIE9iamVjdC52YWx1ZXMocG9saWNpZXMpLmZvckVhY2goKHBvbGljeTogYW55KSA9PiB7XG4gICAgICAgIGNvbnN0IHN0YXRlbWVudHMgPSBwb2xpY3kuUHJvcGVydGllcz8uUG9saWN5RG9jdW1lbnQ/LlN0YXRlbWVudCB8fCBbXTtcbiAgICAgICAgc3RhdGVtZW50cy5mb3JFYWNoKChzdG10OiBhbnkpID0+IHtcbiAgICAgICAgICBjb25zdCBhY3Rpb25zID0gQXJyYXkuaXNBcnJheShzdG10LkFjdGlvbikgPyBzdG10LkFjdGlvbiA6IFtzdG10LkFjdGlvbl07XG4gICAgICAgICAgY29uc3QgcmVzb3VyY2VzID0gQXJyYXkuaXNBcnJheShzdG10LlJlc291cmNlKSA/IHN0bXQuUmVzb3VyY2UgOiBbc3RtdC5SZXNvdXJjZV07XG5cbiAgICAgICAgICAvLyBJZiB0aGlzIGlzIGEgRHluYW1vREIgYWN0aW9uLCB2ZXJpZnkgcmVzb3VyY2VzIGFyZSBub3QganVzdCAnKidcbiAgICAgICAgICBpZiAoYWN0aW9ucy5zb21lKChhOiBzdHJpbmcpID0+IGEuc3RhcnRzV2l0aCgnZHluYW1vZGI6JykpKSB7XG4gICAgICAgICAgICByZXNvdXJjZXMuZm9yRWFjaCgocmVzb3VyY2U6IGFueSkgPT4ge1xuICAgICAgICAgICAgICBpZiAodHlwZW9mIHJlc291cmNlID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgIGV4cGVjdChyZXNvdXJjZSkubm90LnRvQmUoJyonKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9KTtcbn0pO1xuXG5kZXNjcmliZSgnQmVkcm9ja0RvY3VtZW50UHJvY2Vzc2luZyBTZWN1cml0eSAtIFdpdGhvdXQgQ2h1bmtpbmcnLCAoKSA9PiB7XG4gIGxldCBhcHA6IFJldHVyblR5cGU8dHlwZW9mIGNyZWF0ZVRlc3RBcHA+O1xuICBsZXQgc3RhY2s6IFN0YWNrO1xuICBsZXQgdGVtcGxhdGU6IFRlbXBsYXRlO1xuXG4gIGJlZm9yZUFsbCgoKSA9PiB7XG4gICAgYXBwID0gY3JlYXRlVGVzdEFwcCgpO1xuICAgIHN0YWNrID0gbmV3IFN0YWNrKGFwcCwgJ1NlY3VyaXR5Tm9DaHVua2luZ1N0YWNrJywge1xuICAgICAgZW52OiB7XG4gICAgICAgIGFjY291bnQ6ICcxMjM0NTY3ODkwMTInLFxuICAgICAgICByZWdpb246ICd1cy1lYXN0LTEnLFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIG5ldyBCZWRyb2NrRG9jdW1lbnRQcm9jZXNzaW5nKHN0YWNrLCAnQmVkcm9ja0RvY3VtZW50UHJvY2Vzc2luZycsIHtcbiAgICAgIGVuYWJsZUNodW5raW5nOiBmYWxzZSxcbiAgICB9KTtcblxuICAgIHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ0VuY3J5cHRpb24gYXQgUmVzdCAod2l0aG91dCBjaHVua2luZyknLCAoKSA9PiB7XG4gICAgdGVzdCgnUzMgYnVja2V0IHVzZXMgS01TIGVuY3J5cHRpb24nLCAoKSA9PiB7XG4gICAgICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoJ0FXUzo6UzM6OkJ1Y2tldCcsIHtcbiAgICAgICAgQnVja2V0RW5jcnlwdGlvbjoge1xuICAgICAgICAgIFNlcnZlclNpZGVFbmNyeXB0aW9uQ29uZmlndXJhdGlvbjogTWF0Y2guYXJyYXlXaXRoKFtcbiAgICAgICAgICAgIE1hdGNoLm9iamVjdExpa2Uoe1xuICAgICAgICAgICAgICBTZXJ2ZXJTaWRlRW5jcnlwdGlvbkJ5RGVmYXVsdDoge1xuICAgICAgICAgICAgICAgIFNTRUFsZ29yaXRobTogJ2F3czprbXMnLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSksXG4gICAgICAgICAgXSksXG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIHRlc3QoJ0R5bmFtb0RCIHRhYmxlIHVzZXMgS01TIGVuY3J5cHRpb24nLCAoKSA9PiB7XG4gICAgICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoJ0FXUzo6RHluYW1vREI6OlRhYmxlJywge1xuICAgICAgICBTU0VTcGVjaWZpY2F0aW9uOiB7XG4gICAgICAgICAgU1NFRW5hYmxlZDogdHJ1ZSxcbiAgICAgICAgICBTU0VUeXBlOiAnS01TJyxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgdGVzdCgnU3RlcCBGdW5jdGlvbnMgc3RhdGUgbWFjaGluZSB1c2VzIEtNUyBlbmNyeXB0aW9uJywgKCkgPT4ge1xuICAgICAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKCdBV1M6OlN0ZXBGdW5jdGlvbnM6OlN0YXRlTWFjaGluZScsIHtcbiAgICAgICAgRW5jcnlwdGlvbkNvbmZpZ3VyYXRpb246IHtcbiAgICAgICAgICBUeXBlOiAnQ1VTVE9NRVJfTUFOQUdFRF9LTVNfS0VZJyxcbiAgICAgICAgICBLbXNLZXlJZDogTWF0Y2guYW55VmFsdWUoKSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnTGVhc3QgUHJpdmlsZWdlICh3aXRob3V0IGNodW5raW5nKScsICgpID0+IHtcbiAgICB0ZXN0KCdubyB3aWxkY2FyZCBzMzoqIHBlcm1pc3Npb25zJywgKCkgPT4ge1xuICAgICAgY29uc3QgcG9saWNpZXMgPSB0ZW1wbGF0ZS5maW5kUmVzb3VyY2VzKCdBV1M6OklBTTo6UG9saWN5Jyk7XG5cbiAgICAgIE9iamVjdC52YWx1ZXMocG9saWNpZXMpLmZvckVhY2goKHBvbGljeTogYW55KSA9PiB7XG4gICAgICAgIGNvbnN0IHN0YXRlbWVudHMgPSBwb2xpY3kuUHJvcGVydGllcz8uUG9saWN5RG9jdW1lbnQ/LlN0YXRlbWVudCB8fCBbXTtcbiAgICAgICAgc3RhdGVtZW50cy5mb3JFYWNoKChzdG10OiBhbnkpID0+IHtcbiAgICAgICAgICBjb25zdCBhY3Rpb25zID0gQXJyYXkuaXNBcnJheShzdG10LkFjdGlvbikgPyBzdG10LkFjdGlvbiA6IFtzdG10LkFjdGlvbl07XG4gICAgICAgICAgYWN0aW9ucy5mb3JFYWNoKChhY3Rpb246IHN0cmluZykgPT4ge1xuICAgICAgICAgICAgZXhwZWN0KGFjdGlvbikubm90LnRvQmUoJ3MzOionKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIHRlc3QoJ25vIHdpbGRjYXJkIGR5bmFtb2RiOiogcGVybWlzc2lvbnMnLCAoKSA9PiB7XG4gICAgICBjb25zdCBwb2xpY2llcyA9IHRlbXBsYXRlLmZpbmRSZXNvdXJjZXMoJ0FXUzo6SUFNOjpQb2xpY3knKTtcblxuICAgICAgT2JqZWN0LnZhbHVlcyhwb2xpY2llcykuZm9yRWFjaCgocG9saWN5OiBhbnkpID0+IHtcbiAgICAgICAgY29uc3Qgc3RhdGVtZW50cyA9IHBvbGljeS5Qcm9wZXJ0aWVzPy5Qb2xpY3lEb2N1bWVudD8uU3RhdGVtZW50IHx8IFtdO1xuICAgICAgICBzdGF0ZW1lbnRzLmZvckVhY2goKHN0bXQ6IGFueSkgPT4ge1xuICAgICAgICAgIGNvbnN0IGFjdGlvbnMgPSBBcnJheS5pc0FycmF5KHN0bXQuQWN0aW9uKSA/IHN0bXQuQWN0aW9uIDogW3N0bXQuQWN0aW9uXTtcbiAgICAgICAgICBhY3Rpb25zLmZvckVhY2goKGFjdGlvbjogc3RyaW5nKSA9PiB7XG4gICAgICAgICAgICBleHBlY3QoYWN0aW9uKS5ub3QudG9CZSgnZHluYW1vZGI6KicpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9KTtcbn0pO1xuIl19
|