@aws-mdaa/dataops-job-l3-construct 1.3.0 → 1.5.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 +114 -389
- package/lib/dataops-job-l3-construct.d.ts +30 -240
- package/lib/dataops-job-l3-construct.js +25 -25
- package/node_modules/@aws-mdaa/s3-bucketpolicy-helper/.npmignore +34 -0
- package/node_modules/@aws-mdaa/s3-bucketpolicy-helper/jest.config.js +5 -0
- package/node_modules/@aws-mdaa/s3-bucketpolicy-helper/lib/index.js +1 -1
- package/node_modules/@aws-mdaa/s3-bucketpolicy-helper/lib/index.ts +241 -0
- package/node_modules/@aws-mdaa/s3-bucketpolicy-helper/package.json +16 -18
- package/node_modules/@aws-mdaa/s3-bucketpolicy-helper/test/bucketpolicy-helper.test.d.ts +5 -0
- package/node_modules/@aws-mdaa/s3-bucketpolicy-helper/test/bucketpolicy-helper.test.js +200 -0
- package/node_modules/@aws-mdaa/s3-bucketpolicy-helper/test/bucketpolicy-helper.test.ts +215 -0
- package/node_modules/@aws-mdaa/s3-bucketpolicy-helper/tsconfig.json +40 -0
- package/node_modules/@aws-mdaa/s3-bucketpolicy-helper/tsconfig.tsbuildinfo +1 -0
- package/node_modules/@aws-mdaa/s3-bucketpolicy-helper/typedoc.json +7 -0
- package/node_modules/@aws-mdaa/s3-inventory-helper/.npmignore +34 -0
- package/node_modules/@aws-mdaa/s3-inventory-helper/jest.config.js +5 -0
- package/node_modules/@aws-mdaa/s3-inventory-helper/lib/index.d.ts +2 -20
- package/node_modules/@aws-mdaa/s3-inventory-helper/lib/index.js +2 -11
- package/node_modules/@aws-mdaa/s3-inventory-helper/lib/index.ts +241 -0
- package/node_modules/@aws-mdaa/s3-inventory-helper/package.json +15 -17
- package/node_modules/@aws-mdaa/s3-inventory-helper/test/TODO +0 -0
- package/node_modules/@aws-mdaa/s3-inventory-helper/tsconfig.json +40 -0
- package/node_modules/@aws-mdaa/s3-inventory-helper/tsconfig.tsbuildinfo +1 -0
- package/node_modules/@aws-mdaa/s3-inventory-helper/typedoc.json +7 -0
- package/node_modules/lodash/README.md +2 -2
- package/node_modules/lodash/_baseUnset.js +47 -2
- package/node_modules/lodash/core.js +1 -1
- package/node_modules/lodash/core.min.js +1 -1
- package/node_modules/lodash/lodash.js +43 -4
- package/node_modules/lodash/lodash.min.js +57 -57
- package/node_modules/lodash/package.json +1 -1
- package/package.json +33 -47
- package/node_modules/lodash/flake.lock +0 -40
- package/node_modules/lodash/flake.nix +0 -20
- package/node_modules/lodash/release.md +0 -48
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { IPrincipal, PolicyStatement, Effect } from 'aws-cdk-lib/aws-iam';
|
|
7
|
+
import { IBucket } from 'aws-cdk-lib/aws-s3';
|
|
8
|
+
|
|
9
|
+
export interface IRestrictObjectPrefixToRoles {
|
|
10
|
+
readonly s3Bucket: IBucket;
|
|
11
|
+
readonly s3Prefix: string;
|
|
12
|
+
readonly readRoleIds?: string[];
|
|
13
|
+
readonly readWriteRoleIds?: string[];
|
|
14
|
+
readonly readWriteSuperRoleIds?: string[];
|
|
15
|
+
readonly readPrincipals?: IPrincipal[];
|
|
16
|
+
readonly readWritePrincipals?: IPrincipal[];
|
|
17
|
+
readonly readWriteSuperPrincipals?: IPrincipal[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface IRestrictBucketToRoles {
|
|
21
|
+
readonly s3Bucket: IBucket;
|
|
22
|
+
readonly roleExcludeIds: string[];
|
|
23
|
+
readonly principalExcludes?: string[];
|
|
24
|
+
readonly prefixExcludes?: string[];
|
|
25
|
+
readonly prefixIncludes?: string[];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Helper class for generating S3 bucket policy statements which grant access to specific object prefixes */
|
|
29
|
+
export class RestrictObjectPrefixToRoles {
|
|
30
|
+
static readonly READ_ACTIONS = ['s3:GetObject*'];
|
|
31
|
+
static readonly READ_WRITE_ACTIONS = [
|
|
32
|
+
...RestrictObjectPrefixToRoles.READ_ACTIONS,
|
|
33
|
+
's3:PutObject',
|
|
34
|
+
's3:PutObjectTagging',
|
|
35
|
+
's3:DeleteObject',
|
|
36
|
+
];
|
|
37
|
+
static readonly READ_WRITE_SUPER_ACTIONS = [
|
|
38
|
+
...RestrictObjectPrefixToRoles.READ_WRITE_ACTIONS,
|
|
39
|
+
's3:DeleteObjectVersion',
|
|
40
|
+
];
|
|
41
|
+
static readonly BUCKET_ALLOW_ACTIONS = ['s3:List*', 's3:GetBucket*'];
|
|
42
|
+
static readonly BUCKET_DENY_ACTIONS = ['s3:PutObject*', 's3:GetObject*', 's3:DeleteObject*'];
|
|
43
|
+
|
|
44
|
+
private _readStatements: PolicyStatement[] = [];
|
|
45
|
+
private _readWriteStatements: PolicyStatement[] = [];
|
|
46
|
+
private _readWriteSuperStatements: PolicyStatement[] = [];
|
|
47
|
+
private _formattedPrefix: string;
|
|
48
|
+
|
|
49
|
+
constructor(props: IRestrictObjectPrefixToRoles) {
|
|
50
|
+
this._formattedPrefix = '/' + this.formatS3Prefix(props.s3Prefix) + '/*';
|
|
51
|
+
// Covers our case where two / get resolved because our prefix is actually /
|
|
52
|
+
this._formattedPrefix = this._formattedPrefix.replace(/\/\//, '/');
|
|
53
|
+
|
|
54
|
+
// FEDERATED / READ
|
|
55
|
+
if (props.readRoleIds != undefined && props.readRoleIds.length > 0) {
|
|
56
|
+
// Construct our User:Id roles for read
|
|
57
|
+
const statement = this._readStatementScaffold(props);
|
|
58
|
+
statement.addCondition('StringLike', { 'aws:userId': props.readRoleIds.map(x => `${x}:*`) });
|
|
59
|
+
statement.addAnyPrincipal();
|
|
60
|
+
this._readStatements.push(statement);
|
|
61
|
+
}
|
|
62
|
+
// FEDERATED / READWRITE
|
|
63
|
+
if (props.readWriteRoleIds != undefined && props.readWriteRoleIds.length > 0) {
|
|
64
|
+
const statement = this._readWriteStatementScaffold(props);
|
|
65
|
+
statement.addCondition('StringLike', { 'aws:userId': props.readWriteRoleIds.map(x => `${x}:*`) });
|
|
66
|
+
statement.addAnyPrincipal();
|
|
67
|
+
this._readWriteStatements.push(statement);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// FEDERATED / READWRITESUPER
|
|
71
|
+
if (props.readWriteSuperRoleIds != undefined && props.readWriteSuperRoleIds.length > 0) {
|
|
72
|
+
const statement = this._readWriteSuperStatementScaffold(props);
|
|
73
|
+
statement.addCondition('StringLike', { 'aws:userId': props.readWriteSuperRoleIds.map(x => `${x}:*`) });
|
|
74
|
+
statement.addAnyPrincipal();
|
|
75
|
+
this._readWriteSuperStatements.push(statement);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// NONFEDERATED / READ
|
|
79
|
+
if (props.readPrincipals != undefined && props.readPrincipals.length > 0) {
|
|
80
|
+
const statement = this._readStatementScaffold(props);
|
|
81
|
+
props.readPrincipals.forEach(principal => {
|
|
82
|
+
statement.addPrincipals(principal);
|
|
83
|
+
});
|
|
84
|
+
this._readStatements.push(statement);
|
|
85
|
+
}
|
|
86
|
+
// NONFEDERATED / READWRITE
|
|
87
|
+
if (props.readWritePrincipals != undefined && props.readWritePrincipals.length > 0) {
|
|
88
|
+
const statement = this._readWriteStatementScaffold(props);
|
|
89
|
+
props.readWritePrincipals.forEach(principal => {
|
|
90
|
+
statement.addPrincipals(principal);
|
|
91
|
+
});
|
|
92
|
+
this._readWriteStatements.push(statement);
|
|
93
|
+
}
|
|
94
|
+
// NONFEDERATED / READWRITESUPER
|
|
95
|
+
if (props.readWriteSuperPrincipals != undefined && props.readWriteSuperPrincipals.length > 0) {
|
|
96
|
+
const statement = this._readWriteSuperStatementScaffold(props);
|
|
97
|
+
props.readWriteSuperPrincipals.forEach(principal => {
|
|
98
|
+
statement.addPrincipals(principal);
|
|
99
|
+
});
|
|
100
|
+
this._readWriteSuperStatements.push(statement);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private _readStatementScaffold(props: IRestrictObjectPrefixToRoles): PolicyStatement {
|
|
105
|
+
return new PolicyStatement({
|
|
106
|
+
sid: `${props.s3Prefix.replace(/\\W/g, '')}_Read`,
|
|
107
|
+
effect: Effect.ALLOW,
|
|
108
|
+
resources: [props.s3Bucket.bucketArn + this._formattedPrefix],
|
|
109
|
+
actions: RestrictObjectPrefixToRoles.READ_ACTIONS,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private _readWriteStatementScaffold(props: IRestrictObjectPrefixToRoles): PolicyStatement {
|
|
114
|
+
return new PolicyStatement({
|
|
115
|
+
sid: `${props.s3Prefix.replace(/\\W/g, '')}_ReadWrite`,
|
|
116
|
+
effect: Effect.ALLOW,
|
|
117
|
+
resources: [props.s3Bucket.bucketArn + this._formattedPrefix],
|
|
118
|
+
actions: RestrictObjectPrefixToRoles.READ_WRITE_ACTIONS,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
private _readWriteSuperStatementScaffold(props: IRestrictObjectPrefixToRoles): PolicyStatement {
|
|
123
|
+
return new PolicyStatement({
|
|
124
|
+
sid: `${props.s3Prefix.replace(/\\W/g, '')}_ReadWriteSuper`,
|
|
125
|
+
effect: Effect.ALLOW,
|
|
126
|
+
resources: [props.s3Bucket.bucketArn + this._formattedPrefix],
|
|
127
|
+
actions: RestrictObjectPrefixToRoles.READ_WRITE_SUPER_ACTIONS,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
public readStatements(): PolicyStatement[] {
|
|
132
|
+
return this._readStatements;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
public readWriteStatements(): PolicyStatement[] {
|
|
136
|
+
return this._readWriteStatements;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
public readWriteSuperStatements(): PolicyStatement[] {
|
|
140
|
+
return this._readWriteSuperStatements;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
public statements(): PolicyStatement[] {
|
|
144
|
+
return [...this._readStatements, ...this._readWriteStatements, ...this._readWriteSuperStatements];
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
public formatS3Prefix(prefix: string): string {
|
|
148
|
+
let rawPrefix = prefix;
|
|
149
|
+
|
|
150
|
+
// Removes trailing slashes
|
|
151
|
+
rawPrefix = rawPrefix.endsWith('/') ? rawPrefix.slice(0, -1) : rawPrefix;
|
|
152
|
+
// Removes leading slashes
|
|
153
|
+
rawPrefix = rawPrefix.startsWith('/') ? rawPrefix.substring(1) : rawPrefix;
|
|
154
|
+
return rawPrefix;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** Helper class for generating bucket policy statements
|
|
159
|
+
* which allow or deny access to an entire bucket. Used to
|
|
160
|
+
* create bucket-level default deny statements to block accesses
|
|
161
|
+
* not granted in the bucket policy. */
|
|
162
|
+
export class RestrictBucketToRoles {
|
|
163
|
+
public readonly denyStatement: PolicyStatement;
|
|
164
|
+
public readonly allowStatement: PolicyStatement;
|
|
165
|
+
private resource: string[] = [];
|
|
166
|
+
private notResource: string[] = [];
|
|
167
|
+
private denyConditionalNotEquals: {
|
|
168
|
+
'aws:userId'?: string[];
|
|
169
|
+
'aws:PrincipalArn'?: string[];
|
|
170
|
+
} = {};
|
|
171
|
+
|
|
172
|
+
constructor(props: IRestrictBucketToRoles) {
|
|
173
|
+
// Statement allowing access to the bucket for the AROAs
|
|
174
|
+
this.allowStatement = new PolicyStatement({
|
|
175
|
+
sid: `BucketAllow`,
|
|
176
|
+
effect: Effect.ALLOW,
|
|
177
|
+
resources: [props.s3Bucket.bucketArn + '/*', props.s3Bucket.bucketArn],
|
|
178
|
+
actions: RestrictObjectPrefixToRoles.BUCKET_ALLOW_ACTIONS,
|
|
179
|
+
});
|
|
180
|
+
this.allowStatement.addAnyPrincipal();
|
|
181
|
+
this.allowStatement.addCondition('StringLike', { 'aws:userId': props.roleExcludeIds.map(x => `${x}:*`) });
|
|
182
|
+
|
|
183
|
+
// Constuct our deny statement.
|
|
184
|
+
// prefixIncludes denotes we want to include a prefix in our deny meaning Resource
|
|
185
|
+
if (props.prefixIncludes) {
|
|
186
|
+
this.resource = props.prefixIncludes.map(prefix => {
|
|
187
|
+
return `${props.s3Bucket.bucketArn}/${this.formatS3Prefix(prefix)}`;
|
|
188
|
+
});
|
|
189
|
+
} else {
|
|
190
|
+
this.resource = [props.s3Bucket.bucketArn + '/*'];
|
|
191
|
+
}
|
|
192
|
+
// prefixExcludes denote we want to exclude a prefix in our deny meaning notResource
|
|
193
|
+
if (props.prefixExcludes) {
|
|
194
|
+
this.notResource = props.prefixExcludes.map(prefix => {
|
|
195
|
+
return `${props.s3Bucket.bucketArn}/${this.formatS3Prefix(prefix)}`;
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (this.notResource.length > 0) {
|
|
200
|
+
this.denyStatement = new PolicyStatement({
|
|
201
|
+
sid: `BucketDeny`,
|
|
202
|
+
effect: Effect.DENY,
|
|
203
|
+
notResources: this.notResource,
|
|
204
|
+
actions: RestrictObjectPrefixToRoles.BUCKET_DENY_ACTIONS,
|
|
205
|
+
});
|
|
206
|
+
} else {
|
|
207
|
+
this.denyStatement = new PolicyStatement({
|
|
208
|
+
sid: `BucketDeny`,
|
|
209
|
+
effect: Effect.DENY,
|
|
210
|
+
resources: this.resource,
|
|
211
|
+
actions: RestrictObjectPrefixToRoles.BUCKET_DENY_ACTIONS,
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
this.denyStatement.addAnyPrincipal();
|
|
215
|
+
|
|
216
|
+
// Build our conditionals.
|
|
217
|
+
this.denyConditionalNotEquals['aws:userId'] = props.roleExcludeIds.map(x => `${x}:*`);
|
|
218
|
+
if (props.principalExcludes && props.principalExcludes.length > 0) {
|
|
219
|
+
this.denyConditionalNotEquals['aws:PrincipalArn'] = [...new Set(props.principalExcludes)].sort((a, b) =>
|
|
220
|
+
a.localeCompare(b),
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Construct our conditional for our deny
|
|
225
|
+
if (Object.keys(this.denyConditionalNotEquals).length == 1) {
|
|
226
|
+
this.denyStatement.addCondition('StringNotLike', this.denyConditionalNotEquals);
|
|
227
|
+
} else {
|
|
228
|
+
this.denyStatement.addCondition('ForAnyValue:StringNotLike', this.denyConditionalNotEquals);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
private formatS3Prefix(prefix: string): string {
|
|
233
|
+
let rawPrefix = prefix;
|
|
234
|
+
|
|
235
|
+
// Removes trailing slashes
|
|
236
|
+
rawPrefix = rawPrefix.endsWith('/') ? rawPrefix.slice(0, -1) : rawPrefix;
|
|
237
|
+
// Removes leading slashes
|
|
238
|
+
rawPrefix = rawPrefix.startsWith('/') ? rawPrefix.substring(1) : rawPrefix;
|
|
239
|
+
return `${rawPrefix}/*`;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
@@ -5,35 +5,33 @@
|
|
|
5
5
|
"name": "Amazon Web Services",
|
|
6
6
|
"url": "https://aws.amazon.com/solutions"
|
|
7
7
|
},
|
|
8
|
-
"version": "1.
|
|
8
|
+
"version": "1.5.0",
|
|
9
9
|
"license": "Apache-2.0",
|
|
10
10
|
"main": "lib/index.js",
|
|
11
11
|
"types": "lib/index.d.ts",
|
|
12
12
|
"scripts": {
|
|
13
13
|
"build": "tsc",
|
|
14
14
|
"watch": "tsc -w",
|
|
15
|
-
"test": "jest --passWithNoTests --
|
|
16
|
-
"lint": "eslint --max-warnings 0 -c
|
|
17
|
-
"test
|
|
15
|
+
"test": "jest --passWithNoTests --testPathIgnorePatterns='.*\\.snapshot\\.test\\.ts'",
|
|
16
|
+
"lint": "eslint --max-warnings 0 -c ../../../eslint.config.mjs",
|
|
17
|
+
"test:coverage": "jest --passWithNoTests --coverage --testPathIgnorePatterns='.*\\.snapshot\\.test\\.ts'",
|
|
18
|
+
"test:snapshots": "jest --passWithNoTests --testPathPattern='.*\\.snapshot\\.test\\.ts'",
|
|
19
|
+
"test:snapshots:update": "jest --passWithNoTests --testPathPattern='.*\\.snapshot\\.test\\.ts' --updateSnapshot"
|
|
18
20
|
},
|
|
19
21
|
"devDependencies": {
|
|
20
|
-
"@aws-mdaa/testing": "1.
|
|
21
|
-
"@types/jest": "29.5.
|
|
22
|
-
"@types/node": "
|
|
22
|
+
"@aws-mdaa/testing": "1.5.0",
|
|
23
|
+
"@types/jest": "29.5.14",
|
|
24
|
+
"@types/node": "22.9.0",
|
|
23
25
|
"@types/prettier": "2.6.0",
|
|
24
|
-
"jest": "29.
|
|
25
|
-
"ts-jest": "29.
|
|
26
|
-
"ts-node": "10.9.
|
|
27
|
-
"typescript": "
|
|
28
|
-
"typescript-json-schema": "0.
|
|
29
|
-
},
|
|
30
|
-
"overrides": {
|
|
31
|
-
"aws-cdk-lib": "2.220.0",
|
|
32
|
-
"@types/babel__traverse": "7.18.2"
|
|
26
|
+
"jest": "29.7.0",
|
|
27
|
+
"ts-jest": "29.4.6",
|
|
28
|
+
"ts-node": "10.9.2",
|
|
29
|
+
"typescript": "5.9.3",
|
|
30
|
+
"typescript-json-schema": "0.67.1"
|
|
33
31
|
},
|
|
34
32
|
"dependencies": {
|
|
35
|
-
"@aws-mdaa/iam-role-helper": "1.
|
|
36
|
-
"@aws-mdaa/naming": "1.
|
|
33
|
+
"@aws-mdaa/iam-role-helper": "1.5.0",
|
|
34
|
+
"@aws-mdaa/naming": "1.5.0",
|
|
37
35
|
"aws-cdk-lib": "2.220.0",
|
|
38
36
|
"cdk-nag": "2.37.55",
|
|
39
37
|
"constructs": "10.0.96"
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*!
|
|
3
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const testing_1 = require("@aws-mdaa/testing");
|
|
8
|
+
const lib_1 = require("../lib");
|
|
9
|
+
const aws_s3_1 = require("aws-cdk-lib/aws-s3");
|
|
10
|
+
const aws_iam_1 = require("aws-cdk-lib/aws-iam");
|
|
11
|
+
describe('Test BucketPolicy Helper', () => {
|
|
12
|
+
const testApp = new testing_1.MdaaTestApp();
|
|
13
|
+
const testBucket = aws_s3_1.Bucket.fromBucketName(testApp.testStack, 'test-bucket', 'test-bucket');
|
|
14
|
+
describe('RestrictPrefix', () => {
|
|
15
|
+
const baseTestProps = {
|
|
16
|
+
s3Bucket: testBucket,
|
|
17
|
+
s3Prefix: 'test-prefix',
|
|
18
|
+
};
|
|
19
|
+
test('Read Role Ids', () => {
|
|
20
|
+
const testProps = {
|
|
21
|
+
...baseTestProps,
|
|
22
|
+
readRoleIds: ['test-role-id-1', 'test-role-id-2'],
|
|
23
|
+
};
|
|
24
|
+
const restriction = new lib_1.RestrictObjectPrefixToRoles(testProps);
|
|
25
|
+
// console.log( JSON.stringify( restriction.statements()[ 0 ], undefined, 2 ) )
|
|
26
|
+
expect(restriction.statements().length).toBe(1);
|
|
27
|
+
expect(restriction.readStatements().length).toBe(1);
|
|
28
|
+
expect(restriction.readWriteSuperStatements().length).toBe(0);
|
|
29
|
+
expect(restriction.readWriteStatements().length).toBe(0);
|
|
30
|
+
expect(restriction.readStatements()[0].actions).toStrictEqual(['s3:GetObject*']);
|
|
31
|
+
expect(restriction.readStatements()[0].conditions).toStrictEqual({
|
|
32
|
+
StringLike: {
|
|
33
|
+
'aws:userId': ['test-role-id-1:*', 'test-role-id-2:*'],
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
expect(restriction.readStatements()[0].effect).toBe('Allow');
|
|
37
|
+
expect(restriction.readStatements()[0].resources).toStrictEqual([
|
|
38
|
+
'arn:test-partition:s3:::test-bucket/test-prefix/*',
|
|
39
|
+
]);
|
|
40
|
+
});
|
|
41
|
+
test('ReadWrite Role Ids', () => {
|
|
42
|
+
const testProps = {
|
|
43
|
+
...baseTestProps,
|
|
44
|
+
readWriteRoleIds: ['test-role-id-1', 'test-role-id-2'],
|
|
45
|
+
};
|
|
46
|
+
const restriction = new lib_1.RestrictObjectPrefixToRoles(testProps);
|
|
47
|
+
// console.log( JSON.stringify( restriction.statements()[ 0 ], undefined, 2 ) )
|
|
48
|
+
expect(restriction.statements().length).toBe(1);
|
|
49
|
+
expect(restriction.readWriteStatements().length).toBe(1);
|
|
50
|
+
expect(restriction.readStatements().length).toBe(0);
|
|
51
|
+
expect(restriction.readWriteSuperStatements().length).toBe(0);
|
|
52
|
+
expect(restriction.readWriteStatements()[0].actions).toStrictEqual([
|
|
53
|
+
's3:GetObject*',
|
|
54
|
+
's3:PutObject',
|
|
55
|
+
's3:PutObjectTagging',
|
|
56
|
+
's3:DeleteObject',
|
|
57
|
+
]);
|
|
58
|
+
expect(restriction.readWriteStatements()[0].conditions).toStrictEqual({
|
|
59
|
+
StringLike: {
|
|
60
|
+
'aws:userId': ['test-role-id-1:*', 'test-role-id-2:*'],
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
test('ReadWriteSuper Role Ids', () => {
|
|
65
|
+
const testProps = {
|
|
66
|
+
...baseTestProps,
|
|
67
|
+
readWriteSuperRoleIds: ['test-role-id-1', 'test-role-id-2'],
|
|
68
|
+
};
|
|
69
|
+
const restriction = new lib_1.RestrictObjectPrefixToRoles(testProps);
|
|
70
|
+
// console.log( JSON.stringify( restriction.statements()[ 0 ], undefined, 2 ) )
|
|
71
|
+
expect(restriction.statements().length).toBe(1);
|
|
72
|
+
expect(restriction.readWriteSuperStatements().length).toBe(1);
|
|
73
|
+
expect(restriction.readStatements().length).toBe(0);
|
|
74
|
+
expect(restriction.readWriteStatements().length).toBe(0);
|
|
75
|
+
expect(restriction.readWriteSuperStatements()[0].actions).toStrictEqual([
|
|
76
|
+
's3:GetObject*',
|
|
77
|
+
's3:PutObject',
|
|
78
|
+
's3:PutObjectTagging',
|
|
79
|
+
's3:DeleteObject',
|
|
80
|
+
's3:DeleteObjectVersion',
|
|
81
|
+
]);
|
|
82
|
+
expect(restriction.readWriteSuperStatements()[0].conditions).toStrictEqual({
|
|
83
|
+
StringLike: {
|
|
84
|
+
'aws:userId': ['test-role-id-1:*', 'test-role-id-2:*'],
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
test('Read Principals', () => {
|
|
89
|
+
const testProps = {
|
|
90
|
+
...baseTestProps,
|
|
91
|
+
readPrincipals: [new aws_iam_1.ArnPrincipal('test-role-arn-1')],
|
|
92
|
+
};
|
|
93
|
+
const restriction = new lib_1.RestrictObjectPrefixToRoles(testProps);
|
|
94
|
+
// console.log( JSON.stringify( restriction.statements()[ 0 ], undefined, 2 ) )
|
|
95
|
+
expect(restriction.statements().length).toBe(1);
|
|
96
|
+
expect(restriction.readStatements().length).toBe(1);
|
|
97
|
+
expect(restriction.readWriteSuperStatements().length).toBe(0);
|
|
98
|
+
expect(restriction.readWriteStatements().length).toBe(0);
|
|
99
|
+
expect(restriction.readStatements()[0].actions).toStrictEqual(['s3:GetObject*']);
|
|
100
|
+
expect(restriction.readStatements()[0].effect).toBe('Allow');
|
|
101
|
+
expect(restriction.readStatements()[0].resources).toStrictEqual([
|
|
102
|
+
'arn:test-partition:s3:::test-bucket/test-prefix/*',
|
|
103
|
+
]);
|
|
104
|
+
expect(restriction.readStatements()[0].principals.length).toBe(1);
|
|
105
|
+
expect(JSON.stringify(restriction.readStatements()[0].principals[0])).toStrictEqual(JSON.stringify({ AWS: ['test-role-arn-1'] }));
|
|
106
|
+
});
|
|
107
|
+
test('ReadWrite Principals', () => {
|
|
108
|
+
const testProps = {
|
|
109
|
+
...baseTestProps,
|
|
110
|
+
readWritePrincipals: [new aws_iam_1.ArnPrincipal('test-role-arn-1')],
|
|
111
|
+
};
|
|
112
|
+
const restriction = new lib_1.RestrictObjectPrefixToRoles(testProps);
|
|
113
|
+
// console.log( JSON.stringify( restriction.statements()[ 0 ], undefined, 2 ) )
|
|
114
|
+
expect(restriction.statements().length).toBe(1);
|
|
115
|
+
expect(restriction.readWriteStatements().length).toBe(1);
|
|
116
|
+
expect(restriction.readStatements().length).toBe(0);
|
|
117
|
+
expect(restriction.readWriteSuperStatements().length).toBe(0);
|
|
118
|
+
expect(restriction.readWriteStatements()[0].actions).toStrictEqual([
|
|
119
|
+
's3:GetObject*',
|
|
120
|
+
's3:PutObject',
|
|
121
|
+
's3:PutObjectTagging',
|
|
122
|
+
's3:DeleteObject',
|
|
123
|
+
]);
|
|
124
|
+
expect(restriction.readWriteStatements()[0].effect).toBe('Allow');
|
|
125
|
+
expect(restriction.readWriteStatements()[0].resources).toStrictEqual([
|
|
126
|
+
'arn:test-partition:s3:::test-bucket/test-prefix/*',
|
|
127
|
+
]);
|
|
128
|
+
expect(restriction.readWriteStatements()[0].principals.length).toBe(1);
|
|
129
|
+
expect(JSON.stringify(restriction.readWriteStatements()[0].principals[0])).toStrictEqual(JSON.stringify({ AWS: ['test-role-arn-1'] }));
|
|
130
|
+
});
|
|
131
|
+
test('ReadWriteSuper Principals', () => {
|
|
132
|
+
const testProps = {
|
|
133
|
+
...baseTestProps,
|
|
134
|
+
readWriteSuperPrincipals: [new aws_iam_1.ArnPrincipal('test-role-arn-1')],
|
|
135
|
+
};
|
|
136
|
+
const restriction = new lib_1.RestrictObjectPrefixToRoles(testProps);
|
|
137
|
+
// console.log( JSON.stringify( restriction.statements()[ 0 ], undefined, 2 ) )
|
|
138
|
+
expect(restriction.statements().length).toBe(1);
|
|
139
|
+
expect(restriction.readStatements().length).toBe(0);
|
|
140
|
+
expect(restriction.readWriteStatements().length).toBe(0);
|
|
141
|
+
expect(restriction.readWriteSuperStatements().length).toBe(1);
|
|
142
|
+
expect(restriction.readWriteSuperStatements()[0].actions).toStrictEqual([
|
|
143
|
+
's3:GetObject*',
|
|
144
|
+
's3:PutObject',
|
|
145
|
+
's3:PutObjectTagging',
|
|
146
|
+
's3:DeleteObject',
|
|
147
|
+
's3:DeleteObjectVersion',
|
|
148
|
+
]);
|
|
149
|
+
expect(restriction.readWriteSuperStatements()[0].effect).toBe('Allow');
|
|
150
|
+
expect(restriction.readWriteSuperStatements()[0].resources).toStrictEqual([
|
|
151
|
+
'arn:test-partition:s3:::test-bucket/test-prefix/*',
|
|
152
|
+
]);
|
|
153
|
+
expect(restriction.readWriteSuperStatements()[0].principals.length).toBe(1);
|
|
154
|
+
expect(JSON.stringify(restriction.readWriteSuperStatements()[0].principals[0])).toStrictEqual(JSON.stringify({ AWS: ['test-role-arn-1'] }));
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
describe('RestrictBucket', () => {
|
|
158
|
+
const baseTestProps = {
|
|
159
|
+
s3Bucket: testBucket,
|
|
160
|
+
roleExcludeIds: ['test-role-id-1', 'test-role-id-2'],
|
|
161
|
+
principalExcludes: ['test-arn'],
|
|
162
|
+
prefixExcludes: ['exclude-prefix'],
|
|
163
|
+
prefixIncludes: ['exclude-prefix'],
|
|
164
|
+
};
|
|
165
|
+
test('Base Allow', () => {
|
|
166
|
+
const testProps = {
|
|
167
|
+
...baseTestProps,
|
|
168
|
+
};
|
|
169
|
+
const restriction = new lib_1.RestrictBucketToRoles(testProps);
|
|
170
|
+
console.log(JSON.stringify(restriction.allowStatement, undefined, 2));
|
|
171
|
+
expect(restriction.allowStatement.actions).toStrictEqual(['s3:List*', 's3:GetBucket*']);
|
|
172
|
+
expect(restriction.allowStatement.effect).toBe('Allow');
|
|
173
|
+
expect(restriction.allowStatement.conditions).toStrictEqual({
|
|
174
|
+
StringLike: {
|
|
175
|
+
'aws:userId': ['test-role-id-1:*', 'test-role-id-2:*'],
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
expect(restriction.allowStatement.resources).toStrictEqual([
|
|
179
|
+
'arn:test-partition:s3:::test-bucket/*',
|
|
180
|
+
'arn:test-partition:s3:::test-bucket',
|
|
181
|
+
]);
|
|
182
|
+
});
|
|
183
|
+
test('Base Deny', () => {
|
|
184
|
+
const testProps = {
|
|
185
|
+
...baseTestProps,
|
|
186
|
+
};
|
|
187
|
+
const restriction = new lib_1.RestrictBucketToRoles(testProps);
|
|
188
|
+
console.log(JSON.stringify(restriction.denyStatement, undefined, 2));
|
|
189
|
+
expect(restriction.denyStatement.actions).toStrictEqual(['s3:PutObject*', 's3:GetObject*', 's3:DeleteObject*']);
|
|
190
|
+
expect(restriction.denyStatement.effect).toBe('Deny');
|
|
191
|
+
expect(restriction.denyStatement.conditions).toStrictEqual({
|
|
192
|
+
'ForAnyValue:StringNotLike': {
|
|
193
|
+
'aws:userId': ['test-role-id-1:*', 'test-role-id-2:*'],
|
|
194
|
+
'aws:PrincipalArn': ['test-arn'],
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnVja2V0cG9saWN5LWhlbHBlci50ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiYnVja2V0cG9saWN5LWhlbHBlci50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7O0dBR0c7O0FBRUgsK0NBQWdEO0FBQ2hELGdDQUtnQjtBQUNoQiwrQ0FBNEM7QUFDNUMsaURBQW1EO0FBRW5ELFFBQVEsQ0FBQywwQkFBMEIsRUFBRSxHQUFHLEVBQUU7SUFDeEMsTUFBTSxPQUFPLEdBQUcsSUFBSSxxQkFBVyxFQUFFLENBQUM7SUFDbEMsTUFBTSxVQUFVLEdBQUcsZUFBTSxDQUFDLGNBQWMsQ0FBQyxPQUFPLENBQUMsU0FBUyxFQUFFLGFBQWEsRUFBRSxhQUFhLENBQUMsQ0FBQztJQUMxRixRQUFRLENBQUMsZ0JBQWdCLEVBQUUsR0FBRyxFQUFFO1FBQzlCLE1BQU0sYUFBYSxHQUFpQztZQUNsRCxRQUFRLEVBQUUsVUFBVTtZQUNwQixRQUFRLEVBQUUsYUFBYTtTQUN4QixDQUFDO1FBQ0YsSUFBSSxDQUFDLGVBQWUsRUFBRSxHQUFHLEVBQUU7WUFDekIsTUFBTSxTQUFTLEdBQWlDO2dCQUM5QyxHQUFHLGFBQWE7Z0JBQ2hCLFdBQVcsRUFBRSxDQUFDLGdCQUFnQixFQUFFLGdCQUFnQixDQUFDO2FBQ2xELENBQUM7WUFDRixNQUFNLFdBQVcsR0FBRyxJQUFJLGlDQUEyQixDQUFDLFNBQVMsQ0FBQyxDQUFDO1lBQy9ELCtFQUErRTtZQUMvRSxNQUFNLENBQUMsV0FBVyxDQUFDLFVBQVUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUNoRCxNQUFNLENBQUMsV0FBVyxDQUFDLGNBQWMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUNwRCxNQUFNLENBQUMsV0FBVyxDQUFDLHdCQUF3QixFQUFFLENBQUMsTUFBTSxDQUFDLENBQUMsSUFBSSxDQUFD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LEVBQUUsa0JBQWtCLENBQUMsQ0FBQyxDQUFDO1lBQ2hILE1BQU0sQ0FBQyxXQUFXLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUN0RCxNQUFNLENBQUMsV0FBVyxDQUFDLGFBQWEsQ0FBQyxVQUFVLENBQUMsQ0FBQyxhQUFhLENBQUM7Z0JBQ3pELDJCQUEyQixFQUFFO29CQUMzQixZQUFZLEVBQUUsQ0FBQyxrQkFBa0IsRUFBRSxrQkFBa0IsQ0FBQztvQkFDdEQsa0JBQWtCLEVBQUUsQ0FBQyxVQUFVLENBQUM7aUJBQ2pDO2FBQ0YsQ0FBQyxDQUFDO1FBQ0wsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyohXG4gKiBDb3B5cmlnaHQgQW1hem9uLmNvbSwgSW5jLiBvciBpdHMgYWZmaWxpYXRlcy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG4gKi9cblxuaW1wb3J0IHsgTWRhYVRlc3RBcHAgfSBmcm9tICdAYXdzLW1kYWEvdGVzdGluZyc7XG5pbXBvcnQge1xuICBJUmVzdHJpY3RCdWNrZXRUb1JvbGVzLFxuICBJUmVzdHJpY3RPYmplY3RQcmVmaXhUb1JvbGVzLFxuICBSZXN0cmljdEJ1Y2tldFRvUm9sZXMsXG4gIFJlc3RyaWN0T2JqZWN0UHJlZml4VG9Sb2xlcyxcbn0gZnJvbSAnLi4vbGliJztcbmltcG9ydCB7IEJ1Y2tldCB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1zMyc7XG5pbXBvcnQgeyBBcm5QcmluY2lwYWwgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtaWFtJztcblxuZGVzY3JpYmUoJ1Rlc3QgQnVja2V0UG9saWN5IEhlbHBlcicsICgpID0+IHtcbiAgY29uc3QgdGVzdEFwcCA9IG5ldyBNZGFhVGVzdEFwcCgpO1xuICBjb25zdCB0ZXN0QnVja2V0ID0gQnVja2V0LmZyb21CdWNrZXROYW1lKHRlc3RBcHAudGVzdFN0YWNrLCAndGVzdC1idWNrZXQnLCAndGVzdC1idWNrZXQnKTtcbiAgZGVzY3JpYmUoJ1Jlc3RyaWN0UHJlZml4JywgKCkgPT4ge1xuICAgIGNvbnN0IGJhc2VUZXN0UHJvcHM6IElSZXN0cmljdE9iamVjdFByZWZpeFRvUm9sZXMgPSB7XG4gICAgICBzM0J1Y2tldDogdGVzdEJ1Y2tldCxcbiAgICAgIHMzUHJlZml4OiAndGVzdC1wcmVmaXgnLFxuICAgIH07XG4gICAgdGVzdCgnUmVhZCBSb2xlIElkcycsICgpID0+IHtcbiAgICAgIGNvbnN0IHRlc3RQcm9wczogSVJlc3RyaWN0T2JqZWN0UHJlZml4VG9Sb2xlcyA9IHtcbiAgICAgICAgLi4uYmFzZVRlc3RQcm9wcyxcbiAgICAgICAgcmVhZFJvbGVJZHM6IFsndGVzdC1yb2xlLWlkLTEnLCAndGVzdC1yb2xlLWlkLTInXSxcbiAgICAgIH07XG4gICAgICBjb25zdCByZXN0cmljdGlvbiA9IG5ldyBSZXN0cmljdE9iamVjdFByZWZpeFRvUm9sZXModGVzdFByb3BzKTtcbiAgICAgIC8vIGNvbnNvbGUubG9nKCBKU09OLnN0cmluZ2lmeSggcmVzdHJpY3Rpb24uc3RhdGVtZW50cygpWyAwIF0sIHVuZGVmaW5lZCwgMiApIClcbiAgICAgIGV4cGVjdChyZXN0cmljdGlvbi5zdGF0ZW1lbnRzKCkubGVuZ3RoKS50b0JlKDEpO1xuICAgICAgZXhwZWN0KHJlc3RyaWN0aW9uLnJlYWRTdGF0ZW1lbnRzKCkubGVuZ3RoKS50b0JlKDEpO1xuICAgICAgZXhwZWN0KHJlc3RyaWN0aW9uLnJlYWRXcml0ZVN1cGVyU3RhdGVtZW50cygpLmxlbmd0aCkudG9CZSgwKTtcbiAgICAgIGV4cGVjdChyZXN0cmljdGlvbi5yZWFkV3JpdGVTdGF0ZW1lbnRzKCkubGVuZ3RoKS50b0JlKDApO1xuICAgICAgZXhwZWN0KHJlc3RyaWN0aW9uLnJlYWRTdGF0ZW1lbnRzKClbMF0uYWN0aW9ucykudG9TdHJpY3RFcXVhbChbJ3MzOkdldE9iamVjdConXSk7XG4gICAgICBleHBlY3QocmVzdHJpY3Rpb24ucmVhZFN0YXRlbWVudHMoKVswXS5jb25kaXRpb25zKS50b1N0cmljdEVxdWFsKHtcbiAgICAgICAgU3RyaW5nTGlrZToge1xuICAgICAgICAgICdhd3M6dXNlcklkJzogWyd0ZXN0LXJvbGUtaWQtMToqJywgJ3Rlc3Qtcm9sZS1pZC0yOionXSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgICAgZXhwZWN0KHJlc3RyaWN0aW9uLnJlYWRTdGF0ZW1lbnRzKClbMF0uZWZmZWN0KS50b0JlKCdBbGxvdycpO1xuICAgICAgZXhwZWN0KHJlc3RyaWN0aW9uLnJlYWRTdGF0ZW1lbnRzKClbMF0ucmVzb3VyY2VzKS50b1N0cmljdEVxdWFsKFtcbiAgICAgICAgJ2Fybjp0ZXN0LXBhcnRpdGlvbjpzMzo6OnRlc3QtYnVja2V0L3Rlc3QtcHJlZml4LyonLFxuICAgICAgXSk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdSZWFkV3JpdGUgUm9sZSBJZHMnLCAoKSA9PiB7XG4gICAgICBjb25zdCB0ZXN0UHJvcHM6IElSZXN0cmljdE9iamVjdFByZWZpeFRvUm9sZXMgPSB7XG4gICAgICAgIC4uLmJhc2VUZXN0UHJvcHMsXG4gICAgICAgIHJlYWRXcml0ZVJvbGVJZHM6IFsndGVzdC1yb2xlLWlkLTEnLCAndGVzdC1yb2xlLWlkLTInXSxcbiAgICAgIH07XG4gICAgICBjb25zdCByZXN0cmljdGlvbiA9IG5ldyBSZXN0cmljdE9iamVjdFByZWZpeFRvUm9sZXModGVzdFByb3BzKTtcbiAgICAgIC8vIGNvbnNvbGUubG9nKCBKU09OLnN0cmluZ2lmeSggcmVzdHJpY3Rpb24uc3RhdGVtZW50cygpWyAwIF0sIHVuZGVmaW5lZCwgMiApIClcbiAgICAgIGV4cGVjdChyZXN0cmljdGlvbi5zdGF0ZW1lbnRzKCkubGVuZ3RoKS50b0JlKDEpO1xuICAgICAgZXhwZWN0KHJlc3RyaWN0aW9uLnJlYWRXcml0ZVN0YXRlbWVudHMoKS5sZW5ndGgpLnRvQmUoMSk7XG4gICAgICBleHBlY3QocmVzdHJpY3Rpb24ucmVhZFN0YXRlbWVudHMoKS5sZW5ndGgpLnRvQmUoMCk7XG4gICAgICBleHBlY3QocmVzdHJpY3Rpb24ucmVhZFdyaXRlU3VwZXJTdGF0ZW1lbnRzKCkubGVuZ3RoKS50b0JlKDApO1xuICAgICAgZXhwZWN0KHJlc3RyaWN0aW9uLnJlYWRXcml0ZVN0YXRlbWVudHMoKVswXS5hY3Rpb25zKS50b1N0cmljdEVxdWFsKFtcbiAgICAgICAgJ3MzOkdldE9iamVjdConLFxuICAgICAgICAnczM6UHV0T2JqZWN0JyxcbiAgICAgICAgJ3MzOlB1dE9iamVjdFRhZ2dpbmcnLFxuICAgICAgICAnczM6RGVsZXRlT2JqZWN0JyxcbiAgICAgIF0pO1xuICAgICAgZXhwZWN0KHJlc3RyaWN0aW9uLnJlYWRXcml0ZVN0YXRlbWVudHMoKVswXS5jb25kaXRpb25zKS50b1N0cmljdEVxdWFsKHtcbiAgICAgICAgU3RyaW5nTGlrZToge1xuICAgICAgICAgICdhd3M6dXNlcklkJzogWyd0ZXN0LXJvbGUtaWQtMToqJywgJ3Rlc3Qtcm9sZS1pZC0yOionXSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgdGVzdCgnUmVhZFdyaXRlU3VwZXIgUm9sZSBJZHMnLCAoKSA9PiB7XG4gICAgICBjb25zdCB0ZXN0UHJvcHM6IElSZXN0cmljdE9iamVjdFByZWZpeFRvUm9sZXMgPSB7XG4gICAgICAgIC4uLmJhc2VUZXN0UHJvcHMsXG4gICAgICAgIHJlYWRXcml0ZVN1cGVyUm9sZUlkczogWyd0ZXN0LXJvbGUtaWQtMScsICd0ZXN0LXJvbGUtaWQtMiddLFxuICAgICAgfTtcbiAgICAgIGNvbnN0IHJlc3RyaWN0aW9uID0gbmV3IFJlc3RyaWN0T2JqZWN0UHJlZml4VG9Sb2xlcyh0ZXN0UHJvcHMpO1xuICAgICAgLy8gY29uc29sZS5sb2coIEpTT04uc3RyaW5naWZ5KCByZXN0cmljdGlvbi5zdGF0ZW1lbnRzKClbIDAgXSwgdW5kZWZpbmVkLCAyICkgKVxuICAgICAgZXhwZWN0KHJlc3RyaWN0aW9uLnN0YXRlbWVudHMoKS5sZW5ndGgpLnRvQmUoMSk7XG4gICAgICBleHBlY3QocmVzdHJpY3Rpb24ucmVhZFdyaXRlU3VwZXJTdGF0ZW1lbnRzKCkubGVuZ3RoKS50b0JlKDEpO1xuICAgICAgZXhwZWN0KHJlc3RyaWN0aW9uLnJlYWRTdGF0ZW1lbnRzKCkubGVuZ3RoKS50b0JlKDApO1xuICAgICAgZXhwZWN0KHJlc3RyaWN0aW9uLnJlYWRXcml0ZVN0YXRlbWVudHMoKS5sZW5ndGgpLnRvQmUoMCk7XG4gICAgICBleHBlY3QocmVzdHJpY3Rpb24ucmVhZFdyaXRlU3VwZXJTdGF0ZW1lbnRzKClbMF0uYWN0aW9ucykudG9TdHJpY3RFcXVhbChbXG4gICAgICAgICdzMzpHZXRPYmplY3QqJyxcbiAgICAgICAgJ3MzOlB1dE9iamVjdCcsXG4gICAgICAgICdzMzpQdXRPYmplY3RUYWdnaW5nJyxcbiAgICAgICAgJ3MzOkRlbGV0ZU9iamVjdCcsXG4gICAgICAgICdzMzpEZWxldGVPYmplY3RWZXJzaW9uJyxcbiAgICAgIF0pO1xuICAgICAgZXhwZWN0KHJlc3RyaWN0aW9uLnJlYWRXcml0ZVN1cGVyU3RhdGVtZW50cygpWzBdLmNvbmRpdGlvbnMpLnRvU3RyaWN0RXF1YWwoe1xuICAgICAgICBTdHJpbmdMaWtlOiB7XG4gICAgICAgICAgJ2F3czp1c2VySWQnOiBbJ3Rlc3Qtcm9sZS1pZC0xOionLCAndGVzdC1yb2xlLWlkLTI6KiddLFxuICAgICAgICB9LFxuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdSZWFkIFByaW5jaXBhbHMnLCAoKSA9PiB7XG4gICAgICBjb25zdCB0ZXN0UHJvcHM6IElSZXN0cmljdE9iamVjdFByZWZpeFRvUm9sZXMgPSB7XG4gICAgICAgIC4uLmJhc2VUZXN0UHJvcHMsXG4gICAgICAgIHJlYWRQcmluY2lwYWxzOiBbbmV3IEFyblByaW5jaXBhbCgndGVzdC1yb2xlLWFybi0xJyldLFxuICAgICAgfTtcbiAgICAgIGNvbnN0IHJlc3RyaWN0aW9uID0gbmV3IFJlc3RyaWN0T2JqZWN0UHJlZml4VG9Sb2xlcyh0ZXN0UHJvcHMpO1xuICAgICAgLy8gY29uc29sZS5sb2coIEpTT04uc3RyaW5naWZ5KCByZXN0cmljdGlvbi5zdGF0ZW1lbnRzKClbIDAgXSwgdW5kZWZpbmVkLCAyICkgKVxuICAgICAgZXhwZWN0KHJlc3RyaWN0aW9uLnN0YXRlbWVudHMoKS5sZW5ndGgpLnRvQmUoMSk7XG4gICAgICBleHBlY3QocmVzdHJpY3Rpb24ucmVhZFN0YXRlbWVudHMoKS5sZW5ndGgpLnRvQmUoMSk7XG4gICAgICBleHBlY3QocmVzdHJpY3Rpb24ucmVhZFdyaXRlU3VwZXJTdGF0ZW1lbnRzKCkubGVuZ3RoKS50b0JlKDApO1xuICAgICAgZXhwZWN0KHJlc3RyaWN0aW9uLnJlYWRXcml0ZVN0YXRlbWVudHMoKS5sZW5ndGgpLnRvQmUoMCk7XG4gICAgICBleHBlY3QocmVzdHJpY3Rpb24ucmVhZFN0YXRlbWVudHMoKVswXS5hY3Rpb25zKS50b1N0cmljdEVxdWFsKFsnczM6R2V0T2JqZWN0KiddKTtcbiAgICAgIGV4cGVjdChyZXN0cmljdGlvbi5yZWFkU3RhdGVtZW50cygpWzBdLmVmZmVjdCkudG9CZSgnQWxsb3cnKTtcbiAgICAgIGV4cGVjdChyZXN0cmljdGlvbi5yZWFkU3RhdGVtZW50cygpWzBdLnJlc291cmNlcykudG9TdHJpY3RFcXVhbChbXG4gICAgICAgICdhcm46dGVzdC1wYXJ0aXRpb246czM6Ojp0ZXN0LWJ1Y2tldC90ZXN0LXByZWZpeC8qJyxcbiAgICAgIF0pO1xuICAgICAgZXhwZWN0KHJlc3RyaWN0aW9uLnJlYWRTdGF0ZW1lbnRzKClbMF0ucHJpbmNpcGFscy5sZW5ndGgpLnRvQmUoMSk7XG4gICAgICBleHBlY3QoSlNPTi5zdHJpbmdpZnkocmVzdHJpY3Rpb24ucmVhZFN0YXRlbWVudHMoKVswXS5wcmluY2lwYWxzWzBdKSkudG9TdHJpY3RFcXVhbChcbiAgICAgICAgSlNPTi5zdHJpbmdpZnkoeyBBV1M6IFsndGVzdC1yb2xlLWFybi0xJ10gfSksXG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgdGVzdCgnUmVhZFdyaXRlIFByaW5jaXBhbHMnLCAoKSA9PiB7XG4gICAgICBjb25zdCB0ZXN0UHJvcHM6IElSZXN0cmljdE9iamVjdFByZWZpeFRvUm9sZXMgPSB7XG4gICAgICAgIC4uLmJhc2VUZXN0UHJvcHMsXG4gICAgICAgIHJlYWRXcml0ZVByaW5jaXBhbHM6IFtuZXcgQXJuUHJpbmNpcGFsKCd0ZXN0LXJvbGUtYXJuLTEnKV0sXG4gICAgICB9O1xuICAgICAgY29uc3QgcmVzdHJpY3Rpb24gPSBuZXcgUmVzdHJpY3RPYmplY3RQcmVmaXhUb1JvbGVzKHRlc3RQcm9wcyk7XG4gICAgICAvLyBjb25zb2xlLmxvZyggSlNPTi5zdHJpbmdpZnkoIHJlc3RyaWN0aW9uLnN0YXRlbWVudHMoKVsgMCBdLCB1bmRlZmluZWQsIDIgKSApXG4gICAgICBleHBlY3QocmVzdHJpY3Rpb24uc3RhdGVtZW50cygpLmxlbmd0aCkudG9CZSgxKTtcbiAgICAgIGV4cGVjdChyZXN0cmljdGlvbi5yZWFkV3JpdGVTdGF0ZW1lbnRzKCkubGVuZ3RoKS50b0JlKDEpO1xuICAgICAgZXhwZWN0KHJlc3RyaWN0aW9uLnJlYWRTdGF0ZW1lbnRzKCkubGVuZ3RoKS50b0JlKDApO1xuICAgICAgZXhwZWN0KHJlc3RyaWN0aW9uLnJlYWRXcml0ZVN1cGVyU3RhdGVtZW50cygpLmxlbmd0aCkudG9CZSgwKTtcbiAgICAgIGV4cGVjdChyZXN0cmljdGlvbi5yZWFkV3JpdGVTdGF0ZW1lbnRzKClbMF0uYWN0aW9ucykudG9TdHJpY3RFcXVhbChbXG4gICAgICAgICdzMzpHZXRPYmplY3QqJyxcbiAgICAgICAgJ3MzOlB1dE9iamVjdCcsXG4gICAgICAgICdzMzpQdXRPYmplY3RUYWdnaW5nJyxcbiAgICAgICAgJ3MzOkRlbGV0ZU9iamVjdCcsXG4gICAgICBdKTtcbiAgICAgIGV4cGVjdChyZXN0cmljdGlvbi5yZWFkV3JpdGVTdGF0ZW1lbnRzKClbMF0uZWZmZWN0KS50b0JlKCdBbGxvdycpO1xuICAgICAgZXhwZWN0KHJlc3RyaWN0aW9uLnJlYWRXcml0ZVN0YXRlbWVudHMoKVswXS5yZXNvdXJjZXMpLnRvU3RyaWN0RXF1YWwoW1xuICAgICAgICAnYXJuOnRlc3QtcGFydGl0aW9uOnMzOjo6dGVzdC1idWNrZXQvdGVzdC1wcmVmaXgvKicsXG4gICAgICBdKTtcbiAgICAgIGV4cGVjdChyZXN0cmljdGlvbi5yZWFkV3JpdGVTdGF0ZW1lbnRzKClbMF0ucHJpbmNpcGFscy5sZW5ndGgpLnRvQmUoMSk7XG4gICAgICBleHBlY3QoSlNPTi5zdHJpbmdpZnkocmVzdHJpY3Rpb24ucmVhZFdyaXRlU3RhdGVtZW50cygpWzBdLnByaW5jaXBhbHNbMF0pKS50b1N0cmljdEVxdWFsKFxuICAgICAgICBKU09OLnN0cmluZ2lmeSh7IEFXUzogWyd0ZXN0LXJvbGUtYXJuLTEnXSB9KSxcbiAgICAgICk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdSZWFkV3JpdGVTdXBlciBQcmluY2lwYWxzJywgKCkgPT4ge1xuICAgICAgY29uc3QgdGVzdFByb3BzOiBJUmVzdHJpY3RPYmplY3RQcmVmaXhUb1JvbGVzID0ge1xuICAgICAgICAuLi5iYXNlVGVzdFByb3BzLFxuICAgICAgICByZWFkV3JpdGVTdXBlclByaW5jaXBhbHM6IFtuZXcgQXJuUHJpbmNpcGFsKCd0ZXN0LXJvbGUtYXJuLTEnKV0sXG4gICAgICB9O1xuICAgICAgY29uc3QgcmVzdHJpY3Rpb24gPSBuZXcgUmVzdHJpY3RPYmplY3RQcmVmaXhUb1JvbGVzKHRlc3RQcm9wcyk7XG4gICAgICAvLyBjb25zb2xlLmxvZyggSlNPTi5zdHJpbmdpZnkoIHJlc3RyaWN0aW9uLnN0YXRlbWVudHMoKVsgMCBdLCB1bmRlZmluZWQsIDIgKSApXG4gICAgICBleHBlY3QocmVzdHJpY3Rpb24uc3RhdGVtZW50cygpLmxlbmd0aCkudG9CZSgxKTtcbiAgICAgIGV4cGVjdChyZXN0cmljdGlvbi5yZWFkU3RhdGVtZW50cygpLmxlbmd0aCkudG9CZSgwKTtcbiAgICAgIGV4cGVjdChyZXN0cmljdGlvbi5yZWFkV3JpdGVTdGF0ZW1lbnRzKCkubGVuZ3RoKS50b0JlKDApO1xuICAgICAgZXhwZWN0KHJlc3RyaWN0aW9uLnJlYWRXcml0ZVN1cGVyU3RhdGVtZW50cygpLmxlbmd0aCkudG9CZSgxKTtcbiAgICAgIGV4cGVjdChyZXN0cmljdGlvbi5yZWFkV3JpdGVTdXBlclN0YXRlbWVudHMoKVswXS5hY3Rpb25zKS50b1N0cmljdEVxdWFsKFtcbiAgICAgICAgJ3MzOkdldE9iamVjdConLFxuICAgICAgICAnczM6UHV0T2JqZWN0JyxcbiAgICAgICAgJ3MzOlB1dE9iamVjdFRhZ2dpbmcnLFxuICAgICAgICAnczM6RGVsZXRlT2JqZWN0JyxcbiAgICAgICAgJ3MzOkRlbGV0ZU9iamVjdFZlcnNpb24nLFxuICAgICAgXSk7XG4gICAgICBleHBlY3QocmVzdHJpY3Rpb24ucmVhZFdyaXRlU3VwZXJTdGF0ZW1lbnRzKClbMF0uZWZmZWN0KS50b0JlKCdBbGxvdycpO1xuICAgICAgZXhwZWN0KHJlc3RyaWN0aW9uLnJlYWRXcml0ZVN1cGVyU3RhdGVtZW50cygpWzBdLnJlc291cmNlcykudG9TdHJpY3RFcXVhbChbXG4gICAgICAgICdhcm46dGVzdC1wYXJ0aXRpb246czM6Ojp0ZXN0LWJ1Y2tldC90ZXN0LXByZWZpeC8qJyxcbiAgICAgIF0pO1xuICAgICAgZXhwZWN0KHJlc3RyaWN0aW9uLnJlYWRXcml0ZVN1cGVyU3RhdGVtZW50cygpWzBdLnByaW5jaXBhbHMubGVuZ3RoKS50b0JlKDEpO1xuICAgICAgZXhwZWN0KEpTT04uc3RyaW5naWZ5KHJlc3RyaWN0aW9uLnJlYWRXcml0ZVN1cGVyU3RhdGVtZW50cygpWzBdLnByaW5jaXBhbHNbMF0pKS50b1N0cmljdEVxdWFsKFxuICAgICAgICBKU09OLnN0cmluZ2lmeSh7IEFXUzogWyd0ZXN0LXJvbGUtYXJuLTEnXSB9KSxcbiAgICAgICk7XG4gICAgfSk7XG4gIH0pO1xuICBkZXNjcmliZSgnUmVzdHJpY3RCdWNrZXQnLCAoKSA9PiB7XG4gICAgY29uc3QgYmFzZVRlc3RQcm9wczogSVJlc3RyaWN0QnVja2V0VG9Sb2xlcyA9IHtcbiAgICAgIHMzQnVja2V0OiB0ZXN0QnVja2V0LFxuICAgICAgcm9sZUV4Y2x1ZGVJZHM6IFsndGVzdC1yb2xlLWlkLTEnLCAndGVzdC1yb2xlLWlkLTInXSxcbiAgICAgIHByaW5jaXBhbEV4Y2x1ZGVzOiBbJ3Rlc3QtYXJuJ10sXG4gICAgICBwcmVmaXhFeGNsdWRlczogWydleGNsdWRlLXByZWZpeCddLFxuICAgICAgcHJlZml4SW5jbHVkZXM6IFsnZXhjbHVkZS1wcmVmaXgnXSxcbiAgICB9O1xuICAgIHRlc3QoJ0Jhc2UgQWxsb3cnLCAoKSA9PiB7XG4gICAgICBjb25zdCB0ZXN0UHJvcHM6IElSZXN0cmljdEJ1Y2tldFRvUm9sZXMgPSB7XG4gICAgICAgIC4uLmJhc2VUZXN0UHJvcHMsXG4gICAgICB9O1xuICAgICAgY29uc3QgcmVzdHJpY3Rpb24gPSBuZXcgUmVzdHJpY3RCdWNrZXRUb1JvbGVzKHRlc3RQcm9wcyk7XG4gICAgICBjb25zb2xlLmxvZyhKU09OLnN0cmluZ2lmeShyZXN0cmljdGlvbi5hbGxvd1N0YXRlbWVudCwgdW5kZWZpbmVkLCAyKSk7XG4gICAgICBleHBlY3QocmVzdHJpY3Rpb24uYWxsb3dTdGF0ZW1lbnQuYWN0aW9ucykudG9TdHJpY3RFcXVhbChbJ3MzOkxpc3QqJywgJ3MzOkdldEJ1Y2tldConXSk7XG4gICAgICBleHBlY3QocmVzdHJpY3Rpb24uYWxsb3dTdGF0ZW1lbnQuZWZmZWN0KS50b0JlKCdBbGxvdycpO1xuICAgICAgZXhwZWN0KHJlc3RyaWN0aW9uLmFsbG93U3RhdGVtZW50LmNvbmRpdGlvbnMpLnRvU3RyaWN0RXF1YWwoe1xuICAgICAgICBTdHJpbmdMaWtlOiB7XG4gICAgICAgICAgJ2F3czp1c2VySWQnOiBbJ3Rlc3Qtcm9sZS1pZC0xOionLCAndGVzdC1yb2xlLWlkLTI6KiddLFxuICAgICAgICB9LFxuICAgICAgfSk7XG4gICAgICBleHBlY3QocmVzdHJpY3Rpb24uYWxsb3dTdGF0ZW1lbnQucmVzb3VyY2VzKS50b1N0cmljdEVxdWFsKFtcbiAgICAgICAgJ2Fybjp0ZXN0LXBhcnRpdGlvbjpzMzo6OnRlc3QtYnVja2V0LyonLFxuICAgICAgICAnYXJuOnRlc3QtcGFydGl0aW9uOnMzOjo6dGVzdC1idWNrZXQnLFxuICAgICAgXSk7XG4gICAgfSk7XG4gICAgdGVzdCgnQmFzZSBEZW55JywgKCkgPT4ge1xuICAgICAgY29uc3QgdGVzdFByb3BzOiBJUmVzdHJpY3RCdWNrZXRUb1JvbGVzID0ge1xuICAgICAgICAuLi5iYXNlVGVzdFByb3BzLFxuICAgICAgfTtcbiAgICAgIGNvbnN0IHJlc3RyaWN0aW9uID0gbmV3IFJlc3RyaWN0QnVja2V0VG9Sb2xlcyh0ZXN0UHJvcHMpO1xuICAgICAgY29uc29sZS5sb2coSlNPTi5zdHJpbmdpZnkocmVzdHJpY3Rpb24uZGVueVN0YXRlbWVudCwgdW5kZWZpbmVkLCAyKSk7XG4gICAgICBleHBlY3QocmVzdHJpY3Rpb24uZGVueVN0YXRlbWVudC5hY3Rpb25zKS50b1N0cmljdEVxdWFsKFsnczM6UHV0T2JqZWN0KicsICdzMzpHZXRPYmplY3QqJywgJ3MzOkRlbGV0ZU9iamVjdConXSk7XG4gICAgICBleHBlY3QocmVzdHJpY3Rpb24uZGVueVN0YXRlbWVudC5lZmZlY3QpLnRvQmUoJ0RlbnknKTtcbiAgICAgIGV4cGVjdChyZXN0cmljdGlvbi5kZW55U3RhdGVtZW50LmNvbmRpdGlvbnMpLnRvU3RyaWN0RXF1YWwoe1xuICAgICAgICAnRm9yQW55VmFsdWU6U3RyaW5nTm90TGlrZSc6IHtcbiAgICAgICAgICAnYXdzOnVzZXJJZCc6IFsndGVzdC1yb2xlLWlkLTE6KicsICd0ZXN0LXJvbGUtaWQtMjoqJ10sXG4gICAgICAgICAgJ2F3czpQcmluY2lwYWxBcm4nOiBbJ3Rlc3QtYXJuJ10sXG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgICB9KTtcbiAgfSk7XG59KTtcbiJdfQ==
|