@fjall/components-infrastructure 0.73.17 → 0.74.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.
Files changed (51) hide show
  1. package/dist/lib/__tests__/patterns/__snapshots__/compute.test.js.snap +433 -0
  2. package/dist/lib/__tests__/patterns/compute.test.d.ts +1 -0
  3. package/dist/lib/__tests__/patterns/compute.test.js +137 -0
  4. package/dist/lib/__tests__/simple.test.d.ts +0 -0
  5. package/dist/lib/__tests__/simple.test.js +12 -0
  6. package/dist/lib/config/aws/disasterRecovery.d.ts +27 -0
  7. package/dist/lib/config/aws/disasterRecovery.js +227 -0
  8. package/dist/lib/patterns/aws/managedAccount.js +15 -2
  9. package/dist/lib/resources/aws/backup/backupPlan.d.ts +19 -0
  10. package/dist/lib/resources/aws/backup/backupPlan.js +71 -0
  11. package/dist/lib/resources/aws/backup/backupVault.d.ts +19 -0
  12. package/dist/lib/resources/aws/backup/backupVault.js +43 -0
  13. package/dist/lib/resources/aws/backup/index.d.ts +2 -0
  14. package/dist/lib/resources/aws/backup/index.js +19 -0
  15. package/dist/lib/resources/aws/index.d.ts +1 -0
  16. package/dist/lib/resources/aws/index.js +2 -1
  17. package/dist/lib/resources/aws/organisations/account.d.ts +37 -0
  18. package/dist/lib/resources/aws/organisations/account.js +220 -0
  19. package/dist/lib/resources/aws/organisations/delegatedAdministrator.d.ts +14 -0
  20. package/dist/lib/resources/aws/organisations/delegatedAdministrator.js +61 -0
  21. package/dist/lib/resources/aws/organisations/index.d.ts +8 -0
  22. package/dist/lib/resources/aws/organisations/index.js +22 -0
  23. package/dist/lib/resources/aws/organisations/interfaces.d.ts +105 -0
  24. package/dist/lib/resources/aws/organisations/interfaces.js +3 -0
  25. package/dist/lib/resources/aws/organisations/organisation.d.ts +47 -0
  26. package/dist/lib/resources/aws/organisations/organisation.js +263 -0
  27. package/dist/lib/resources/aws/organisations/organisationalUnit.d.ts +28 -0
  28. package/dist/lib/resources/aws/organisations/organisationalUnit.js +170 -0
  29. package/dist/lib/resources/aws/organisations/policy.d.ts +17 -0
  30. package/dist/lib/resources/aws/organisations/policy.js +93 -0
  31. package/dist/lib/resources/aws/organisations/trustedServiceAccess.d.ts +13 -0
  32. package/dist/lib/resources/aws/organisations/trustedServiceAccess.js +58 -0
  33. package/dist/lib/resources/aws/organisations/types.d.ts +165 -0
  34. package/dist/lib/resources/aws/organisations/types.js +36 -0
  35. package/dist/lib/utils/directTagging.d.ts +31 -0
  36. package/dist/lib/utils/directTagging.js +86 -0
  37. package/dist/lib/utils/fjallConstruct.d.ts +8 -0
  38. package/dist/lib/utils/fjallConstruct.js +18 -0
  39. package/dist/lib/utils/fjallStackSynthesizer.d.ts +9 -0
  40. package/dist/lib/utils/fjallStackSynthesizer.js +22 -0
  41. package/dist/lib/utils/getConfig.d.ts +1 -0
  42. package/dist/lib/utils/getConfig.js +2 -1
  43. package/dist/lib/utils/tagContext.d.ts +28 -0
  44. package/dist/lib/utils/tagContext.js +53 -0
  45. package/dist/lib/utils/tagSynthesizer.d.ts +13 -0
  46. package/dist/lib/utils/tagSynthesizer.js +55 -0
  47. package/package.json +3 -3
  48. package/dist/lib/patterns/aws/ec2.d.ts +0 -43
  49. package/dist/lib/patterns/aws/ec2.js +0 -123
  50. package/dist/lib/utils/getCidr.d.ts +0 -8
  51. package/dist/lib/utils/getCidr.js +0 -40
@@ -0,0 +1,263 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Organisation = exports.OrganisationRoot = void 0;
4
+ const aws_cdk_lib_1 = require("aws-cdk-lib");
5
+ const customResources = require("aws-cdk-lib/custom-resources");
6
+ const aws_iam_1 = require("aws-cdk-lib/aws-iam");
7
+ const constructs_1 = require("constructs");
8
+ const types_1 = require("./types");
9
+ const awsCustomResource_1 = require("../utilities/awsCustomResource");
10
+ /**
11
+ * Organisation root construct - represents the root organisational unit
12
+ */
13
+ class OrganisationRoot extends constructs_1.Construct {
14
+ constructor(scope, id, organisationId) {
15
+ super(scope, id);
16
+ this.organisationalUnitName = "Root";
17
+ this.organisationalUnitId = organisationId;
18
+ this.organisationalUnitArn = `arn:aws:organizations::${this.node.tryGetContext("account")}:ou/${organisationId}/r-${organisationId.substring(2)}`;
19
+ }
20
+ attachPolicy(policy) {
21
+ const policyName = this.normalizePolicyName(policy.policyName);
22
+ new awsCustomResource_1.AwsCustomResource(this, `AttachPolicy${policyName}`, {
23
+ functionName: `attachPolicyToRoot${policyName}`,
24
+ onCreate: {
25
+ service: "organizations",
26
+ action: "AttachPolicyCommand",
27
+ parameters: {
28
+ PolicyId: policy.policyId,
29
+ TargetId: this.organisationalUnitId
30
+ },
31
+ physicalResourceId: customResources.PhysicalResourceId.of(`attach-policy-${policy.policyId}-to-${this.organisationalUnitId}`)
32
+ },
33
+ onDelete: {
34
+ service: "organizations",
35
+ action: "DetachPolicyCommand",
36
+ parameters: {
37
+ PolicyId: policy.policyId,
38
+ TargetId: this.organisationalUnitId
39
+ }
40
+ },
41
+ resourceType: "Custom::AttachPolicyToRoot",
42
+ policy: customResources.AwsCustomResourcePolicy.fromStatements([
43
+ new aws_iam_1.PolicyStatement({
44
+ actions: [
45
+ "organizations:AttachPolicy",
46
+ "organizations:DetachPolicy",
47
+ "organizations:ListPoliciesForTarget"
48
+ ],
49
+ resources: ["*"],
50
+ effect: aws_iam_1.Effect.ALLOW
51
+ })
52
+ ])
53
+ });
54
+ }
55
+ /**
56
+ * Helper to normalize policy names for construct IDs
57
+ */
58
+ normalizePolicyName(policyName) {
59
+ return policyName
60
+ .replace(/[^a-zA-Z0-9]/g, "")
61
+ .replace(/^([a-z])/, (match) => match.toUpperCase());
62
+ }
63
+ }
64
+ exports.OrganisationRoot = OrganisationRoot;
65
+ /**
66
+ * AWS Organisations construct for managing organisations
67
+ */
68
+ class Organisation extends constructs_1.Construct {
69
+ constructor(scope, id, props = {}) {
70
+ super(scope, id);
71
+ const featureSet = props.featureSet ?? types_1.FeatureSet.ALL;
72
+ const importOnDuplicate = props.importOnDuplicate ?? true;
73
+ // Create or get existing organisation
74
+ const orgResource = new awsCustomResource_1.AwsCustomResource(this, "OrganisationResource", {
75
+ functionName: "manageOrganisation",
76
+ onCreate: {
77
+ service: "organizations",
78
+ action: "CreateOrganizationCommand",
79
+ parameters: {
80
+ FeatureSet: featureSet
81
+ },
82
+ physicalResourceId: customResources.PhysicalResourceId.of("organisation"),
83
+ ignoreErrorCodesMatching: importOnDuplicate
84
+ ? "AlreadyInOrganizationException"
85
+ : undefined
86
+ },
87
+ onUpdate: {
88
+ service: "organizations",
89
+ action: "DescribeOrganizationCommand",
90
+ physicalResourceId: customResources.PhysicalResourceId.of("organisation")
91
+ },
92
+ onDelete: importOnDuplicate
93
+ ? undefined
94
+ : {
95
+ service: "organizations",
96
+ action: "DeleteOrganizationCommand"
97
+ },
98
+ resourceType: "Custom::Organisation",
99
+ policy: customResources.AwsCustomResourcePolicy.fromStatements([
100
+ new aws_iam_1.PolicyStatement({
101
+ actions: [
102
+ "organizations:CreateOrganization",
103
+ "organizations:DescribeOrganization",
104
+ "organizations:DeleteOrganization",
105
+ "organizations:EnableAllFeatures",
106
+ "organizations:ListRoots"
107
+ ],
108
+ resources: ["*"],
109
+ effect: aws_iam_1.Effect.ALLOW
110
+ })
111
+ ])
112
+ });
113
+ // Get organisation details
114
+ this.organisationId = orgResource.getResponseField("Organization.Id");
115
+ this.organisationArn = orgResource.getResponseField("Organization.Arn");
116
+ this.principal = `arn:aws:organizations::${this.node.tryGetContext("account")}:organization/${this.organisationId}`;
117
+ // Create the root organisational unit
118
+ this.root = new OrganisationRoot(this, "Root", this.organisationId);
119
+ // Export organisation ID
120
+ new aws_cdk_lib_1.CfnOutput(this, "OrganisationId", {
121
+ key: "OrganisationId",
122
+ value: this.organisationId,
123
+ exportName: "OrganisationId"
124
+ });
125
+ new aws_cdk_lib_1.CfnOutput(this, "OrganisationArn", {
126
+ key: "OrganisationArn",
127
+ value: this.organisationArn,
128
+ exportName: "OrganisationArn"
129
+ });
130
+ }
131
+ /**
132
+ * Enable AWS service access for the organisation
133
+ */
134
+ enableAwsServiceAccess(servicePrincipal) {
135
+ new awsCustomResource_1.AwsCustomResource(this, `EnableService${this.normalizeServiceName(servicePrincipal)}`, {
136
+ functionName: `enableAwsServiceAccess${this.normalizeServiceName(servicePrincipal)}`,
137
+ onCreate: {
138
+ service: "organizations",
139
+ action: "EnableAWSServiceAccessCommand",
140
+ parameters: {
141
+ ServicePrincipal: servicePrincipal
142
+ },
143
+ physicalResourceId: customResources.PhysicalResourceId.of(`enable-service-${servicePrincipal}`)
144
+ },
145
+ onDelete: {
146
+ service: "organizations",
147
+ action: "DisableAWSServiceAccessCommand",
148
+ parameters: {
149
+ ServicePrincipal: servicePrincipal
150
+ }
151
+ },
152
+ resourceType: "Custom::EnableAWSServiceAccess",
153
+ policy: customResources.AwsCustomResourcePolicy.fromStatements([
154
+ new aws_iam_1.PolicyStatement({
155
+ actions: [
156
+ "organizations:EnableAWSServiceAccess",
157
+ "organizations:DisableAWSServiceAccess",
158
+ "organizations:ListAWSServiceAccessForOrganization"
159
+ ],
160
+ resources: ["*"],
161
+ effect: aws_iam_1.Effect.ALLOW
162
+ })
163
+ ])
164
+ });
165
+ }
166
+ /**
167
+ * Enable policy type for the organisation
168
+ */
169
+ enablePolicyType(policyType) {
170
+ new awsCustomResource_1.AwsCustomResource(this, `EnablePolicyType${policyType}`, {
171
+ functionName: `enablePolicyType${policyType}`,
172
+ onCreate: {
173
+ service: "organizations",
174
+ action: "EnablePolicyTypeCommand",
175
+ parameters: {
176
+ RootId: this.root.organisationalUnitId,
177
+ PolicyType: policyType
178
+ },
179
+ physicalResourceId: customResources.PhysicalResourceId.of(`enable-policy-type-${policyType}`)
180
+ },
181
+ onDelete: {
182
+ service: "organizations",
183
+ action: "DisablePolicyTypeCommand",
184
+ parameters: {
185
+ RootId: this.root.organisationalUnitId,
186
+ PolicyType: policyType
187
+ }
188
+ },
189
+ resourceType: "Custom::EnablePolicyType",
190
+ policy: customResources.AwsCustomResourcePolicy.fromStatements([
191
+ new aws_iam_1.PolicyStatement({
192
+ actions: [
193
+ "organizations:EnablePolicyType",
194
+ "organizations:DisablePolicyType",
195
+ "organizations:ListRoots"
196
+ ],
197
+ resources: ["*"],
198
+ effect: aws_iam_1.Effect.ALLOW
199
+ })
200
+ ])
201
+ });
202
+ }
203
+ /**
204
+ * Attach policy to organisation root
205
+ */
206
+ attachPolicy(policy) {
207
+ this.root.attachPolicy(policy);
208
+ }
209
+ /**
210
+ * Helper to normalize service names for construct IDs
211
+ */
212
+ normalizeServiceName(servicePrincipal) {
213
+ return servicePrincipal
214
+ .replace(/[^a-zA-Z0-9]/g, "")
215
+ .replace(/^([a-z])/, (match) => match.toUpperCase());
216
+ }
217
+ /**
218
+ * Static method to get organisation from context (for use in member accounts)
219
+ */
220
+ static of(scope, id) {
221
+ return new OrganisationReference(scope, id);
222
+ }
223
+ }
224
+ exports.Organisation = Organisation;
225
+ /**
226
+ * Reference to an existing organisation (for use in member accounts)
227
+ */
228
+ class OrganisationReference extends constructs_1.Construct {
229
+ constructor(scope, id) {
230
+ super(scope, id);
231
+ // Get organisation details via custom resource
232
+ const orgDetails = new awsCustomResource_1.AwsCustomResource(this, "GetOrganisation", {
233
+ functionName: "getOrganisationDetails",
234
+ onCreate: {
235
+ service: "organizations",
236
+ action: "DescribeOrganizationCommand",
237
+ physicalResourceId: customResources.PhysicalResourceId.of("org-reference")
238
+ },
239
+ resourceType: "Custom::OrganisationReference",
240
+ policy: customResources.AwsCustomResourcePolicy.fromStatements([
241
+ new aws_iam_1.PolicyStatement({
242
+ actions: ["organizations:DescribeOrganization"],
243
+ resources: ["*"],
244
+ effect: aws_iam_1.Effect.ALLOW
245
+ })
246
+ ])
247
+ });
248
+ this.organisationId = orgDetails.getResponseField("Organization.Id");
249
+ this.organisationArn = orgDetails.getResponseField("Organization.Arn");
250
+ this.principal = `arn:aws:organizations::${orgDetails.getResponseField("Organization.MasterAccountId")}:organization/${this.organisationId}`;
251
+ this.root = new OrganisationRoot(this, "Root", this.organisationId);
252
+ }
253
+ enableAwsServiceAccess(servicePrincipal) {
254
+ throw new Error("Cannot enable AWS service access from member account");
255
+ }
256
+ enablePolicyType(policyType) {
257
+ throw new Error("Cannot enable policy type from member account");
258
+ }
259
+ attachPolicy(policy) {
260
+ throw new Error("Cannot attach policy from member account");
261
+ }
262
+ }
263
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3JnYW5pc2F0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vbGliL3Jlc291cmNlcy9hd3Mvb3JnYW5pc2F0aW9ucy9vcmdhbmlzYXRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsNkNBQXVEO0FBQ3ZELGdFQUFnRTtBQUNoRSxpREFBOEQ7QUFDOUQsMkNBQXVDO0FBRXZDLG1DQUFvRTtBQUNwRSxzRUFBbUU7QUFFbkU7O0dBRUc7QUFDSCxNQUFhLGdCQUFpQixTQUFRLHNCQUFTO0lBSzdDLFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsY0FBc0I7UUFDOUQsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUhWLDJCQUFzQixHQUFXLE1BQU0sQ0FBQztRQUsvQyxJQUFJLENBQUMsb0JBQW9CLEdBQUcsY0FBYyxDQUFDO1FBQzNDLElBQUksQ0FBQyxxQkFBcUIsR0FBRywwQkFBMEIsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsU0FBUyxDQUFDLE9BQU8sY0FBYyxNQUFNLGNBQWMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztJQUNwSixDQUFDO0lBRUQsWUFBWSxDQUFDLE1BQWU7UUFDMUIsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLG1CQUFtQixDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUUvRCxJQUFJLHFDQUFpQixDQUFDLElBQUksRUFBRSxlQUFlLFVBQVUsRUFBRSxFQUFFO1lBQ3ZELFlBQVksRUFBRSxxQkFBcUIsVUFBVSxFQUFFO1lBQy9DLFFBQVEsRUFBRTtnQkFDUixPQUFPLEVBQUUsZUFBZTtnQkFDeEIsTUFBTSxFQUFFLHFCQUFxQjtnQkFDN0IsVUFBVSxFQUFFO29CQUNWLFFBQVEsRUFBRSxNQUFNLENBQUMsUUFBUTtvQkFDekIsUUFBUSxFQUFFLElBQUksQ0FBQyxvQkFBb0I7aUJBQ3BDO2dCQUNELGtCQUFrQixFQUFF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QUFJLEtBQUssQ0FBQywrQ0FBK0MsQ0FBQyxDQUFDO0lBQ25FLENBQUM7SUFFRCxZQUFZLENBQUMsTUFBZTtRQUMxQixNQUFNLElBQUksS0FBSyxDQUFDLDBDQUEwQyxDQUFDLENBQUM7SUFDOUQsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ2ZuT3V0cHV0LCBSZW1vdmFsUG9saWN5IH0gZnJvbSBcImF3cy1jZGstbGliXCI7XG5pbXBvcnQgKiBhcyBjdXN0b21SZXNvdXJjZXMgZnJvbSBcImF3cy1jZGstbGliL2N1c3RvbS1yZXNvdXJjZXNcIjtcbmltcG9ydCB7IEVmZmVjdCwgUG9saWN5U3RhdGVtZW50IH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1pYW1cIjtcbmltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gXCJjb25zdHJ1Y3RzXCI7XG5pbXBvcnQgeyBJT3JnYW5pc2F0aW9uLCBJT3JnYW5pc2F0aW9uYWxVbml0LCBJUG9saWN5IH0gZnJvbSBcIi4vaW50ZXJmYWNlc1wiO1xuaW1wb3J0IHsgT3JnYW5pc2F0aW9uUHJvcHMsIEZlYXR1cmVTZXQsIFBvbGljeVR5cGUgfSBmcm9tIFwiLi90eXBlc1wiO1xuaW1wb3J0IHsgQXdzQ3VzdG9tUmVzb3VyY2UgfSBmcm9tIFwiLi4vdXRpbGl0aWVzL2F3c0N1c3RvbVJlc291cmNlXCI7XG5cbi8qKlxuICogT3JnYW5pc2F0aW9uIHJvb3QgY29uc3RydWN0IC0gcmVwcmVzZW50cyB0aGUgcm9vdCBvcmdhbmlzYXRpb25hbCB1bml0XG4gKi9cbmV4cG9ydCBjbGFzcyBPcmdhbmlzYXRpb25Sb290IGV4dGVuZHMgQ29uc3RydWN0IGltcGxlbWVudHMgSU9yZ2FuaXNhdGlvbmFsVW5pdCB7XG4gIHJlYWRvbmx5IG9yZ2FuaXNhdGlvbmFsVW5pdElkOiBzdHJpbmc7XG4gIHJlYWRvbmx5IG9yZ2FuaXNhdGlvbmFsVW5pdEFybjogc3RyaW5nO1xuICByZWFkb25seSBvcmdhbmlzYXRpb25hbFVuaXROYW1lOiBzdHJpbmcgPSBcIlJvb3RcIjtcblxuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBvcmdhbmlzYXRpb25JZDogc3RyaW5nKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcblxuICAgIHRoaXMub3JnYW5pc2F0aW9uYWxVbml0SWQgPSBvcmdhbmlzYXRpb25JZDtcbiAgICB0aGlzLm9yZ2FuaXNhdGlvbmFsVW5pdEFybiA9IGBhcm46YXdzOm9yZ2FuaXphdGlvbnM6OiR7dGhpcy5ub2RlLnRyeUdldENvbnRleHQoXCJhY2NvdW50XCIpfTpvdS8ke29yZ2FuaXNhdGlvbklkfS9yLSR7b3JnYW5pc2F0aW9uSWQuc3Vic3RyaW5nKDIpfWA7XG4gIH1cblxuICBhdHRhY2hQb2xpY3kocG9saWN5OiBJUG9saWN5KTogdm9pZCB7XG4gICAgY29uc3QgcG9saWN5TmFtZSA9IHRoaXMubm9ybWFsaXplUG9saWN5TmFtZShwb2xpY3kucG9saWN5TmFtZSk7XG5cbiAgICBuZXcgQXdzQ3VzdG9tUmVzb3VyY2UodGhpcywgYEF0dGFjaFBvbGljeSR7cG9saWN5TmFtZX1gLCB7XG4gICAgICBmdW5jdGlvbk5hbWU6IGBhdHRhY2hQb2xpY3lUb1Jvb3Qke3BvbGljeU5hbWV9YCxcbiAgICAgIG9uQ3JlYXRlOiB7XG4gICAgICAgIHNlcnZpY2U6IFwib3JnYW5pemF0aW9uc1wiLFxuICAgICAgICBhY3Rpb246IFwiQXR0YWNoUG9saWN5Q29tbWFuZFwiLFxuICAgICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgICAgUG9saWN5SWQ6IHBvbGljeS5wb2xpY3lJZCxcbiAgICAgICAgICBUYXJnZXRJZDogdGhpcy5vcmdhbmlzYXRpb25hbFVuaXRJZFxuICAgICAgICB9LFxuICAgICAgICBwaHlzaWNhbFJlc291cmNlSWQ6IGN1c3RvbVJlc291cmNlcy5QaHlzaWNhbFJlc291cmNlSWQub2YoXG4gICAgICAgICAgYGF0dGFjaC1wb2xpY3ktJHtwb2xpY3kucG9saWN5SWR9LXRvLSR7dGhpcy5vcmdhbmlzYXRpb25hbFVuaXRJZH1gXG4gICAgICAgIClcbiAgICAgIH0sXG4gICAgICBvbkRlbGV0ZToge1xuICAgICAgICBzZXJ2aWNlOiBcIm9yZ2FuaXphdGlvbnNcIixcbiAgICAgICAgYWN0aW9uOiBcIkRldGFjaFBvbGljeUNvbW1hbmRcIixcbiAgICAgICAgcGFyYW1ldGVyczoge1xuICAgICAgICAgIFBvbGljeUlkOiBwb2xpY3kucG9saWN5SWQsXG4gICAgICAgICAgVGFyZ2V0SWQ6IHRoaXMub3JnYW5pc2F0aW9uYWxVbml0SWRcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIHJlc291cmNlVHlwZTogXCJDdXN0b206OkF0dGFjaFBvbGljeVRvUm9vdFwiLFxuICAgICAgcG9saWN5OiBjdXN0b21SZXNvdXJjZXMuQXdzQ3VzdG9tUmVzb3VyY2VQb2xpY3kuZnJvbVN0YXRlbWVudHMoW1xuICAgICAgICBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgICBhY3Rpb25zOiBbXG4gICAgICAgICAgICBcIm9yZ2FuaXphdGlvbnM6QXR0YWNoUG9saWN5XCIsXG4gICAgICAgICAgICBcIm9yZ2FuaXphdGlvbnM6RGV0YWNoUG9saWN5XCIsXG4gICAgICAgICAgICBcIm9yZ2FuaXphdGlvbnM6TGlzdFBvbGljaWVzRm9yVGFyZ2V0XCJcbiAgICAgICAgICBdLFxuICAgICAgICAgIHJlc291cmNlczogW1wiKlwiXSxcbiAgICAgICAgICBlZmZlY3Q6IEVmZmVjdC5BTExPV1xuICAgICAgICB9KVxuICAgICAgXSlcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBIZWxwZXIgdG8gbm9ybWFsaXplIHBvbGljeSBuYW1lcyBmb3IgY29uc3RydWN0IElEc1xuICAgKi9cbiAgcHJpdmF0ZSBub3JtYWxpemVQb2xpY3lOYW1lKHBvbGljeU5hbWU6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHBvbGljeU5hbWVcbiAgICAgIC5yZXBsYWNlKC9bXmEtekEtWjAtOV0vZywgXCJcIilcbiAgICAgIC5yZXBsYWNlKC9eKFthLXpdKS8sIChtYXRjaCkgPT4gbWF0Y2gudG9VcHBlckNhc2UoKSk7XG4gIH1cbn1cblxuLyoqXG4gKiBBV1MgT3JnYW5pc2F0aW9ucyBjb25zdHJ1Y3QgZm9yIG1hbmFnaW5nIG9yZ2FuaXNhdGlvbnNcbiAqL1xuZXhwb3J0IGNsYXNzIE9yZ2FuaXNhdGlvbiBleHRlbmRzIENvbnN0cnVjdCBpbXBsZW1lbnRzIElPcmdhbmlzYXRpb24ge1xuICByZWFkb25seSBvcmdhbmlzYXRpb25JZDogc3RyaW5nO1xuICByZWFkb25seSBvcmdhbmlzYXRpb25Bcm46IHN0cmluZztcbiAgcmVhZG9ubHkgcm9vdDogSU9yZ2FuaXNhdGlvbmFsVW5pdDtcbiAgcmVhZG9ubHkgcHJpbmNpcGFsOiBzdHJpbmc7XG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IE9yZ2FuaXNhdGlvblByb3BzID0ge30pIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgY29uc3QgZmVhdHVyZVNldCA9IHByb3BzLmZlYXR1cmVTZXQgPz8gRmVhdHVyZVNldC5BTEw7XG4gICAgY29uc3QgaW1wb3J0T25EdXBsaWNhdGUgPSBwcm9wcy5pbXBvcnRPbkR1cGxpY2F0ZSA/PyB0cnVlO1xuXG4gICAgLy8gQ3JlYXRlIG9yIGdldCBleGlzdGluZyBvcmdhbmlzYXRpb25cbiAgICBjb25zdCBvcmdSZXNvdXJjZSA9IG5ldyBBd3NDdXN0b21SZXNvdXJjZSh0aGlzLCBcIk9yZ2FuaXNhdGlvblJlc291cmNlXCIsIHtcbiAgICAgIGZ1bmN0aW9uTmFtZTogXCJtYW5hZ2VPcmdhbmlzYXRpb25cIixcbiAgICAgIG9uQ3JlYXRlOiB7XG4gICAgICAgIHNlcnZpY2U6IFwib3JnYW5pemF0aW9uc1wiLFxuICAgICAgICBhY3Rpb246IFwiQ3JlYXRlT3JnYW5pemF0aW9uQ29tbWFuZFwiLFxuICAgICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgICAgRmVhdHVyZVNldDogZmVhdHVyZVNldFxuICAgICAgICB9LFxuICAgICAgICBwaHlzaWNhbFJlc291cmNlSWQ6XG4gICAgICAgICAgY3VzdG9tUmVzb3VyY2VzLlBoeXNpY2FsUmVzb3VyY2VJZC5vZihcIm9yZ2FuaXNhdGlvblwiKSxcbiAgICAgICAgaWdub3JlRXJyb3JDb2Rlc01hdGNoaW5nOiBpbXBvcnRPbkR1cGxpY2F0ZVxuICAgICAgICAgID8gXCJBbHJlYWR5SW5Pcmdhbml6YXRpb25FeGNlcHRpb25cIlxuICAgICAgICAgIDogdW5kZWZpbmVkXG4gICAgICB9LFxuICAgICAgb25VcGRhdGU6IHtcbiAgICAgICAgc2VydmljZTogXCJvcmdhbml6YXRpb25zXCIsXG4gICAgICAgIGFjdGlvbjogXCJEZXNjcmliZU9yZ2FuaXphdGlvbkNvbW1hbmRcIixcbiAgICAgICAgcGh5c2ljYWxSZXNvdXJjZUlkOlxuICAgICAgICAgIGN1c3RvbVJlc291cmNlcy5QaHlzaWNhbFJlc291cmNlSWQub2YoXCJvcmdhbmlzYXRpb25cIilcbiAgICAgIH0sXG4gICAgICBvbkRlbGV0ZTogaW1wb3J0T25EdXBsaWNhdGVcbiAgICAgICAgPyB1bmRlZmluZWRcbiAgICAgICAgOiB7XG4gICAgICAgICAgICBzZXJ2aWNlOiBcIm9yZ2FuaXphdGlvbnNcIixcbiAgICAgICAgICAgIGFjdGlvbjogXCJEZWxldGVPcmdhbml6YXRpb25Db21tYW5kXCJcbiAgICAgICAgICB9LFxuICAgICAgcmVzb3VyY2VUeXBlOiBcIkN1c3RvbTo6T3JnYW5pc2F0aW9uXCIsXG4gICAgICBwb2xpY3k6IGN1c3RvbVJlc291cmNlcy5Bd3NDdXN0b21SZXNvdXJjZVBvbGljeS5mcm9tU3RhdGVtZW50cyhbXG4gICAgICAgIG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgICAgIFwib3JnYW5pemF0aW9uczpDcmVhdGVPcmdhbml6YXRpb25cIixcbiAgICAgICAgICAgIFwib3JnYW5pemF0aW9uczpEZXNjcmliZU9yZ2FuaXphdGlvblwiLFxuICAgICAgICAgICAgXCJvcmdhbml6YXRpb25zOkRlbGV0ZU9yZ2FuaXphdGlvblwiLFxuICAgICAgICAgICAgXCJvcmdhbml6YXRpb25zOkVuYWJsZUFsbEZlYXR1cmVzXCIsXG4gICAgICAgICAgICBcIm9yZ2FuaXphdGlvbnM6TGlzdFJvb3RzXCJcbiAgICAgICAgICBdLFxuICAgICAgICAgIHJlc291cmNlczogW1wiKlwiXSxcbiAgICAgICAgICBlZmZlY3Q6IEVmZmVjdC5BTExPV1xuICAgICAgICB9KVxuICAgICAgXSlcbiAgICB9KTtcblxuICAgIC8vIEdldCBvcmdhbmlzYXRpb24gZGV0YWlsc1xuICAgIHRoaXMub3JnYW5pc2F0aW9uSWQgPSBvcmdSZXNvdXJjZS5nZXRSZXNwb25zZUZpZWxkKFwiT3JnYW5pemF0aW9uLklkXCIpO1xuICAgIHRoaXMub3JnYW5pc2F0aW9uQXJuID0gb3JnUmVzb3VyY2UuZ2V0UmVzcG9uc2VGaWVsZChcIk9yZ2FuaXphdGlvbi5Bcm5cIik7XG4gICAgdGhpcy5wcmluY2lwYWwgPSBgYXJuOmF3czpvcmdhbml6YXRpb25zOjoke3RoaXMubm9kZS50cnlHZXRDb250ZXh0KFwiYWNjb3VudFwiKX06b3JnYW5pemF0aW9uLyR7dGhpcy5vcmdhbmlzYXRpb25JZH1gO1xuXG4gICAgLy8gQ3JlYXRlIHRoZSByb290IG9yZ2FuaXNhdGlvbmFsIHVuaXRcbiAgICB0aGlzLnJvb3QgPSBuZXcgT3JnYW5pc2F0aW9uUm9vdCh0aGlzLCBcIlJvb3RcIiwgdGhpcy5vcmdhbmlzYXRpb25JZCk7XG5cbiAgICAvLyBFeHBvcnQgb3JnYW5pc2F0aW9uIElEXG4gICAgbmV3IENmbk91dHB1dCh0aGlzLCBcIk9yZ2FuaXNhdGlvbklkXCIsIHtcbiAgICAgIGtleTogXCJPcmdhbmlzYXRpb25JZFwiLFxuICAgICAgdmFsdWU6IHRoaXMub3JnYW5pc2F0aW9uSWQsXG4gICAgICBleHBvcnROYW1lOiBcIk9yZ2FuaXNhdGlvbklkXCJcbiAgICB9KTtcblxuICAgIG5ldyBDZm5PdXRwdXQodGhpcywgXCJPcmdhbmlzYXRpb25Bcm5cIiwge1xuICAgICAga2V5OiBcIk9yZ2FuaXNhdGlvbkFyblwiLFxuICAgICAgdmFsdWU6IHRoaXMub3JnYW5pc2F0aW9uQXJuLFxuICAgICAgZXhwb3J0TmFtZTogXCJPcmdhbmlzYXRpb25Bcm5cIlxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEVuYWJsZSBBV1Mgc2VydmljZSBhY2Nlc3MgZm9yIHRoZSBvcmdhbmlzYXRpb25cbiAgICovXG4gIGVuYWJsZUF3c1NlcnZpY2VBY2Nlc3Moc2VydmljZVByaW5jaXBhbDogc3RyaW5nKTogdm9pZCB7XG4gICAgbmV3IEF3c0N1c3RvbVJlc291cmNlKFxuICAgICAgdGhpcyxcbiAgICAgIGBFbmFibGVTZXJ2aWNlJHt0aGlzLm5vcm1hbGl6ZVNlcnZpY2VOYW1lKHNlcnZpY2VQcmluY2lwYWwpfWAsXG4gICAgICB7XG4gICAgICAgIGZ1bmN0aW9uTmFtZTogYGVuYWJsZUF3c1NlcnZpY2VBY2Nlc3Mke3RoaXMubm9ybWFsaXplU2VydmljZU5hbWUoc2VydmljZVByaW5jaXBhbCl9YCxcbiAgICAgICAgb25DcmVhdGU6IHtcbiAgICAgICAgICBzZXJ2aWNlOiBcIm9yZ2FuaXphdGlvbnNcIixcbiAgICAgICAgICBhY3Rpb246IFwiRW5hYmxlQVdTU2VydmljZUFjY2Vzc0NvbW1hbmRcIixcbiAgICAgICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgICAgICBTZXJ2aWNlUHJpbmNpcGFsOiBzZXJ2aWNlUHJpbmNpcGFsXG4gICAgICAgICAgfSxcbiAgICAgICAgICBwaHlzaWNhbFJlc291cmNlSWQ6IGN1c3RvbVJlc291cmNlcy5QaHlzaWNhbFJlc291cmNlSWQub2YoXG4gICAgICAgICAgICBgZW5hYmxlLXNlcnZpY2UtJHtzZXJ2aWNlUHJpbmNpcGFsfWBcbiAgICAgICAgICApXG4gICAgICAgIH0sXG4gICAgICAgIG9uRGVsZXRlOiB7XG4gICAgICAgICAgc2VydmljZTogXCJvcmdhbml6YXRpb25zXCIsXG4gICAgICAgICAgYWN0aW9uOiBcIkRpc2FibGVBV1NTZXJ2aWNlQWNjZXNzQ29tbWFuZFwiLFxuICAgICAgICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgICAgICAgIFNlcnZpY2VQcmluY2lwYWw6IHNlcnZpY2VQcmluY2lwYWxcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHJlc291cmNlVHlwZTogXCJDdXN0b206OkVuYWJsZUFXU1NlcnZpY2VBY2Nlc3NcIixcbiAgICAgICAgcG9saWN5OiBjdXN0b21SZXNvdXJjZXMuQXdzQ3VzdG9tUmVzb3VyY2VQb2xpY3kuZnJvbVN0YXRlbWVudHMoW1xuICAgICAgICAgIG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICAgICAgYWN0aW9uczogW1xuICAgICAgICAgICAgICBcIm9yZ2FuaXphdGlvbnM6RW5hYmxlQVdTU2VydmljZUFjY2Vzc1wiLFxuICAgICAgICAgICAgICBcIm9yZ2FuaXphdGlvbnM6RGlzYWJsZUFXU1NlcnZpY2VBY2Nlc3NcIixcbiAgICAgICAgICAgICAgXCJvcmdhbml6YXRpb25zOkxpc3RBV1NTZXJ2aWNlQWNjZXNzRm9yT3JnYW5pemF0aW9uXCJcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgICByZXNvdXJjZXM6IFtcIipcIl0sXG4gICAgICAgICAgICBlZmZlY3Q6IEVmZmVjdC5BTExPV1xuICAgICAgICAgIH0pXG4gICAgICAgIF0pXG4gICAgICB9XG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFbmFibGUgcG9saWN5IHR5cGUgZm9yIHRoZSBvcmdhbmlzYXRpb25cbiAgICovXG4gIGVuYWJsZVBvbGljeVR5cGUocG9saWN5VHlwZTogUG9saWN5VHlwZSk6IHZvaWQge1xuICAgIG5ldyBBd3NDdXN0b21SZXNvdXJjZSh0aGlzLCBgRW5hYmxlUG9saWN5VHlwZSR7cG9saWN5VHlwZX1gLCB7XG4gICAgICBmdW5jdGlvbk5hbWU6IGBlbmFibGVQb2xpY3lUeXBlJHtwb2xpY3lUeXBlfWAsXG4gICAgICBvbkNyZWF0ZToge1xuICAgICAgICBzZXJ2aWNlOiBcIm9yZ2FuaXphdGlvbnNcIixcbiAgICAgICAgYWN0aW9uOiBcIkVuYWJsZVBvbGljeVR5cGVDb21tYW5kXCIsXG4gICAgICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgICAgICBSb290SWQ6IHRoaXMucm9vdC5vcmdhbmlzYXRpb25hbFVuaXRJZCxcbiAgICAgICAgICBQb2xpY3lUeXBlOiBwb2xpY3lUeXBlXG4gICAgICAgIH0sXG4gICAgICAgIHBoeXNpY2FsUmVzb3VyY2VJZDogY3VzdG9tUmVzb3VyY2VzLlBoeXNpY2FsUmVzb3VyY2VJZC5vZihcbiAgICAgICAgICBgZW5hYmxlLXBvbGljeS10eXBlLSR7cG9saWN5VHlwZX1gXG4gICAgICAgIClcbiAgICAgIH0sXG4gICAgICBvbkRlbGV0ZToge1xuICAgICAgICBzZXJ2aWNlOiBcIm9yZ2FuaXphdGlvbnNcIixcbiAgICAgICAgYWN0aW9uOiBcIkRpc2FibGVQb2xpY3lUeXBlQ29tbWFuZFwiLFxuICAgICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgICAgUm9vdElkOiB0aGlzLnJvb3Qub3JnYW5pc2F0aW9uYWxVbml0SWQsXG4gICAgICAgICAgUG9saWN5VHlwZTogcG9saWN5VHlwZVxuICAgICAgICB9XG4gICAgICB9LFxuICAgICAgcmVzb3VyY2VUeXBlOiBcIkN1c3RvbTo6RW5hYmxlUG9saWN5VHlwZVwiLFxuICAgICAgcG9saWN5OiBjdXN0b21SZXNvdXJjZXMuQXdzQ3VzdG9tUmVzb3VyY2VQb2xpY3kuZnJvbVN0YXRlbWVudHMoW1xuICAgICAgICBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgICBhY3Rpb25zOiBbXG4gICAgICAgICAgICBcIm9yZ2FuaXphdGlvbnM6RW5hYmxlUG9saWN5VHlwZVwiLFxuICAgICAgICAgICAgXCJvcmdhbml6YXRpb25zOkRpc2FibGVQb2xpY3lUeXBlXCIsXG4gICAgICAgICAgICBcIm9yZ2FuaXphdGlvbnM6TGlzdFJvb3RzXCJcbiAgICAgICAgICBdLFxuICAgICAgICAgIHJlc291cmNlczogW1wiKlwiXSxcbiAgICAgICAgICBlZmZlY3Q6IEVmZmVjdC5BTExPV1xuICAgICAgICB9KVxuICAgICAgXSlcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBdHRhY2ggcG9saWN5IHRvIG9yZ2FuaXNhdGlvbiByb290XG4gICAqL1xuICBhdHRhY2hQb2xpY3kocG9saWN5OiBJUG9saWN5KTogdm9pZCB7XG4gICAgdGhpcy5yb290LmF0dGFjaFBvbGljeShwb2xpY3kpO1xuICB9XG5cbiAgLyoqXG4gICAqIEhlbHBlciB0byBub3JtYWxpemUgc2VydmljZSBuYW1lcyBmb3IgY29uc3RydWN0IElEc1xuICAgKi9cbiAgcHJpdmF0ZSBub3JtYWxpemVTZXJ2aWNlTmFtZShzZXJ2aWNlUHJpbmNpcGFsOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiBzZXJ2aWNlUHJpbmNpcGFsXG4gICAgICAucmVwbGFjZSgvW15hLXpBLVowLTldL2csIFwiXCIpXG4gICAgICAucmVwbGFjZSgvXihbYS16XSkvLCAobWF0Y2gpID0+IG1hdGNoLnRvVXBwZXJDYXNlKCkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFN0YXRpYyBtZXRob2QgdG8gZ2V0IG9yZ2FuaXNhdGlvbiBmcm9tIGNvbnRleHQgKGZvciB1c2UgaW4gbWVtYmVyIGFjY291bnRzKVxuICAgKi9cbiAgc3RhdGljIG9mKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcpOiBJT3JnYW5pc2F0aW9uIHtcbiAgICByZXR1cm4gbmV3IE9yZ2FuaXNhdGlvblJlZmVyZW5jZShzY29wZSwgaWQpO1xuICB9XG59XG5cbi8qKlxuICogUmVmZXJlbmNlIHRvIGFuIGV4aXN0aW5nIG9yZ2FuaXNhdGlvbiAoZm9yIHVzZSBpbiBtZW1iZXIgYWNjb3VudHMpXG4gKi9cbmNsYXNzIE9yZ2FuaXNhdGlvblJlZmVyZW5jZSBleHRlbmRzIENvbnN0cnVjdCBpbXBsZW1lbnRzIElPcmdhbmlzYXRpb24ge1xuICByZWFkb25seSBvcmdhbmlzYXRpb25JZDogc3RyaW5nO1xuICByZWFkb25seSBvcmdhbmlzYXRpb25Bcm46IHN0cmluZztcbiAgcmVhZG9ubHkgcHJpbmNpcGFsOiBzdHJpbmc7XG4gIHJlYWRvbmx5IHJvb3Q6IElPcmdhbmlzYXRpb25hbFVuaXQ7XG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG5cbiAgICAvLyBHZXQgb3JnYW5pc2F0aW9uIGRldGFpbHMgdmlhIGN1c3RvbSByZXNvdXJjZVxuICAgIGNvbnN0IG9yZ0RldGFpbHMgPSBuZXcgQXdzQ3VzdG9tUmVzb3VyY2UodGhpcywgXCJHZXRPcmdhbmlzYXRpb25cIiwge1xuICAgICAgZnVuY3Rpb25OYW1lOiBcImdldE9yZ2FuaXNhdGlvbkRldGFpbHNcIixcbiAgICAgIG9uQ3JlYXRlOiB7XG4gICAgICAgIHNlcnZpY2U6IFwib3JnYW5pemF0aW9uc1wiLFxuICAgICAgICBhY3Rpb246IFwiRGVzY3JpYmVPcmdhbml6YXRpb25Db21tYW5kXCIsXG4gICAgICAgIHBoeXNpY2FsUmVzb3VyY2VJZDpcbiAgICAgICAgICBjdXN0b21SZXNvdXJjZXMuUGh5c2ljYWxSZXNvdXJjZUlkLm9mKFwib3JnLXJlZmVyZW5jZVwiKVxuICAgICAgfSxcbiAgICAgIHJlc291cmNlVHlwZTogXCJDdXN0b206Ok9yZ2FuaXNhdGlvblJlZmVyZW5jZVwiLFxuICAgICAgcG9saWN5OiBjdXN0b21SZXNvdXJjZXMuQXdzQ3VzdG9tUmVzb3VyY2VQb2xpY3kuZnJvbVN0YXRlbWVudHMoW1xuICAgICAgICBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgICBhY3Rpb25zOiBbXCJvcmdhbml6YXRpb25zOkRlc2NyaWJlT3JnYW5pemF0aW9uXCJdLFxuICAgICAgICAgIHJlc291cmNlczogW1wiKlwiXSxcbiAgICAgICAgICBlZmZlY3Q6IEVmZmVjdC5BTExPV1xuICAgICAgICB9KVxuICAgICAgXSlcbiAgICB9KTtcblxuICAgIHRoaXMub3JnYW5pc2F0aW9uSWQgPSBvcmdEZXRhaWxzLmdldFJlc3BvbnNlRmllbGQoXCJPcmdhbml6YXRpb24uSWRcIik7XG4gICAgdGhpcy5vcmdhbmlzYXRpb25Bcm4gPSBvcmdEZXRhaWxzLmdldFJlc3BvbnNlRmllbGQoXCJPcmdhbml6YXRpb24uQXJuXCIpO1xuICAgIHRoaXMucHJpbmNpcGFsID0gYGFybjphd3M6b3JnYW5pemF0aW9uczo6JHtvcmdEZXRhaWxzLmdldFJlc3BvbnNlRmllbGQoXCJPcmdhbml6YXRpb24uTWFzdGVyQWNjb3VudElkXCIpfTpvcmdhbml6YXRpb24vJHt0aGlzLm9yZ2FuaXNhdGlvbklkfWA7XG4gICAgdGhpcy5yb290ID0gbmV3IE9yZ2FuaXNhdGlvblJvb3QodGhpcywgXCJSb290XCIsIHRoaXMub3JnYW5pc2F0aW9uSWQpO1xuICB9XG5cbiAgZW5hYmxlQXdzU2VydmljZUFjY2VzcyhzZXJ2aWNlUHJpbmNpcGFsOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJDYW5ub3QgZW5hYmxlIEFXUyBzZXJ2aWNlIGFjY2VzcyBmcm9tIG1lbWJlciBhY2NvdW50XCIpO1xuICB9XG5cbiAgZW5hYmxlUG9saWN5VHlwZShwb2xpY3lUeXBlOiBQb2xpY3lUeXBlKTogdm9pZCB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFwiQ2Fubm90IGVuYWJsZSBwb2xpY3kgdHlwZSBmcm9tIG1lbWJlciBhY2NvdW50XCIpO1xuICB9XG5cbiAgYXR0YWNoUG9saWN5KHBvbGljeTogSVBvbGljeSk6IHZvaWQge1xuICAgIHRocm93IG5ldyBFcnJvcihcIkNhbm5vdCBhdHRhY2ggcG9saWN5IGZyb20gbWVtYmVyIGFjY291bnRcIik7XG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1,28 @@
1
+ import { Construct } from "constructs";
2
+ import { IOrganisationalUnit, IPolicy } from "./interfaces";
3
+ import { OrganisationalUnitProps } from "./types";
4
+ /**
5
+ * AWS Organisational Unit construct for managing OUs
6
+ */
7
+ export declare class OrganisationalUnit extends Construct implements IOrganisationalUnit {
8
+ readonly organisationalUnitId: string;
9
+ readonly organisationalUnitArn: string;
10
+ readonly organisationalUnitName: string;
11
+ constructor(scope: Construct, id: string, props: OrganisationalUnitProps);
12
+ /**
13
+ * Attach policy to this organisational unit
14
+ */
15
+ attachPolicy(policy: IPolicy): void;
16
+ /**
17
+ * Helper to normalize OU names for construct IDs
18
+ */
19
+ private normalizeOUName;
20
+ /**
21
+ * Helper to normalize policy names for construct IDs
22
+ */
23
+ private normalizePolicyName;
24
+ /**
25
+ * Extract OU ID from list response (this would need custom logic in the Lambda)
26
+ */
27
+ private extractOUIdFromList;
28
+ }
@@ -0,0 +1,170 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OrganisationalUnit = void 0;
4
+ const aws_cdk_lib_1 = require("aws-cdk-lib");
5
+ const customResources = require("aws-cdk-lib/custom-resources");
6
+ const aws_iam_1 = require("aws-cdk-lib/aws-iam");
7
+ const constructs_1 = require("constructs");
8
+ const awsCustomResource_1 = require("../utilities/awsCustomResource");
9
+ /**
10
+ * AWS Organisational Unit construct for managing OUs
11
+ */
12
+ class OrganisationalUnit extends constructs_1.Construct {
13
+ constructor(scope, id, props) {
14
+ super(scope, id);
15
+ this.organisationalUnitName = props.organisationalUnitName;
16
+ const importOnDuplicate = props.importOnDuplicate ?? true;
17
+ const removalPolicy = props.removalPolicy ?? aws_cdk_lib_1.RemovalPolicy.RETAIN;
18
+ // Create organisational unit
19
+ const ouResource = new awsCustomResource_1.AwsCustomResource(this, "OrganisationalUnitResource", {
20
+ functionName: `manageOU${this.normalizeOUName(props.organisationalUnitName)}`,
21
+ onCreate: {
22
+ service: "organizations",
23
+ action: "CreateOrganizationalUnitCommand",
24
+ parameters: {
25
+ ParentId: props.parent.organisationalUnitId,
26
+ Name: props.organisationalUnitName
27
+ },
28
+ physicalResourceId: customResources.PhysicalResourceId.of(`ou-${props.organisationalUnitName}-${props.parent.organisationalUnitId}`),
29
+ ignoreErrorCodesMatching: importOnDuplicate
30
+ ? "DuplicateOrganizationalUnitException"
31
+ : undefined
32
+ },
33
+ onUpdate: {
34
+ service: "organizations",
35
+ action: "DescribeOrganizationalUnitCommand",
36
+ parameters: {
37
+ OrganizationalUnitId: this.organisationalUnitId
38
+ },
39
+ physicalResourceId: customResources.PhysicalResourceId.of(`ou-${props.organisationalUnitName}-${props.parent.organisationalUnitId}`)
40
+ },
41
+ onDelete: removalPolicy === aws_cdk_lib_1.RemovalPolicy.DESTROY
42
+ ? {
43
+ service: "organizations",
44
+ action: "DeleteOrganizationalUnitCommand",
45
+ parameters: {
46
+ OrganizationalUnitId: this.organisationalUnitId
47
+ }
48
+ }
49
+ : undefined,
50
+ resourceType: "Custom::OrganisationalUnit",
51
+ policy: customResources.AwsCustomResourcePolicy.fromStatements([
52
+ new aws_iam_1.PolicyStatement({
53
+ actions: [
54
+ "organizations:CreateOrganizationalUnit",
55
+ "organizations:DescribeOrganizationalUnit",
56
+ "organizations:DeleteOrganizationalUnit",
57
+ "organizations:ListOrganizationalUnitsForParent",
58
+ "organizations:UpdateOrganizationalUnit"
59
+ ],
60
+ resources: ["*"],
61
+ effect: aws_iam_1.Effect.ALLOW
62
+ })
63
+ ])
64
+ });
65
+ // Handle import case - if OU already exists, get its details
66
+ if (importOnDuplicate) {
67
+ const existingOUResource = new awsCustomResource_1.AwsCustomResource(this, "FindExistingOU", {
68
+ functionName: `findOU${this.normalizeOUName(props.organisationalUnitName)}`,
69
+ onCreate: {
70
+ service: "organizations",
71
+ action: "ListOrganizationalUnitsForParentCommand",
72
+ parameters: {
73
+ ParentId: props.parent.organisationalUnitId
74
+ },
75
+ physicalResourceId: customResources.PhysicalResourceId.of(`find-ou-${props.organisationalUnitName}-${props.parent.organisationalUnitId}`)
76
+ },
77
+ resourceType: "Custom::FindExistingOU",
78
+ policy: customResources.AwsCustomResourcePolicy.fromStatements([
79
+ new aws_iam_1.PolicyStatement({
80
+ actions: ["organizations:ListOrganizationalUnitsForParent"],
81
+ resources: ["*"],
82
+ effect: aws_iam_1.Effect.ALLOW
83
+ })
84
+ ])
85
+ });
86
+ // Use a custom function to extract the OU ID from the list
87
+ this.organisationalUnitId =
88
+ this.extractOUIdFromList(existingOUResource.getResponseField("OrganizationalUnits"), props.organisationalUnitName) || ouResource.getResponseField("OrganizationalUnit.Id");
89
+ }
90
+ else {
91
+ this.organisationalUnitId = ouResource.getResponseField("OrganizationalUnit.Id");
92
+ }
93
+ this.organisationalUnitArn = ouResource.getResponseField("OrganizationalUnit.Arn");
94
+ // Export OU details
95
+ new aws_cdk_lib_1.CfnOutput(this, "OrganisationalUnitId", {
96
+ key: `${id}Id`,
97
+ value: this.organisationalUnitId,
98
+ exportName: `${id}Id`
99
+ });
100
+ new aws_cdk_lib_1.CfnOutput(this, "OrganisationalUnitArn", {
101
+ key: `${id}Arn`,
102
+ value: this.organisationalUnitArn,
103
+ exportName: `${id}Arn`
104
+ });
105
+ }
106
+ /**
107
+ * Attach policy to this organisational unit
108
+ */
109
+ attachPolicy(policy) {
110
+ const policyName = this.normalizePolicyName(policy.policyName);
111
+ new awsCustomResource_1.AwsCustomResource(this, `AttachPolicy${policyName}`, {
112
+ functionName: `attachPolicyToOU${policyName}${this.normalizeOUName(this.organisationalUnitName)}`,
113
+ onCreate: {
114
+ service: "organizations",
115
+ action: "AttachPolicyCommand",
116
+ parameters: {
117
+ PolicyId: policy.policyId,
118
+ TargetId: this.organisationalUnitId
119
+ },
120
+ physicalResourceId: customResources.PhysicalResourceId.of(`attach-policy-${policy.policyId}-to-${this.organisationalUnitId}`)
121
+ },
122
+ onDelete: {
123
+ service: "organizations",
124
+ action: "DetachPolicyCommand",
125
+ parameters: {
126
+ PolicyId: policy.policyId,
127
+ TargetId: this.organisationalUnitId
128
+ }
129
+ },
130
+ resourceType: "Custom::AttachPolicyToOU",
131
+ policy: customResources.AwsCustomResourcePolicy.fromStatements([
132
+ new aws_iam_1.PolicyStatement({
133
+ actions: [
134
+ "organizations:AttachPolicy",
135
+ "organizations:DetachPolicy",
136
+ "organizations:ListPoliciesForTarget"
137
+ ],
138
+ resources: ["*"],
139
+ effect: aws_iam_1.Effect.ALLOW
140
+ })
141
+ ])
142
+ });
143
+ }
144
+ /**
145
+ * Helper to normalize OU names for construct IDs
146
+ */
147
+ normalizeOUName(ouName) {
148
+ return ouName
149
+ .replace(/[^a-zA-Z0-9]/g, "")
150
+ .replace(/^([a-z])/, (match) => match.toUpperCase());
151
+ }
152
+ /**
153
+ * Helper to normalize policy names for construct IDs
154
+ */
155
+ normalizePolicyName(policyName) {
156
+ return policyName
157
+ .replace(/[^a-zA-Z0-9]/g, "")
158
+ .replace(/^([a-z])/, (match) => match.toUpperCase());
159
+ }
160
+ /**
161
+ * Extract OU ID from list response (this would need custom logic in the Lambda)
162
+ */
163
+ extractOUIdFromList(organisationalUnits, name) {
164
+ // This is a placeholder - in reality, you'd need custom Lambda logic to parse the list
165
+ // For now, we'll rely on the create operation with ignoreErrorCodesMatching
166
+ return undefined;
167
+ }
168
+ }
169
+ exports.OrganisationalUnit = OrganisationalUnit;
170
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3JnYW5pc2F0aW9uYWxVbml0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vbGliL3Jlc291cmNlcy9hd3Mvb3JnYW5pc2F0aW9ucy9vcmdhbmlzYXRpb25hbFVuaXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsNkNBQXVEO0FBQ3ZELGdFQUFnRTtBQUNoRSxpREFBOEQ7QUFDOUQsMkNBQXVDO0FBR3ZDLHNFQUFtRTtBQUVuRTs7R0FFRztBQUNILE1BQWEsa0JBQ1gsU0FBUSxzQkFBUztJQU9qQixZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLEtBQThCO1FBQ3RFLEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFFakIsSUFBSSxDQUFDLHNCQUFzQixHQUFHLEtBQUssQ0FBQyxzQkFBc0IsQ0FBQztRQUMzRCxNQUFNLGlCQUFpQixHQUFHLEtBQUssQ0FBQyxpQkFBaUIsSUFBSSxJQUFJLENBQUM7UUFDMUQsTUFBTSxhQUFhLEdBQUcsS0FBSyxDQUFDLGFBQWEsSUFBSSwyQkFBYSxDQUFDLE1BQU0sQ0FBQztRQUVsRSw2QkFBNkI7UUFDN0IsTUFBTSxVQUFVLEdBQUcsSUFBSSxxQ0FBaUIsQ0FDdEMsSUFBSSxFQUNKLDRCQUE0QixFQUM1QjtZQUNFLFlBQVksRUFBRSxXQUFXLElBQUksQ0FBQyxlQUFlLENBQUMsS0FBSyxDQUFDLHNCQUFzQixDQUFDLEVBQUU7WUFDN0UsUUFBUSxFQUFFO2dCQUNSLE9BQU8sRUFBRSxlQUFlO2dCQUN4QixNQUFNLEVBQUUsaUNBQWlDO2dCQUN6QyxVQUFVLEVBQUU7b0JBQ1YsUUFBUSxFQUFFLEtBQUssQ0FBQyxNQUFNLENBQUMsb0JBQW9CO29CQUMzQyxJQUFJLEVBQUUsS0FBSyxDQUFDLHNCQUFzQjtpQkFDbkM7Z0JBQ0Qsa0JBQWtCLEVBQUUsZUFBZSxDQUFDLGtCQUFrQixDQUFDLEVBQUUsQ0FDdkQsTUFBTSxLQUFLLENBQUMsc0JBQXNCLElBQUks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cm9tIFwiYXdzLWNkay1saWJcIjtcbmltcG9ydCAqIGFzIGN1c3RvbVJlc291cmNlcyBmcm9tIFwiYXdzLWNkay1saWIvY3VzdG9tLXJlc291cmNlc1wiO1xuaW1wb3J0IHsgRWZmZWN0LCBQb2xpY3lTdGF0ZW1lbnQgfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWlhbVwiO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcbmltcG9ydCB7IElPcmdhbmlzYXRpb25hbFVuaXQsIElQb2xpY3kgfSBmcm9tIFwiLi9pbnRlcmZhY2VzXCI7XG5pbXBvcnQgeyBPcmdhbmlzYXRpb25hbFVuaXRQcm9wcyB9IGZyb20gXCIuL3R5cGVzXCI7XG5pbXBvcnQgeyBBd3NDdXN0b21SZXNvdXJjZSB9IGZyb20gXCIuLi91dGlsaXRpZXMvYXdzQ3VzdG9tUmVzb3VyY2VcIjtcblxuLyoqXG4gKiBBV1MgT3JnYW5pc2F0aW9uYWwgVW5pdCBjb25zdHJ1Y3QgZm9yIG1hbmFnaW5nIE9Vc1xuICovXG5leHBvcnQgY2xhc3MgT3JnYW5pc2F0aW9uYWxVbml0XG4gIGV4dGVuZHMgQ29uc3RydWN0XG4gIGltcGxlbWVudHMgSU9yZ2FuaXNhdGlvbmFsVW5pdFxue1xuICByZWFkb25seSBvcmdhbmlzYXRpb25hbFVuaXRJZDogc3RyaW5nO1xuICByZWFkb25seSBvcmdhbmlzYXRpb25hbFVuaXRBcm46IHN0cmluZztcbiAgcmVhZG9ubHkgb3JnYW5pc2F0aW9uYWxVbml0TmFtZTogc3RyaW5nO1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBPcmdhbmlzYXRpb25hbFVuaXRQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG5cbiAgICB0aGlzLm9yZ2FuaXNhdGlvbmFsVW5pdE5hbWUgPSBwcm9wcy5vcmdhbmlzYXRpb25hbFVuaXROYW1lO1xuICAgIGNvbnN0IGltcG9ydE9uRHVwbGljYXRlID0gcHJvcHMuaW1wb3J0T25EdXBsaWNhdGUgPz8gdHJ1ZTtcbiAgICBjb25zdCByZW1vdmFsUG9saWN5ID0gcHJvcHMucmVtb3ZhbFBvbGljeSA/PyBSZW1vdmFsUG9saWN5LlJFVEFJTjtcblxuICAgIC8vIENyZWF0ZSBvcmdhbmlzYXRpb25hbCB1bml0XG4gICAgY29uc3Qgb3VSZXNvdXJjZSA9IG5ldyBBd3NDdXN0b21SZXNvdXJjZShcbiAgICAgIHRoaXMsXG4gICAgICBcIk9yZ2FuaXNhdGlvbmFsVW5pdFJlc291cmNlXCIsXG4gICAgICB7XG4gICAgICAgIGZ1bmN0aW9uTmFtZTogYG1hbmFnZU9VJHt0aGlzLm5vcm1hbGl6ZU9VTmFtZShwcm9wcy5vcmdhbmlzYXRpb25hbFVuaXROYW1lKX1gLFxuICAgICAgICBvbkNyZWF0ZToge1xuICAgICAgICAgIHNlcnZpY2U6IFwib3JnYW5pemF0aW9uc1wiLFxuICAgICAgICAgIGFjdGlvbjogXCJDcmVhdGVPcmdhbml6YXRpb25hbFVuaXRDb21tYW5kXCIsXG4gICAgICAgICAgcGFyYW1ldGVyczoge1xuICAgICAgICAgICAgUGFyZW50SWQ6IHByb3BzLnBhcmVudC5vcmdhbmlzYXRpb25hbFVuaXRJZCxcbiAgICAgICAgICAgIE5hbWU6IHByb3BzLm9yZ2FuaXNhdGlvbmFsVW5pdE5hbWVcbiAgICAgICAgICB9LFxuICAgICAgICAgIHBoeXNpY2FsUmVzb3VyY2VJZDogY3VzdG9tUmVzb3VyY2VzLlBoeXNpY2FsUmVzb3VyY2VJZC5vZihcbiAgICAgICAgICAgIGBvdS0ke3Byb3BzLm9yZ2FuaXNhdGlvbmFsVW5pdE5hbWV9LSR7cHJvcHMucGFyZW50Lm9yZ2FuaXNhdGlvbmFsVW5pdElkfWBcbiAgICAgICAgICApLFxuICAgICAgICAgIGlnbm9yZUVycm9yQ29kZXNNYXRjaGluZzogaW1wb3J0T25EdXBsaWNhdGVcbiAgICAgICAgICAgID8gXCJEdXBsaWNhdGVPcmdhbml6YXRpb25hbFVuaXRFeGNlcHRpb25cIlxuICAgICAgICAgICAgOiB1bmRlZmluZWRcbiAgICAgICAgfSxcbiAgICAgICAgb25VcGRhdGU6IHtcbiAgICAgICAgICBzZXJ2aWNlOiBcIm9yZ2FuaXphdGlvbnNcIixcbiAgICAgICAgICBhY3Rpb246IFwiRGVzY3JpYmVPcmdhbml6YXRpb25hbFVuaXRDb21tYW5kXCIsXG4gICAgICAgICAgcGFyYW1ldGVyczoge1xuICAgICAgICAgICAgT3JnYW5pemF0aW9uYWxVbml0SWQ6IHRoaXMub3JnYW5pc2F0aW9uYWxVbml0SWRcbiAgICAgICAgICB9LFxuICAgICAgICAgIHBoeXNpY2FsUmVzb3VyY2VJZDogY3VzdG9tUmVzb3VyY2VzLlBoeXNpY2FsUmVzb3VyY2VJZC5vZihcbiAgICAgICAgICAgIGBvdS0ke3Byb3BzLm9yZ2FuaXNhdGlvbmFsVW5pdE5hbWV9LSR7cHJvcHMucGFyZW50Lm9yZ2FuaXNhdGlvbmFsVW5pdElkfWBcbiAgICAgICAgICApXG4gICAgICAgIH0sXG4gICAgICAgIG9uRGVsZXRlOlxuICAgICAgICAgIHJlbW92YWxQb2xpY3kgPT09IFJlbW92YWxQb2xpY3kuREVTVFJPWVxuICAgICAgICAgICAgPyB7XG4gICAgICAgICAgICAgICAgc2VydmljZTogXCJvcmdhbml6YXRpb25zXCIsXG4gICAgICAgICAgICAgICAgYWN0aW9uOiBcIkRlbGV0ZU9yZ2FuaXphdGlvbmFsVW5pdENvbW1hbmRcIixcbiAgICAgICAgICAgICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgICAgICAgICAgICBPcmdhbml6YXRpb25hbFVuaXRJZDogdGhpcy5vcmdhbmlzYXRpb25hbFVuaXRJZFxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgOiB1bmRlZmluZWQsXG4gICAgICAgIHJlc291cmNlVHlwZTogXCJDdXN0b206Ok9yZ2FuaXNhdGlvbmFsVW5pdFwiLFxuICAgICAgICBwb2xpY3k6IGN1c3RvbVJlc291cmNlcy5Bd3NDdXN0b21SZXNvdXJjZVBvbGljeS5mcm9tU3RhdGVtZW50cyhbXG4gICAgICAgICAgbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgICAgICBhY3Rpb25zOiBbXG4gICAgICAgICAgICAgIFwib3JnYW5pemF0aW9uczpDcmVhdGVPcmdhbml6YXRpb25hbFVuaXRcIixcbiAgICAgICAgICAgICAgXCJvcmdhbml6YXRpb25zOkRlc2NyaWJlT3JnYW5pemF0aW9uYWxVbml0XCIsXG4gICAgICAgICAgICAgIFwib3JnYW5pemF0aW9uczpEZWxldGVPcmdhbml6YXRpb25hbFVuaXRcIixcbiAgICAgICAgICAgICAgXCJvcmdhbml6YXRpb25zOkxpc3RPcmdhbml6YXRpb25hbFVuaXRzRm9yUGFyZW50XCIsXG4gICAgICAgICAgICAgIFwib3JnYW5pemF0aW9uczpVcGRhdGVPcmdhbml6YXRpb25hbFVuaXRcIlxuICAgICAgICAgICAgXSxcbiAgICAgICAgICAgIHJlc291cmNlczogW1wiKlwiXSxcbiAgICAgICAgICAgIGVmZmVjdDogRWZmZWN0LkFMTE9XXG4gICAgICAgICAgfSlcbiAgICAgICAgXSlcbiAgICAgIH1cbiAgICApO1xuXG4gICAgLy8gSGFuZGxlIGltcG9ydCBjYXNlIC0gaWYgT1UgYWxyZWFkeSBleGlzdHMsIGdldCBpdHMgZGV0YWlsc1xuICAgIGlmIChpbXBvcnRPbkR1cGxpY2F0ZSkge1xuICAgICAgY29uc3QgZXhpc3RpbmdPVVJlc291cmNlID0gbmV3IEF3c0N1c3RvbVJlc291cmNlKHRoaXMsIFwiRmluZEV4aXN0aW5nT1VcIiwge1xuICAgICAgICBmdW5jdGlvbk5hbWU6IGBmaW5kT1Uke3RoaXMubm9ybWFsaXplT1VOYW1lKHByb3BzLm9yZ2FuaXNhdGlvbmFsVW5pdE5hbWUpfWAsXG4gICAgICAgIG9uQ3JlYXRlOiB7XG4gICAgICAgICAgc2VydmljZTogXCJvcmdhbml6YXRpb25zXCIsXG4gICAgICAgICAgYWN0aW9uOiBcIkxpc3RPcmdhbml6YXRpb25hbFVuaXRzRm9yUGFyZW50Q29tbWFuZFwiLFxuICAgICAgICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgICAgICAgIFBhcmVudElkOiBwcm9wcy5wYXJlbnQub3JnYW5pc2F0aW9uYWxVbml0SWRcbiAgICAgICAgICB9LFxuICAgICAgICAgIHBoeXNpY2FsUmVzb3VyY2VJZDogY3VzdG9tUmVzb3VyY2VzLlBoeXNpY2FsUmVzb3VyY2VJZC5vZihcbiAgICAgICAgICAgIGBmaW5kLW91LSR7cHJvcHMub3JnYW5pc2F0aW9uYWxVbml0TmFtZX0tJHtwcm9wcy5wYXJlbnQub3JnYW5pc2F0aW9uYWxVbml0SWR9YFxuICAgICAgICAgIClcbiAgICAgICAgfSxcbiAgICAgICAgcmVzb3VyY2VUeXBlOiBcIkN1c3RvbTo6RmluZEV4aXN0aW5nT1VcIixcbiAgICAgICAgcG9saWN5OiBjdXN0b21SZXNvdXJjZXMuQXdzQ3VzdG9tUmVzb3VyY2VQb2xpY3kuZnJvbVN0YXRlbWVudHMoW1xuICAgICAgICAgIG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICAgICAgYWN0aW9uczogW1wib3JnYW5pemF0aW9uczpMaXN0T3JnYW5pemF0aW9uYWxVbml0c0ZvclBhcmVudFwiXSxcbiAgICAgICAgICAgIHJlc291cmNlczogW1wiKlwiXSxcbiAgICAgICAgICAgIGVmZmVjdDogRWZmZWN0LkFMTE9XXG4gICAgICAgICAgfSlcbiAgICAgICAgXSlcbiAgICAgIH0pO1xuXG4gICAgICAvLyBVc2UgYSBjdXN0b20gZnVuY3Rpb24gdG8gZXh0cmFjdCB0aGUgT1UgSUQgZnJvbSB0aGUgbGlzdFxuICAgICAgdGhpcy5vcmdhbmlzYXRpb25hbFVuaXRJZCA9XG4gICAgICAgIHRoaXMuZXh0cmFjdE9VSWRGcm9tTGlzdChcbiAgICAgICAgICBleGlzdGluZ09VUmVzb3VyY2UuZ2V0UmVzcG9uc2VGaWVsZChcIk9yZ2FuaXphdGlvbmFsVW5pdHNcIiksXG4gICAgICAgICAgcHJvcHMub3JnYW5pc2F0aW9uYWxVbml0TmFtZVxuICAgICAgICApIHx8IG91UmVzb3VyY2UuZ2V0UmVzcG9uc2VGaWVsZChcIk9yZ2FuaXphdGlvbmFsVW5pdC5JZFwiKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5vcmdhbmlzYXRpb25hbFVuaXRJZCA9IG91UmVzb3VyY2UuZ2V0UmVzcG9uc2VGaWVsZChcbiAgICAgICAgXCJPcmdhbml6YXRpb25hbFVuaXQuSWRcIlxuICAgICAgKTtcbiAgICB9XG5cbiAgICB0aGlzLm9yZ2FuaXNhdGlvbmFsVW5pdEFybiA9IG91UmVzb3VyY2UuZ2V0UmVzcG9uc2VGaWVsZChcbiAgICAgIFwiT3JnYW5pemF0aW9uYWxVbml0LkFyblwiXG4gICAgKTtcblxuICAgIC8vIEV4cG9ydCBPVSBkZXRhaWxzXG4gICAgbmV3IENmbk91dHB1dCh0aGlzLCBcIk9yZ2FuaXNhdGlvbmFsVW5pdElkXCIsIHtcbiAgICAgIGtleTogYCR7aWR9SWRgLFxuICAgICAgdmFsdWU6IHRoaXMub3JnYW5pc2F0aW9uYWxVbml0SWQsXG4gICAgICBleHBvcnROYW1lOiBgJHtpZH1JZGBcbiAgICB9KTtcblxuICAgIG5ldyBDZm5PdXRwdXQodGhpcywgXCJPcmdhbmlzYXRpb25hbFVuaXRBcm5cIiwge1xuICAgICAga2V5OiBgJHtpZH1Bcm5gLFxuICAgICAgdmFsdWU6IHRoaXMub3JnYW5pc2F0aW9uYWxVbml0QXJuLFxuICAgICAgZXhwb3J0TmFtZTogYCR7aWR9QXJuYFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEF0dGFjaCBwb2xpY3kgdG8gdGhpcyBvcmdhbmlzYXRpb25hbCB1bml0XG4gICAqL1xuICBhdHRhY2hQb2xpY3kocG9saWN5OiBJUG9saWN5KTogdm9pZCB7XG4gICAgY29uc3QgcG9saWN5TmFtZSA9IHRoaXMubm9ybWFsaXplUG9saWN5TmFtZShwb2xpY3kucG9saWN5TmFtZSk7XG5cbiAgICBuZXcgQXdzQ3VzdG9tUmVzb3VyY2UodGhpcywgYEF0dGFjaFBvbGljeSR7cG9saWN5TmFtZX1gLCB7XG4gICAgICBmdW5jdGlvbk5hbWU6IGBhdHRhY2hQb2xpY3lUb09VJHtwb2xpY3lOYW1lfSR7dGhpcy5ub3JtYWxpemVPVU5hbWUodGhpcy5vcmdhbmlzYXRpb25hbFVuaXROYW1lKX1gLFxuICAgICAgb25DcmVhdGU6IHtcbiAgICAgICAgc2VydmljZTogXCJvcmdhbml6YXRpb25zXCIsXG4gICAgICAgIGFjdGlvbjogXCJBdHRhY2hQb2xpY3lDb21tYW5kXCIsXG4gICAgICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgICAgICBQb2xpY3lJZDogcG9saWN5LnBvbGljeUlkLFxuICAgICAgICAgIFRhcmdldElkOiB0aGlzLm9yZ2FuaXNhdGlvbmFsVW5pdElkXG4gICAgICAgIH0sXG4gICAgICAgIHBoeXNpY2FsUmVzb3VyY2VJZDogY3VzdG9tUmVzb3VyY2VzLlBoeXNpY2FsUmVzb3VyY2VJZC5vZihcbiAgICAgICAgICBgYXR0YWNoLXBvbGljeS0ke3BvbGljeS5wb2xpY3lJZH0tdG8tJHt0aGlzLm9yZ2FuaXNhdGlvbmFsVW5pdElkfWBcbiAgICAgICAgKVxuICAgICAgfSxcbiAgICAgIG9uRGVsZXRlOiB7XG4gICAgICAgIHNlcnZpY2U6IFwib3JnYW5pemF0aW9uc1wiLFxuICAgICAgICBhY3Rpb246IFwiRGV0YWNoUG9saWN5Q29tbWFuZFwiLFxuICAgICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgICAgUG9saWN5SWQ6IHBvbGljeS5wb2xpY3lJZCxcbiAgICAgICAgICBUYXJnZXRJZDogdGhpcy5vcmdhbmlzYXRpb25hbFVuaXRJZFxuICAgICAgICB9XG4gICAgICB9LFxuICAgICAgcmVzb3VyY2VUeXBlOiBcIkN1c3RvbTo6QXR0YWNoUG9saWN5VG9PVVwiLFxuICAgICAgcG9saWN5OiBjdXN0b21SZXNvdXJjZXMuQXdzQ3VzdG9tUmVzb3VyY2VQb2xpY3kuZnJvbVN0YXRlbWVudHMoW1xuICAgICAgICBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgICBhY3Rpb25zOiBbXG4gICAgICAgICAgICBcIm9yZ2FuaXphdGlvbnM6QXR0YWNoUG9saWN5XCIsXG4gICAgICAgICAgICBcIm9yZ2FuaXphdGlvbnM6RGV0YWNoUG9saWN5XCIsXG4gICAgICAgICAgICBcIm9yZ2FuaXphdGlvbnM6TGlzdFBvbGljaWVzRm9yVGFyZ2V0XCJcbiAgICAgICAgICBdLFxuICAgICAgICAgIHJlc291cmNlczogW1wiKlwiXSxcbiAgICAgICAgICBlZmZlY3Q6IEVmZmVjdC5BTExPV1xuICAgICAgICB9KVxuICAgICAgXSlcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBIZWxwZXIgdG8gbm9ybWFsaXplIE9VIG5hbWVzIGZvciBjb25zdHJ1Y3QgSURzXG4gICAqL1xuICBwcml2YXRlIG5vcm1hbGl6ZU9VTmFtZShvdU5hbWU6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIG91TmFtZVxuICAgICAgLnJlcGxhY2UoL1teYS16QS1aMC05XS9nLCBcIlwiKVxuICAgICAgLnJlcGxhY2UoL14oW2Etel0pLywgKG1hdGNoKSA9PiBtYXRjaC50b1VwcGVyQ2FzZSgpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBIZWxwZXIgdG8gbm9ybWFsaXplIHBvbGljeSBuYW1lcyBmb3IgY29uc3RydWN0IElEc1xuICAgKi9cbiAgcHJpdmF0ZSBub3JtYWxpemVQb2xpY3lOYW1lKHBvbGljeU5hbWU6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHBvbGljeU5hbWVcbiAgICAgIC5yZXBsYWNlKC9bXmEtekEtWjAtOV0vZywgXCJcIilcbiAgICAgIC5yZXBsYWNlKC9eKFthLXpdKS8sIChtYXRjaCkgPT4gbWF0Y2gudG9VcHBlckNhc2UoKSk7XG4gIH1cblxuICAvKipcbiAgICogRXh0cmFjdCBPVSBJRCBmcm9tIGxpc3QgcmVzcG9uc2UgKHRoaXMgd291bGQgbmVlZCBjdXN0b20gbG9naWMgaW4gdGhlIExhbWJkYSlcbiAgICovXG4gIHByaXZhdGUgZXh0cmFjdE9VSWRGcm9tTGlzdChcbiAgICBvcmdhbmlzYXRpb25hbFVuaXRzOiBhbnksXG4gICAgbmFtZTogc3RyaW5nXG4gICk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gICAgLy8gVGhpcyBpcyBhIHBsYWNlaG9sZGVyIC0gaW4gcmVhbGl0eSwgeW91J2QgbmVlZCBjdXN0b20gTGFtYmRhIGxvZ2ljIHRvIHBhcnNlIHRoZSBsaXN0XG4gICAgLy8gRm9yIG5vdywgd2UnbGwgcmVseSBvbiB0aGUgY3JlYXRlIG9wZXJhdGlvbiB3aXRoIGlnbm9yZUVycm9yQ29kZXNNYXRjaGluZ1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1,17 @@
1
+ import { Construct } from "constructs";
2
+ import { IPolicy } from "./interfaces";
3
+ import { PolicyProps, PolicyType } from "./types";
4
+ /**
5
+ * AWS Organisations Policy construct for managing policies
6
+ */
7
+ export declare class Policy extends Construct implements IPolicy {
8
+ readonly policyId: string;
9
+ readonly policyArn: string;
10
+ readonly policyName: string;
11
+ readonly policyType: PolicyType;
12
+ constructor(scope: Construct, id: string, props: PolicyProps);
13
+ /**
14
+ * Helper to normalize policy names for construct IDs
15
+ */
16
+ private normalizePolicyName;
17
+ }