@kensio/yulin 1.21.4 → 1.21.6
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/dist/service/cloudformation/cdk/assets/sim-cdk-assets-publisher.d.ts +18 -13
- package/dist/service/cloudformation/cdk/assets/sim-cdk-assets-publisher.js +16 -24
- package/dist/service/cloudformation/cdk/sim-cdk-cloud-assembly.factory.d.ts +12 -0
- package/dist/service/cloudformation/cdk/sim-cdk-cloud-assembly.factory.js +16 -7
- package/dist/service/cloudformation/command/create-stack/create-stack.handler.d.ts +3 -0
- package/dist/service/cloudformation/command/create-stack/create-stack.handler.js +4 -1
- package/dist/service/cloudformation/command/update-stack/update-stack.handler.d.ts +6 -0
- package/dist/service/cloudformation/command/update-stack/update-stack.handler.js +7 -1
- package/dist/service/cloudformation/deploy/sim-cfn-cdk-out-deployer.js +2 -1
- package/dist/service/cloudformation/deploy/sim-cfn-cdk-out-options-deployed.d.ts +10 -0
- package/dist/service/cloudformation/deploy/sim-cfn-cdk-out-options-deployed.js +14 -0
- package/dist/service/cloudformation/deploy/sim-cfn-cdk-out-plan.d.ts +11 -1
- package/dist/service/cloudformation/deploy/sim-cfn-cdk-out-plan.js +3 -2
- package/dist/service/cloudformation/deploy/sim-cfn-cdk-out-stack-options.d.ts +5 -8
- package/dist/service/cloudformation/deploy/sim-cfn-cdk-out-stack-options.js +0 -14
- package/dist/service/cloudformation/deploy/sim-cfn-template-deployer.d.ts +9 -0
- package/dist/service/cloudformation/deploy/sim-cfn-template-deployer.js +2 -0
- package/dist/service/cloudformation/deploy/sim-cfn-template-file-loader.d.ts +10 -0
- package/dist/service/cloudformation/deploy/sim-cfn-template-file-loader.js +2 -1
- package/dist/service/cloudformation/deploy/sim-cfn-template-file-updater.js +1 -0
- package/dist/service/cloudformation/resource/cfn/sim-cfn-default-resource-value-adapter.d.ts +8 -1
- package/dist/service/cloudformation/resource/cfn/sim-cfn-default-resource-value-adapter.js +9 -2
- package/dist/service/cloudformation/resource/cfn/sim-cfn-resource-value-adapter.d.ts +6 -1
- package/dist/service/cloudformation/resource/cfn/sim-cfn-resource-value-adapter.js +2 -1
- package/dist/service/cloudformation/resource/create/sim-cfn-resource-create-operation.d.ts +4 -0
- package/dist/service/cloudformation/resource/create/sim-cfn-resource-create-operation.js +6 -0
- package/dist/service/cloudformation/resource/sim-cfn-resource-record.d.ts +19 -0
- package/dist/service/cloudformation/resource/sim-cfn-resource-record.js +26 -0
- package/dist/service/cloudformation/resource/sim-cfn-resource.js +1 -0
- package/dist/service/cloudformation/resource/unsupported/sim-cfn-named-skip.d.ts +26 -0
- package/dist/service/cloudformation/resource/unsupported/sim-cfn-named-skip.js +31 -0
- package/dist/service/cloudformation/stack/sim-cfn-stack-deploy-context.d.ts +47 -0
- package/dist/service/cloudformation/stack/sim-cfn-stack-deploy-context.js +46 -0
- package/dist/service/cloudformation/stack/sim-cfn-stack-resource-operations.d.ts +9 -19
- package/dist/service/cloudformation/stack/sim-cfn-stack-resource-operations.js +12 -26
- package/dist/service/cloudformation/stack/sim-cfn-stack.js +2 -1
- package/dist/service/cloudformation/stack/sim-cfn-stack.type.d.ts +14 -0
- package/dist/service/cloudfront/cfn/cache-policy/sim-cfn-cf-cache-policy-creator.d.ts +5 -2
- package/dist/service/cloudfront/cfn/cache-policy/sim-cfn-cf-cache-policy-creator.js +10 -2
- package/dist/service/cloudfront/cfn/origin-access-control/sim-cfn-cf-oac-creator.d.ts +5 -2
- package/dist/service/cloudfront/cfn/origin-access-control/sim-cfn-cf-oac-creator.js +10 -2
- package/dist/service/cloudfront/cfn/origin-request-policy/sim-cfn-cf-orp-creator.d.ts +5 -2
- package/dist/service/cloudfront/cfn/origin-request-policy/sim-cfn-cf-orp-creator.js +10 -2
- package/dist/service/cloudfront/cfn/policy/sim-cfn-cf-policy-creators.d.ts +33 -0
- package/dist/service/cloudfront/cfn/policy/sim-cfn-cf-policy-creators.js +39 -0
- package/dist/service/cloudfront/cfn/response-headers-policy/sim-cfn-cf-rh-policy-creator.d.ts +5 -2
- package/dist/service/cloudfront/cfn/response-headers-policy/sim-cfn-cf-rh-policy-creator.js +10 -2
- package/dist/service/cloudfront/cfn/sim-cfn-cf-authorizer.d.ts +40 -0
- package/dist/service/cloudfront/cfn/sim-cfn-cf-authorizer.js +50 -0
- package/dist/service/cloudfront/cfn/sim-cfn-cloudfront-resource-factory.d.ts +1 -4
- package/dist/service/cloudfront/cfn/sim-cfn-cloudfront-resource-factory.js +14 -46
- package/dist/service/cloudfront/sim-cloudfront-commands.d.ts +6 -0
- package/dist/service/cloudfront/sim-cloudfront-commands.js +7 -0
- package/dist/service/cloudfront/sim-cloudfront.d.ts +6 -0
- package/dist/service/cloudfront/sim-cloudfront.js +7 -0
- package/dist/service/dynamodb/document/sim-dynamodb-document-command-paths.d.ts +8 -0
- package/dist/service/dynamodb/document/sim-dynamodb-document-command-paths.js +62 -0
- package/dist/service/dynamodb/document/sim-dynamodb-document-routes.d.ts +1 -1
- package/dist/service/dynamodb/document/sim-dynamodb-document-routes.js +3 -1
- package/dist/service/iam/authorize/sim-iam-action-authorizer.d.ts +8 -3
- package/dist/service/iam/authorize/sim-iam-action-authorizer.js +13 -4
- package/dist/service/iam/cfn/role/sim-cfn-iam-role-creator.js +1 -0
- package/dist/service/iam/cfn/role/sim-cfn-iam-role-properties-parser.d.ts +1 -0
- package/dist/service/iam/cfn/role/sim-cfn-iam-role-properties-parser.js +21 -14
- package/dist/service/iam/cfn/{sim-cfn-iam-optional-string.d.ts → sim-cfn-iam-property.d.ts} +10 -2
- package/dist/service/iam/cfn/sim-cfn-iam-property.js +31 -0
- package/dist/service/iam/cfn/user/sim-cfn-iam-user-properties-parser.js +1 -1
- package/dist/service/iam/command/role/create-role/create-role-record-factory.js +3 -0
- package/dist/service/iam/command/role/create-role/create-role.command.d.ts +10 -0
- package/dist/service/iam/command/role/get-role/get-role.command.d.ts +2 -0
- package/dist/service/iam/command/role/get-role/get-role.handler.js +2 -0
- package/dist/service/iam/command/role/sim-iam-role-command-handlers.js +15 -1
- package/dist/service/iam/role/sim-iam-role-boundary.d.ts +24 -0
- package/dist/service/iam/role/sim-iam-role-boundary.js +24 -0
- package/dist/service/iam/role/sim-iam-role-with-policy.factory.d.ts +1 -0
- package/dist/service/iam/role/sim-iam-role.d.ts +10 -0
- package/dist/service/iam/serve/sim-iam-query-entity.d.ts +6 -1
- package/dist/service/iam/serve/sim-iam-query-entity.js +10 -4
- package/dist/service/iam/serve/sim-iam-query-role-operations.js +15 -3
- package/dist/service/lambda/cfn/function/sim-cfn-lambda-runtime-skip.d.ts +6 -0
- package/dist/service/lambda/cfn/function/sim-cfn-lambda-runtime-skip.js +9 -2
- package/dist/service/route53/command/create-hosted-zone/sim-route53-zone-id.js +23 -1
- package/dist/service/s3/bucket/sim-s3-bucket-maker.d.ts +31 -0
- package/dist/service/s3/bucket/sim-s3-bucket-maker.js +41 -0
- package/dist/service/s3/command/create-bucket/create-bucket.handler.d.ts +2 -2
- package/dist/service/s3/command/create-bucket/create-bucket.handler.js +4 -12
- package/dist/service/s3/sim-s3-commands.d.ts +6 -0
- package/dist/service/s3/sim-s3-commands.js +7 -0
- package/dist/service/s3/sim-s3.d.ts +16 -0
- package/dist/service/s3/sim-s3.js +25 -0
- package/docs/services/cloudformation/README.md +144 -25
- package/docs/services/cloudfront/README.md +109 -0
- package/docs/services/dynamodb/README.md +128 -8
- package/docs/services/iam/README.md +125 -2
- package/docs/services/route53/README.md +11 -0
- package/package.json +2 -2
- package/dist/service/iam/cfn/sim-cfn-iam-optional-string.js +0 -17
|
@@ -6,6 +6,7 @@ export interface SimCfnIamRoleProperties {
|
|
|
6
6
|
readonly path: string | undefined;
|
|
7
7
|
readonly description: string | undefined;
|
|
8
8
|
readonly assumeRolePolicyDocument: string;
|
|
9
|
+
readonly permissionsBoundary: string | undefined;
|
|
9
10
|
readonly inlinePolicies: readonly SimCfnIamInlinePolicy[];
|
|
10
11
|
readonly managedPolicyArns: readonly string[];
|
|
11
12
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
/* oxlint-disable security/detect-object-injection -- each lookup here reads a
|
|
2
|
+
template property under the name this parser asks for by literal. */
|
|
1
3
|
import { simCfnIamPrincipalGeneratedName } from "../name/sim-cfn-iam-generated-name.js";
|
|
2
|
-
import { simCfnIamOptionalString } from "../sim-cfn-iam-
|
|
4
|
+
import { simCfnIamJsonObject, simCfnIamOptionalString, } from "../sim-cfn-iam-property.js";
|
|
3
5
|
import { SimCfnIamPoliciesParser, } from "../sim-cfn-iam-policies-parser.js";
|
|
6
|
+
const resourceType = "AWS::IAM::Role";
|
|
4
7
|
/**
|
|
5
8
|
* Parses and validates AWS::IAM::Role CloudFormation properties into the shape
|
|
6
9
|
* the sim IAM Role creator needs.
|
|
@@ -10,34 +13,38 @@ import { SimCfnIamPoliciesParser, } from "../sim-cfn-iam-policies-parser.js";
|
|
|
10
13
|
*/
|
|
11
14
|
export class SimCfnIamRolePropertiesParser {
|
|
12
15
|
policiesParser = new SimCfnIamPoliciesParser({
|
|
13
|
-
resourceType
|
|
16
|
+
resourceType,
|
|
14
17
|
});
|
|
15
18
|
/**
|
|
16
19
|
* Parse the resolved CloudFormation properties for an AWS::IAM::Role.
|
|
17
20
|
*/
|
|
18
21
|
parse(resource, properties) {
|
|
19
22
|
return {
|
|
20
|
-
roleName: this.optionalString(resource, properties
|
|
23
|
+
roleName: this.optionalString(resource, properties, "RoleName") ??
|
|
21
24
|
simCfnIamPrincipalGeneratedName(resource),
|
|
22
|
-
path: this.optionalString(resource, properties
|
|
23
|
-
description: this.optionalString(resource, properties
|
|
24
|
-
assumeRolePolicyDocument: this.jsonObject(resource, properties
|
|
25
|
+
path: this.optionalString(resource, properties, "Path"),
|
|
26
|
+
description: this.optionalString(resource, properties, "Description"),
|
|
27
|
+
assumeRolePolicyDocument: this.jsonObject(resource, properties),
|
|
28
|
+
permissionsBoundary: this.optionalString(resource, properties, "PermissionsBoundary"),
|
|
25
29
|
inlinePolicies: this.policiesParser.inlinePolicies(resource, properties),
|
|
26
30
|
managedPolicyArns: this.policiesParser.managedPolicyArns(resource, properties),
|
|
27
31
|
};
|
|
28
32
|
}
|
|
29
|
-
optionalString(resource,
|
|
33
|
+
optionalString(resource, properties, label) {
|
|
30
34
|
return simCfnIamOptionalString({
|
|
31
|
-
resourceType
|
|
35
|
+
resourceType,
|
|
32
36
|
resource,
|
|
33
|
-
value,
|
|
37
|
+
value: properties[label],
|
|
34
38
|
label,
|
|
35
39
|
});
|
|
36
40
|
}
|
|
37
|
-
jsonObject(resource,
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
jsonObject(resource, properties) {
|
|
42
|
+
const label = "AssumeRolePolicyDocument";
|
|
43
|
+
return simCfnIamJsonObject({
|
|
44
|
+
resourceType,
|
|
45
|
+
resource,
|
|
46
|
+
value: properties[label],
|
|
47
|
+
label,
|
|
48
|
+
});
|
|
42
49
|
}
|
|
43
50
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { SimCfnResource } from "../../cloudformation/resource/sim-cfn-resource.js";
|
|
2
2
|
import type { SimCfnTemplateValueRecord } from "../../cloudformation/template/value/sim-cfn-template-value.js";
|
|
3
|
-
interface
|
|
3
|
+
interface SimCfnIamPropertyInput {
|
|
4
4
|
readonly resourceType: string;
|
|
5
5
|
readonly resource: SimCfnResource;
|
|
6
6
|
readonly value: SimCfnTemplateValueRecord[string] | undefined;
|
|
@@ -13,5 +13,13 @@ interface SimCfnIamOptionalStringProperties {
|
|
|
13
13
|
* refuse a non-string the same way, naming the Resource type the template
|
|
14
14
|
* declared.
|
|
15
15
|
*/
|
|
16
|
-
export declare function simCfnIamOptionalString(properties:
|
|
16
|
+
export declare function simCfnIamOptionalString(properties: SimCfnIamPropertyInput): string | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Read a JSON-object property an IAM Resource requires.
|
|
19
|
+
*
|
|
20
|
+
* A Role's trust policy arrives as the object the template wrote, and IAM
|
|
21
|
+
* takes its policy documents as JSON text. A value of any other shape fails
|
|
22
|
+
* the Resource, naming the Resource type the template declared.
|
|
23
|
+
*/
|
|
24
|
+
export declare function simCfnIamJsonObject(properties: SimCfnIamPropertyInput): string;
|
|
17
25
|
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read a string property an IAM Resource may leave out.
|
|
3
|
+
*
|
|
4
|
+
* A Role and a User read most of their own properties this way, and both
|
|
5
|
+
* refuse a non-string the same way, naming the Resource type the template
|
|
6
|
+
* declared.
|
|
7
|
+
*/
|
|
8
|
+
export function simCfnIamOptionalString(properties) {
|
|
9
|
+
const { resourceType, resource, value, label } = properties;
|
|
10
|
+
if (value === undefined) {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
if (typeof value !== "string") {
|
|
14
|
+
throw new TypeError(`Invalid ${resourceType} ${resource.logicalId}: ${label} must be a string`);
|
|
15
|
+
}
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Read a JSON-object property an IAM Resource requires.
|
|
20
|
+
*
|
|
21
|
+
* A Role's trust policy arrives as the object the template wrote, and IAM
|
|
22
|
+
* takes its policy documents as JSON text. A value of any other shape fails
|
|
23
|
+
* the Resource, naming the Resource type the template declared.
|
|
24
|
+
*/
|
|
25
|
+
export function simCfnIamJsonObject(properties) {
|
|
26
|
+
const { resourceType, resource, value, label } = properties;
|
|
27
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
28
|
+
throw new TypeError(`Invalid ${resourceType} ${resource.logicalId}: ${label} must be an object`);
|
|
29
|
+
}
|
|
30
|
+
return JSON.stringify(value);
|
|
31
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { simCfnIamPrincipalGeneratedName } from "../name/sim-cfn-iam-generated-name.js";
|
|
2
|
-
import { simCfnIamOptionalString } from "../sim-cfn-iam-
|
|
2
|
+
import { simCfnIamOptionalString } from "../sim-cfn-iam-property.js";
|
|
3
3
|
import { SimCfnIamPoliciesParser, } from "../sim-cfn-iam-policies-parser.js";
|
|
4
4
|
const resourceType = "AWS::IAM::User";
|
|
5
5
|
/**
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { makeSimIamRoleId } from "../../../role/sim-iam-role-id.js";
|
|
2
|
+
import { simIamAttachedPermissionsBoundary } from "../../../role/sim-iam-role-boundary.js";
|
|
2
3
|
/**
|
|
3
4
|
* Creates simulated IAM Role records and command outputs.
|
|
4
5
|
*/
|
|
@@ -19,6 +20,7 @@ export class CreateRoleRecordFactory {
|
|
|
19
20
|
assumeRolePolicyDocument: cmd.input.AssumeRolePolicyDocument,
|
|
20
21
|
description: cmd.input.Description,
|
|
21
22
|
creationDate,
|
|
23
|
+
permissionsBoundaryArn: cmd.input.PermissionsBoundary,
|
|
22
24
|
inlinePolicies: new Map(),
|
|
23
25
|
attachedPolicyArns: new Set(),
|
|
24
26
|
};
|
|
@@ -36,6 +38,7 @@ export class CreateRoleRecordFactory {
|
|
|
36
38
|
CreateDate: role.creationDate,
|
|
37
39
|
AssumeRolePolicyDocument: role.assumeRolePolicyDocument,
|
|
38
40
|
Description: role.description,
|
|
41
|
+
PermissionsBoundary: simIamAttachedPermissionsBoundary(role),
|
|
39
42
|
},
|
|
40
43
|
};
|
|
41
44
|
}
|
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
import type { SimArn } from "../../../../aws/arn.js";
|
|
2
|
+
import type { SimIamAttachedPermissionsBoundary } from "../../../role/sim-iam-role-boundary.js";
|
|
2
3
|
export interface SimCreateRoleCommandInput {
|
|
3
4
|
readonly RoleName?: string | undefined;
|
|
4
5
|
readonly Path?: string | undefined;
|
|
5
6
|
readonly AssumeRolePolicyDocument?: string | undefined;
|
|
6
7
|
readonly Description?: string | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* ARN of the managed policy to attach to the new Role as its permissions
|
|
10
|
+
* boundary.
|
|
11
|
+
*
|
|
12
|
+
* The request carries this ARN as `iam:PermissionsBoundary`, which is the
|
|
13
|
+
* key an account requiring a boundary conditions `iam:CreateRole` on.
|
|
14
|
+
*/
|
|
15
|
+
readonly PermissionsBoundary?: string | undefined;
|
|
7
16
|
}
|
|
8
17
|
export interface SimCreateRoleCommand {
|
|
9
18
|
readonly input: SimCreateRoleCommandInput;
|
|
@@ -17,5 +26,6 @@ export interface SimCreateRoleCommandOutput {
|
|
|
17
26
|
readonly CreateDate: Date;
|
|
18
27
|
readonly AssumeRolePolicyDocument?: string | undefined;
|
|
19
28
|
readonly Description?: string | undefined;
|
|
29
|
+
readonly PermissionsBoundary?: SimIamAttachedPermissionsBoundary | undefined;
|
|
20
30
|
};
|
|
21
31
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { SimArn } from "../../../../aws/arn.js";
|
|
2
2
|
import type { SimIamRoleName } from "../../../role/sim-iam-role.js";
|
|
3
|
+
import type { SimIamAttachedPermissionsBoundary } from "../../../role/sim-iam-role-boundary.js";
|
|
3
4
|
export interface SimGetRoleCommandInput {
|
|
4
5
|
readonly RoleName?: string | undefined;
|
|
5
6
|
}
|
|
@@ -15,5 +16,6 @@ export interface SimGetRoleCommandOutput {
|
|
|
15
16
|
readonly CreateDate: Date;
|
|
16
17
|
readonly AssumeRolePolicyDocument?: string | undefined;
|
|
17
18
|
readonly Description?: string | undefined;
|
|
19
|
+
readonly PermissionsBoundary?: SimIamAttachedPermissionsBoundary | undefined;
|
|
18
20
|
};
|
|
19
21
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BackgroundTasks, } from "../../../../../util/background/background.js";
|
|
2
2
|
import { SimIamNoSuchEntity } from "../../../error/sim-iam.error.js";
|
|
3
|
+
import { simIamAttachedPermissionsBoundary } from "../../../role/sim-iam-role-boundary.js";
|
|
3
4
|
/**
|
|
4
5
|
* IAM GetRoleCommand handler.
|
|
5
6
|
*
|
|
@@ -36,6 +37,7 @@ export class GetRoleCommandHandler {
|
|
|
36
37
|
CreateDate: role.creationDate,
|
|
37
38
|
AssumeRolePolicyDocument: role.assumeRolePolicyDocument,
|
|
38
39
|
Description: role.description,
|
|
40
|
+
PermissionsBoundary: simIamAttachedPermissionsBoundary(role),
|
|
39
41
|
},
|
|
40
42
|
};
|
|
41
43
|
}
|
|
@@ -31,7 +31,7 @@ export class SimIamRoleCommandHandlers {
|
|
|
31
31
|
* Handle a CreateRole command from the SDK.
|
|
32
32
|
*/
|
|
33
33
|
async createRole(command, options) {
|
|
34
|
-
this.authorizer.authorize("iam:CreateRole", this.roleArn(command.input.RoleName), options?.caller);
|
|
34
|
+
this.authorizer.authorize("iam:CreateRole", this.roleArn(command.input.RoleName), options?.caller, permissionsBoundaryCondition(command.input.PermissionsBoundary));
|
|
35
35
|
const handler = new CreateRoleCommandHandler({
|
|
36
36
|
accountId: this.accountId,
|
|
37
37
|
roles: this.roles,
|
|
@@ -123,3 +123,17 @@ export class SimIamRoleCommandHandlers {
|
|
|
123
123
|
return `arn:aws:iam::${this.accountId}:role/${roleName ?? "*"}`;
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* What a Role-creating request says about the boundary it declares.
|
|
128
|
+
*
|
|
129
|
+
* An account that requires a permissions boundary allows `iam:CreateRole`
|
|
130
|
+
* only under `StringEquals` on `iam:PermissionsBoundary`, and the CDK
|
|
131
|
+
* permissions-boundary guard is written that way. A request declaring no
|
|
132
|
+
* boundary leaves the key out, which is what refuses it: a positive operator
|
|
133
|
+
* over an absent key matches nothing.
|
|
134
|
+
*/
|
|
135
|
+
function permissionsBoundaryCondition(permissionsBoundary) {
|
|
136
|
+
return permissionsBoundary === undefined
|
|
137
|
+
? undefined
|
|
138
|
+
: { "iam:PermissionsBoundary": permissionsBoundary };
|
|
139
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { SimArn } from "../../aws/arn.js";
|
|
2
|
+
import type { SimIamRole } from "./sim-iam-role.js";
|
|
3
|
+
/**
|
|
4
|
+
* A permissions boundary attached to a Role, as IAM describes one.
|
|
5
|
+
*
|
|
6
|
+
* IAM answers with the attachment rather than the bare ARN, and the type has
|
|
7
|
+
* only ever taken one value.
|
|
8
|
+
*/
|
|
9
|
+
export interface SimIamAttachedPermissionsBoundary {
|
|
10
|
+
readonly PermissionsBoundaryType: "PermissionsBoundaryPolicy";
|
|
11
|
+
readonly PermissionsBoundaryArn: SimArn;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The member names IAM describes an attached boundary with.
|
|
15
|
+
*/
|
|
16
|
+
export declare const simIamAttachedBoundaryMembers: string[];
|
|
17
|
+
/**
|
|
18
|
+
* How a Role's boundary appears in a CreateRole or GetRole answer.
|
|
19
|
+
*
|
|
20
|
+
* A Role created without one has no attachment to describe, and IAM leaves
|
|
21
|
+
* the field out. `ListRoles` leaves it out whatever the Role carries, along
|
|
22
|
+
* with the Role's tags and last use, and points the caller at `GetRole`.
|
|
23
|
+
*/
|
|
24
|
+
export declare function simIamAttachedPermissionsBoundary(role: SimIamRole): SimIamAttachedPermissionsBoundary | undefined;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The member names IAM describes an attached boundary with.
|
|
3
|
+
*/
|
|
4
|
+
export const simIamAttachedBoundaryMembers = [
|
|
5
|
+
"PermissionsBoundaryType",
|
|
6
|
+
"PermissionsBoundaryArn",
|
|
7
|
+
];
|
|
8
|
+
/**
|
|
9
|
+
* How a Role's boundary appears in a CreateRole or GetRole answer.
|
|
10
|
+
*
|
|
11
|
+
* A Role created without one has no attachment to describe, and IAM leaves
|
|
12
|
+
* the field out. `ListRoles` leaves it out whatever the Role carries, along
|
|
13
|
+
* with the Role's tags and last use, and points the caller at `GetRole`.
|
|
14
|
+
*/
|
|
15
|
+
export function simIamAttachedPermissionsBoundary(role) {
|
|
16
|
+
const permissionsBoundaryArn = role.permissionsBoundaryArn;
|
|
17
|
+
if (permissionsBoundaryArn === undefined) {
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
PermissionsBoundaryType: "PermissionsBoundaryPolicy",
|
|
22
|
+
PermissionsBoundaryArn: permissionsBoundaryArn,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -56,4 +56,5 @@ export declare const simIamRoleWithPolicyFactory: AsyncMappedFactory<SimIamRoleW
|
|
|
56
56
|
readonly CreateDate: Date;
|
|
57
57
|
readonly AssumeRolePolicyDocument?: string | undefined;
|
|
58
58
|
readonly Description?: string | undefined;
|
|
59
|
+
readonly PermissionsBoundary?: import("./sim-iam-role-boundary.js").SimIamAttachedPermissionsBoundary | undefined;
|
|
59
60
|
}, SimAws>;
|
|
@@ -19,6 +19,16 @@ export interface SimIamRole extends SimIamPrincipal {
|
|
|
19
19
|
readonly assumeRolePolicyDocument?: JSONString<SimIamPolicyDocument> | undefined;
|
|
20
20
|
readonly description?: string | undefined;
|
|
21
21
|
readonly creationDate: Date;
|
|
22
|
+
/**
|
|
23
|
+
* ARN of the managed policy attached to this Role as its permissions
|
|
24
|
+
* boundary, where the request creating it declared one.
|
|
25
|
+
*
|
|
26
|
+
* This records what the Role was created with, so that a policy conditioned
|
|
27
|
+
* on `iam:PermissionsBoundary` can be tested against the Roles a deployment
|
|
28
|
+
* makes. The boundary is not yet evaluated as a policy source, so it does
|
|
29
|
+
* not narrow what the Role itself may do.
|
|
30
|
+
*/
|
|
31
|
+
readonly permissionsBoundaryArn?: SimArn | undefined;
|
|
22
32
|
/**
|
|
23
33
|
* Inline identity-based permissions policies stored directly on this role.
|
|
24
34
|
*/
|
|
@@ -7,5 +7,10 @@ import type { SimQueryOutput } from "../../../serve/http/api/query/sim-query-res
|
|
|
7
7
|
* same structures are what a listing repeats. The Query layer writes the
|
|
8
8
|
* members of a structure and the items of a list, and this is the one shape
|
|
9
9
|
* left between them.
|
|
10
|
+
*
|
|
11
|
+
* An entity carrying a member of its own that is a structure passes `nested`,
|
|
12
|
+
* which writes whatever a scalar member cannot. A Role's permissions boundary
|
|
13
|
+
* is the case that exists for, and a listing that leaves it out passes
|
|
14
|
+
* nothing.
|
|
10
15
|
*/
|
|
11
|
-
export declare function iamQueryEntity(output: SimQueryOutput, name: string, members: readonly string[]): string;
|
|
16
|
+
export declare function iamQueryEntity(output: SimQueryOutput, name: string, members: readonly string[], nested?: (entity: SimQueryOutput) => string): string;
|
|
@@ -12,10 +12,16 @@ import { xmlElement } from "../../../util/xml/xml-writer.js";
|
|
|
12
12
|
* same structures are what a listing repeats. The Query layer writes the
|
|
13
13
|
* members of a structure and the items of a list, and this is the one shape
|
|
14
14
|
* left between them.
|
|
15
|
+
*
|
|
16
|
+
* An entity carrying a member of its own that is a structure passes `nested`,
|
|
17
|
+
* which writes whatever a scalar member cannot. A Role's permissions boundary
|
|
18
|
+
* is the case that exists for, and a listing that leaves it out passes
|
|
19
|
+
* nothing.
|
|
15
20
|
*/
|
|
16
|
-
export function iamQueryEntity(output, name, members) {
|
|
21
|
+
export function iamQueryEntity(output, name, members, nested) {
|
|
17
22
|
const entity = output[name];
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
if (!isRecord(entity)) {
|
|
24
|
+
return "";
|
|
25
|
+
}
|
|
26
|
+
return xmlElement(name, queryMembers(entity, members) + (nested?.(entity) ?? ""));
|
|
21
27
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { queryList, queryMembers, } from "../../../serve/http/api/query/sim-query-result.js";
|
|
1
|
+
import { queryList, queryMembers, queryStructure, } from "../../../serve/http/api/query/sim-query-result.js";
|
|
2
|
+
import { simIamAttachedBoundaryMembers } from "../role/sim-iam-role-boundary.js";
|
|
2
3
|
import { iamQueryEntity } from "./sim-iam-query-entity.js";
|
|
3
4
|
import { iamQueryListingInput, iamQueryListingResult, } from "./sim-iam-query-listing.js";
|
|
4
5
|
/**
|
|
@@ -13,6 +14,16 @@ const roleMembers = [
|
|
|
13
14
|
"AssumeRolePolicyDocument",
|
|
14
15
|
"Description",
|
|
15
16
|
];
|
|
17
|
+
/**
|
|
18
|
+
* Write the permissions boundary a Role carries, where it carries one.
|
|
19
|
+
*
|
|
20
|
+
* A boundary is a structure of its own, and `queryMembers` would write it as
|
|
21
|
+
* the JSON text of an object. `ListRoles` leaves the field out altogether, as
|
|
22
|
+
* IAM does, so only the create and the get pass this.
|
|
23
|
+
*/
|
|
24
|
+
function roleBoundary(role) {
|
|
25
|
+
return queryStructure(role, "PermissionsBoundary", (boundary) => queryMembers(boundary, simIamAttachedBoundaryMembers));
|
|
26
|
+
}
|
|
16
27
|
/**
|
|
17
28
|
* The Role operations simulated IAM serves over the Query protocol.
|
|
18
29
|
*
|
|
@@ -30,8 +41,9 @@ export function simIamQueryRoleOperations() {
|
|
|
30
41
|
Path: fields.text("Path"),
|
|
31
42
|
AssumeRolePolicyDocument: fields.text("AssumeRolePolicyDocument"),
|
|
32
43
|
Description: fields.text("Description"),
|
|
44
|
+
PermissionsBoundary: fields.text("PermissionsBoundary"),
|
|
33
45
|
}),
|
|
34
|
-
result: (output) => iamQueryEntity(output, "Role", roleMembers),
|
|
46
|
+
result: (output) => iamQueryEntity(output, "Role", roleMembers, roleBoundary),
|
|
35
47
|
},
|
|
36
48
|
],
|
|
37
49
|
[
|
|
@@ -40,7 +52,7 @@ export function simIamQueryRoleOperations() {
|
|
|
40
52
|
input: (fields) => ({
|
|
41
53
|
RoleName: fields.text("RoleName"),
|
|
42
54
|
}),
|
|
43
|
-
result: (output) => iamQueryEntity(output, "Role", roleMembers),
|
|
55
|
+
result: (output) => iamQueryEntity(output, "Role", roleMembers, roleBoundary),
|
|
44
56
|
},
|
|
45
57
|
],
|
|
46
58
|
[
|
|
@@ -26,6 +26,12 @@ import type { SimCfnLambdaFunctionProperties } from "./sim-cfn-lambda-function-p
|
|
|
26
26
|
* CloudFormation carries out itself is recorded as inert instead, because this
|
|
27
27
|
* message would otherwise tell a reader to bind a handler to a function that
|
|
28
28
|
* has nothing left to do.
|
|
29
|
+
*
|
|
30
|
+
* The refusal carries the function's name, which the properties parser has
|
|
31
|
+
* already worked out by the time this gate is asked. CDK writes a function's
|
|
32
|
+
* log group name as `/aws/lambda/` joined to a Ref of the function. A refusal
|
|
33
|
+
* carrying no name puts the log group under `/aws/lambda/` and a logical ID,
|
|
34
|
+
* a name no account would hold.
|
|
29
35
|
*/
|
|
30
36
|
export declare class SimCfnLambdaRuntimeSkip {
|
|
31
37
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SimCfnNamedSkip } from "../../../cloudformation/resource/unsupported/sim-cfn-named-skip.js";
|
|
1
2
|
/**
|
|
2
3
|
* Sim Lambda runs handler modules in a Node.js vm, so it simulates the
|
|
3
4
|
* Node.js managed runtimes.
|
|
@@ -29,6 +30,12 @@ const nodeJsRuntimePrefix = "nodejs";
|
|
|
29
30
|
* CloudFormation carries out itself is recorded as inert instead, because this
|
|
30
31
|
* message would otherwise tell a reader to bind a handler to a function that
|
|
31
32
|
* has nothing left to do.
|
|
33
|
+
*
|
|
34
|
+
* The refusal carries the function's name, which the properties parser has
|
|
35
|
+
* already worked out by the time this gate is asked. CDK writes a function's
|
|
36
|
+
* log group name as `/aws/lambda/` joined to a Ref of the function. A refusal
|
|
37
|
+
* carrying no name puts the log group under `/aws/lambda/` and a logical ID,
|
|
38
|
+
* a name no account would hold.
|
|
32
39
|
*/
|
|
33
40
|
export class SimCfnLambdaRuntimeSkip {
|
|
34
41
|
/**
|
|
@@ -42,9 +49,9 @@ export class SimCfnLambdaRuntimeSkip {
|
|
|
42
49
|
runtimeName.startsWith(nodeJsRuntimePrefix)) {
|
|
43
50
|
return undefined;
|
|
44
51
|
}
|
|
45
|
-
return new
|
|
52
|
+
return new SimCfnNamedSkip(`Unsupported sim Lambda CloudFormation Resource ${resource.logicalId}: ` +
|
|
46
53
|
`sim Lambda simulates Node.js runtimes, and this function declares ` +
|
|
47
54
|
`Runtime ${runtimeName}. Bind a real in-process handler to this ` +
|
|
48
|
-
`function to simulate it
|
|
55
|
+
`function to simulate it.`, functionProperties.functionName);
|
|
49
56
|
}
|
|
50
57
|
}
|
|
@@ -34,10 +34,32 @@ export function makeSimRoute53HostedZoneId(existing = new Set()) {
|
|
|
34
34
|
export function normalizeSimRoute53HostedZoneId(value) {
|
|
35
35
|
const hostedZoneId = value?.replace(/^\/?hostedzone\//u, "");
|
|
36
36
|
if (!isSimRoute53HostedZoneId(hostedZoneId)) {
|
|
37
|
-
throw new SimRoute53InvalidInput(
|
|
37
|
+
throw new SimRoute53InvalidInput(rejectedSimRoute53HostedZoneId(value, hostedZoneId));
|
|
38
38
|
}
|
|
39
39
|
return hostedZoneId;
|
|
40
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* The literal CDK writes into a synthesized template when
|
|
43
|
+
* `HostedZone.fromLookup` runs against no credentials and no cached context.
|
|
44
|
+
*/
|
|
45
|
+
const cdkUnresolvedLookupHostedZoneId = "DUMMY";
|
|
46
|
+
/**
|
|
47
|
+
* The message for a Hosted Zone ID that fails the shape check.
|
|
48
|
+
*
|
|
49
|
+
* CDK writes its unresolved lookup stand-in into every RecordSet of the
|
|
50
|
+
* synthesized template, and that value arrives here looking like any other
|
|
51
|
+
* malformed ID. Reporting it as one sends the reader to check an ID they never
|
|
52
|
+
* wrote, so the stand-in is named and the synth that produced it is pointed at.
|
|
53
|
+
*/
|
|
54
|
+
function rejectedSimRoute53HostedZoneId(value, hostedZoneId) {
|
|
55
|
+
const reported = `Invalid Route53 Hosted Zone ID: ${value ?? "(missing)"}`;
|
|
56
|
+
if (hostedZoneId !== cdkUnresolvedLookupHostedZoneId) {
|
|
57
|
+
return reported;
|
|
58
|
+
}
|
|
59
|
+
return (`${reported}. CDK fills an unresolved \`HostedZone.fromLookup\` with this ` +
|
|
60
|
+
"stand-in. Run `cdk synth` with credentials for the account holding the " +
|
|
61
|
+
"zone, or commit the `cdk.context.json` a resolved lookup writes.");
|
|
62
|
+
}
|
|
41
63
|
/**
|
|
42
64
|
* Whether a value has the shape of a Route53 Hosted Zone ID.
|
|
43
65
|
*/
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { BackgroundScheduler } from "../../../util/background/background.js";
|
|
2
|
+
import type { SimAwsAccountRegionScope } from "../../aws/sim-aws-account-region-scope.js";
|
|
3
|
+
import { SimS3Bucket, type SimS3BucketName } from "./sim-s3-bucket.js";
|
|
4
|
+
import type { SimS3GlobalRegistry } from "../sim-s3-global-registry.js";
|
|
5
|
+
interface SimS3BucketMakerProperties {
|
|
6
|
+
readonly accountRegionScope: SimAwsAccountRegionScope;
|
|
7
|
+
readonly buckets: Map<SimS3BucketName, SimS3Bucket>;
|
|
8
|
+
readonly s3GlobalRegistry: SimS3GlobalRegistry;
|
|
9
|
+
readonly background: BackgroundScheduler;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Puts a Bucket into a simulated S3 scope, once something has decided it may
|
|
13
|
+
* be there.
|
|
14
|
+
*
|
|
15
|
+
* `CreateBucketCommand` decides that by authorizing the caller. A Bucket real
|
|
16
|
+
* AWS provisions outside the deployment being simulated, such as the CDK
|
|
17
|
+
* bootstrap staging Bucket, has no caller to authorize and comes through
|
|
18
|
+
* `SimS3.makeSimBucket` instead. Both arrive at the same Bucket registered in
|
|
19
|
+
* the same two places, because the name check and the registration are here
|
|
20
|
+
* rather than in the command handler.
|
|
21
|
+
*/
|
|
22
|
+
export declare class SimS3BucketMaker {
|
|
23
|
+
private readonly properties;
|
|
24
|
+
constructor(properties: SimS3BucketMakerProperties);
|
|
25
|
+
/**
|
|
26
|
+
* Make a Bucket of the given name, reporting a name this scope cannot take
|
|
27
|
+
* the way `CreateBucketCommand` reports it.
|
|
28
|
+
*/
|
|
29
|
+
make(bucketName: string): SimS3Bucket;
|
|
30
|
+
}
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { SimS3BucketNameAvailability } from "./name-availability/sim-s3-bucket-name-availability.js";
|
|
2
|
+
import { validateS3BucketName } from "./validate/validate-s3-bucket-name.js";
|
|
3
|
+
import { SimS3Bucket } from "./sim-s3-bucket.js";
|
|
4
|
+
/**
|
|
5
|
+
* Puts a Bucket into a simulated S3 scope, once something has decided it may
|
|
6
|
+
* be there.
|
|
7
|
+
*
|
|
8
|
+
* `CreateBucketCommand` decides that by authorizing the caller. A Bucket real
|
|
9
|
+
* AWS provisions outside the deployment being simulated, such as the CDK
|
|
10
|
+
* bootstrap staging Bucket, has no caller to authorize and comes through
|
|
11
|
+
* `SimS3.makeSimBucket` instead. Both arrive at the same Bucket registered in
|
|
12
|
+
* the same two places, because the name check and the registration are here
|
|
13
|
+
* rather than in the command handler.
|
|
14
|
+
*/
|
|
15
|
+
export class SimS3BucketMaker {
|
|
16
|
+
properties;
|
|
17
|
+
constructor(properties) {
|
|
18
|
+
this.properties = properties;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Make a Bucket of the given name, reporting a name this scope cannot take
|
|
22
|
+
* the way `CreateBucketCommand` reports it.
|
|
23
|
+
*/
|
|
24
|
+
make(bucketName) {
|
|
25
|
+
const { accountRegionScope, buckets, s3GlobalRegistry, background } = this.properties;
|
|
26
|
+
validateS3BucketName(bucketName);
|
|
27
|
+
new SimS3BucketNameAvailability({
|
|
28
|
+
accountRegionScope,
|
|
29
|
+
buckets,
|
|
30
|
+
s3GlobalRegistry,
|
|
31
|
+
}).ensureCanCreateBucketNamed(bucketName);
|
|
32
|
+
const bucket = new SimS3Bucket({
|
|
33
|
+
bucketName,
|
|
34
|
+
accountRegionScope,
|
|
35
|
+
clock: background,
|
|
36
|
+
});
|
|
37
|
+
buckets.set(bucketName, bucket);
|
|
38
|
+
s3GlobalRegistry.registerBucket(bucketName, accountRegionScope);
|
|
39
|
+
return bucket;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CommandHandler } from "../../../../command/command-handler.js";
|
|
2
2
|
import type { SimCreateBucketCommand, SimCreateBucketCommandOutput } from "./create-bucket.command.js";
|
|
3
|
-
import { SimS3Bucket } from "../../bucket/sim-s3-bucket.js";
|
|
3
|
+
import type { SimS3Bucket, SimS3BucketName } from "../../bucket/sim-s3-bucket.js";
|
|
4
4
|
import type { SimS3GlobalRegistry } from "../../sim-s3-global-registry.js";
|
|
5
5
|
import type { SimAwsAccountRegionScope } from "../../../aws/sim-aws-account-region-scope.js";
|
|
6
6
|
import { type BackgroundScheduler } from "../../../../util/background/background.js";
|
|
@@ -8,7 +8,7 @@ import { type SimIamInterServiceAuthZ } from "../../../iam/authorize/sim-iam-int
|
|
|
8
8
|
import type { SimS3RequestOptions } from "../sim-s3-request-options.js";
|
|
9
9
|
interface CreateBucketCommandHandlerProperties {
|
|
10
10
|
readonly accountRegionScope: SimAwsAccountRegionScope;
|
|
11
|
-
readonly buckets: Map<
|
|
11
|
+
readonly buckets: Map<SimS3BucketName, SimS3Bucket>;
|
|
12
12
|
readonly s3GlobalRegistry: SimS3GlobalRegistry;
|
|
13
13
|
readonly iam?: SimIamInterServiceAuthZ;
|
|
14
14
|
readonly background?: BackgroundScheduler;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { SimS3Bucket } from "../../bucket/sim-s3-bucket.js";
|
|
2
1
|
import { assertDefined } from "../../../../util/type-guard/defined.js";
|
|
3
2
|
import { BackgroundTasks, } from "../../../../util/background/background.js";
|
|
4
|
-
import {
|
|
3
|
+
import { SimS3BucketMaker } from "../../bucket/sim-s3-bucket-maker.js";
|
|
5
4
|
import { validateS3BucketName } from "../../bucket/validate/validate-s3-bucket-name.js";
|
|
6
5
|
import { SimIamAllowAllAuth, } from "../../../iam/authorize/sim-iam-inter-service-auth-z.js";
|
|
7
6
|
import { SimIamAccessDenied } from "../../../iam/error/sim-iam.error.js";
|
|
@@ -49,19 +48,12 @@ export class CreateBucketCommandHandler {
|
|
|
49
48
|
resource,
|
|
50
49
|
});
|
|
51
50
|
}
|
|
52
|
-
|
|
51
|
+
new SimS3BucketMaker({
|
|
53
52
|
accountRegionScope: this.accountRegionScope,
|
|
54
53
|
buckets: this.buckets,
|
|
55
54
|
s3GlobalRegistry: this.s3GlobalRegistry,
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const bucket = new SimS3Bucket({
|
|
59
|
-
bucketName,
|
|
60
|
-
accountRegionScope: this.accountRegionScope,
|
|
61
|
-
clock: this.background,
|
|
62
|
-
});
|
|
63
|
-
this.buckets.set(bucketName, bucket);
|
|
64
|
-
this.s3GlobalRegistry.registerBucket(bucketName, this.accountRegionScope);
|
|
55
|
+
background: this.background,
|
|
56
|
+
}).make(bucketName);
|
|
65
57
|
return {
|
|
66
58
|
BucketArn: resource,
|
|
67
59
|
Location: `/${bucketName}`,
|
|
@@ -63,6 +63,12 @@ export declare class SimS3Commands {
|
|
|
63
63
|
readonly objectTagging: SimS3ObjectTaggingCommands;
|
|
64
64
|
readonly multipartUploads: SimS3MultipartCommands;
|
|
65
65
|
readonly objectNotifier: SimS3ObjectNotifier;
|
|
66
|
+
/**
|
|
67
|
+
* The scheduler and clock every command area here shares, which a
|
|
68
|
+
* simulator-only control on the service facade needs to hand a Bucket it
|
|
69
|
+
* makes outside the commands.
|
|
70
|
+
*/
|
|
71
|
+
readonly background: BackgroundScheduler;
|
|
66
72
|
constructor(properties: SimS3CommandsProperties);
|
|
67
73
|
}
|
|
68
74
|
export {};
|
|
@@ -35,8 +35,15 @@ export class SimS3Commands {
|
|
|
35
35
|
objectTagging;
|
|
36
36
|
multipartUploads;
|
|
37
37
|
objectNotifier;
|
|
38
|
+
/**
|
|
39
|
+
* The scheduler and clock every command area here shares, which a
|
|
40
|
+
* simulator-only control on the service facade needs to hand a Bucket it
|
|
41
|
+
* makes outside the commands.
|
|
42
|
+
*/
|
|
43
|
+
background;
|
|
38
44
|
constructor(properties) {
|
|
39
45
|
const { background = new BackgroundTasks(), notificationDestinations = new SimS3NoNotificationDestinations(), } = properties;
|
|
46
|
+
this.background = background;
|
|
40
47
|
const iam = simIamInRegion(properties.iam, properties.accountRegionScope.regionName);
|
|
41
48
|
this.objectNotifier = new SimS3ObjectNotifier({
|
|
42
49
|
destinations: notificationDestinations,
|