@fjall/components-infrastructure 0.8.0 → 0.9.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.
@@ -0,0 +1,43 @@
1
+ import { BlockDevice, IMachineImage, IVpc, SubnetType, UserData, SecurityGroup, IConnectable, Connections } from "aws-cdk-lib/aws-ec2";
2
+ import { Construct } from "constructs";
3
+ import { StackProps } from "aws-cdk-lib";
4
+ import { Role } from "aws-cdk-lib/aws-iam";
5
+ import { KeyValue } from "../../types";
6
+ interface ExistingVpcConfig {
7
+ vpcId?: string;
8
+ subnetType?: SubnetType;
9
+ }
10
+ interface NewVpcConfig {
11
+ subnetType: SubnetType;
12
+ }
13
+ export type VpcProps = ExistingVpcConfig | NewVpcConfig;
14
+ interface Ec2InstanceProps extends StackProps {
15
+ spotCapacityPercentage?: number;
16
+ blockDevices?: BlockDevice[];
17
+ accountId?: string;
18
+ serviceName: string;
19
+ vpc: VpcProps;
20
+ minCapcity?: number;
21
+ maxCapacity?: number;
22
+ instanceType: string;
23
+ machineImage?: IMachineImage;
24
+ userData?: UserData;
25
+ role?: Role;
26
+ enableSSH?: boolean;
27
+ tags: KeyValue;
28
+ }
29
+ export declare class Ec2Instance extends Construct implements IConnectable {
30
+ private launchTemplate;
31
+ vpc: IVpc;
32
+ asgSecurityGroup: SecurityGroup;
33
+ private autoScalingGroup;
34
+ private keyPair;
35
+ constructor(scope: Construct, id: string, props: Ec2InstanceProps);
36
+ connections: Connections;
37
+ addVpc(props: Ec2InstanceProps): void;
38
+ addKeyPair(props: Ec2InstanceProps): void;
39
+ addLaunchTemplate(props: Ec2InstanceProps): void;
40
+ addAutoScalingGroup(props: Ec2InstanceProps): void;
41
+ suspendAutoScaling(): void;
42
+ }
43
+ export {};
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Ec2Instance = void 0;
4
+ const aws_ec2_1 = require("aws-cdk-lib/aws-ec2");
5
+ const constructs_1 = require("constructs");
6
+ const aws_cdk_lib_1 = require("aws-cdk-lib");
7
+ const tagResource_1 = require("../../utils/tagResource");
8
+ const aws_autoscaling_1 = require("aws-cdk-lib/aws-autoscaling");
9
+ const awsCustomResource_1 = require("../../resources/aws/utilities/awsCustomResource");
10
+ const custom_resources_1 = require("aws-cdk-lib/custom-resources");
11
+ const vpc_1 = require("../../resources/aws/networking/vpc");
12
+ class Ec2Instance extends constructs_1.Construct {
13
+ constructor(scope, id, props) {
14
+ super(scope, id);
15
+ this.addVpc(props);
16
+ if (props.enableSSH) {
17
+ this.addKeyPair(props);
18
+ }
19
+ this.addLaunchTemplate(props);
20
+ this.addAutoScalingGroup(props);
21
+ this.suspendAutoScaling();
22
+ //TODO: Add load balancer as boolean prop, then configure load balancer
23
+ }
24
+ addVpc(props) {
25
+ if ("vpcId" in props.vpc) {
26
+ this.vpc = vpc_1.Vpc.fromLookup(this, `${props.serviceName}Vpc`, {
27
+ vpcId: props.vpc.vpcId
28
+ });
29
+ }
30
+ else {
31
+ this.vpc = new vpc_1.Vpc(this, `${props.serviceName}Vpc`, {
32
+ accountId: props.accountId,
33
+ tags: props.tags,
34
+ subnetConfiguration: [
35
+ {
36
+ name: `${props.serviceName}`,
37
+ subnetType: props.vpc.subnetType || aws_ec2_1.SubnetType.PRIVATE_WITH_EGRESS
38
+ }
39
+ ]
40
+ });
41
+ }
42
+ }
43
+ addKeyPair(props) {
44
+ // TODO: Breakout into a seperate construct for use with better prop handling
45
+ this.keyPair = new aws_ec2_1.KeyPair(this, "KeyPair", {
46
+ keyPairName: `${props.serviceName}KeyPair`
47
+ });
48
+ }
49
+ addLaunchTemplate(props) {
50
+ this.asgSecurityGroup = new aws_ec2_1.SecurityGroup(this, `AsgSecurityGroup`, {
51
+ vpc: this.vpc,
52
+ description: `Security group for the ${props.serviceName} auto scaling group`
53
+ });
54
+ if (props.enableSSH) {
55
+ this.asgSecurityGroup.addIngressRule(aws_ec2_1.Peer.anyIpv4(), aws_ec2_1.Port.tcp(22), "Allow SSH");
56
+ }
57
+ this.launchTemplate = new aws_ec2_1.LaunchTemplate(this, "LaunchTemplate", {
58
+ launchTemplateName: `${props.serviceName}LaunchTemplate`,
59
+ instanceType: new aws_ec2_1.InstanceType(`${props.instanceType}`),
60
+ machineImage: props.machineImage || aws_ec2_1.MachineImage.latestAmazonLinux2(),
61
+ userData: props.userData,
62
+ role: props.role,
63
+ blockDevices: props?.blockDevices,
64
+ securityGroup: this.asgSecurityGroup,
65
+ detailedMonitoring: true,
66
+ requireImdsv2: true,
67
+ httpPutResponseHopLimit: 2,
68
+ httpTokens: aws_ec2_1.LaunchTemplateHttpTokens.REQUIRED,
69
+ instanceMetadataTags: true,
70
+ keyPair: this.keyPair
71
+ });
72
+ }
73
+ addAutoScalingGroup(props) {
74
+ // TODO: Support spot instances
75
+ // TODO: Handle terminating EC2 instances when updating, currently hangs.
76
+ this.autoScalingGroup = new aws_autoscaling_1.AutoScalingGroup(this, "AutoScalingGroup", {
77
+ vpc: this.vpc,
78
+ vpcSubnets: {
79
+ subnetType: props.enableSSH ? aws_ec2_1.SubnetType.PUBLIC : undefined
80
+ },
81
+ minCapacity: props.minCapcity,
82
+ maxCapacity: props.maxCapacity,
83
+ launchTemplate: this.launchTemplate,
84
+ cooldown: aws_cdk_lib_1.Duration.seconds(60),
85
+ groupMetrics: [aws_autoscaling_1.GroupMetrics.all()],
86
+ updatePolicy: aws_autoscaling_1.UpdatePolicy.replacingUpdate(),
87
+ newInstancesProtectedFromScaleIn: true,
88
+ // securityGroup: this.asgSecurityGroup,
89
+ terminationPolicies: [
90
+ aws_autoscaling_1.TerminationPolicy.OLDEST_LAUNCH_CONFIGURATION,
91
+ aws_autoscaling_1.TerminationPolicy.CLOSEST_TO_NEXT_INSTANCE_HOUR
92
+ ],
93
+ ssmSessionPermissions: true
94
+ });
95
+ (0, tagResource_1.default)(this.autoScalingGroup, props.tags);
96
+ }
97
+ suspendAutoScaling() {
98
+ new awsCustomResource_1.AwsCustomResource(this, "SuspendAutoscaling", {
99
+ functionName: "suspendAutoScaling",
100
+ onCreate: {
101
+ service: "AutoScaling",
102
+ action: "suspendProcesses",
103
+ parameters: {
104
+ AutoScalingGroupName: this.autoScalingGroup.autoScalingGroupName,
105
+ ScalingProcesses: ["AZRebalance"]
106
+ },
107
+ physicalResourceId: custom_resources_1.PhysicalResourceId.of("suspendAutoScaling")
108
+ },
109
+ onUpdate: {
110
+ service: "AutoScaling",
111
+ action: "suspendProcesses",
112
+ parameters: {
113
+ AutoScalingGroupName: this.autoScalingGroup.autoScalingGroupName,
114
+ ScalingProcesses: ["AZRebalance"]
115
+ },
116
+ physicalResourceId: custom_resources_1.PhysicalResourceId.of("suspendAutoScaling")
117
+ },
118
+ resourceType: "Custom::suspendAutoscaling"
119
+ });
120
+ }
121
+ }
122
+ exports.Ec2Instance = Ec2Instance;
123
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWMyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vbGliL3BhdHRlcm5zL2F3cy9lYzIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsaURBaUI2QjtBQUM3QiwyQ0FBdUM7QUFDdkMsNkNBQW1EO0FBQ25ELHlEQUFrRDtBQUVsRCxpRUFLcUM7QUFFckMsdUZBQW9GO0FBQ3BGLG1FQUFrRTtBQUNsRSw0REFBeUQ7QUE2QnpELE1BQWEsV0FBWSxTQUFRLHNCQUFTO0lBT3hDLFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBdUI7UUFDL0QsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUVqQixJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ25CLElBQUksS0FBSyxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQ3BCLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDekIsQ0FBQztRQUNELElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUM5QixJQUFJLENBQUMsbUJBQW1CLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDaEMsSUFBSSxDQUFDLGtCQUFrQixFQUFFLENBQUM7UUFFMUIsdUVBQXVFO0lBQ3pFLENBQUM7SUFHRCxNQUFNLENBQUMsS0FBdUI7UUFDNUIsSUFBSSxPQUFPLElBQUksS0FBSyxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQ3pCLElBQUksQ0FBQyxHQUFHLEdBQUcsU0FBRyxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsR0FBRyxLQUFLLENBQUMsV0FBVyxLQUFLLEVBQUU7Z0JBQ3pELEtBQUssRUFBRSxLQUFLLENBQUMsR0FBRyxDQUFDLEtBQUs7YUFDdkIsQ0FBQyxDQUFDO1FBQ0wsQ0FBQzthQUFNLENBQUM7WUFDTixJQUFJLENBQUMsR0FBRyxHQUFHLElBQUksU0FBRyxDQUFDLElBQUksRUFBRSxHQUFHLEtBQUssQ0FBQyxX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QXdDO1lBQ3hDLG1CQUFtQixFQUFFO2dCQUNuQixtQ0FBaUIsQ0FBQywyQkFBMkI7Z0JBQzdDLG1DQUFpQixDQUFDLDZCQUE2QjthQUNoRDtZQUNELHFCQUFxQixFQUFFLElBQUk7U0FDNUIsQ0FBQyxDQUFDO1FBQ0gsSUFBQSxxQkFBVyxFQUFDLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDakQsQ0FBQztJQUVELGtCQUFrQjtRQUNoQixJQUFJLHFDQUFpQixDQUFDLElBQUksRUFBRSxvQkFBb0IsRUFBRTtZQUNoRCxZQUFZLEVBQUUsb0JBQW9CO1lBQ2xDLFFBQVEsRUFBRTtnQkFDUixPQUFPLEVBQUUsYUFBYTtnQkFDdEIsTUFBTSxFQUFFLGtCQUFrQjtnQkFDMUIsVUFBVSxFQUFFO29CQUNWLG9CQUFvQixFQUFFLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxvQkFBb0I7b0JBQ2hFLGdCQUFnQixFQUFFLENBQUMsYUFBYSxDQUFDO2lCQUNsQztnQkFDRCxrQkFBa0IsRUFBRSxxQ0FBa0IsQ0FBQyxFQUFFLENBQUMsb0JBQW9CLENBQUM7YUFDaEU7WUFDRCxRQUFRLEVBQUU7Z0JBQ1IsT0FBTyxFQUFFLGFBQWE7Z0JBQ3RCLE1BQU0sRUFBRSxrQkFBa0I7Z0JBQzFCLFVBQVUsRUFBRTtvQkFDVixvQkFBb0IsRUFBRSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsb0JBQW9CO29CQUNoRSxnQkFBZ0IsRUFBRSxDQUFDLGFBQWEsQ0FBQztpQkFDbEM7Z0JBQ0Qsa0JBQWtCLEVBQUUscUNBQWtCLENBQUMsRUFBRSxDQUFDLG9CQUFvQixDQUFDO2FBQ2hFO1lBQ0QsWUFBWSxFQUFFLDRCQUE0QjtTQUMzQyxDQUFDLENBQUM7SUFDTCxDQUFDO0NBQ0Y7QUFoSUQsa0NBZ0lDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQmxvY2tEZXZpY2UsXG4gIElNYWNoaW5lSW1hZ2UsXG4gIEluc3RhbmNlVHlwZSxcbiAgSVZwYyxcbiAgTGF1bmNoVGVtcGxhdGUsXG4gIFN1Ym5ldFR5cGUsXG4gIFVzZXJEYXRhLFxuICBNYWNoaW5lSW1hZ2UsXG4gIExhdW5jaFRlbXBsYXRlSHR0cFRva2VucyxcbiAgS2V5UGFpcixcbiAgSUtleVBhaXIsXG4gIFNlY3VyaXR5R3JvdXAsXG4gIFBlZXIsXG4gIFBvcnQsXG4gIElDb25uZWN0YWJsZSxcbiAgQ29ubmVjdGlvbnNcbn0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1lYzJcIjtcbmltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gXCJjb25zdHJ1Y3RzXCI7XG5pbXBvcnQgeyBEdXJhdGlvbiwgU3RhY2tQcm9wcyB9IGZyb20gXCJhd3MtY2RrLWxpYlwiO1xuaW1wb3J0IHRhZ1Jlc291cmNlIGZyb20gXCIuLi8uLi91dGlscy90YWdSZXNvdXJjZVwiO1xuaW1wb3J0IHsgUm9sZSB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtaWFtXCI7XG5pbXBvcnQge1xuICBBdXRvU2NhbGluZ0dyb3VwLFxuICBHcm91cE1ldHJpY3MsXG4gIFRlcm1pbmF0aW9uUG9saWN5LFxuICBVcGRhdGVQb2xpY3lcbn0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1hdXRvc2NhbGluZ1wiO1xuaW1wb3J0IHsgS2V5VmFsdWUgfSBmcm9tIFwiLi4vLi4vdHlwZXNcIjtcbmltcG9ydCB7IEF3c0N1c3RvbVJlc291cmNlIH0gZnJvbSBcIi4uLy4uL3Jlc291cmNlcy9hd3MvdXRpbGl0aWVzL2F3c0N1c3RvbVJlc291cmNlXCI7XG5pbXBvcnQgeyBQaHlzaWNhbFJlc291cmNlSWQgfSBmcm9tIFwiYXdzLWNkay1saWIvY3VzdG9tLXJlc291cmNlc1wiO1xuaW1wb3J0IHsgVnBjIH0gZnJvbSBcIi4uLy4uL3Jlc291cmNlcy9hd3MvbmV0d29ya2luZy92cGNcIjtcblxuaW50ZXJmYWNlIEV4aXN0aW5nVnBjQ29uZmlnIHtcbiAgdnBjSWQ/OiBzdHJpbmc7XG4gIHN1Ym5ldFR5cGU/OiBTdWJuZXRUeXBlO1xufVxuXG5pbnRlcmZhY2UgTmV3VnBjQ29uZmlnIHtcbiAgc3VibmV0VHlwZTogU3VibmV0VHlwZTtcbn1cblxuZXhwb3J0IHR5cGUgVnBjUHJvcHMgPSBFeGlzdGluZ1ZwY0NvbmZpZyB8IE5ld1ZwY0NvbmZpZztcblxuaW50ZXJmYWNlIEVjMkluc3RhbmNlUHJvcHMgZXh0ZW5kcyBTdGFja1Byb3BzIHtcbiAgc3BvdENhcGFjaXR5UGVyY2VudGFnZT86IG51bWJlcjtcbiAgYmxvY2tEZXZpY2VzPzogQmxvY2tEZXZpY2VbXTtcbiAgYWNjb3VudElkPzogc3RyaW5nO1xuICBzZXJ2aWNlTmFtZTogc3RyaW5nO1xuICB2cGM6IFZwY1Byb3BzO1xuICBtaW5DYXBjaXR5PzogbnVtYmVyO1xuICBtYXhDYXBhY2l0eT86IG51bWJlcjtcbiAgaW5zdGFuY2VUeXBlOiBzdHJpbmc7XG4gIG1hY2hpbmVJbWFnZT86IElNYWNoaW5lSW1hZ2U7XG4gIHVzZXJEYXRhPzogVXNlckRhdGE7XG4gIHJvbGU/OiBSb2xlO1xuICBlbmFibGVTU0g/OiBib29sZWFuO1xuICB0YWdzOiBLZXlWYWx1ZTtcbn1cblxuZXhwb3J0IGNsYXNzIEVjMkluc3RhbmNlIGV4dGVuZHMgQ29uc3RydWN0IGltcGxlbWVudHMgSUNvbm5lY3RhYmxlIHtcbiAgcHJpdmF0ZSBsYXVuY2hUZW1wbGF0ZTogTGF1bmNoVGVtcGxhdGU7XG4gIHB1YmxpYyB2cGM6IElWcGM7XG4gIHB1YmxpYyBhc2dTZWN1cml0eUdyb3VwOiBTZWN1cml0eUdyb3VwO1xuICBwcml2YXRlIGF1dG9TY2FsaW5nR3JvdXA6IEF1dG9TY2FsaW5nR3JvdXA7XG4gIHByaXZhdGUga2V5UGFpcjogSUtleVBhaXI7XG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IEVjMkluc3RhbmNlUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgdGhpcy5hZGRWcGMocHJvcHMpO1xuICAgIGlmIChwcm9wcy5lbmFibGVTU0gpIHtcbiAgICAgIHRoaXMuYWRkS2V5UGFpcihwcm9wcyk7XG4gICAgfVxuICAgIHRoaXMuYWRkTGF1bmNoVGVtcGxhdGUocHJvcHMpO1xuICAgIHRoaXMuYWRkQXV0b1NjYWxpbmdHcm91cChwcm9wcyk7XG4gICAgdGhpcy5zdXNwZW5kQXV0b1NjYWxpbmcoKTtcblxuICAgIC8vVE9ETzogQWRkIGxvYWQgYmFsYW5jZXIgYXMgYm9vbGVhbiBwcm9wLCB0aGVuIGNvbmZpZ3VyZSBsb2FkIGJhbGFuY2VyXG4gIH1cbiAgY29ubmVjdGlvbnM6IENvbm5lY3Rpb25zO1xuXG4gIGFkZFZwYyhwcm9wczogRWMySW5zdGFuY2VQcm9wcykge1xuICAgIGlmIChcInZwY0lkXCIgaW4gcHJvcHMudnBjKSB7XG4gICAgICB0aGlzLnZwYyA9IFZwYy5mcm9tTG9va3VwKHRoaXMsIGAke3Byb3BzLnNlcnZpY2VOYW1lfVZwY2AsIHtcbiAgICAgICAgdnBjSWQ6IHByb3BzLnZwYy52cGNJZFxuICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMudnBjID0gbmV3IFZwYyh0aGlzLCBgJHtwcm9wcy5zZXJ2aWNlTmFtZX1WcGNgLCB7XG4gICAgICAgIGFjY291bnRJZDogcHJvcHMuYWNjb3VudElkLFxuICAgICAgICB0YWdzOiBwcm9wcy50YWdzLFxuICAgICAgICBzdWJuZXRDb25maWd1cmF0aW9uOiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgbmFtZTogYCR7cHJvcHMuc2VydmljZU5hbWV9YCxcbiAgICAgICAgICAgIHN1Ym5ldFR5cGU6IHByb3BzLnZwYy5zdWJuZXRUeXBlIHx8IFN1Ym5ldFR5cGUuUFJJVkFURV9XSVRIX0VHUkVTU1xuICAgICAgICAgIH1cbiAgICAgICAgXVxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgYWRkS2V5UGFpcihwcm9wczogRWMySW5zdGFuY2VQcm9wcykge1xuICAgIC8vIFRPRE86IEJyZWFrb3V0IGludG8gYSBzZXBlcmF0ZSBjb25zdHJ1Y3QgZm9yIHVzZSB3aXRoIGJldHRlciBwcm9wIGhhbmRsaW5nXG4gICAgdGhpcy5rZXlQYWlyID0gbmV3IEtleVBhaXIodGhpcywgXCJLZXlQYWlyXCIsIHtcbiAgICAgIGtleVBhaXJOYW1lOiBgJHtwcm9wcy5zZXJ2aWNlTmFtZX1LZXlQYWlyYFxuICAgIH0pO1xuICB9XG5cbiAgYWRkTGF1bmNoVGVtcGxhdGUocHJvcHM6IEVjMkluc3RhbmNlUHJvcHMpIHtcbiAgICB0aGlzLmFzZ1NlY3VyaXR5R3JvdXAgPSBuZXcgU2VjdXJpdHlHcm91cCh0aGlzLCBgQXNnU2VjdXJpdHlHcm91cGAsIHtcbiAgICAgIHZwYzogdGhpcy52cGMsXG4gICAgICBkZXNjcmlwdGlvbjogYFNlY3VyaXR5IGdyb3VwIGZvciB0aGUgJHtwcm9wcy5zZXJ2aWNlTmFtZX0gYXV0byBzY2FsaW5nIGdyb3VwYFxuICAgIH0pO1xuXG4gICAgaWYgKHByb3BzLmVuYWJsZVNTSCkge1xuICAgICAgdGhpcy5hc2dTZWN1cml0eUdyb3VwLmFkZEluZ3Jlc3NSdWxlKFxuICAgICAgICBQZWVyLmFueUlwdjQoKSxcbiAgICAgICAgUG9ydC50Y3AoMjIpLFxuICAgICAgICBcIkFsbG93IFNTSFwiXG4gICAgICApO1xuICAgIH1cblxuICAgIHRoaXMubGF1bmNoVGVtcGxhdGUgPSBuZXcgTGF1bmNoVGVtcGxhdGUodGhpcywgXCJMYXVuY2hUZW1wbGF0ZVwiLCB7XG4gICAgICBsYXVuY2hUZW1wbGF0ZU5hbWU6IGAke3Byb3BzLnNlcnZpY2VOYW1lfUxhdW5jaFRlbXBsYXRlYCxcbiAgICAgIGluc3RhbmNlVHlwZTogbmV3IEluc3RhbmNlVHlwZShgJHtwcm9wcy5pbnN0YW5jZVR5cGV9YCksXG4gICAgICBtYWNoaW5lSW1hZ2U6IHByb3BzLm1hY2hpbmVJbWFnZSB8fCBNYWNoaW5lSW1hZ2UubGF0ZXN0QW1hem9uTGludXgyKCksXG4gICAgICB1c2VyRGF0YTogcHJvcHMudXNlckRhdGEsXG4gICAgICByb2xlOiBwcm9wcy5yb2xlLFxuICAgICAgYmxvY2tEZXZpY2VzOiBwcm9wcz8uYmxvY2tEZXZpY2VzLFxuICAgICAgc2VjdXJpdHlHcm91cDogdGhpcy5hc2dTZWN1cml0eUdyb3VwLFxuICAgICAgZGV0YWlsZWRNb25pdG9yaW5nOiB0cnVlLFxuICAgICAgcmVxdWlyZUltZHN2MjogdHJ1ZSxcbiAgICAgIGh0dHBQdXRSZXNwb25zZUhvcExpbWl0OiAyLFxuICAgICAgaHR0cFRva2VuczogTGF1bmNoVGVtcGxhdGVIdHRwVG9rZW5zLlJFUVVJUkVELFxuICAgICAgaW5zdGFuY2VNZXRhZGF0YVRhZ3M6IHRydWUsXG4gICAgICBrZXlQYWlyOiB0aGlzLmtleVBhaXJcbiAgICB9KTtcbiAgfVxuXG4gIGFkZEF1dG9TY2FsaW5nR3JvdXAocHJvcHM6IEVjMkluc3RhbmNlUHJvcHMpIHtcbiAgICAvLyBUT0RPOiBTdXBwb3J0IHNwb3QgaW5zdGFuY2VzXG4gICAgLy8gVE9ETzogSGFuZGxlIHRlcm1pbmF0aW5nIEVDMiBpbnN0YW5jZXMgd2hlbiB1cGRhdGluZywgY3VycmVudGx5IGhhbmdzLlxuICAgIHRoaXMuYXV0b1NjYWxpbmdHcm91cCA9IG5ldyBBdXRvU2NhbGluZ0dyb3VwKHRoaXMsIFwiQXV0b1NjYWxpbmdHcm91cFwiLCB7XG4gICAgICB2cGM6IHRoaXMudnBjLFxuICAgICAgdnBjU3VibmV0czoge1xuICAgICAgICBzdWJuZXRUeXBlOiBwcm9wcy5lbmFibGVTU0ggPyBTdWJuZXRUeXBlLlBVQkxJQyA6IHVuZGVmaW5lZFxuICAgICAgfSxcbiAgICAgIG1pbkNhcGFjaXR5OiBwcm9wcy5taW5DYXBjaXR5LFxuICAgICAgbWF4Q2FwYWNpdHk6IHByb3BzLm1heENhcGFjaXR5LFxuICAgICAgbGF1bmNoVGVtcGxhdGU6IHRoaXMubGF1bmNoVGVtcGxhdGUsXG4gICAgICBjb29sZG93bjogRHVyYXRpb24uc2Vjb25kcyg2MCksXG4gICAgICBncm91cE1ldHJpY3M6IFtHcm91cE1ldHJpY3MuYWxsKCldLFxuICAgICAgdXBkYXRlUG9saWN5OiBVcGRhdGVQb2xpY3kucmVwbGFjaW5nVXBkYXRlKCksXG4gICAgICBuZXdJbnN0YW5jZXNQcm90ZWN0ZWRGcm9tU2NhbGVJbjogdHJ1ZSxcbiAgICAgIC8vIHNlY3VyaXR5R3JvdXA6IHRoaXMuYXNnU2VjdXJpdHlHcm91cCxcbiAgICAgIHRlcm1pbmF0aW9uUG9saWNpZXM6IFtcbiAgICAgICAgVGVybWluYXRpb25Qb2xpY3kuT0xERVNUX0xBVU5DSF9DT05GSUdVUkFUSU9OLFxuICAgICAgICBUZXJtaW5hdGlvblBvbGljeS5DTE9TRVNUX1RPX05FWFRfSU5TVEFOQ0VfSE9VUlxuICAgICAgXSxcbiAgICAgIHNzbVNlc3Npb25QZXJtaXNzaW9uczogdHJ1ZVxuICAgIH0pO1xuICAgIHRhZ1Jlc291cmNlKHRoaXMuYXV0b1NjYWxpbmdHcm91cCwgcHJvcHMudGFncyk7XG4gIH1cblxuICBzdXNwZW5kQXV0b1NjYWxpbmcoKSB7XG4gICAgbmV3IEF3c0N1c3RvbVJlc291cmNlKHRoaXMsIFwiU3VzcGVuZEF1dG9zY2FsaW5nXCIsIHtcbiAgICAgIGZ1bmN0aW9uTmFtZTogXCJzdXNwZW5kQXV0b1NjYWxpbmdcIixcbiAgICAgIG9uQ3JlYXRlOiB7XG4gICAgICAgIHNlcnZpY2U6IFwiQXV0b1NjYWxpbmdcIixcbiAgICAgICAgYWN0aW9uOiBcInN1c3BlbmRQcm9jZXNzZXNcIixcbiAgICAgICAgcGFyYW1ldGVyczoge1xuICAgICAgICAgIEF1dG9TY2FsaW5nR3JvdXBOYW1lOiB0aGlzLmF1dG9TY2FsaW5nR3JvdXAuYXV0b1NjYWxpbmdHcm91cE5hbWUsXG4gICAgICAgICAgU2NhbGluZ1Byb2Nlc3NlczogW1wiQVpSZWJhbGFuY2VcIl1cbiAgICAgICAgfSxcbiAgICAgICAgcGh5c2ljYWxSZXNvdXJjZUlkOiBQaHlzaWNhbFJlc291cmNlSWQub2YoXCJzdXNwZW5kQXV0b1NjYWxpbmdcIilcbiAgICAgIH0sXG4gICAgICBvblVwZGF0ZToge1xuICAgICAgICBzZXJ2aWNlOiBcIkF1dG9TY2FsaW5nXCIsXG4gICAgICAgIGFjdGlvbjogXCJzdXNwZW5kUHJvY2Vzc2VzXCIsXG4gICAgICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgICAgICBBdXRvU2NhbGluZ0dyb3VwTmFtZTogdGhpcy5hdXRvU2NhbGluZ0dyb3VwLmF1dG9TY2FsaW5nR3JvdXBOYW1lLFxuICAgICAgICAgIFNjYWxpbmdQcm9jZXNzZXM6IFtcIkFaUmViYWxhbmNlXCJdXG4gICAgICAgIH0sXG4gICAgICAgIHBoeXNpY2FsUmVzb3VyY2VJZDogUGh5c2ljYWxSZXNvdXJjZUlkLm9mKFwic3VzcGVuZEF1dG9TY2FsaW5nXCIpXG4gICAgICB9LFxuICAgICAgcmVzb3VyY2VUeXBlOiBcIkN1c3RvbTo6c3VzcGVuZEF1dG9zY2FsaW5nXCJcbiAgICB9KTtcbiAgfVxufVxuIl19
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fjall/components-infrastructure",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "bin": {
5
5
  "infrastructure": "bin/infrastructure.js"
6
6
  },
@@ -35,7 +35,7 @@
35
35
  "dependencies": {
36
36
  "@aws-sdk/client-cost-explorer": "^3.717.0",
37
37
  "@aws-sdk/client-organizations": "^3.716.0",
38
- "@fjall/util": "^0.8.0",
38
+ "@fjall/util": "^0.9.0",
39
39
  "@pepperize/cdk-organizations": "^0.7.135",
40
40
  "aws-cdk": "^2.146.0",
41
41
  "aws-cdk-lib": "^2.146.0",
@@ -48,5 +48,5 @@
48
48
  "overrides": {
49
49
  "@smithy/core": "2.5.5"
50
50
  },
51
- "gitHead": "d2860d6f440920681949841d40ffda41b7d3b6c1"
51
+ "gitHead": "7e028d98cd10385ca80f1482198443d6cc29ce76"
52
52
  }
@@ -1,11 +0,0 @@
1
- import { Construct } from "constructs";
2
- export declare class AssignmentNew extends Construct {
3
- constructor(scope: Construct, id: string, props: {
4
- instanceArn: string;
5
- permissionSetArn: string;
6
- principalType: string;
7
- principalId: string;
8
- targetType: string;
9
- targetId: string;
10
- });
11
- }
@@ -1,102 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AssignmentNew = void 0;
4
- const aws_cdk_lib_1 = require("aws-cdk-lib");
5
- const aws_iam_1 = require("aws-cdk-lib/aws-iam");
6
- const aws_lambda_1 = require("aws-cdk-lib/aws-lambda");
7
- const aws_logs_1 = require("aws-cdk-lib/aws-logs");
8
- const custom_resources_1 = require("aws-cdk-lib/custom-resources");
9
- const constructs_1 = require("constructs");
10
- const path_1 = require("path");
11
- const aws_cdk_lib_2 = require("aws-cdk-lib");
12
- class AssignmentNew extends constructs_1.Construct {
13
- constructor(scope, id, props) {
14
- super(scope, id);
15
- // 1. Create a dedicated IAM role with the necessary permissions
16
- const lambdaRole = new aws_iam_1.Role(this, `${id}LambdaRole`, {
17
- assumedBy: new aws_iam_1.ServicePrincipal("lambda.amazonaws.com"),
18
- description: `Role for AWS Identity Center Assignment for ${id}`,
19
- inlinePolicies: {
20
- // CloudWatch Logs permissions
21
- "logs-policy": new aws_iam_1.PolicyDocument({
22
- statements: [
23
- new aws_iam_1.PolicyStatement({
24
- effect: aws_iam_1.Effect.ALLOW,
25
- actions: [
26
- "logs:CreateLogGroup",
27
- "logs:CreateLogStream",
28
- "logs:PutLogEvents"
29
- ],
30
- resources: ["*"]
31
- })
32
- ]
33
- }),
34
- // SSO Admin permissions - comprehensive permissions for both sso: and sso-admin: namespaces
35
- "sso-admin-policy": new aws_iam_1.PolicyDocument({
36
- statements: [
37
- new aws_iam_1.PolicyStatement({
38
- effect: aws_iam_1.Effect.ALLOW,
39
- actions: [
40
- // SSO Admin permissions (using both prefixes to ensure compatibility)
41
- "sso:*",
42
- "sso-admin:CreateAccountAssignment",
43
- "sso-admin:DeleteAccountAssignment",
44
- "sso-admin:ListAccountAssignments",
45
- "sso-admin:DescribeAccountAssignmentCreationStatus",
46
- "sso-admin:DescribeAccountAssignmentDeletionStatus",
47
- // Original SSO permissions (may still be needed)
48
- "sso:CreateAccountAssignment",
49
- "sso:UpdateAccountAssignment",
50
- "sso:DeleteAccountAssignment",
51
- "sso:ListAccountAssignments",
52
- "sso:DescribeAccountAssignmentCreationStatus",
53
- "sso:DescribeAccountAssignmentDeletionStatus",
54
- // Identity Store permissions
55
- "identitystore:DescribeGroup",
56
- "identitystore:ListGroupMemberships",
57
- "identitystore:ListUsers",
58
- "identitystore:ListGroups",
59
- // Organizations permissions that may be needed for cross-account operations
60
- "organizations:DescribeAccount",
61
- "organizations:ListAccounts"
62
- ],
63
- resources: ["*"]
64
- })
65
- ]
66
- })
67
- }
68
- });
69
- // 2. Create the Lambda function with the dedicated role
70
- const lambda = new aws_lambda_1.Function(this, `${id}Lambda`, {
71
- runtime: aws_lambda_1.Runtime.NODEJS_18_X,
72
- code: aws_lambda_1.Code.fromAsset((0, path_1.join)(__dirname, "lambda")),
73
- handler: "assignmentHandler.handler",
74
- role: lambdaRole,
75
- timeout: aws_cdk_lib_1.Duration.minutes(5),
76
- description: `AWS Identity Center Assignment Handler for ${id}`,
77
- logRetention: aws_logs_1.RetentionDays.ONE_WEEK,
78
- memorySize: 256 // Increase memory for better performance
79
- });
80
- // 3. Create a custom resource provider
81
- const provider = new custom_resources_1.Provider(this, `${id}Provider`, {
82
- onEventHandler: lambda,
83
- logRetention: aws_logs_1.RetentionDays.ONE_WEEK
84
- });
85
- // 4. Create the custom resource
86
- new aws_cdk_lib_2.CustomResource(this, `${id}Resource`, {
87
- serviceToken: provider.serviceToken,
88
- properties: {
89
- InstanceArn: props.instanceArn,
90
- PermissionSetArn: props.permissionSetArn,
91
- PrincipalType: props.principalType,
92
- PrincipalId: props.principalId,
93
- TargetType: props.targetType,
94
- TargetId: props.targetId,
95
- // Add a timestamp to ensure updates are processed
96
- Timestamp: new Date().toISOString()
97
- }
98
- });
99
- }
100
- }
101
- exports.AssignmentNew = AssignmentNew;
102
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXNzaWdubWVudE5ldy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL2xpYi9yZXNvdXJjZXMvYXdzL2lhbS9pZGVudGl0eUNlbnRlci9hc3NpZ25tZW50TmV3LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDZDQUF1QztBQUN2QyxpREFNNkI7QUFDN0IsdURBQWlFO0FBQ2pFLG1EQUFxRDtBQUNyRCxtRUFBd0Q7QUFDeEQsMkNBQXVDO0FBQ3ZDLCtCQUE0QjtBQUM1Qiw2Q0FBNkM7QUFFN0MsTUFBYSxhQUFjLFNBQVEsc0JBQVM7SUFDMUMsWUFDRSxLQUFnQixFQUNoQixFQUFVLEVBQ1YsS0FPQztRQUVELEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFFakIsZ0VBQWdFO1FBQ2hFLE1BQU0sVUFBVSxHQUFHLElBQUksY0FBSSxDQUFDLElBQUksRUFBRSxHQUFHLEVBQUUsWUFBWSxFQUFFO1lBQ25ELFNBQVMsRUFBRSxJQUFJLDBCQUFnQixDQUFDLHNCQUFzQixDQUFDO1lBQ3ZELFdBQVcsRUFBRSwrQ0FBK0MsRUFBRSxFQUFFO1lBQ2hFLGNBQWMsRUFBRTtnQkFDZCw4QkFBOEI7Z0JBQzlCLGFBQWEsRUFBRSxJQUFJLHdCQUFjLENBQUM7b0JBQ2hDLFVBQVUsRUFBRTt3QkFDVixJQUFJLHlCQUFlLENBQUM7NEJBQ2xCLE1BQU0sRUFBRSxnQkFBTSxDQUFDLEtBQUs7NEJBQ3BCLE9BQU8sRUFBRTtnQ0FDUCxxQkFBcUI7Z0NBQ3JCLHNCQUFzQjtnQ0FDdEIsbUJBQW1COzZCQUNwQjs0QkFDRCxTQUFTLEVBQUUsQ0FBQyxHQUFHLENBQUM7eUJBQ2pCLENBQUM7cUJBQ0g7aUJBQ0YsQ0FBQztnQkFDRiw0RkFBNEY7Z0JBQzVGLGtCQUFrQixFQUFFLElBQUksd0JBQWMsQ0FBQztvQkFDckMsVUFBVSxFQUFFO3dCQUNWLElBQUkseUJBQWUsQ0FBQzs0QkFDbEIsTUFBTSxFQUFFLGdCQUFNLENBQUMsS0FBSzs0QkFDcEIsT0FBTyxFQUFFO2dDQUNQLHNFQUFzRTtnQ0FDdEUsT0FBTztnQ0FDUCxtQ0FBbUM7Z0NBQ25DLG1DQUFtQztnQ0FDbkMsa0NBQWtDO2dDQUNsQyxtREFBbUQ7Z0NBQ25ELG1EQUFtRDtnQ0FFbkQsaURBQWlEO2dDQUNqRCw2QkFBNkI7Z0NBQzdCLDZCQUE2QjtnQ0FDN0IsNkJBQTZCO2dDQUM3Qiw0QkFBNEI7Z0NBQzVCLDZDQUE2QztnQ0FDN0MsNkNBQTZDO2dDQUU3Qyw2QkFBNkI7Z0NBQzdCLDZCQUE2QjtnQ0FDN0Isb0NBQW9DO2dDQUNwQyx5QkFBeUI7Z0NBQ3pCLDBCQUEwQjtnQ0FFMUIsNEVBQTRFO2dDQUM1RSwrQkFBK0I7Z0NBQy9CLDRCQUE0Qjs2QkFDN0I7NEJBQ0QsU0FBUyxFQUFFLENBQUMsR0FBRyxDQUFDO3lCQUNqQixDQUFDO3FCQUNIO2lCQUNGLENBQUM7YUFDSDtTQUNGLENBQUMsQ0FBQztRQUVILHdEQUF3RDtRQUN4RCxNQUFNLE1BQU0sR0FBRyxJQUFJLHFCQUFRLENBQUMsSUFBSSxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUU7WUFDL0MsT0FBTyxFQUFFLG9CQUFPLENBQUMsV0FBVztZQUM1QixJQUFJLEVBQUUsaUJBQUksQ0FBQyxTQUFTLENBQUMsSUFBQSxXQUFJLEVBQUMsU0FBUyxFQUFFLFFBQVEsQ0FBQyxDQUFDO1lBQy9DLE9BQU8sRUFBRSwyQkFBMkI7WUFDcEMsSUFBSSxFQUFFLFVBQVU7WUFDaEIsT0FBTyxFQUFFLHNCQUFRLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQztZQUM1QixXQUFXLEVBQUUsOENBQThDLEVBQUUsRUFBRTtZQUMvRCxZQUFZLEVBQUUsd0JBQWEsQ0FBQyxRQUFRO1lBQ3BDLFVBQVUsRUFBRSxHQUFHLENBQUMseUNBQXlDO1NBQzFELENBQUMsQ0FBQztRQUVILHVDQUF1QztRQUN2QyxNQUFNLFFBQVEsR0FBRyxJQUFJLDJCQUFRLENBQUMsSUFBSSxFQUFFLEdBQUcsRUFBRSxVQUFVLEVBQUU7WUFDbkQsY0FBYyxFQUFFLE1BQU07WUFDdEIsWUFBWSxFQUFFLHdCQUFhLENBQUMsUUFBUTtTQUNyQyxDQUFDLENBQUM7UUFFSCxnQ0FBZ0M7UUFDaEMsSUFBSSw0QkFBYyxDQUFDLElBQUksRUFBRSxHQUFHLEVBQUUsVUFBVSxFQUFFO1lBQ3hDLFlBQVksRUFBRSxRQUFRLENBQUMsWUFBWTtZQUNuQyxVQUFVLEVBQUU7Z0JBQ1YsV0FBVyxFQUFFLEtBQUssQ0FBQyxXQUFXO2dCQUM5QixnQkFBZ0IsRUFBRSxLQUFLLENBQUMsZ0JBQWdCO2dCQUN4QyxhQUFhLEVBQUUsS0FBSyxDQUFDLGFBQWE7Z0JBQ2xDLFdBQVcsRUFBRSxLQUFLLENBQUMsV0FBVztnQkFDOUIsVUFBVSxFQUFFLEtBQUssQ0FBQyxVQUFVO2dCQUM1QixRQUFRLEVBQUUsS0FBSyxDQUFDLFFBQVE7Z0JBQ3hCLGtEQUFrRDtnQkFDbEQsU0FBUyxFQUFFLElBQUksSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFO2FBQ3BDO1NBQ0YsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztDQUNGO0FBMUdELHNDQTBHQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IER1cmF0aW9uIH0gZnJvbSBcImF3cy1jZGstbGliXCI7XG5pbXBvcnQge1xuICBQb2xpY3lEb2N1bWVudCxcbiAgUG9saWN5U3RhdGVtZW50LFxuICBFZmZlY3QsXG4gIFJvbGUsXG4gIFNlcnZpY2VQcmluY2lwYWxcbn0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1pYW1cIjtcbmltcG9ydCB7IENvZGUsIEZ1bmN0aW9uLCBSdW50aW1lIH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1sYW1iZGFcIjtcbmltcG9ydCB7IFJldGVudGlvbkRheXMgfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWxvZ3NcIjtcbmltcG9ydCB7IFByb3ZpZGVyIH0gZnJvbSBcImF3cy1jZGstbGliL2N1c3RvbS1yZXNvdXJjZXNcIjtcbmltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gXCJjb25zdHJ1Y3RzXCI7XG5pbXBvcnQgeyBqb2luIH0gZnJvbSBcInBhdGhcIjtcbmltcG9ydCB7IEN1c3RvbVJlc291cmNlIH0gZnJvbSBcImF3cy1jZGstbGliXCI7XG5cbmV4cG9ydCBjbGFzcyBBc3NpZ25tZW50TmV3IGV4dGVuZHMgQ29uc3RydWN0IHtcbiAgY29uc3RydWN0b3IoXG4gICAgc2NvcGU6IENvbnN0cnVjdCxcbiAgICBpZDogc3RyaW5nLFxuICAgIHByb3BzOiB7XG4gICAgICBpbnN0YW5jZUFybjogc3RyaW5nO1xuICAgICAgcGVybWlzc2lvblNldEFybjogc3RyaW5nO1xuICAgICAgcHJpbmNpcGFsVHlwZTogc3RyaW5nO1xuICAgICAgcHJpbmNpcGFsSWQ6IHN0cmluZztcbiAgICAgIHRhcmdldFR5cGU6IHN0cmluZztcbiAgICAgIHRhcmdldElkOiBzdHJpbmc7XG4gICAgfVxuICApIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgLy8gMS4gQ3JlYXRlIGEgZGVkaWNhdGVkIElBTSByb2xlIHdpdGggdGhlIG5lY2Vzc2FyeSBwZXJtaXNzaW9uc1xuICAgIGNvbnN0IGxhbWJkYVJvbGUgPSBuZXcgUm9sZSh0aGlzLCBgJHtpZH1MYW1iZGFSb2xlYCwge1xuICAgICAgYXNzdW1lZEJ5OiBuZXcgU2VydmljZVByaW5jaXBhbChcImxhbWJkYS5hbWF6b25hd3MuY29tXCIpLFxuICAgICAgZGVzY3JpcHRpb246IGBSb2xlIGZvciBBV1MgSWRlbnRpdHkgQ2VudGVyIEFzc2lnbm1lbnQgZm9yICR7aWR9YCxcbiAgICAgIGlubGluZVBvbGljaWVzOiB7XG4gICAgICAgIC8vIENsb3VkV2F0Y2ggTG9ncyBwZXJtaXNzaW9uc1xuICAgICAgICBcImxvZ3MtcG9saWN5XCI6IG5ldyBQb2xpY3lEb2N1bWVudCh7XG4gICAgICAgICAgc3RhdGVtZW50czogW1xuICAgICAgICAgICAgbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgICAgICAgIGVmZmVjdDogRWZmZWN0LkFMTE9XLFxuICAgICAgICAgICAgICBhY3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgXCJsb2dzOkNyZWF0ZUxvZ0dyb3VwXCIsXG4gICAgICAgICAgICAgICAgXCJsb2dzOkNyZWF0ZUxvZ1N0cmVhbVwiLFxuICAgICAgICAgICAgICAgIFwibG9nczpQdXRMb2dFdmVudHNcIlxuICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICByZXNvdXJjZXM6IFtcIipcIl1cbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgXVxuICAgICAgICB9KSxcbiAgICAgICAgLy8gU1NPIEFkbWluIHBlcm1pc3Npb25zIC0gY29tcHJlaGVuc2l2ZSBwZXJtaXNzaW9ucyBmb3IgYm90aCBzc286IGFuZCBzc28tYWRtaW46IG5hbWVzcGFjZXNcbiAgICAgICAgXCJzc28tYWRtaW4tcG9saWN5XCI6IG5ldyBQb2xpY3lEb2N1bWVudCh7XG4gICAgICAgICAgc3RhdGVtZW50czogW1xuICAgICAgICAgICAgbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgICAgICAgIGVmZmVjdDogRWZmZWN0LkFMTE9XLFxuICAgICAgICAgICAgICBhY3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgLy8gU1NPIEFkbWluIHBlcm1pc3Npb25zICh1c2luZyBib3RoIHByZWZpeGVzIHRvIGVuc3VyZSBjb21wYXRpYmlsaXR5KVxuICAgICAgICAgICAgICAgIFwic3NvOipcIixcbiAgICAgICAgICAgICAgICBcInNzby1hZG1pbjpDcmVhdGVBY2NvdW50QXNzaWdubWVudFwiLFxuICAgICAgICAgICAgICAgIFwic3NvLWFkbWluOkRlbGV0ZUFjY291bnRBc3NpZ25tZW50XCIsXG4gICAgICAgICAgICAgICAgXCJzc28tYWRtaW46TGlzdEFjY291bnRBc3NpZ25tZW50c1wiLFxuICAgICAgICAgICAgICAgIFwic3NvLWFkbWluOkRlc2NyaWJlQWNjb3VudEFzc2lnbm1lbnRDcmVhdGlvblN0YXR1c1wiLFxuICAgICAgICAgICAgICAgIFwic3NvLWFkbWluOkRlc2NyaWJlQWNjb3VudEFzc2lnbm1lbnREZWxldGlvblN0YXR1c1wiLFxuXG4gICAgICAgICAgICAgICAgLy8gT3JpZ2luYWwgU1NPIHBlcm1pc3Npb25zIChtYXkgc3RpbGwgYmUgbmVlZGVkKVxuICAgICAgICAgICAgICAgIFwic3NvOkNyZWF0ZUFjY291bnRBc3NpZ25tZW50XCIsXG4gICAgICAgICAgICAgICAgXCJzc286VXBkYXRlQWNjb3VudEFzc2lnbm1lbnRcIixcbiAgICAgICAgICAgICAgICBcInNzbzpEZWxldGVBY2NvdW50QXNzaWdubWVudFwiLFxuICAgICAgICAgICAgICAgIFwic3NvOkxpc3RBY2NvdW50QXNzaWdubWVudHNcIixcbiAgICAgICAgICAgICAgICBcInNzbzpEZXNjcmliZUFjY291bnRBc3NpZ25tZW50Q3JlYXRpb25TdGF0dXNcIixcbiAgICAgICAgICAgICAgICBcInNzbzpEZXNjcmliZUFjY291bnRBc3NpZ25tZW50RGVsZXRpb25TdGF0dXNcIixcblxuICAgICAgICAgICAgICAgIC8vIElkZW50aXR5IFN0b3JlIHBlcm1pc3Npb25zXG4gICAgICAgICAgICAgICAgXCJpZGVudGl0eXN0b3JlOkRlc2NyaWJlR3JvdXBcIixcbiAgICAgICAgICAgICAgICBcImlkZW50aXR5c3RvcmU6TGlzdEdyb3VwTWVtYmVyc2hpcHNcIixcbiAgICAgICAgICAgICAgICBcImlkZW50aXR5c3RvcmU6TGlzdFVzZXJzXCIsXG4gICAgICAgICAgICAgICAgXCJpZGVudGl0eXN0b3JlOkxpc3RHcm91cHNcIixcblxuICAgICAgICAgICAgICAgIC8vIE9yZ2FuaXphdGlvbnMgcGVybWlzc2lvbnMgdGhhdCBtYXkgYmUgbmVlZGVkIGZvciBjcm9zcy1hY2NvdW50IG9wZXJhdGlvbnNcbiAgICAgICAgICAgICAgICBcIm9yZ2FuaXphdGlvbnM6RGVzY3JpYmVBY2NvdW50XCIsXG4gICAgICAgICAgICAgICAgXCJvcmdhbml6YXRpb25zOkxpc3RBY2NvdW50c1wiXG4gICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgIHJlc291cmNlczogW1wiKlwiXVxuICAgICAgICAgICAgfSlcbiAgICAgICAgICBdXG4gICAgICAgIH0pXG4gICAgICB9XG4gICAgfSk7XG5cbiAgICAvLyAyLiBDcmVhdGUgdGhlIExhbWJkYSBmdW5jdGlvbiB3aXRoIHRoZSBkZWRpY2F0ZWQgcm9sZVxuICAgIGNvbnN0IGxhbWJkYSA9IG5ldyBGdW5jdGlvbih0aGlzLCBgJHtpZH1MYW1iZGFgLCB7XG4gICAgICBydW50aW1lOiBSdW50aW1lLk5PREVKU18xOF9YLFxuICAgICAgY29kZTogQ29kZS5mcm9tQXNzZXQoam9pbihfX2Rpcm5hbWUsIFwibGFtYmRhXCIpKSxcbiAgICAgIGhhbmRsZXI6IFwiYXNzaWdubWVudEhhbmRsZXIuaGFuZGxlclwiLFxuICAgICAgcm9sZTogbGFtYmRhUm9sZSxcbiAgICAgIHRpbWVvdXQ6IER1cmF0aW9uLm1pbnV0ZXMoNSksXG4gICAgICBkZXNjcmlwdGlvbjogYEFXUyBJZGVudGl0eSBDZW50ZXIgQXNzaWdubWVudCBIYW5kbGVyIGZvciAke2lkfWAsXG4gICAgICBsb2dSZXRlbnRpb246IFJldGVudGlvbkRheXMuT05FX1dFRUssXG4gICAgICBtZW1vcnlTaXplOiAyNTYgLy8gSW5jcmVhc2UgbWVtb3J5IGZvciBiZXR0ZXIgcGVyZm9ybWFuY2VcbiAgICB9KTtcblxuICAgIC8vIDMuIENyZWF0ZSBhIGN1c3RvbSByZXNvdXJjZSBwcm92aWRlclxuICAgIGNvbnN0IHByb3ZpZGVyID0gbmV3IFByb3ZpZGVyKHRoaXMsIGAke2lkfVByb3ZpZGVyYCwge1xuICAgICAgb25FdmVudEhhbmRsZXI6IGxhbWJkYSxcbiAgICAgIGxvZ1JldGVudGlvbjogUmV0ZW50aW9uRGF5cy5PTkVfV0VFS1xuICAgIH0pO1xuXG4gICAgLy8gNC4gQ3JlYXRlIHRoZSBjdXN0b20gcmVzb3VyY2VcbiAgICBuZXcgQ3VzdG9tUmVzb3VyY2UodGhpcywgYCR7aWR9UmVzb3VyY2VgLCB7XG4gICAgICBzZXJ2aWNlVG9rZW46IHByb3ZpZGVyLnNlcnZpY2VUb2tlbixcbiAgICAgIHByb3BlcnRpZXM6IHtcbiAgICAgICAgSW5zdGFuY2VBcm46IHByb3BzLmluc3RhbmNlQXJuLFxuICAgICAgICBQZXJtaXNzaW9uU2V0QXJuOiBwcm9wcy5wZXJtaXNzaW9uU2V0QXJuLFxuICAgICAgICBQcmluY2lwYWxUeXBlOiBwcm9wcy5wcmluY2lwYWxUeXBlLFxuICAgICAgICBQcmluY2lwYWxJZDogcHJvcHMucHJpbmNpcGFsSWQsXG4gICAgICAgIFRhcmdldFR5cGU6IHByb3BzLnRhcmdldFR5cGUsXG4gICAgICAgIFRhcmdldElkOiBwcm9wcy50YXJnZXRJZCxcbiAgICAgICAgLy8gQWRkIGEgdGltZXN0YW1wIHRvIGVuc3VyZSB1cGRhdGVzIGFyZSBwcm9jZXNzZWRcbiAgICAgICAgVGltZXN0YW1wOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKClcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxufVxuIl19
@@ -1,24 +0,0 @@
1
- interface CloudFormationEvent {
2
- RequestType: "Create" | "Update" | "Delete";
3
- ResponseURL: string;
4
- StackId: string;
5
- RequestId: string;
6
- ResourceType: string;
7
- LogicalResourceId: string;
8
- PhysicalResourceId?: string;
9
- ResourceProperties: {
10
- ServiceToken: string;
11
- InstanceArn: string;
12
- PermissionSetArn: string;
13
- PrincipalType: string;
14
- PrincipalId: string;
15
- TargetType: string;
16
- TargetId: string;
17
- [key: string]: any;
18
- };
19
- OldResourceProperties?: {
20
- [key: string]: any;
21
- };
22
- }
23
- export declare const handler: (event: CloudFormationEvent) => Promise<any>;
24
- export {};
@@ -1,246 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.handler = void 0;
4
- const client_sso_admin_1 = require("@aws-sdk/client-sso-admin");
5
- const client_sts_1 = require("@aws-sdk/client-sts");
6
- const client_s3_1 = require("@aws-sdk/client-s3");
7
- const ssoAdmin = new client_sso_admin_1.SSOAdminClient();
8
- const sts = new client_sts_1.STSClient();
9
- const s3 = new client_s3_1.S3Client();
10
- // Helper function to add delay
11
- const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
12
- // Function to send response to CloudFormation
13
- const sendResponse = async (event, response) => {
14
- console.info("Sending CloudFormation response:");
15
- console.info(`Status: ${response.Status}`);
16
- console.info(`PhysicalResourceId: ${response.PhysicalResourceId}`);
17
- if (response.Reason) {
18
- console.info(`Reason: ${response.Reason}`);
19
- }
20
- const responseBody = JSON.stringify(response);
21
- console.info(`Sending response to: ${event.ResponseURL}`);
22
- try {
23
- // Extract bucket and key from the pre-signed URL
24
- const url = new URL(event.ResponseURL);
25
- const bucketName = url.hostname.split(".")[0];
26
- const key = url.pathname.substring(1); // remove leading slash
27
- // Use S3 client to upload directly
28
- await s3.send(new client_s3_1.PutObjectCommand({
29
- Bucket: bucketName,
30
- Key: key,
31
- Body: responseBody,
32
- ContentType: "application/json"
33
- }));
34
- console.info(`Status code: 200`);
35
- console.info(`Status message: OK`);
36
- }
37
- catch (error) {
38
- console.error("Error sending response:", error);
39
- throw error;
40
- }
41
- };
42
- // Function to check if an assignment exists
43
- const verifyAssignmentExists = async (instanceArn, permissionSetArn, targetId, principalId, principalType, retries = 10, delay = 5000) => {
44
- for (let attempt = 1; attempt <= retries; attempt++) {
45
- try {
46
- console.info(`Verifying assignment exists - attempt ${attempt}/${retries}`);
47
- const listResponse = await ssoAdmin.send(new client_sso_admin_1.ListAccountAssignmentsCommand({
48
- InstanceArn: instanceArn,
49
- AccountId: targetId,
50
- PermissionSetArn: permissionSetArn
51
- }));
52
- const assignments = listResponse.AccountAssignments || [];
53
- console.info(`Found ${assignments.length} assignments for account ${targetId} and permission set`);
54
- const exists = assignments.some((assignment) => assignment.PrincipalId === principalId &&
55
- assignment.PrincipalType === principalType);
56
- if (exists) {
57
- console.info("Assignment exists");
58
- return true;
59
- }
60
- if (attempt < retries) {
61
- console.info(`Assignment not found, waiting ${delay / 1000} seconds before retrying...`);
62
- await sleep(delay);
63
- }
64
- }
65
- catch (error) {
66
- console.error(`Error verifying assignment (attempt ${attempt}/${retries}):`, error);
67
- if (attempt < retries) {
68
- console.info(`Waiting ${delay / 1000} seconds before retrying...`);
69
- await sleep(delay);
70
- }
71
- }
72
- }
73
- console.info("Assignment not found after maximum retries");
74
- return false;
75
- };
76
- // Handle CloudFormation custom resource event
77
- const handler = async (event) => {
78
- console.info("Received event: ", JSON.stringify(event, null, 2));
79
- // Log environment variables (without sensitive data)
80
- console.info("Environment variables: " +
81
- JSON.stringify({
82
- AWS_REGION: process.env.AWS_REGION,
83
- AWS_EXECUTION_ENV: process.env.AWS_EXECUTION_ENV,
84
- AWS_LAMBDA_FUNCTION_NAME: process.env.AWS_LAMBDA_FUNCTION_NAME,
85
- AWS_LAMBDA_FUNCTION_VERSION: process.env.AWS_LAMBDA_FUNCTION_VERSION,
86
- AWS_LAMBDA_FUNCTION_MEMORY_SIZE: process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE
87
- }));
88
- // Get current identity for debugging purposes
89
- try {
90
- const identity = await sts.send(new client_sts_1.GetCallerIdentityCommand({}));
91
- console.info("Current identity: ", JSON.stringify(identity, null, 2));
92
- }
93
- catch (error) {
94
- console.error("Error getting caller identity:", error);
95
- }
96
- const { InstanceArn: instanceArn, PermissionSetArn: permissionSetArn, PrincipalType: principalTypeStr, PrincipalId: principalId, TargetType: targetTypeStr, TargetId: targetId } = event.ResourceProperties;
97
- // Convert string types to enum types
98
- const principalType = principalTypeStr;
99
- const targetType = targetTypeStr;
100
- // Generate a consistent physical ID regardless of whether the assignment exists
101
- const physicalResourceId = event.PhysicalResourceId ||
102
- `${permissionSetArn}-${principalId}-${targetId}`;
103
- // Prepare the response
104
- const response = {
105
- Status: "SUCCESS",
106
- PhysicalResourceId: physicalResourceId,
107
- StackId: event.StackId,
108
- RequestId: event.RequestId,
109
- LogicalResourceId: event.LogicalResourceId
110
- };
111
- const MAX_RETRIES = 5;
112
- try {
113
- switch (event.RequestType) {
114
- case "Create":
115
- case "Update":
116
- const operation = event.RequestType === "Create" ? "Creating" : "Updating";
117
- // Check if assignment already exists for updates to avoid errors
118
- if (event.RequestType === "Update") {
119
- const exists = await verifyAssignmentExists(instanceArn, permissionSetArn, targetId, principalId, principalTypeStr);
120
- if (exists) {
121
- console.info("Assignment already exists for update operation - no action needed");
122
- await sendResponse(event, response);
123
- return response;
124
- }
125
- }
126
- // Create the assignment
127
- for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
128
- console.info(`Attempt ${attempt}/${MAX_RETRIES}`);
129
- console.info(`${operation} Account Assignment`);
130
- try {
131
- await ssoAdmin.send(new client_sso_admin_1.CreateAccountAssignmentCommand({
132
- InstanceArn: instanceArn,
133
- PermissionSetArn: permissionSetArn,
134
- PrincipalType: principalType,
135
- PrincipalId: principalId,
136
- TargetType: targetType,
137
- TargetId: targetId
138
- }));
139
- console.info("Create assignment command sent successfully");
140
- console.info("Verifying assignment exists");
141
- // Verify the assignment was created
142
- const exists = await verifyAssignmentExists(instanceArn, permissionSetArn, targetId, principalId, principalTypeStr);
143
- if (exists) {
144
- console.info("Assignment verified successfully");
145
- await sendResponse(event, response);
146
- return response;
147
- }
148
- else {
149
- throw new Error("Assignment verification failed: Assignment not found after creation");
150
- }
151
- }
152
- catch (error) {
153
- console.error(`Error in attempt ${attempt}:`, error);
154
- // If it's the last attempt, propagate the error
155
- if (attempt === MAX_RETRIES) {
156
- throw error;
157
- }
158
- // If it's a ConflictException or the assignment already exists, consider it a success
159
- if (error.name === "ConflictException" ||
160
- error.message.includes("already exists") ||
161
- (await verifyAssignmentExists(instanceArn, permissionSetArn, targetId, principalId, principalTypeStr))) {
162
- console.info("Assignment already exists or was created successfully");
163
- await sendResponse(event, response);
164
- return response;
165
- }
166
- // Otherwise, wait and retry
167
- await sleep(2000 * attempt); // Exponential backoff
168
- }
169
- }
170
- break;
171
- case "Delete":
172
- // Check if assignment exists before attempting deletion
173
- const assignmentExists = await verifyAssignmentExists(instanceArn, permissionSetArn, targetId, principalId, principalTypeStr);
174
- if (!assignmentExists) {
175
- console.info("Assignment does not exist, no need to delete");
176
- await sendResponse(event, response);
177
- return response;
178
- }
179
- // Delete the assignment
180
- for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
181
- console.info(`Attempt ${attempt}/${MAX_RETRIES}`);
182
- console.info("Deleting Account Assignment");
183
- try {
184
- await ssoAdmin.send(new client_sso_admin_1.DeleteAccountAssignmentCommand({
185
- InstanceArn: instanceArn,
186
- PermissionSetArn: permissionSetArn,
187
- PrincipalType: principalType,
188
- PrincipalId: principalId,
189
- TargetType: targetType,
190
- TargetId: targetId
191
- }));
192
- console.info("Delete assignment command sent successfully");
193
- console.info("Verifying assignment does not exist");
194
- // Here we're inverting the logic - wait for the assignment to NOT exist
195
- const stillExists = await verifyAssignmentExists(instanceArn, permissionSetArn, targetId, principalId, principalTypeStr);
196
- if (!stillExists) {
197
- console.info("Assignment deleted successfully");
198
- await sendResponse(event, response);
199
- return response;
200
- }
201
- else {
202
- // On the final attempt, consider it an error if it still exists
203
- if (attempt === MAX_RETRIES) {
204
- throw new Error("Assignment verification failed: Assignment still exists after deletion");
205
- }
206
- // Otherwise, wait and retry the verification
207
- console.info(`Assignment still exists after deletion attempt ${attempt}, waiting...`);
208
- await sleep(3000);
209
- }
210
- }
211
- catch (error) {
212
- console.error(`Error in delete attempt ${attempt}:`, error);
213
- // If it's a ResourceNotFoundException, consider it a success
214
- if (error.name === "ResourceNotFoundException" ||
215
- error.message.includes("does not exist")) {
216
- console.info("Assignment does not exist or was already deleted");
217
- await sendResponse(event, response);
218
- return response;
219
- }
220
- // On the last attempt, propagate the error
221
- if (attempt === MAX_RETRIES) {
222
- throw error;
223
- }
224
- // Otherwise, wait and retry
225
- await sleep(2000 * attempt);
226
- }
227
- }
228
- break;
229
- }
230
- }
231
- catch (error) {
232
- console.error(`Operation failed: ${error.message}`, error);
233
- response.Status = "FAILED";
234
- response.Reason = `${event.RequestType} operation failed: ${error.message}`;
235
- try {
236
- await sendResponse(event, response);
237
- }
238
- catch (responseError) {
239
- console.error("Failed to send response to CloudFormation:", responseError);
240
- }
241
- throw error;
242
- }
243
- return response;
244
- };
245
- exports.handler = handler;
246
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXNzaWdubWVudEhhbmRsZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9saWIvcmVzb3VyY2VzL2F3cy9pYW0vaWRlbnRpdHlDZW50ZXIvbGFtYmRhL2Fzc2lnbm1lbnRIYW5kbGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLGdFQVFtQztBQUNuQyxvREFBMEU7QUFDMUUsa0RBQWdFO0FBcUNoRSxNQUFNLFFBQVEsR0FBRyxJQUFJLGlDQUFjLEVBQUUsQ0FBQztBQUN0QyxNQUFNLEdBQUcsR0FBRyxJQUFJLHNCQUFTLEVBQUUsQ0FBQztBQUM1QixNQUFNLEVBQUUsR0FBRyxJQUFJLG9CQUFRLEVBQUUsQ0FBQztBQUUxQiwrQkFBK0I7QUFDL0IsTUFBTSxLQUFLLEdBQUcsQ0FBQyxFQUFVLEVBQUUsRUFBRSxDQUFDLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxVQUFVLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUM7QUFFaEYsOENBQThDO0FBQzlDLE1BQU0sWUFBWSxHQUFHLEtBQUssRUFDeEIsS0FBMEIsRUFDMUIsUUFBZ0MsRUFDakIsRUFBRTtJQUNqQixPQUFPLENBQUMsSUFBSSxDQUFDLGtDQUFrQyxDQUFDLENBQUM7SUFDakQsT0FBTyxDQUFDLElBQUksQ0FBQyxXQUFXLFFBQVEsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO0lBQzNDLE9BQU8sQ0FBQyxJQUFJLENBQUMsdUJBQXVCLFFBQVEsQ0FBQyxrQkFBa0IsRUFBRSxDQUFDLENBQUM7SUFDbkUsSUFBSSxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDcEIsT0FBTyxDQUFDLElBQUksQ0FBQyxXQUFXLFFBQVEsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO0lBQzdDLENBQUM7SUFFRCxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQzlD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Q3BCLE9BQU8sQ0FBQyxLQUFLLENBQUMscUJBQXFCLEtBQUssQ0FBQyxPQUFPLEVBQUUsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUMzRCxRQUFRLENBQUMsTUFBTSxHQUFHLFFBQVEsQ0FBQztRQUMzQixRQUFRLENBQUMsTUFBTSxHQUFHLEdBQUcsS0FBSyxDQUFDLFdBQVcsc0JBQXNCLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUU1RSxJQUFJLENBQUM7WUFDSCxNQUFNLFlBQVksQ0FBQyxLQUFLLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDdEMsQ0FBQztRQUFDLE9BQU8sYUFBYSxFQUFFLENBQUM7WUFDdkIsT0FBTyxDQUFDLEtBQUssQ0FDWCw0Q0FBNEMsRUFDNUMsYUFBYSxDQUNkLENBQUM7UUFDSixDQUFDO1FBRUQsTUFBTSxLQUFLLENBQUM7SUFDZCxDQUFDO0lBRUQsT0FBTyxRQUFRLENBQUM7QUFDbEIsQ0FBQyxDQUFDO0FBalFXLFFBQUEsT0FBTyxXQWlRbEIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBTU09BZG1pbkNsaWVudCxcbiAgQ3JlYXRlQWNjb3VudEFzc2lnbm1lbnRDb21tYW5kLFxuICBEZWxldGVBY2NvdW50QXNzaWdubWVudENvbW1hbmQsXG4gIExpc3RBY2NvdW50QXNzaWdubWVudHNDb21tYW5kLFxuICBBY2NvdW50QXNzaWdubWVudCxcbiAgUHJpbmNpcGFsVHlwZSxcbiAgVGFyZ2V0VHlwZVxufSBmcm9tIFwiQGF3cy1zZGsvY2xpZW50LXNzby1hZG1pblwiO1xuaW1wb3J0IHsgU1RTQ2xpZW50LCBHZXRDYWxsZXJJZGVudGl0eUNvbW1hbmQgfSBmcm9tIFwiQGF3cy1zZGsvY2xpZW50LXN0c1wiO1xuaW1wb3J0IHsgUHV0T2JqZWN0Q29tbWFuZCwgUzNDbGllbnQgfSBmcm9tIFwiQGF3cy1zZGsvY2xpZW50LXMzXCI7XG5cbmludGVyZmFjZSBDbG91ZEZvcm1hdGlvbkV2ZW50IHtcbiAgUmVxdWVzdFR5cGU6IFwiQ3JlYXRlXCIgfCBcIlVwZGF0ZVwiIHwgXCJEZWxldGVcIjtcbiAgUmVzcG9uc2VVUkw6IHN0cmluZztcbiAgU3RhY2tJZDogc3RyaW5nO1xuICBSZXF1ZXN0SWQ6IHN0cmluZztcbiAgUmVzb3VyY2VUeXBlOiBzdHJpbmc7XG4gIExvZ2ljYWxSZXNvdXJjZUlkOiBzdHJpbmc7XG4gIFBoeXNpY2FsUmVzb3VyY2VJZD86IHN0cmluZztcbiAgUmVzb3VyY2VQcm9wZXJ0aWVzOiB7XG4gICAgU2VydmljZVRva2VuOiBzdHJpbmc7XG4gICAgSW5zdGFuY2VBcm46IHN0cmluZztcbiAgICBQZXJtaXNzaW9uU2V0QXJuOiBzdHJpbmc7XG4gICAgUHJpbmNpcGFsVHlwZTogc3RyaW5nO1xuICAgIFByaW5jaXBhbElkOiBzdHJpbmc7XG4gICAgVGFyZ2V0VHlwZTogc3RyaW5nO1xuICAgIFRhcmdldElkOiBzdHJpbmc7XG4gICAgW2tleTogc3RyaW5nXTogYW55O1xuICB9O1xuICBPbGRSZXNvdXJjZVByb3BlcnRpZXM/OiB7XG4gICAgW2tleTogc3RyaW5nXTogYW55O1xuICB9O1xufVxuXG5pbnRlcmZhY2UgQ2xvdWRGb3JtYXRpb25SZXNwb25zZSB7XG4gIFN0YXR1czogXCJTVUNDRVNTXCIgfCBcIkZBSUxFRFwiO1xuICBQaHlzaWNhbFJlc291cmNlSWQ6IHN0cmluZztcbiAgU3RhY2tJZDogc3RyaW5nO1xuICBSZXF1ZXN0SWQ6IHN0cmluZztcbiAgTG9naWNhbFJlc291cmNlSWQ6IHN0cmluZztcbiAgUmVhc29uPzogc3RyaW5nO1xuICBEYXRhPzoge1xuICAgIFtrZXk6IHN0cmluZ106IGFueTtcbiAgfTtcbn1cblxuY29uc3Qgc3NvQWRtaW4gPSBuZXcgU1NPQWRtaW5DbGllbnQoKTtcbmNvbnN0IHN0cyA9IG5ldyBTVFNDbGllbnQoKTtcbmNvbnN0IHMzID0gbmV3IFMzQ2xpZW50KCk7XG5cbi8vIEhlbHBlciBmdW5jdGlvbiB0byBhZGQgZGVsYXlcbmNvbnN0IHNsZWVwID0gKG1zOiBudW1iZXIpID0+IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIG1zKSk7XG5cbi8vIEZ1bmN0aW9uIHRvIHNlbmQgcmVzcG9uc2UgdG8gQ2xvdWRGb3JtYXRpb25cbmNvbnN0IHNlbmRSZXNwb25zZSA9IGFzeW5jIChcbiAgZXZlbnQ6IENsb3VkRm9ybWF0aW9uRXZlbnQsXG4gIHJlc3BvbnNlOiBDbG91ZEZvcm1hdGlvblJlc3BvbnNlXG4pOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgY29uc29sZS5pbmZvKFwiU2VuZGluZyBDbG91ZEZvcm1hdGlvbiByZXNwb25zZTpcIik7XG4gIGNvbnNvbGUuaW5mbyhgU3RhdHVzOiAke3Jlc3BvbnNlLlN0YXR1c31gKTtcbiAgY29uc29sZS5pbmZvKGBQaHlzaWNhbFJlc291cmNlSWQ6ICR7cmVzcG9uc2UuUGh5c2ljYWxSZXNvdXJjZUlkfWApO1xuICBpZiAocmVzcG9uc2UuUmVhc29uKSB7XG4gICAgY29uc29sZS5pbmZvKGBSZWFzb246ICR7cmVzcG9uc2UuUmVhc29ufWApO1xuICB9XG5cbiAgY29uc3QgcmVzcG9uc2VCb2R5ID0gSlNPTi5zdHJpbmdpZnkocmVzcG9uc2UpO1xuICBjb25zb2xlLmluZm8oYFNlbmRpbmcgcmVzcG9uc2UgdG86ICR7ZXZlbnQuUmVzcG9uc2VVUkx9YCk7XG5cbiAgdHJ5IHtcbiAgICAvLyBFeHRyYWN0IGJ1Y2tldCBhbmQga2V5IGZyb20gdGhlIHByZS1zaWduZWQgVVJMXG4gICAgY29uc3QgdXJsID0gbmV3IFVSTChldmVudC5SZXNwb25zZVVSTCk7XG4gICAgY29uc3QgYnVja2V0TmFtZSA9IHVybC5ob3N0bmFtZS5zcGxpdChcIi5cIilbMF07XG4gICAgY29uc3Qga2V5ID0gdXJsLnBhdGhuYW1lLnN1YnN0cmluZygxKTsgLy8gcmVtb3ZlIGxlYWRpbmcgc2xhc2hcblxuICAgIC8vIFVzZSBTMyBjbGllbnQgdG8gdXBsb2FkIGRpcmVjdGx5XG4gICAgYXdhaXQgczMuc2VuZChcbiAgICAgIG5ldyBQdXRPYmplY3RDb21tYW5kKHtcbiAgICAgICAgQnVja2V0OiBidWNrZXROYW1lLFxuICAgICAgICBLZXk6IGtleSxcbiAgICAgICAgQm9keTogcmVzcG9uc2VCb2R5LFxuICAgICAgICBDb250ZW50VHlwZTogXCJhcHBsaWNhdGlvbi9qc29uXCJcbiAgICAgIH0pXG4gICAgKTtcblxuICAgIGNvbnNvbGUuaW5mbyhgU3RhdHVzIGNvZGU6IDIwMGApO1xuICAgIGNvbnNvbGUuaW5mbyhgU3RhdHVzIG1lc3NhZ2U6IE9LYCk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgY29uc29sZS5lcnJvcihcIkVycm9yIHNlbmRpbmcgcmVzcG9uc2U6XCIsIGVycm9yKTtcbiAgICB0aHJvdyBlcnJvcjtcbiAgfVxufTtcblxuLy8gRnVuY3Rpb24gdG8gY2hlY2sgaWYgYW4gYXNzaWdubWVudCBleGlzdHNcbmNvbnN0IHZlcmlmeUFzc2lnbm1lbnRFeGlzdHMgPSBhc3luYyAoXG4gIGluc3RhbmNlQXJuOiBzdHJpbmcsXG4gIHBlcm1pc3Npb25TZXRBcm46IHN0cmluZyxcbiAgdGFyZ2V0SWQ6IHN0cmluZyxcbiAgcHJpbmNpcGFsSWQ6IHN0cmluZyxcbiAgcHJpbmNpcGFsVHlwZTogc3RyaW5nLFxuICByZXRyaWVzID0gMTAsXG4gIGRlbGF5ID0gNTAwMFxuKTogUHJvbWlzZTxib29sZWFuPiA9PiB7XG4gIGZvciAobGV0IGF0dGVtcHQgPSAxOyBhdHRlbXB0IDw9IHJldHJpZXM7IGF0dGVtcHQrKykge1xuICAgIHRyeSB7XG4gICAgICBjb25zb2xlLmluZm8oXG4gICAgICAgIGBWZXJpZnlpbmcgYXNzaWdubWVudCBleGlzdHMgLSBhdHRlbXB0ICR7YXR0ZW1wdH0vJHtyZXRyaWVzfWBcbiAgICAgICk7XG5cbiAgICAgIGNvbnN0IGxpc3RSZXNwb25zZSA9IGF3YWl0IHNzb0FkbWluLnNlbmQoXG4gICAgICAgIG5ldyBMaXN0QWNjb3VudEFzc2lnbm1lbnRzQ29tbWFuZCh7XG4gICAgICAgICAgSW5zdGFuY2VBcm46IGluc3RhbmNlQXJuLFxuICAgICAgICAgIEFjY291bnRJZDogdGFyZ2V0SWQsXG4gICAgICAgICAgUGVybWlzc2lvblNldEFybjogcGVybWlzc2lvblNldEFyblxuICAgICAgICB9KVxuICAgICAgKTtcblxuICAgICAgY29uc3QgYXNzaWdubWVudHMgPSBsaXN0UmVzcG9uc2UuQWNjb3VudEFzc2lnbm1lbnRzIHx8IFtdO1xuXG4gICAgICBjb25zb2xlLmluZm8oXG4gICAgICAgIGBGb3VuZCAke2Fzc2lnbm1lbnRzLmxlbmd0aH0gYXNzaWdubWVudHMgZm9yIGFjY291bnQgJHt0YXJnZXRJZH0gYW5kIHBlcm1pc3Npb24gc2V0YFxuICAgICAgKTtcblxuICAgICAgY29uc3QgZXhpc3RzID0gYXNzaWdubWVudHMuc29tZShcbiAgICAgICAgKGFzc2lnbm1lbnQ6IEFjY291bnRBc3NpZ25tZW50KSA9PlxuICAgICAgICAgIGFzc2lnbm1lbnQuUHJpbmNpcGFsSWQgPT09IHByaW5jaXBhbElkICYmXG4gICAgICAgICAgYXNzaWdubWVudC5QcmluY2lwYWxUeXBlID09PSAocHJpbmNpcGFsVHlwZSBhcyBQcmluY2lwYWxUeXBlKVxuICAgICAgKTtcblxuICAgICAgaWYgKGV4aXN0cykge1xuICAgICAgICBjb25zb2xlLmluZm8oXCJBc3NpZ25tZW50IGV4aXN0c1wiKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG5cbiAgICAgIGlmIChhdHRlbXB0IDwgcmV0cmllcykge1xuICAgICAgICBjb25zb2xlLmluZm8oXG4gICAgICAgICAgYEFzc2lnbm1lbnQgbm90IGZvdW5kLCB3YWl0aW5nICR7XG4gICAgICAgICAgICBkZWxheSAvIDEwMDBcbiAgICAgICAgICB9IHNlY29uZHMgYmVmb3JlIHJldHJ5aW5nLi4uYFxuICAgICAgICApO1xuICAgICAgICBhd2FpdCBzbGVlcChkZWxheSk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgY29uc29sZS5lcnJvcihcbiAgICAgICAgYEVycm9yIHZlcmlmeWluZyBhc3NpZ25tZW50IChhdHRlbXB0ICR7YXR0ZW1wdH0vJHtyZXRyaWVzfSk6YCxcbiAgICAgICAgZXJyb3JcbiAgICAgICk7XG5cbiAgICAgIGlmIChhdHRlbXB0IDwgcmV0cmllcykge1xuICAgICAgICBjb25zb2xlLmluZm8oYFdhaXRpbmcgJHtkZWxheSAvIDEwMDB9IHNlY29uZHMgYmVmb3JlIHJldHJ5aW5nLi4uYCk7XG4gICAgICAgIGF3YWl0IHNsZWVwKGRlbGF5KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBjb25zb2xlLmluZm8oXCJBc3NpZ25tZW50IG5vdCBmb3VuZCBhZnRlciBtYXhpbXVtIHJldHJpZXNcIik7XG4gIHJldHVybiBmYWxzZTtcbn07XG5cbi8vIEhhbmRsZSBDbG91ZEZvcm1hdGlvbiBjdXN0b20gcmVzb3VyY2UgZXZlbnRcbmV4cG9ydCBjb25zdCBoYW5kbGVyID0gYXN5bmMgKGV2ZW50OiBDbG91ZEZvcm1hdGlvbkV2ZW50KTogUHJvbWlzZTxhbnk+ID0+IHtcbiAgY29uc29sZS5pbmZvKFwiUmVjZWl2ZWQgZXZlbnQ6IFwiLCBKU09OLnN0cmluZ2lmeShldmVudCwgbnVsbCwgMikpO1xuXG4gIC8vIExvZyBlbnZpcm9ubWVudCB2YXJpYWJsZXMgKHdpdGhvdXQgc2Vuc2l0aXZlIGRhdGEpXG4gIGNvbnNvbGUuaW5mbyhcbiAgICBcIkVudmlyb25tZW50IHZhcmlhYmxlczogXCIgK1xuICAgICAgSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICBBV1NfUkVHSU9OOiBwcm9jZXNzLmVudi5BV1NfUkVHSU9OLFxuICAgICAgICBBV1NfRVhFQ1VUSU9OX0VOVjogcHJvY2Vzcy5lbnYuQVdTX0VYRUNVVElPTl9FTlYsXG4gICAgICAgIEFXU19MQU1CREFfRlVOQ1RJT05fTkFNRTogcHJvY2Vzcy5lbnYuQVdTX0xBTUJEQV9GVU5DVElPTl9OQU1FLFxuICAgICAgICBBV1NfTEFNQkRBX0ZVTkNUSU9OX1ZFUlNJT046IHByb2Nlc3MuZW52LkFXU19MQU1CREFfRlVOQ1RJT05fVkVSU0lPTixcbiAgICAgICAgQVdTX0xBTUJEQV9GVU5DVElPTl9NRU1PUllfU0laRTpcbiAgICAgICAgICBwcm9jZXNzLmVudi5BV1NfTEFNQkRBX0ZVTkNUSU9OX01FTU9SWV9TSVpFXG4gICAgICB9KVxuICApO1xuXG4gIC8vIEdldCBjdXJyZW50IGlkZW50aXR5IGZvciBkZWJ1Z2dpbmcgcHVycG9zZXNcbiAgdHJ5IHtcbiAgICBjb25zdCBpZGVudGl0eSA9IGF3YWl0IHN0cy5zZW5kKG5ldyBHZXRDYWxsZXJJZGVudGl0eUNvbW1hbmQoe30pKTtcbiAgICBjb25zb2xlLmluZm8oXCJDdXJyZW50IGlkZW50aXR5OiBcIiwgSlNPTi5zdHJpbmdpZnkoaWRlbnRpdHksIG51bGwsIDIpKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBjb25zb2xlLmVycm9yKFwiRXJyb3IgZ2V0dGluZyBjYWxsZXIgaWRlbnRpdHk6XCIsIGVycm9yKTtcbiAgfVxuXG4gIGNvbnN0IHtcbiAgICBJbnN0YW5jZUFybjogaW5zdGFuY2VBcm4sXG4gICAgUGVybWlzc2lvblNldEFybjogcGVybWlzc2lvblNldEFybixcbiAgICBQcmluY2lwYWxUeXBlOiBwcmluY2lwYWxUeXBlU3RyLFxuICAgIFByaW5jaXBhbElkOiBwcmluY2lwYWxJZCxcbiAgICBUYXJnZXRUeXBlOiB0YXJnZXRUeXBlU3RyLFxuICAgIFRhcmdldElkOiB0YXJnZXRJZFxuICB9ID0gZXZlbnQuUmVzb3VyY2VQcm9wZXJ0aWVzO1xuXG4gIC8vIENvbnZlcnQgc3RyaW5nIHR5cGVzIHRvIGVudW0gdHlwZXNcbiAgY29uc3QgcHJpbmNpcGFsVHlwZSA9IHByaW5jaXBhbFR5cGVTdHIgYXMgUHJpbmNpcGFsVHlwZTtcbiAgY29uc3QgdGFyZ2V0VHlwZSA9IHRhcmdldFR5cGVTdHIgYXMgVGFyZ2V0VHlwZTtcblxuICAvLyBHZW5lcmF0ZSBhIGNvbnNpc3RlbnQgcGh5c2ljYWwgSUQgcmVnYXJkbGVzcyBvZiB3aGV0aGVyIHRoZSBhc3NpZ25tZW50IGV4aXN0c1xuICBjb25zdCBwaHlzaWNhbFJlc291cmNlSWQgPVxuICAgIGV2ZW50LlBoeXNpY2FsUmVzb3VyY2VJZCB8fFxuICAgIGAke3Blcm1pc3Npb25TZXRBcm59LSR7cHJpbmNpcGFsSWR9LSR7dGFyZ2V0SWR9YDtcblxuICAvLyBQcmVwYXJlIHRoZSByZXNwb25zZVxuICBjb25zdCByZXNwb25zZTogQ2xvdWRGb3JtYXRpb25SZXNwb25zZSA9IHtcbiAgICBTdGF0dXM6IFwiU1VDQ0VTU1wiLFxuICAgIFBoeXNpY2FsUmVzb3VyY2VJZDogcGh5c2ljYWxSZXNvdXJjZUlkLFxuICAgIFN0YWNrSWQ6IGV2ZW50LlN0YWNrSWQsXG4gICAgUmVxdWVzdElkOiBldmVudC5SZXF1ZXN0SWQsXG4gICAgTG9naWNhbFJlc291cmNlSWQ6IGV2ZW50LkxvZ2ljYWxSZXNvdXJjZUlkXG4gIH07XG5cbiAgY29uc3QgTUFYX1JFVFJJRVMgPSA1O1xuXG4gIHRyeSB7XG4gICAgc3dpdGNoIChldmVudC5SZXF1ZXN0VHlwZSkge1xuICAgICAgY2FzZSBcIkNyZWF0ZVwiOlxuICAgICAgY2FzZSBcIlVwZGF0ZVwiOlxuICAgICAgICBjb25zdCBvcGVyYXRpb24gPVxuICAgICAgICAgIGV2ZW50LlJlcXVlc3RUeXBlID09PSBcIkNyZWF0ZVwiID8gXCJDcmVhdGluZ1wiIDogXCJVcGRhdGluZ1wiO1xuXG4gICAgICAgIC8vIENoZWNrIGlmIGFzc2lnbm1lbnQgYWxyZWFkeSBleGlzdHMgZm9yIHVwZGF0ZXMgdG8gYXZvaWQgZXJyb3JzXG4gICAgICAgIGlmIChldmVudC5SZXF1ZXN0VHlwZSA9PT0gXCJVcGRhdGVcIikge1xuICAgICAgICAgIGNvbnN0IGV4aXN0cyA9IGF3YWl0IHZlcmlmeUFzc2lnbm1lbnRFeGlzdHMoXG4gICAgICAgICAgICBpbnN0YW5jZUFybixcbiAgICAgICAgICAgIHBlcm1pc3Npb25TZXRBcm4sXG4gICAgICAgICAgICB0YXJnZXRJZCxcbiAgICAgICAgICAgIHByaW5jaXBhbElkLFxuICAgICAgICAgICAgcHJpbmNpcGFsVHlwZVN0clxuICAgICAgICAgICk7XG5cbiAgICAgICAgICBpZiAoZXhpc3RzKSB7XG4gICAgICAgICAgICBjb25zb2xlLmluZm8oXG4gICAgICAgICAgICAgIFwiQXNzaWdubWVudCBhbHJlYWR5IGV4aXN0cyBmb3IgdXBkYXRlIG9wZXJhdGlvbiAtIG5vIGFjdGlvbiBuZWVkZWRcIlxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGF3YWl0IHNlbmRSZXNwb25zZShldmVudCwgcmVzcG9uc2UpO1xuICAgICAgICAgICAgcmV0dXJuIHJlc3BvbnNlO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIENyZWF0ZSB0aGUgYXNzaWdubWVudFxuICAgICAgICBmb3IgKGxldCBhdHRlbXB0ID0gMTsgYXR0ZW1wdCA8PSBNQVhfUkVUUklFUzsgYXR0ZW1wdCsrKSB7XG4gICAgICAgICAgY29uc29sZS5pbmZvKGBBdHRlbXB0ICR7YXR0ZW1wdH0vJHtNQVhfUkVUUklFU31gKTtcbiAgICAgICAgICBjb25zb2xlLmluZm8oYCR7b3BlcmF0aW9ufSBBY2NvdW50IEFzc2lnbm1lbnRgKTtcblxuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCBzc29BZG1pbi5zZW5kKFxuICAgICAgICAgICAgICBuZXcgQ3JlYXRlQWNjb3VudEFzc2lnbm1lbnRDb21tYW5kKHtcbiAgICAgICAgICAgICAgICBJbnN0YW5jZUFybjogaW5zdGFuY2VBcm4sXG4gICAgICAgICAgICAgICAgUGVybWlzc2lvblNldEFybjogcGVybWlzc2lvblNldEFybixcbiAgICAgICAgICAgICAgICBQcmluY2lwYWxUeXBlOiBwcmluY2lwYWxUeXBlLFxuICAgICAgICAgICAgICAgIFByaW5jaXBhbElkOiBwcmluY2lwYWxJZCxcbiAgICAgICAgICAgICAgICBUYXJnZXRUeXBlOiB0YXJnZXRUeXBlLFxuICAgICAgICAgICAgICAgIFRhcmdldElkOiB0YXJnZXRJZFxuICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiQ3JlYXRlIGFzc2lnbm1lbnQgY29tbWFuZCBzZW50IHN1Y2Nlc3NmdWxseVwiKTtcbiAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIlZlcmlmeWluZyBhc3NpZ25tZW50IGV4aXN0c1wiKTtcblxuICAgICAgICAgICAgLy8gVmVyaWZ5IHRoZSBhc3NpZ25tZW50IHdhcyBjcmVhdGVkXG4gICAgICAgICAgICBjb25zdCBleGlzdHMgPSBhd2FpdCB2ZXJpZnlBc3NpZ25tZW50RXhpc3RzKFxuICAgICAgICAgICAgICBpbnN0YW5jZUFybixcbiAgICAgICAgICAgICAgcGVybWlzc2lvblNldEFybixcbiAgICAgICAgICAgICAgdGFyZ2V0SWQsXG4gICAgICAgICAgICAgIHByaW5jaXBhbElkLFxuICAgICAgICAgICAgICBwcmluY2lwYWxUeXBlU3RyXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBpZiAoZXhpc3RzKSB7XG4gICAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIkFzc2lnbm1lbnQgdmVyaWZpZWQgc3VjY2Vzc2Z1bGx5XCIpO1xuICAgICAgICAgICAgICBhd2FpdCBzZW5kUmVzcG9uc2UoZXZlbnQsIHJlc3BvbnNlKTtcbiAgICAgICAgICAgICAgcmV0dXJuIHJlc3BvbnNlO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgICAgIFwiQXNzaWdubWVudCB2ZXJpZmljYXRpb24gZmFpbGVkOiBBc3NpZ25tZW50IG5vdCBmb3VuZCBhZnRlciBjcmVhdGlvblwiXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihgRXJyb3IgaW4gYXR0ZW1wdCAke2F0dGVtcHR9OmAsIGVycm9yKTtcblxuICAgICAgICAgICAgLy8gSWYgaXQncyB0aGUgbGFzdCBhdHRlbXB0LCBwcm9wYWdhdGUgdGhlIGVycm9yXG4gICAgICAgICAgICBpZiAoYXR0ZW1wdCA9PT0gTUFYX1JFVFJJRVMpIHtcbiAgICAgICAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIElmIGl0J3MgYSBDb25mbGljdEV4Y2VwdGlvbiBvciB0aGUgYXNzaWdubWVudCBhbHJlYWR5IGV4aXN0cywgY29uc2lkZXIgaXQgYSBzdWNjZXNzXG4gICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgIGVycm9yLm5hbWUgPT09IFwiQ29uZmxpY3RFeGNlcHRpb25cIiB8fFxuICAgICAgICAgICAgICBlcnJvci5tZXNzYWdlLmluY2x1ZGVzKFwiYWxyZWFkeSBleGlzdHNcIikgfHxcbiAgICAgICAgICAgICAgKGF3YWl0IHZlcmlmeUFzc2lnbm1lbnRFeGlzdHMoXG4gICAgICAgICAgICAgICAgaW5zdGFuY2VBcm4sXG4gICAgICAgICAgICAgICAgcGVybWlzc2lvblNldEFybixcbiAgICAgICAgICAgICAgICB0YXJnZXRJZCxcbiAgICAgICAgICAgICAgICBwcmluY2lwYWxJZCxcbiAgICAgICAgICAgICAgICBwcmluY2lwYWxUeXBlU3RyXG4gICAgICAgICAgICAgICkpXG4gICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgY29uc29sZS5pbmZvKFxuICAgICAgICAgICAgICAgIFwiQXNzaWdubWVudCBhbHJlYWR5IGV4aXN0cyBvciB3YXMgY3JlYXRlZCBzdWNjZXNzZnVsbHlcIlxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICBhd2FpdCBzZW5kUmVzcG9uc2UoZXZlbnQsIHJlc3BvbnNlKTtcbiAgICAgICAgICAgICAgcmV0dXJuIHJlc3BvbnNlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBPdGhlcndpc2UsIHdhaXQgYW5kIHJldHJ5XG4gICAgICAgICAgICBhd2FpdCBzbGVlcCgyMDAwICogYXR0ZW1wdCk7IC8vIEV4cG9uZW50aWFsIGJhY2tvZmZcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBicmVhaztcblxuICAgICAgY2FzZSBcIkRlbGV0ZVwiOlxuICAgICAgICAvLyBDaGVjayBpZiBhc3NpZ25tZW50IGV4aXN0cyBiZWZvcmUgYXR0ZW1wdGluZyBkZWxldGlvblxuICAgICAgICBjb25zdCBhc3NpZ25tZW50RXhpc3RzID0gYXdhaXQgdmVyaWZ5QXNzaWdubWVudEV4aXN0cyhcbiAgICAgICAgICBpbnN0YW5jZUFybixcbiAgICAgICAgICBwZXJtaXNzaW9uU2V0QXJuLFxuICAgICAgICAgIHRhcmdldElkLFxuICAgICAgICAgIHByaW5jaXBhbElkLFxuICAgICAgICAgIHByaW5jaXBhbFR5cGVTdHJcbiAgICAgICAgKTtcblxuICAgICAgICBpZiAoIWFzc2lnbm1lbnRFeGlzdHMpIHtcbiAgICAgICAgICBjb25zb2xlLmluZm8oXCJBc3NpZ25tZW50IGRvZXMgbm90IGV4aXN0LCBubyBuZWVkIHRvIGRlbGV0ZVwiKTtcbiAgICAgICAgICBhd2FpdCBzZW5kUmVzcG9uc2UoZXZlbnQsIHJlc3BvbnNlKTtcbiAgICAgICAgICByZXR1cm4gcmVzcG9uc2U7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBEZWxldGUgdGhlIGFzc2lnbm1lbnRcbiAgICAgICAgZm9yIChsZXQgYXR0ZW1wdCA9IDE7IGF0dGVtcHQgPD0gTUFYX1JFVFJJRVM7IGF0dGVtcHQrKykge1xuICAgICAgICAgIGNvbnNvbGUuaW5mbyhgQXR0ZW1wdCAke2F0dGVtcHR9LyR7TUFYX1JFVFJJRVN9YCk7XG4gICAgICAgICAgY29uc29sZS5pbmZvKFwiRGVsZXRpbmcgQWNjb3VudCBBc3NpZ25tZW50XCIpO1xuXG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGF3YWl0IHNzb0FkbWluLnNlbmQoXG4gICAgICAgICAgICAgIG5ldyBEZWxldGVBY2NvdW50QXNzaWdubWVudENvbW1hbmQoe1xuICAgICAgICAgICAgICAgIEluc3RhbmNlQXJuOiBpbnN0YW5jZUFybixcbiAgICAgICAgICAgICAgICBQZXJtaXNzaW9uU2V0QXJuOiBwZXJtaXNzaW9uU2V0QXJuLFxuICAgICAgICAgICAgICAgIFByaW5jaXBhbFR5cGU6IHByaW5jaXBhbFR5cGUsXG4gICAgICAgICAgICAgICAgUHJpbmNpcGFsSWQ6IHByaW5jaXBhbElkLFxuICAgICAgICAgICAgICAgIFRhcmdldFR5cGU6IHRhcmdldFR5cGUsXG4gICAgICAgICAgICAgICAgVGFyZ2V0SWQ6IHRhcmdldElkXG4gICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBjb25zb2xlLmluZm8oXCJEZWxldGUgYXNzaWdubWVudCBjb21tYW5kIHNlbnQgc3VjY2Vzc2Z1bGx5XCIpO1xuICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiVmVyaWZ5aW5nIGFzc2lnbm1lbnQgZG9lcyBub3QgZXhpc3RcIik7XG5cbiAgICAgICAgICAgIC8vIEhlcmUgd2UncmUgaW52ZXJ0aW5nIHRoZSBsb2dpYyAtIHdhaXQgZm9yIHRoZSBhc3NpZ25tZW50IHRvIE5PVCBleGlzdFxuICAgICAgICAgICAgY29uc3Qgc3RpbGxFeGlzdHMgPSBhd2FpdCB2ZXJpZnlBc3NpZ25tZW50RXhpc3RzKFxuICAgICAgICAgICAgICBpbnN0YW5jZUFybixcbiAgICAgICAgICAgICAgcGVybWlzc2lvblNldEFybixcbiAgICAgICAgICAgICAgdGFyZ2V0SWQsXG4gICAgICAgICAgICAgIHByaW5jaXBhbElkLFxuICAgICAgICAgICAgICBwcmluY2lwYWxUeXBlU3RyXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBpZiAoIXN0aWxsRXhpc3RzKSB7XG4gICAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIkFzc2lnbm1lbnQgZGVsZXRlZCBzdWNjZXNzZnVsbHlcIik7XG4gICAgICAgICAgICAgIGF3YWl0IHNlbmRSZXNwb25zZShldmVudCwgcmVzcG9uc2UpO1xuICAgICAgICAgICAgICByZXR1cm4gcmVzcG9uc2U7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAvLyBPbiB0aGUgZmluYWwgYXR0ZW1wdCwgY29uc2lkZXIgaXQgYW4gZXJyb3IgaWYgaXQgc3RpbGwgZXhpc3RzXG4gICAgICAgICAgICAgIGlmIChhdHRlbXB0ID09PSBNQVhfUkVUUklFUykge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgICAgICAgIFwiQXNzaWdubWVudCB2ZXJpZmljYXRpb24gZmFpbGVkOiBBc3NpZ25tZW50IHN0aWxsIGV4aXN0cyBhZnRlciBkZWxldGlvblwiXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIC8vIE90aGVyd2lzZSwgd2FpdCBhbmQgcmV0cnkgdGhlIHZlcmlmaWNhdGlvblxuICAgICAgICAgICAgICBjb25zb2xlLmluZm8oXG4gICAgICAgICAgICAgICAgYEFzc2lnbm1lbnQgc3RpbGwgZXhpc3RzIGFmdGVyIGRlbGV0aW9uIGF0dGVtcHQgJHthdHRlbXB0fSwgd2FpdGluZy4uLmBcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgYXdhaXQgc2xlZXAoMzAwMCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihgRXJyb3IgaW4gZGVsZXRlIGF0dGVtcHQgJHthdHRlbXB0fTpgLCBlcnJvcik7XG5cbiAgICAgICAgICAgIC8vIElmIGl0J3MgYSBSZXNvdXJjZU5vdEZvdW5kRXhjZXB0aW9uLCBjb25zaWRlciBpdCBhIHN1Y2Nlc3NcbiAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgZXJyb3IubmFtZSA9PT0gXCJSZXNvdXJjZU5vdEZvdW5kRXhjZXB0aW9uXCIgfHxcbiAgICAgICAgICAgICAgZXJyb3IubWVzc2FnZS5pbmNsdWRlcyhcImRvZXMgbm90IGV4aXN0XCIpXG4gICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiQXNzaWdubWVudCBkb2VzIG5vdCBleGlzdCBvciB3YXMgYWxyZWFkeSBkZWxldGVkXCIpO1xuICAgICAgICAgICAgICBhd2FpdCBzZW5kUmVzcG9uc2UoZXZlbnQsIHJlc3BvbnNlKTtcbiAgICAgICAgICAgICAgcmV0dXJuIHJlc3BvbnNlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBPbiB0aGUgbGFzdCBhdHRlbXB0LCBwcm9wYWdhdGUgdGhlIGVycm9yXG4gICAgICAgICAgICBpZiAoYXR0ZW1wdCA9PT0gTUFYX1JFVFJJRVMpIHtcbiAgICAgICAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIE90aGVyd2lzZSwgd2FpdCBhbmQgcmV0cnlcbiAgICAgICAgICAgIGF3YWl0IHNsZWVwKDIwMDAgKiBhdHRlbXB0KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBicmVhaztcbiAgICB9XG4gIH0gY2F0Y2ggKGVycm9yOiBhbnkpIHtcbiAgICBjb25zb2xlLmVycm9yKGBPcGVyYXRpb24gZmFpbGVkOiAke2Vycm9yLm1lc3NhZ2V9YCwgZXJyb3IpO1xuICAgIHJlc3BvbnNlLlN0YXR1cyA9IFwiRkFJTEVEXCI7XG4gICAgcmVzcG9uc2UuUmVhc29uID0gYCR7ZXZlbnQuUmVxdWVzdFR5cGV9IG9wZXJhdGlvbiBmYWlsZWQ6ICR7ZXJyb3IubWVzc2FnZX1gO1xuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHNlbmRSZXNwb25zZShldmVudCwgcmVzcG9uc2UpO1xuICAgIH0gY2F0Y2ggKHJlc3BvbnNlRXJyb3IpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoXG4gICAgICAgIFwiRmFpbGVkIHRvIHNlbmQgcmVzcG9uc2UgdG8gQ2xvdWRGb3JtYXRpb246XCIsXG4gICAgICAgIHJlc3BvbnNlRXJyb3JcbiAgICAgICk7XG4gICAgfVxuXG4gICAgdGhyb3cgZXJyb3I7XG4gIH1cblxuICByZXR1cm4gcmVzcG9uc2U7XG59O1xuIl19