@beesolve/aws-accounts 1.1.0 → 1.2.1

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.
@@ -1,13 +1,24 @@
1
- import { PutAccountNameCommand } from "@aws-sdk/client-account";
2
1
  import {
2
+ DeleteAlternateContactCommand,
3
+ PutAccountNameCommand,
4
+ PutAlternateContactCommand
5
+ } from "@aws-sdk/client-account";
6
+ import {
7
+ AttachPolicyCommand,
3
8
  CreateOrganizationalUnitCommand,
9
+ CreatePolicyCommand,
10
+ DeregisterDelegatedAdministratorCommand,
4
11
  DeleteOrganizationalUnitCommand,
12
+ DeletePolicyCommand,
13
+ DetachPolicyCommand,
5
14
  ListAccountsForParentCommand,
6
15
  ListOrganizationalUnitsForParentCommand,
7
16
  MoveAccountCommand,
17
+ RegisterDelegatedAdministratorCommand,
8
18
  TagResourceCommand,
9
19
  UntagResourceCommand,
10
- UpdateOrganizationalUnitCommand
20
+ UpdateOrganizationalUnitCommand,
21
+ UpdatePolicyCommand
11
22
  } from "@aws-sdk/client-organizations";
12
23
  import {
13
24
  CreateGroupMembershipCommand,
@@ -27,6 +38,7 @@ import {
27
38
  CreatePermissionSetCommand,
28
39
  DeleteAccountAssignmentCommand,
29
40
  DeleteInlinePolicyFromPermissionSetCommand,
41
+ DeletePermissionsBoundaryFromPermissionSetCommand,
30
42
  DeletePermissionSetCommand,
31
43
  DescribeAccountAssignmentCreationStatusCommand,
32
44
  DescribeAccountAssignmentDeletionStatusCommand,
@@ -35,6 +47,8 @@ import {
35
47
  DetachManagedPolicyFromPermissionSetCommand,
36
48
  ProvisionPermissionSetCommand,
37
49
  PutInlinePolicyToPermissionSetCommand,
50
+ PutPermissionsBoundaryToPermissionSetCommand,
51
+ UpdateInstanceAccessControlAttributeConfigurationCommand,
38
52
  UpdatePermissionSetCommand
39
53
  } from "@aws-sdk/client-sso-admin";
40
54
  import { createAccountAndMoveToOu } from "./accountCreation.js";
@@ -42,55 +56,60 @@ import { assertUnreachable, delay } from "./helpers.js";
42
56
  import {
43
57
  addGroupMembershipToWorkingState,
44
58
  addAccountAssignmentToWorkingState,
59
+ addOrgPolicyAttachmentToWorkingState,
45
60
  createGroupMembershipKey,
46
61
  moveAccountInWorkingState,
47
62
  removeAccountAssignmentFromWorkingState,
63
+ removeDelegatedAdministratorFromWorkingState,
48
64
  removeGroupMembershipFromWorkingState,
49
65
  removeIdcGroupFromWorkingState,
50
66
  removeIdcPermissionSetFromWorkingState,
51
67
  removeIdcUserFromWorkingState,
52
68
  removeOrganizationalUnitFromWorkingState,
69
+ removeOrgPolicyAttachmentFromWorkingState,
70
+ removeOrgPolicyFromWorkingState,
53
71
  renameOrganizationalUnitInWorkingState,
72
+ upsertDelegatedAdministratorInWorkingState,
54
73
  upsertIdcGroupInWorkingState,
55
74
  upsertIdcPermissionSetInWorkingState,
56
75
  upsertIdcUserInWorkingState,
57
76
  upsertAccountInWorkingState,
58
- upsertOrganizationalUnitInWorkingState
77
+ upsertOrganizationalUnitInWorkingState,
78
+ upsertOrgPolicyInWorkingState
59
79
  } from "./state.js";
60
80
  async function executeOperation(props) {
61
- const operation = props.operation;
62
- if (operation.kind === "moveAccount") {
81
+ if (props.operation.kind === "moveAccount") {
63
82
  props.logger.log(
64
- `Moving "${operation.accountName}" (${operation.accountId}): ${operation.fromOuName} -> ${operation.toOuName}`
83
+ `Moving "${props.operation.accountName}" (${props.operation.accountId}): ${props.operation.fromOuName} -> ${props.operation.toOuName}`
65
84
  );
66
85
  await props.organizationsClient.send(
67
86
  new MoveAccountCommand({
68
- AccountId: operation.accountId,
69
- SourceParentId: operation.fromOuId,
70
- DestinationParentId: operation.toOuId
87
+ AccountId: props.operation.accountId,
88
+ SourceParentId: props.operation.fromOuId,
89
+ DestinationParentId: props.operation.toOuId
71
90
  })
72
91
  );
73
- props.logger.log(`Done: "${operation.accountName}"`);
92
+ props.logger.log(`Done: "${props.operation.accountName}"`);
74
93
  return moveAccountInWorkingState({
75
94
  workingState: props.state,
76
- accountId: operation.accountId,
77
- parentId: operation.toOuId
95
+ accountId: props.operation.accountId,
96
+ parentId: props.operation.toOuId
78
97
  });
79
98
  }
80
- if (operation.kind === "createOu") {
99
+ if (props.operation.kind === "createOu") {
81
100
  props.logger.log(
82
- `Creating OU "${operation.ouName}" under ${operation.parentOuName}...`
101
+ `Creating OU "${props.operation.ouName}" under ${props.operation.parentOuName}...`
83
102
  );
84
103
  const response = await props.organizationsClient.send(
85
104
  new CreateOrganizationalUnitCommand({
86
- ParentId: operation.parentOuId,
87
- Name: operation.ouName
105
+ ParentId: props.operation.parentOuId,
106
+ Name: props.operation.ouName
88
107
  })
89
108
  );
90
109
  const createdOu = response.OrganizationalUnit;
91
110
  if (createdOu?.Id == null || createdOu.Arn == null || createdOu.Name == null) {
92
111
  throw new Error(
93
- `CreateOrganizationalUnit for "${operation.ouName}" returned incomplete OU data.`
112
+ `CreateOrganizationalUnit for "${props.operation.ouName}" returned incomplete OU data.`
94
113
  );
95
114
  }
96
115
  props.logger.log(`Done: "${createdOu.Name}"`);
@@ -98,55 +117,55 @@ async function executeOperation(props) {
98
117
  workingState: props.state,
99
118
  organizationalUnit: {
100
119
  id: createdOu.Id,
101
- parentId: operation.parentOuId,
120
+ parentId: props.operation.parentOuId,
102
121
  arn: createdOu.Arn,
103
122
  name: createdOu.Name
104
123
  }
105
124
  });
106
125
  }
107
- if (operation.kind === "renameOu") {
126
+ if (props.operation.kind === "renameOu") {
108
127
  props.logger.log(
109
- `Renaming OU "${operation.fromOuName}" -> "${operation.toOuName}"...`
128
+ `Renaming OU "${props.operation.fromOuName}" -> "${props.operation.toOuName}"...`
110
129
  );
111
130
  await props.organizationsClient.send(
112
131
  new UpdateOrganizationalUnitCommand({
113
- OrganizationalUnitId: operation.ouId,
114
- Name: operation.toOuName
132
+ OrganizationalUnitId: props.operation.ouId,
133
+ Name: props.operation.toOuName
115
134
  })
116
135
  );
117
- props.logger.log(`Done: "${operation.toOuName}"`);
136
+ props.logger.log(`Done: "${props.operation.toOuName}"`);
118
137
  return renameOrganizationalUnitInWorkingState({
119
138
  workingState: props.state,
120
- organizationalUnitId: operation.ouId,
121
- name: operation.toOuName
139
+ organizationalUnitId: props.operation.ouId,
140
+ name: props.operation.toOuName
122
141
  });
123
142
  }
124
- if (operation.kind === "deleteOu") {
125
- props.logger.log(`Deleting OU "${operation.ouName}"...`);
143
+ if (props.operation.kind === "deleteOu") {
144
+ props.logger.log(`Deleting OU "${props.operation.ouName}"...`);
126
145
  await assertOrganizationalUnitIsEmpty({
127
146
  organizationsClient: props.organizationsClient,
128
- organizationalUnitId: operation.ouId,
129
- organizationalUnitName: operation.ouName
147
+ organizationalUnitId: props.operation.ouId,
148
+ organizationalUnitName: props.operation.ouName
130
149
  });
131
150
  await props.organizationsClient.send(
132
151
  new DeleteOrganizationalUnitCommand({
133
- OrganizationalUnitId: operation.ouId
152
+ OrganizationalUnitId: props.operation.ouId
134
153
  })
135
154
  );
136
- props.logger.log(`Done: "${operation.ouName}"`);
155
+ props.logger.log(`Done: "${props.operation.ouName}"`);
137
156
  return removeOrganizationalUnitFromWorkingState({
138
157
  workingState: props.state,
139
- organizationalUnitId: operation.ouId
158
+ organizationalUnitId: props.operation.ouId
140
159
  });
141
160
  }
142
- if (operation.kind === "createAccount") {
161
+ if (props.operation.kind === "createAccount") {
143
162
  const result = await createAccountAndMoveToOu({
144
163
  organizationsClient: props.organizationsClient,
145
164
  logger: props.logger,
146
- accountName: operation.accountName,
147
- accountEmail: operation.accountEmail,
165
+ accountName: props.operation.accountName,
166
+ accountEmail: props.operation.accountEmail,
148
167
  sourceParentId: props.context.organization.rootId,
149
- destinationParentId: operation.targetOuId,
168
+ destinationParentId: props.operation.targetOuId,
150
169
  timeoutInMs: props.runtime.createAccount.timeoutInMs,
151
170
  pollIntervalInMs: props.runtime.createAccount.pollIntervalInMs
152
171
  });
@@ -158,33 +177,33 @@ async function executeOperation(props) {
158
177
  name: result.account.name,
159
178
  email: result.account.email,
160
179
  status: result.account.status,
161
- parentId: operation.targetOuId,
180
+ parentId: props.operation.targetOuId,
162
181
  tags: []
163
182
  }
164
183
  });
165
184
  }
166
- if (operation.kind === "updateAccountTags") {
167
- const account = props.state.organization.accountsById[operation.accountId];
185
+ if (props.operation.kind === "updateAccountTags") {
186
+ const account = props.state.organization.accountsById[props.operation.accountId];
168
187
  if (account == null) {
169
188
  throw new Error(
170
- `Could not resolve account "${operation.accountName}" (${operation.accountId}) in working state.`
189
+ `Could not resolve account "${props.operation.accountName}" (${props.operation.accountId}) in working state.`
171
190
  );
172
191
  }
173
192
  const currentTags = new Map(
174
193
  (account.tags ?? []).map((tag) => [tag.key, tag.value])
175
194
  );
176
- const desiredTags = new Map(Object.entries(operation.tags));
195
+ const desiredTags = new Map(Object.entries(props.operation.tags));
177
196
  const tagsToApply = [...desiredTags.entries()].filter(([key, value]) => currentTags.get(key) !== value).map(([Key, Value]) => ({ Key, Value }));
178
197
  const tagKeysToRemove = [...currentTags.keys()].filter(
179
198
  (key) => desiredTags.has(key) === false
180
199
  );
181
200
  props.logger.log(
182
- `Updating account tags "${operation.accountName}" (${operation.accountId})...`
201
+ `Updating account tags "${props.operation.accountName}" (${props.operation.accountId})...`
183
202
  );
184
203
  if (tagsToApply.length > 0) {
185
204
  await props.organizationsClient.send(
186
205
  new TagResourceCommand({
187
- ResourceId: operation.accountId,
206
+ ResourceId: props.operation.accountId,
188
207
  Tags: tagsToApply
189
208
  })
190
209
  );
@@ -192,84 +211,84 @@ async function executeOperation(props) {
192
211
  if (tagKeysToRemove.length > 0) {
193
212
  await props.organizationsClient.send(
194
213
  new UntagResourceCommand({
195
- ResourceId: operation.accountId,
214
+ ResourceId: props.operation.accountId,
196
215
  TagKeys: tagKeysToRemove
197
216
  })
198
217
  );
199
218
  }
200
- props.logger.log(`Done: tags updated for "${operation.accountName}"`);
219
+ props.logger.log(`Done: tags updated for "${props.operation.accountName}"`);
201
220
  return upsertAccountInWorkingState({
202
221
  workingState: props.state,
203
222
  account: {
204
223
  ...account,
205
- tags: Object.entries(operation.tags).map(([key, value]) => ({
224
+ tags: Object.entries(props.operation.tags).map(([key, value]) => ({
206
225
  key,
207
226
  value
208
227
  }))
209
228
  }
210
229
  });
211
230
  }
212
- if (operation.kind === "updateAccountName") {
231
+ if (props.operation.kind === "updateAccountName") {
213
232
  props.logger.log(
214
- `Renaming account (${operation.accountId}): "${operation.fromAccountName}" -> "${operation.toAccountName}"...`
233
+ `Renaming account (${props.operation.accountId}): "${props.operation.fromAccountName}" -> "${props.operation.toAccountName}"...`
215
234
  );
216
235
  await props.accountClient.send(
217
236
  new PutAccountNameCommand({
218
- AccountId: operation.accountId,
219
- AccountName: operation.toAccountName
237
+ AccountId: props.operation.accountId,
238
+ AccountName: props.operation.toAccountName
220
239
  })
221
240
  );
222
241
  props.logger.log(
223
- `Done: account "${operation.toAccountName}" (${operation.accountId})`
242
+ `Done: account "${props.operation.toAccountName}" (${props.operation.accountId})`
224
243
  );
225
- const account = props.state.organization.accountsById[operation.accountId];
244
+ const account = props.state.organization.accountsById[props.operation.accountId];
226
245
  if (account == null) {
227
246
  throw new Error(
228
- `Could not resolve account (${operation.accountId}) in working state after rename.`
247
+ `Could not resolve account (${props.operation.accountId}) in working state after rename.`
229
248
  );
230
249
  }
231
250
  return upsertAccountInWorkingState({
232
251
  workingState: props.state,
233
252
  account: {
234
253
  ...account,
235
- name: operation.toAccountName
254
+ name: props.operation.toAccountName
236
255
  }
237
256
  });
238
257
  }
239
- if (operation.kind === "removeAccount") {
258
+ if (props.operation.kind === "removeAccount") {
240
259
  props.logger.log(
241
- `Moving removed account "${operation.accountName}" (${operation.accountId}) to ${operation.toOuName}...`
260
+ `Moving removed account "${props.operation.accountName}" (${props.operation.accountId}) to ${props.operation.toOuName}...`
242
261
  );
243
262
  await props.organizationsClient.send(
244
263
  new MoveAccountCommand({
245
- AccountId: operation.accountId,
246
- SourceParentId: operation.fromOuId,
247
- DestinationParentId: operation.toOuId
264
+ AccountId: props.operation.accountId,
265
+ SourceParentId: props.operation.fromOuId,
266
+ DestinationParentId: props.operation.toOuId
248
267
  })
249
268
  );
250
269
  props.logger.log(
251
- `Done: "${operation.accountName}" -> ${operation.toOuName}`
270
+ `Done: "${props.operation.accountName}" -> ${props.operation.toOuName}`
252
271
  );
253
272
  return moveAccountInWorkingState({
254
273
  workingState: props.state,
255
- accountId: operation.accountId,
256
- parentId: operation.toOuId
274
+ accountId: props.operation.accountId,
275
+ parentId: props.operation.toOuId
257
276
  });
258
277
  }
259
- if (operation.kind === "createIdcUser") {
260
- props.logger.log(`Creating IdC user "${operation.userName}"...`);
278
+ if (props.operation.kind === "createIdcUser") {
279
+ props.logger.log(`Creating IdC user "${props.operation.userName}"...`);
261
280
  const response = await props.identityStoreClient.send(
262
281
  new CreateUserCommand({
263
282
  IdentityStoreId: props.state.identityCenter.identityStoreId,
264
- UserName: operation.userName,
265
- DisplayName: operation.displayName,
283
+ UserName: props.operation.userName,
284
+ DisplayName: props.operation.displayName,
266
285
  Name: buildIdentityStoreUserName({
267
- userName: operation.userName,
268
- displayName: operation.displayName
286
+ userName: props.operation.userName,
287
+ displayName: props.operation.displayName
269
288
  }),
270
- Emails: operation.email.length > 0 ? [
289
+ Emails: props.operation.email.length > 0 ? [
271
290
  {
272
- Value: operation.email,
291
+ Value: props.operation.email,
273
292
  Type: "Work",
274
293
  Primary: true
275
294
  }
@@ -278,45 +297,45 @@ async function executeOperation(props) {
278
297
  );
279
298
  if (response.UserId == null) {
280
299
  throw new Error(
281
- `CreateUser for "${operation.userName}" returned no user id.`
300
+ `CreateUser for "${props.operation.userName}" returned no user id.`
282
301
  );
283
302
  }
284
- props.logger.log(`Done: "${operation.userName}"`);
303
+ props.logger.log(`Done: "${props.operation.userName}"`);
285
304
  return upsertIdcUserInWorkingState({
286
305
  workingState: props.state,
287
306
  user: {
288
307
  userId: response.UserId,
289
- userName: operation.userName,
290
- displayName: operation.displayName,
291
- email: operation.email
308
+ userName: props.operation.userName,
309
+ displayName: props.operation.displayName,
310
+ email: props.operation.email
292
311
  }
293
312
  });
294
313
  }
295
- if (operation.kind === "updateIdcUser") {
314
+ if (props.operation.kind === "updateIdcUser") {
296
315
  const user = resolveUserByName({
297
316
  state: props.state,
298
- userName: operation.userName
317
+ userName: props.operation.userName
299
318
  });
300
319
  const operations = [];
301
- if (user.displayName !== operation.displayName) {
320
+ if (user.displayName !== props.operation.displayName) {
302
321
  operations.push({
303
322
  AttributePath: "displayName",
304
- AttributeValue: operation.displayName
323
+ AttributeValue: props.operation.displayName
305
324
  });
306
325
  operations.push({
307
326
  AttributePath: "name",
308
327
  AttributeValue: buildIdentityStoreUserName({
309
- userName: operation.userName,
310
- displayName: operation.displayName
328
+ userName: props.operation.userName,
329
+ displayName: props.operation.displayName
311
330
  })
312
331
  });
313
332
  }
314
- if (user.email !== operation.email && operation.email.length > 0) {
333
+ if (user.email !== props.operation.email && props.operation.email.length > 0) {
315
334
  operations.push({
316
335
  AttributePath: "emails",
317
336
  AttributeValue: [
318
337
  {
319
- Value: operation.email,
338
+ Value: props.operation.email,
320
339
  Type: "Work",
321
340
  Primary: true
322
341
  }
@@ -326,7 +345,7 @@ async function executeOperation(props) {
326
345
  if (operations.length === 0) {
327
346
  return props.state;
328
347
  }
329
- props.logger.log(`Updating IdC user "${operation.userName}"...`);
348
+ props.logger.log(`Updating IdC user "${props.operation.userName}"...`);
330
349
  await props.identityStoreClient.send(
331
350
  new UpdateUserCommand({
332
351
  IdentityStoreId: props.state.identityCenter.identityStoreId,
@@ -334,65 +353,65 @@ async function executeOperation(props) {
334
353
  Operations: operations
335
354
  })
336
355
  );
337
- props.logger.log(`Done: "${operation.userName}"`);
356
+ props.logger.log(`Done: "${props.operation.userName}"`);
338
357
  return upsertIdcUserInWorkingState({
339
358
  workingState: props.state,
340
359
  user: {
341
360
  ...user,
342
- displayName: operation.displayName,
343
- email: operation.email.length > 0 ? operation.email : user.email
361
+ displayName: props.operation.displayName,
362
+ email: props.operation.email.length > 0 ? props.operation.email : user.email
344
363
  }
345
364
  });
346
365
  }
347
- if (operation.kind === "deleteIdcUser") {
366
+ if (props.operation.kind === "deleteIdcUser") {
348
367
  const user = resolveUserByName({
349
368
  state: props.state,
350
- userName: operation.userName
369
+ userName: props.operation.userName
351
370
  });
352
- props.logger.log(`Deleting IdC user "${operation.userName}"...`);
371
+ props.logger.log(`Deleting IdC user "${props.operation.userName}"...`);
353
372
  await props.identityStoreClient.send(
354
373
  new DeleteUserCommand({
355
374
  IdentityStoreId: props.state.identityCenter.identityStoreId,
356
375
  UserId: user.userId
357
376
  })
358
377
  );
359
- props.logger.log(`Done: "${operation.userName}"`);
378
+ props.logger.log(`Done: "${props.operation.userName}"`);
360
379
  return removeIdcUserFromWorkingState({
361
380
  workingState: props.state,
362
- userName: operation.userName
381
+ userName: props.operation.userName
363
382
  });
364
383
  }
365
- if (operation.kind === "createIdcGroup") {
366
- props.logger.log(`Creating IdC group "${operation.groupDisplayName}"...`);
384
+ if (props.operation.kind === "createIdcGroup") {
385
+ props.logger.log(`Creating IdC group "${props.operation.groupDisplayName}"...`);
367
386
  const response = await props.identityStoreClient.send(
368
387
  new CreateGroupCommand({
369
388
  IdentityStoreId: props.state.identityCenter.identityStoreId,
370
- DisplayName: operation.groupDisplayName,
371
- Description: operation.description.trim().length > 0 ? operation.description : void 0
389
+ DisplayName: props.operation.groupDisplayName,
390
+ Description: props.operation.description.trim().length > 0 ? props.operation.description : void 0
372
391
  })
373
392
  );
374
393
  if (response.GroupId == null) {
375
394
  throw new Error(
376
- `CreateGroup for "${operation.groupDisplayName}" returned no group id.`
395
+ `CreateGroup for "${props.operation.groupDisplayName}" returned no group id.`
377
396
  );
378
397
  }
379
- props.logger.log(`Done: "${operation.groupDisplayName}"`);
398
+ props.logger.log(`Done: "${props.operation.groupDisplayName}"`);
380
399
  return upsertIdcGroupInWorkingState({
381
400
  workingState: props.state,
382
401
  group: {
383
402
  groupId: response.GroupId,
384
- displayName: operation.groupDisplayName,
385
- description: operation.description
403
+ displayName: props.operation.groupDisplayName,
404
+ description: props.operation.description
386
405
  }
387
406
  });
388
407
  }
389
- if (operation.kind === "updateIdcGroupDescription") {
408
+ if (props.operation.kind === "updateIdcGroupDescription") {
390
409
  const group = resolveGroupByDisplayName({
391
410
  state: props.state,
392
- groupDisplayName: operation.groupDisplayName
411
+ groupDisplayName: props.operation.groupDisplayName
393
412
  });
394
413
  props.logger.log(
395
- `Updating IdC group description for "${operation.groupDisplayName}"...`
414
+ `Updating IdC group description for "${props.operation.groupDisplayName}"...`
396
415
  );
397
416
  await props.identityStoreClient.send(
398
417
  new UpdateGroupCommand({
@@ -401,46 +420,46 @@ async function executeOperation(props) {
401
420
  Operations: [
402
421
  {
403
422
  AttributePath: "description",
404
- AttributeValue: operation.description
423
+ AttributeValue: props.operation.description
405
424
  }
406
425
  ]
407
426
  })
408
427
  );
409
- props.logger.log(`Done: group "${operation.groupDisplayName}"`);
428
+ props.logger.log(`Done: group "${props.operation.groupDisplayName}"`);
410
429
  return upsertIdcGroupInWorkingState({
411
430
  workingState: props.state,
412
431
  group: {
413
432
  ...group,
414
- description: operation.description
433
+ description: props.operation.description
415
434
  }
416
435
  });
417
436
  }
418
- if (operation.kind === "deleteIdcGroup") {
437
+ if (props.operation.kind === "deleteIdcGroup") {
419
438
  const group = resolveGroupByDisplayName({
420
439
  state: props.state,
421
- groupDisplayName: operation.groupDisplayName
440
+ groupDisplayName: props.operation.groupDisplayName
422
441
  });
423
- props.logger.log(`Deleting IdC group "${operation.groupDisplayName}"...`);
442
+ props.logger.log(`Deleting IdC group "${props.operation.groupDisplayName}"...`);
424
443
  await props.identityStoreClient.send(
425
444
  new DeleteGroupCommand({
426
445
  IdentityStoreId: props.state.identityCenter.identityStoreId,
427
446
  GroupId: group.groupId
428
447
  })
429
448
  );
430
- props.logger.log(`Done: "${operation.groupDisplayName}"`);
449
+ props.logger.log(`Done: "${props.operation.groupDisplayName}"`);
431
450
  return removeIdcGroupFromWorkingState({
432
451
  workingState: props.state,
433
- groupDisplayName: operation.groupDisplayName
452
+ groupDisplayName: props.operation.groupDisplayName
434
453
  });
435
454
  }
436
- if (operation.kind === "addIdcGroupMembership") {
455
+ if (props.operation.kind === "addIdcGroupMembership") {
437
456
  const resolvedMembership = resolveGroupMembershipDependencies({
438
457
  state: props.state,
439
- groupDisplayName: operation.groupDisplayName,
440
- userName: operation.userName
458
+ groupDisplayName: props.operation.groupDisplayName,
459
+ userName: props.operation.userName
441
460
  });
442
461
  props.logger.log(
443
- `Adding user "${operation.userName}" to IdC group "${operation.groupDisplayName}"...`
462
+ `Adding user "${props.operation.userName}" to IdC group "${props.operation.groupDisplayName}"...`
444
463
  );
445
464
  const response = await props.identityStoreClient.send(
446
465
  new CreateGroupMembershipCommand({
@@ -453,11 +472,11 @@ async function executeOperation(props) {
453
472
  );
454
473
  if (response.MembershipId == null) {
455
474
  throw new Error(
456
- `CreateGroupMembership for group "${operation.groupDisplayName}" and user "${operation.userName}" returned no membership id.`
475
+ `CreateGroupMembership for group "${props.operation.groupDisplayName}" and user "${props.operation.userName}" returned no membership id.`
457
476
  );
458
477
  }
459
478
  props.logger.log(
460
- `Done: user "${operation.userName}" -> group "${operation.groupDisplayName}"`
479
+ `Done: user "${props.operation.userName}" -> group "${props.operation.groupDisplayName}"`
461
480
  );
462
481
  return addGroupMembershipToWorkingState({
463
482
  workingState: props.state,
@@ -468,93 +487,94 @@ async function executeOperation(props) {
468
487
  }
469
488
  });
470
489
  }
471
- if (operation.kind === "createIdcPermissionSet") {
490
+ if (props.operation.kind === "createIdcPermissionSet") {
472
491
  props.logger.log(
473
- `Creating IdC permission set "${operation.permissionSetName}"...`
492
+ `Creating IdC permission set "${props.operation.permissionSetName}"...`
474
493
  );
475
494
  const response = await props.ssoAdminClient.send(
476
495
  new CreatePermissionSetCommand({
477
496
  InstanceArn: props.state.identityCenter.instanceArn,
478
- Name: operation.permissionSetName,
479
- Description: operation.description.length > 0 ? operation.description : void 0,
480
- SessionDuration: operation.sessionDuration ?? void 0
497
+ Name: props.operation.permissionSetName,
498
+ Description: props.operation.description.length > 0 ? props.operation.description : void 0,
499
+ SessionDuration: props.operation.sessionDuration ?? void 0
481
500
  })
482
501
  );
483
502
  const permissionSetArn = response.PermissionSet?.PermissionSetArn;
484
503
  if (permissionSetArn == null) {
485
504
  throw new Error(
486
- `CreatePermissionSet for "${operation.permissionSetName}" returned no permission set arn.`
505
+ `CreatePermissionSet for "${props.operation.permissionSetName}" returned no permission set arn.`
487
506
  );
488
507
  }
489
- props.logger.log(`Done: "${operation.permissionSetName}"`);
508
+ props.logger.log(`Done: "${props.operation.permissionSetName}"`);
490
509
  return upsertIdcPermissionSetInWorkingState({
491
510
  workingState: props.state,
492
511
  permissionSet: {
493
512
  permissionSetArn,
494
- name: operation.permissionSetName,
495
- description: operation.description,
496
- sessionDuration: operation.sessionDuration,
513
+ name: props.operation.permissionSetName,
514
+ description: props.operation.description,
515
+ sessionDuration: props.operation.sessionDuration,
497
516
  inlinePolicy: null,
498
517
  awsManagedPolicies: [],
499
- customerManagedPolicies: []
518
+ customerManagedPolicies: [],
519
+ permissionsBoundary: null
500
520
  }
501
521
  });
502
522
  }
503
- if (operation.kind === "updateIdcPermissionSetDescription") {
523
+ if (props.operation.kind === "updateIdcPermissionSetDescription") {
504
524
  const permissionSet = resolvePermissionSetByName({
505
525
  state: props.state,
506
- permissionSetName: operation.permissionSetName
526
+ permissionSetName: props.operation.permissionSetName
507
527
  });
508
528
  props.logger.log(
509
- `Updating IdC permission set description for "${operation.permissionSetName}"...`
529
+ `Updating IdC permission set description for "${props.operation.permissionSetName}"...`
510
530
  );
511
531
  await props.ssoAdminClient.send(
512
532
  new UpdatePermissionSetCommand({
513
533
  InstanceArn: props.state.identityCenter.instanceArn,
514
534
  PermissionSetArn: permissionSet.permissionSetArn,
515
- Description: operation.description.trim().length > 0 ? operation.description : void 0
535
+ Description: props.operation.description.trim().length > 0 ? props.operation.description : void 0
516
536
  })
517
537
  );
518
- props.logger.log(`Done: "${operation.permissionSetName}"`);
538
+ props.logger.log(`Done: "${props.operation.permissionSetName}"`);
519
539
  return upsertIdcPermissionSetInWorkingState({
520
540
  workingState: props.state,
521
541
  permissionSet: {
522
542
  ...permissionSet,
523
- description: operation.description
543
+ description: props.operation.description
524
544
  }
525
545
  });
526
546
  }
527
- if (operation.kind === "updateIdcPermissionSetSessionDuration") {
547
+ if (props.operation.kind === "updateIdcPermissionSetSessionDuration") {
528
548
  const permissionSet = resolvePermissionSetByName({
529
549
  state: props.state,
530
- permissionSetName: operation.permissionSetName
550
+ permissionSetName: props.operation.permissionSetName
531
551
  });
532
552
  props.logger.log(
533
- `Updating IdC permission set session duration for "${operation.permissionSetName}"...`
553
+ `Updating IdC permission set session duration for "${props.operation.permissionSetName}"...`
534
554
  );
535
555
  await props.ssoAdminClient.send(
536
556
  new UpdatePermissionSetCommand({
537
557
  InstanceArn: props.state.identityCenter.instanceArn,
538
558
  PermissionSetArn: permissionSet.permissionSetArn,
539
- SessionDuration: operation.sessionDuration ?? void 0
559
+ SessionDuration: props.operation.sessionDuration ?? void 0
540
560
  })
541
561
  );
542
- props.logger.log(`Done: "${operation.permissionSetName}"`);
562
+ props.logger.log(`Done: "${props.operation.permissionSetName}"`);
543
563
  return upsertIdcPermissionSetInWorkingState({
544
564
  workingState: props.state,
545
565
  permissionSet: {
546
566
  ...permissionSet,
547
- sessionDuration: operation.sessionDuration
567
+ sessionDuration: props.operation.sessionDuration
548
568
  }
549
569
  });
550
570
  }
551
- if (operation.kind === "deleteIdcPermissionSet") {
571
+ if (props.operation.kind === "deleteIdcPermissionSet") {
552
572
  const permissionSet = resolvePermissionSetByName({
553
573
  state: props.state,
554
- permissionSetName: operation.permissionSetName
574
+ permissionSetName: props.operation.permissionSetName
555
575
  });
556
576
  props.logger.log(
557
- `Deleting IdC permission set "${operation.permissionSetName}"...`
577
+ `Deleting IdC permission set "${props.operation.permissionSetName}"...`
558
578
  );
559
579
  await props.ssoAdminClient.send(
560
580
  new DeletePermissionSetCommand({
@@ -562,44 +582,45 @@ async function executeOperation(props) {
562
582
  PermissionSetArn: permissionSet.permissionSetArn
563
583
  })
564
584
  );
565
- props.logger.log(`Done: "${operation.permissionSetName}"`);
585
+ props.logger.log(`Done: "${props.operation.permissionSetName}"`);
566
586
  return removeIdcPermissionSetFromWorkingState({
567
587
  workingState: props.state,
568
- permissionSetName: operation.permissionSetName
588
+ permissionSetName: props.operation.permissionSetName
569
589
  });
570
590
  }
571
- if (operation.kind === "putIdcPermissionSetInlinePolicy") {
591
+ if (props.operation.kind === "putIdcPermissionSetInlinePolicy") {
592
+ const { inlinePolicy } = props.operation;
572
593
  const permissionSet = resolvePermissionSetByName({
573
594
  state: props.state,
574
- permissionSetName: operation.permissionSetName
595
+ permissionSetName: props.operation.permissionSetName
575
596
  });
576
597
  props.logger.log(
577
- `Putting inline policy on IdC permission set "${operation.permissionSetName}"...`
598
+ `Putting inline policy on IdC permission set "${props.operation.permissionSetName}"...`
578
599
  );
579
600
  await props.ssoAdminClient.send(
580
601
  new PutInlinePolicyToPermissionSetCommand({
581
602
  InstanceArn: props.state.identityCenter.instanceArn,
582
603
  PermissionSetArn: permissionSet.permissionSetArn,
583
- InlinePolicy: operation.inlinePolicy
604
+ InlinePolicy: inlinePolicy
584
605
  })
585
606
  );
586
- props.logger.log(`Done: "${operation.permissionSetName}"`);
607
+ props.logger.log(`Done: "${props.operation.permissionSetName}"`);
587
608
  return upsertPermissionSetPolicyState({
588
609
  state: props.state,
589
- permissionSetName: operation.permissionSetName,
610
+ permissionSetName: props.operation.permissionSetName,
590
611
  update: (currentPermissionSet) => ({
591
612
  ...currentPermissionSet,
592
- inlinePolicy: operation.inlinePolicy
613
+ inlinePolicy
593
614
  })
594
615
  });
595
616
  }
596
- if (operation.kind === "deleteIdcPermissionSetInlinePolicy") {
617
+ if (props.operation.kind === "deleteIdcPermissionSetInlinePolicy") {
597
618
  const permissionSet = resolvePermissionSetByName({
598
619
  state: props.state,
599
- permissionSetName: operation.permissionSetName
620
+ permissionSetName: props.operation.permissionSetName
600
621
  });
601
622
  props.logger.log(
602
- `Deleting inline policy from IdC permission set "${operation.permissionSetName}"...`
623
+ `Deleting inline policy from IdC permission set "${props.operation.permissionSetName}"...`
603
624
  );
604
625
  await props.ssoAdminClient.send(
605
626
  new DeleteInlinePolicyFromPermissionSetCommand({
@@ -607,154 +628,158 @@ async function executeOperation(props) {
607
628
  PermissionSetArn: permissionSet.permissionSetArn
608
629
  })
609
630
  );
610
- props.logger.log(`Done: "${operation.permissionSetName}"`);
631
+ props.logger.log(`Done: "${props.operation.permissionSetName}"`);
611
632
  return upsertPermissionSetPolicyState({
612
633
  state: props.state,
613
- permissionSetName: operation.permissionSetName,
634
+ permissionSetName: props.operation.permissionSetName,
614
635
  update: (currentPermissionSet) => ({
615
636
  ...currentPermissionSet,
616
637
  inlinePolicy: null
617
638
  })
618
639
  });
619
640
  }
620
- if (operation.kind === "attachIdcManagedPolicyToPermissionSet") {
641
+ if (props.operation.kind === "attachIdcManagedPolicyToPermissionSet") {
642
+ const { managedPolicyArn } = props.operation;
621
643
  const permissionSet = resolvePermissionSetByName({
622
644
  state: props.state,
623
- permissionSetName: operation.permissionSetName
645
+ permissionSetName: props.operation.permissionSetName
624
646
  });
625
647
  props.logger.log(
626
- `Attaching managed policy "${operation.managedPolicyArn}" to IdC permission set "${operation.permissionSetName}"...`
648
+ `Attaching managed policy "${managedPolicyArn}" to IdC permission set "${props.operation.permissionSetName}"...`
627
649
  );
628
650
  await props.ssoAdminClient.send(
629
651
  new AttachManagedPolicyToPermissionSetCommand({
630
652
  InstanceArn: props.state.identityCenter.instanceArn,
631
653
  PermissionSetArn: permissionSet.permissionSetArn,
632
- ManagedPolicyArn: operation.managedPolicyArn
654
+ ManagedPolicyArn: managedPolicyArn
633
655
  })
634
656
  );
635
- props.logger.log(`Done: "${operation.permissionSetName}"`);
657
+ props.logger.log(`Done: "${props.operation.permissionSetName}"`);
636
658
  return upsertPermissionSetPolicyState({
637
659
  state: props.state,
638
- permissionSetName: operation.permissionSetName,
660
+ permissionSetName: props.operation.permissionSetName,
639
661
  update: (currentPermissionSet) => ({
640
662
  ...currentPermissionSet,
641
663
  awsManagedPolicies: [
642
664
  ...currentPermissionSet.awsManagedPolicies,
643
- operation.managedPolicyArn
665
+ managedPolicyArn
644
666
  ]
645
667
  })
646
668
  });
647
669
  }
648
- if (operation.kind === "detachIdcManagedPolicyFromPermissionSet") {
670
+ if (props.operation.kind === "detachIdcManagedPolicyFromPermissionSet") {
671
+ const { managedPolicyArn } = props.operation;
649
672
  const permissionSet = resolvePermissionSetByName({
650
673
  state: props.state,
651
- permissionSetName: operation.permissionSetName
674
+ permissionSetName: props.operation.permissionSetName
652
675
  });
653
676
  props.logger.log(
654
- `Detaching managed policy "${operation.managedPolicyArn}" from IdC permission set "${operation.permissionSetName}"...`
677
+ `Detaching managed policy "${managedPolicyArn}" from IdC permission set "${props.operation.permissionSetName}"...`
655
678
  );
656
679
  await props.ssoAdminClient.send(
657
680
  new DetachManagedPolicyFromPermissionSetCommand({
658
681
  InstanceArn: props.state.identityCenter.instanceArn,
659
682
  PermissionSetArn: permissionSet.permissionSetArn,
660
- ManagedPolicyArn: operation.managedPolicyArn
683
+ ManagedPolicyArn: managedPolicyArn
661
684
  })
662
685
  );
663
- props.logger.log(`Done: "${operation.permissionSetName}"`);
686
+ props.logger.log(`Done: "${props.operation.permissionSetName}"`);
664
687
  return upsertPermissionSetPolicyState({
665
688
  state: props.state,
666
- permissionSetName: operation.permissionSetName,
689
+ permissionSetName: props.operation.permissionSetName,
667
690
  update: (currentPermissionSet) => ({
668
691
  ...currentPermissionSet,
669
692
  awsManagedPolicies: currentPermissionSet.awsManagedPolicies.filter(
670
- (managedPolicyArn) => managedPolicyArn !== operation.managedPolicyArn
693
+ (arn) => arn !== managedPolicyArn
671
694
  )
672
695
  })
673
696
  });
674
697
  }
675
- if (operation.kind === "attachIdcCustomerManagedPolicyReferenceToPermissionSet") {
698
+ if (props.operation.kind === "attachIdcCustomerManagedPolicyReferenceToPermissionSet") {
699
+ const { customerManagedPolicyName, customerManagedPolicyPath } = props.operation;
676
700
  const permissionSet = resolvePermissionSetByName({
677
701
  state: props.state,
678
- permissionSetName: operation.permissionSetName
702
+ permissionSetName: props.operation.permissionSetName
679
703
  });
680
704
  props.logger.log(
681
- `Attaching customer-managed policy "${operation.customerManagedPolicyPath}${operation.customerManagedPolicyName}" to IdC permission set "${operation.permissionSetName}"...`
705
+ `Attaching customer-managed policy "${customerManagedPolicyPath}${customerManagedPolicyName}" to IdC permission set "${props.operation.permissionSetName}"...`
682
706
  );
683
707
  await props.ssoAdminClient.send(
684
708
  new AttachCustomerManagedPolicyReferenceToPermissionSetCommand({
685
709
  InstanceArn: props.state.identityCenter.instanceArn,
686
710
  PermissionSetArn: permissionSet.permissionSetArn,
687
711
  CustomerManagedPolicyReference: {
688
- Name: operation.customerManagedPolicyName,
689
- Path: operation.customerManagedPolicyPath
712
+ Name: customerManagedPolicyName,
713
+ Path: customerManagedPolicyPath
690
714
  }
691
715
  })
692
716
  );
693
- props.logger.log(`Done: "${operation.permissionSetName}"`);
717
+ props.logger.log(`Done: "${props.operation.permissionSetName}"`);
694
718
  return upsertPermissionSetPolicyState({
695
719
  state: props.state,
696
- permissionSetName: operation.permissionSetName,
720
+ permissionSetName: props.operation.permissionSetName,
697
721
  update: (currentPermissionSet) => ({
698
722
  ...currentPermissionSet,
699
723
  customerManagedPolicies: [
700
724
  ...currentPermissionSet.customerManagedPolicies,
701
725
  {
702
- name: operation.customerManagedPolicyName,
703
- path: operation.customerManagedPolicyPath
726
+ name: customerManagedPolicyName,
727
+ path: customerManagedPolicyPath
704
728
  }
705
729
  ]
706
730
  })
707
731
  });
708
732
  }
709
- if (operation.kind === "detachIdcCustomerManagedPolicyReferenceFromPermissionSet") {
733
+ if (props.operation.kind === "detachIdcCustomerManagedPolicyReferenceFromPermissionSet") {
734
+ const { customerManagedPolicyName, customerManagedPolicyPath } = props.operation;
710
735
  const permissionSet = resolvePermissionSetByName({
711
736
  state: props.state,
712
- permissionSetName: operation.permissionSetName
737
+ permissionSetName: props.operation.permissionSetName
713
738
  });
714
739
  props.logger.log(
715
- `Detaching customer-managed policy "${operation.customerManagedPolicyPath}${operation.customerManagedPolicyName}" from IdC permission set "${operation.permissionSetName}"...`
740
+ `Detaching customer-managed policy "${customerManagedPolicyPath}${customerManagedPolicyName}" from IdC permission set "${props.operation.permissionSetName}"...`
716
741
  );
717
742
  await props.ssoAdminClient.send(
718
743
  new DetachCustomerManagedPolicyReferenceFromPermissionSetCommand({
719
744
  InstanceArn: props.state.identityCenter.instanceArn,
720
745
  PermissionSetArn: permissionSet.permissionSetArn,
721
746
  CustomerManagedPolicyReference: {
722
- Name: operation.customerManagedPolicyName,
723
- Path: operation.customerManagedPolicyPath
747
+ Name: customerManagedPolicyName,
748
+ Path: customerManagedPolicyPath
724
749
  }
725
750
  })
726
751
  );
727
- props.logger.log(`Done: "${operation.permissionSetName}"`);
752
+ props.logger.log(`Done: "${props.operation.permissionSetName}"`);
728
753
  return upsertPermissionSetPolicyState({
729
754
  state: props.state,
730
- permissionSetName: operation.permissionSetName,
755
+ permissionSetName: props.operation.permissionSetName,
731
756
  update: (currentPermissionSet) => ({
732
757
  ...currentPermissionSet,
733
758
  customerManagedPolicies: currentPermissionSet.customerManagedPolicies.filter(
734
- (customerManagedPolicy) => customerManagedPolicy.name !== operation.customerManagedPolicyName || customerManagedPolicy.path !== operation.customerManagedPolicyPath
759
+ (policy) => policy.name !== customerManagedPolicyName || policy.path !== customerManagedPolicyPath
735
760
  )
736
761
  })
737
762
  });
738
763
  }
739
- if (operation.kind === "provisionIdcPermissionSet") {
764
+ if (props.operation.kind === "provisionIdcPermissionSet") {
740
765
  const permissionSet = resolvePermissionSetByName({
741
766
  state: props.state,
742
- permissionSetName: operation.permissionSetName
767
+ permissionSetName: props.operation.permissionSetName
743
768
  });
744
769
  props.logger.log(
745
- `Provisioning IdC permission set "${operation.permissionSetName}" to all provisioned accounts...`
770
+ `Provisioning IdC permission set "${props.operation.permissionSetName}" to all provisioned accounts...`
746
771
  );
747
772
  const response = await props.ssoAdminClient.send(
748
773
  new ProvisionPermissionSetCommand({
749
774
  InstanceArn: props.state.identityCenter.instanceArn,
750
775
  PermissionSetArn: permissionSet.permissionSetArn,
751
- TargetType: operation.targetScope
776
+ TargetType: props.operation.targetScope
752
777
  })
753
778
  );
754
779
  const requestId = response.PermissionSetProvisioningStatus?.RequestId ?? void 0;
755
780
  if (requestId == null) {
756
781
  throw new Error(
757
- `ProvisionPermissionSet for "${operation.permissionSetName}" returned no request id.`
782
+ `ProvisionPermissionSet for "${props.operation.permissionSetName}" returned no request id.`
758
783
  );
759
784
  }
760
785
  await waitForPermissionSetProvisioningSuccess({
@@ -764,16 +789,63 @@ async function executeOperation(props) {
764
789
  requestId,
765
790
  timeoutInMs: props.runtime.permissionSetProvisioning.timeoutInMs,
766
791
  pollIntervalInMs: props.runtime.permissionSetProvisioning.pollIntervalInMs,
767
- operationLabel: `"${operation.permissionSetName}"`
792
+ operationLabel: `"${props.operation.permissionSetName}"`
768
793
  });
769
- props.logger.log(`Done: "${operation.permissionSetName}"`);
794
+ props.logger.log(`Done: "${props.operation.permissionSetName}"`);
770
795
  return props.state;
771
796
  }
772
- if (operation.kind === "removeIdcGroupMembership") {
797
+ if (props.operation.kind === "putIdcPermissionSetPermissionsBoundary") {
798
+ const permissionSet = resolvePermissionSetByName({
799
+ state: props.state,
800
+ permissionSetName: props.operation.permissionSetName
801
+ });
802
+ props.logger.log(
803
+ `Putting permissions boundary on IdC permission set "${props.operation.permissionSetName}"...`
804
+ );
805
+ const boundary = props.operation.permissionsBoundary;
806
+ await props.ssoAdminClient.send(
807
+ new PutPermissionsBoundaryToPermissionSetCommand({
808
+ InstanceArn: props.state.identityCenter.instanceArn,
809
+ PermissionSetArn: permissionSet.permissionSetArn,
810
+ PermissionsBoundary: "managedPolicyArn" in boundary ? { ManagedPolicyArn: boundary.managedPolicyArn } : {
811
+ CustomerManagedPolicyReference: {
812
+ Name: boundary.customerManagedPolicyName,
813
+ Path: boundary.customerManagedPolicyPath
814
+ }
815
+ }
816
+ })
817
+ );
818
+ props.logger.log(`Done: "${props.operation.permissionSetName}"`);
819
+ return upsertIdcPermissionSetInWorkingState({
820
+ workingState: props.state,
821
+ permissionSet: { ...permissionSet, permissionsBoundary: boundary }
822
+ });
823
+ }
824
+ if (props.operation.kind === "deleteIdcPermissionSetPermissionsBoundary") {
825
+ const permissionSet = resolvePermissionSetByName({
826
+ state: props.state,
827
+ permissionSetName: props.operation.permissionSetName
828
+ });
829
+ props.logger.log(
830
+ `Deleting permissions boundary from IdC permission set "${props.operation.permissionSetName}"...`
831
+ );
832
+ await props.ssoAdminClient.send(
833
+ new DeletePermissionsBoundaryFromPermissionSetCommand({
834
+ InstanceArn: props.state.identityCenter.instanceArn,
835
+ PermissionSetArn: permissionSet.permissionSetArn
836
+ })
837
+ );
838
+ props.logger.log(`Done: "${props.operation.permissionSetName}"`);
839
+ return upsertIdcPermissionSetInWorkingState({
840
+ workingState: props.state,
841
+ permissionSet: { ...permissionSet, permissionsBoundary: null }
842
+ });
843
+ }
844
+ if (props.operation.kind === "removeIdcGroupMembership") {
773
845
  const resolvedMembership = resolveGroupMembershipDependencies({
774
846
  state: props.state,
775
- groupDisplayName: operation.groupDisplayName,
776
- userName: operation.userName
847
+ groupDisplayName: props.operation.groupDisplayName,
848
+ userName: props.operation.userName
777
849
  });
778
850
  const membershipId = await resolveGroupMembershipId({
779
851
  state: props.state,
@@ -782,7 +854,7 @@ async function executeOperation(props) {
782
854
  userId: resolvedMembership.userId
783
855
  });
784
856
  props.logger.log(
785
- `Removing user "${operation.userName}" from IdC group "${operation.groupDisplayName}"...`
857
+ `Removing user "${props.operation.userName}" from IdC group "${props.operation.groupDisplayName}"...`
786
858
  );
787
859
  await props.identityStoreClient.send(
788
860
  new DeleteGroupMembershipCommand({
@@ -791,7 +863,7 @@ async function executeOperation(props) {
791
863
  })
792
864
  );
793
865
  props.logger.log(
794
- `Done: user "${operation.userName}" x group "${operation.groupDisplayName}"`
866
+ `Done: user "${props.operation.userName}" x group "${props.operation.groupDisplayName}"`
795
867
  );
796
868
  return removeGroupMembershipFromWorkingState({
797
869
  workingState: props.state,
@@ -801,21 +873,21 @@ async function executeOperation(props) {
801
873
  }
802
874
  });
803
875
  }
804
- if (operation.kind === "grantIdcAccountAssignment") {
876
+ if (props.operation.kind === "grantIdcAccountAssignment") {
805
877
  const resolvedAssignment = resolveAssignmentDependencies({
806
878
  state: props.state,
807
- accountName: operation.accountName,
808
- permissionSetName: operation.permissionSetName,
809
- principalType: operation.principalType,
810
- principalName: operation.principalName
879
+ accountName: props.operation.accountName,
880
+ permissionSetName: props.operation.permissionSetName,
881
+ principalType: props.operation.principalType,
882
+ principalName: props.operation.principalName
811
883
  });
812
884
  props.logger.log(
813
- `Granting IdC assignment "${operation.permissionSetName}" to ${formatPrincipalLabel(
885
+ `Granting IdC assignment "${props.operation.permissionSetName}" to ${formatPrincipalLabel(
814
886
  {
815
- principalType: operation.principalType,
816
- principalName: operation.principalName
887
+ principalType: props.operation.principalType,
888
+ principalName: props.operation.principalName
817
889
  }
818
- )} on "${operation.accountName}"...`
890
+ )} on "${props.operation.accountName}"...`
819
891
  );
820
892
  const response = await props.ssoAdminClient.send(
821
893
  new CreateAccountAssignmentCommand({
@@ -830,7 +902,7 @@ async function executeOperation(props) {
830
902
  const requestId = response.AccountAssignmentCreationStatus?.RequestId;
831
903
  if (requestId == null) {
832
904
  throw new Error(
833
- `CreateAccountAssignment for "${operation.permissionSetName}" on "${operation.accountName}" returned no request id.`
905
+ `CreateAccountAssignment for "${props.operation.permissionSetName}" on "${props.operation.accountName}" returned no request id.`
834
906
  );
835
907
  }
836
908
  await waitForAccountAssignmentCreationSuccess({
@@ -840,10 +912,10 @@ async function executeOperation(props) {
840
912
  requestId,
841
913
  timeoutInMs: props.runtime.accountAssignment.timeoutInMs,
842
914
  pollIntervalInMs: props.runtime.accountAssignment.pollIntervalInMs,
843
- operationLabel: `"${operation.permissionSetName}" on "${operation.accountName}"`
915
+ operationLabel: `"${props.operation.permissionSetName}" on "${props.operation.accountName}"`
844
916
  });
845
917
  props.logger.log(
846
- `Done: "${operation.permissionSetName}" -> "${operation.accountName}"`
918
+ `Done: "${props.operation.permissionSetName}" -> "${props.operation.accountName}"`
847
919
  );
848
920
  return addAccountAssignmentToWorkingState({
849
921
  workingState: props.state,
@@ -855,21 +927,21 @@ async function executeOperation(props) {
855
927
  }
856
928
  });
857
929
  }
858
- if (operation.kind === "revokeIdcAccountAssignment") {
930
+ if (props.operation.kind === "revokeIdcAccountAssignment") {
859
931
  const resolvedAssignment = resolveAssignmentDependencies({
860
932
  state: props.state,
861
- accountName: operation.accountName,
862
- permissionSetName: operation.permissionSetName,
863
- principalType: operation.principalType,
864
- principalName: operation.principalName
933
+ accountName: props.operation.accountName,
934
+ permissionSetName: props.operation.permissionSetName,
935
+ principalType: props.operation.principalType,
936
+ principalName: props.operation.principalName
865
937
  });
866
938
  props.logger.log(
867
- `Revoking IdC assignment "${operation.permissionSetName}" from ${formatPrincipalLabel(
939
+ `Revoking IdC assignment "${props.operation.permissionSetName}" from ${formatPrincipalLabel(
868
940
  {
869
- principalType: operation.principalType,
870
- principalName: operation.principalName
941
+ principalType: props.operation.principalType,
942
+ principalName: props.operation.principalName
871
943
  }
872
- )} on "${operation.accountName}"...`
944
+ )} on "${props.operation.accountName}"...`
873
945
  );
874
946
  const response = await props.ssoAdminClient.send(
875
947
  new DeleteAccountAssignmentCommand({
@@ -884,7 +956,7 @@ async function executeOperation(props) {
884
956
  const requestId = response.AccountAssignmentDeletionStatus?.RequestId;
885
957
  if (requestId == null) {
886
958
  throw new Error(
887
- `DeleteAccountAssignment for "${operation.permissionSetName}" on "${operation.accountName}" returned no request id.`
959
+ `DeleteAccountAssignment for "${props.operation.permissionSetName}" on "${props.operation.accountName}" returned no request id.`
888
960
  );
889
961
  }
890
962
  await waitForAccountAssignmentDeletionSuccess({
@@ -894,10 +966,10 @@ async function executeOperation(props) {
894
966
  requestId,
895
967
  timeoutInMs: props.runtime.accountAssignment.timeoutInMs,
896
968
  pollIntervalInMs: props.runtime.accountAssignment.pollIntervalInMs,
897
- operationLabel: `"${operation.permissionSetName}" on "${operation.accountName}"`
969
+ operationLabel: `"${props.operation.permissionSetName}" on "${props.operation.accountName}"`
898
970
  });
899
971
  props.logger.log(
900
- `Done: "${operation.permissionSetName}" x "${operation.accountName}"`
972
+ `Done: "${props.operation.permissionSetName}" x "${props.operation.accountName}"`
901
973
  );
902
974
  return removeAccountAssignmentFromWorkingState({
903
975
  workingState: props.state,
@@ -909,7 +981,271 @@ async function executeOperation(props) {
909
981
  }
910
982
  });
911
983
  }
912
- assertUnreachable(operation, "Unsupported operation kind in apply.");
984
+ if (props.operation.kind === "createOrgPolicy") {
985
+ props.logger.log(
986
+ `Creating org policy "${props.operation.policyName}" (${props.operation.policyType})...`
987
+ );
988
+ const response = await props.organizationsClient.send(
989
+ new CreatePolicyCommand({
990
+ Name: props.operation.policyName,
991
+ Description: props.operation.description.length > 0 ? props.operation.description : void 0,
992
+ Content: props.operation.content,
993
+ Type: props.operation.policyType
994
+ })
995
+ );
996
+ const policy = response.Policy?.PolicySummary;
997
+ if (policy?.Id == null || policy.Arn == null) {
998
+ throw new Error(
999
+ `CreatePolicy for "${props.operation.policyName}" returned incomplete data.`
1000
+ );
1001
+ }
1002
+ props.logger.log(`Done: "${props.operation.policyName}"`);
1003
+ return upsertOrgPolicyInWorkingState({
1004
+ workingState: props.state,
1005
+ policy: {
1006
+ id: policy.Id,
1007
+ arn: policy.Arn,
1008
+ name: props.operation.policyName,
1009
+ description: props.operation.description,
1010
+ type: props.operation.policyType,
1011
+ content: props.operation.content
1012
+ }
1013
+ });
1014
+ }
1015
+ if (props.operation.kind === "updateOrgPolicyContent") {
1016
+ props.logger.log(
1017
+ `Updating org policy content "${props.operation.policyName}"...`
1018
+ );
1019
+ await props.organizationsClient.send(
1020
+ new UpdatePolicyCommand({
1021
+ PolicyId: props.operation.policyId,
1022
+ Content: props.operation.content
1023
+ })
1024
+ );
1025
+ props.logger.log(`Done: "${props.operation.policyName}"`);
1026
+ const currentPolicy = props.state.organization.policiesById[props.operation.policyId];
1027
+ if (currentPolicy == null) {
1028
+ return props.state;
1029
+ }
1030
+ return upsertOrgPolicyInWorkingState({
1031
+ workingState: props.state,
1032
+ policy: { ...currentPolicy, content: props.operation.content }
1033
+ });
1034
+ }
1035
+ if (props.operation.kind === "updateOrgPolicyDescription") {
1036
+ props.logger.log(
1037
+ `Updating org policy description "${props.operation.policyName}"...`
1038
+ );
1039
+ await props.organizationsClient.send(
1040
+ new UpdatePolicyCommand({
1041
+ PolicyId: props.operation.policyId,
1042
+ Description: props.operation.description
1043
+ })
1044
+ );
1045
+ props.logger.log(`Done: "${props.operation.policyName}"`);
1046
+ const currentPolicy = props.state.organization.policiesById[props.operation.policyId];
1047
+ if (currentPolicy == null) {
1048
+ return props.state;
1049
+ }
1050
+ return upsertOrgPolicyInWorkingState({
1051
+ workingState: props.state,
1052
+ policy: { ...currentPolicy, description: props.operation.description }
1053
+ });
1054
+ }
1055
+ if (props.operation.kind === "attachOrgPolicy") {
1056
+ props.logger.log(
1057
+ `Attaching org policy "${props.operation.policyName}" to "${props.operation.targetName}"...`
1058
+ );
1059
+ const resolvedPolicyId = resolvePolicyId({
1060
+ state: props.state,
1061
+ policyId: props.operation.policyId,
1062
+ policyName: props.operation.policyName
1063
+ });
1064
+ await props.organizationsClient.send(
1065
+ new AttachPolicyCommand({
1066
+ PolicyId: resolvedPolicyId,
1067
+ TargetId: props.operation.targetId
1068
+ })
1069
+ );
1070
+ props.logger.log(
1071
+ `Done: "${props.operation.policyName}" -> "${props.operation.targetName}"`
1072
+ );
1073
+ const targetType = props.operation.targetId === props.context.organization.rootId ? "ROOT" : props.state.organization.organizationalUnitsById[props.operation.targetId] != null ? "ORGANIZATIONAL_UNIT" : "ACCOUNT";
1074
+ return addOrgPolicyAttachmentToWorkingState({
1075
+ workingState: props.state,
1076
+ attachment: {
1077
+ policyId: resolvedPolicyId,
1078
+ targetId: props.operation.targetId,
1079
+ targetType
1080
+ }
1081
+ });
1082
+ }
1083
+ if (props.operation.kind === "detachOrgPolicy") {
1084
+ props.logger.log(
1085
+ `Detaching org policy "${props.operation.policyName}" from "${props.operation.targetName}"...`
1086
+ );
1087
+ await props.organizationsClient.send(
1088
+ new DetachPolicyCommand({
1089
+ PolicyId: props.operation.policyId,
1090
+ TargetId: props.operation.targetId
1091
+ })
1092
+ );
1093
+ props.logger.log(
1094
+ `Done: "${props.operation.policyName}" x "${props.operation.targetName}"`
1095
+ );
1096
+ return removeOrgPolicyAttachmentFromWorkingState({
1097
+ workingState: props.state,
1098
+ policyId: props.operation.policyId,
1099
+ targetId: props.operation.targetId
1100
+ });
1101
+ }
1102
+ if (props.operation.kind === "deleteOrgPolicy") {
1103
+ props.logger.log(`Deleting org policy "${props.operation.policyName}"...`);
1104
+ await props.organizationsClient.send(
1105
+ new DeletePolicyCommand({ PolicyId: props.operation.policyId })
1106
+ );
1107
+ props.logger.log(`Done: "${props.operation.policyName}"`);
1108
+ return removeOrgPolicyFromWorkingState({
1109
+ workingState: props.state,
1110
+ policyId: props.operation.policyId
1111
+ });
1112
+ }
1113
+ if (props.operation.kind === "putAlternateContact") {
1114
+ const { contactType } = props.operation;
1115
+ props.logger.log(
1116
+ `Setting ${contactType} alternate contact for "${props.operation.accountName}" (${props.operation.accountId})...`
1117
+ );
1118
+ await props.accountClient.send(
1119
+ new PutAlternateContactCommand({
1120
+ AccountId: props.operation.accountId,
1121
+ AlternateContactType: contactType,
1122
+ Name: props.operation.name,
1123
+ EmailAddress: props.operation.email,
1124
+ PhoneNumber: props.operation.phone,
1125
+ Title: props.operation.title
1126
+ })
1127
+ );
1128
+ props.logger.log(
1129
+ `Done: ${contactType} contact for "${props.operation.accountName}"`
1130
+ );
1131
+ const account = props.state.organization.accountsById[props.operation.accountId];
1132
+ if (account == null) {
1133
+ throw new Error(
1134
+ `Could not resolve account (${props.operation.accountId}) in working state.`
1135
+ );
1136
+ }
1137
+ const updatedContacts = [
1138
+ ...(account.alternateContacts ?? []).filter(
1139
+ (c) => c.contactType !== contactType
1140
+ ),
1141
+ {
1142
+ contactType,
1143
+ name: props.operation.name,
1144
+ email: props.operation.email,
1145
+ phone: props.operation.phone,
1146
+ title: props.operation.title
1147
+ }
1148
+ ];
1149
+ return upsertAccountInWorkingState({
1150
+ workingState: props.state,
1151
+ account: { ...account, alternateContacts: updatedContacts }
1152
+ });
1153
+ }
1154
+ if (props.operation.kind === "deleteAlternateContact") {
1155
+ const { contactType } = props.operation;
1156
+ props.logger.log(
1157
+ `Deleting ${contactType} alternate contact for "${props.operation.accountName}" (${props.operation.accountId})...`
1158
+ );
1159
+ await props.accountClient.send(
1160
+ new DeleteAlternateContactCommand({
1161
+ AccountId: props.operation.accountId,
1162
+ AlternateContactType: contactType
1163
+ })
1164
+ );
1165
+ props.logger.log(
1166
+ `Done: removed ${contactType} contact for "${props.operation.accountName}"`
1167
+ );
1168
+ const account = props.state.organization.accountsById[props.operation.accountId];
1169
+ if (account == null) {
1170
+ throw new Error(
1171
+ `Could not resolve account (${props.operation.accountId}) in working state.`
1172
+ );
1173
+ }
1174
+ return upsertAccountInWorkingState({
1175
+ workingState: props.state,
1176
+ account: {
1177
+ ...account,
1178
+ alternateContacts: (account.alternateContacts ?? []).filter(
1179
+ (c) => c.contactType !== contactType
1180
+ )
1181
+ }
1182
+ });
1183
+ }
1184
+ if (props.operation.kind === "setIdcAccessControlAttributes") {
1185
+ props.logger.log(
1186
+ `Setting IdC access control attributes (${props.operation.attributes.length} attribute(s))...`
1187
+ );
1188
+ await props.ssoAdminClient.send(
1189
+ new UpdateInstanceAccessControlAttributeConfigurationCommand({
1190
+ InstanceArn: props.state.identityCenter.instanceArn,
1191
+ InstanceAccessControlAttributeConfiguration: {
1192
+ AccessControlAttributes: props.operation.attributes.map((attr) => ({
1193
+ Key: attr.key,
1194
+ Value: { Source: attr.source }
1195
+ }))
1196
+ }
1197
+ })
1198
+ );
1199
+ props.logger.log(`Done: access control attributes updated`);
1200
+ return {
1201
+ ...props.state,
1202
+ identityCenter: {
1203
+ ...props.state.identityCenter,
1204
+ accessControlAttributes: props.operation.attributes
1205
+ }
1206
+ };
1207
+ }
1208
+ if (props.operation.kind === "registerDelegatedAdministrator") {
1209
+ props.logger.log(
1210
+ `Registering delegated administrator "${props.operation.accountName}" (${props.operation.accountId}) for ${props.operation.servicePrincipal}...`
1211
+ );
1212
+ await props.organizationsClient.send(
1213
+ new RegisterDelegatedAdministratorCommand({
1214
+ AccountId: props.operation.accountId,
1215
+ ServicePrincipal: props.operation.servicePrincipal
1216
+ })
1217
+ );
1218
+ props.logger.log(
1219
+ `Done: "${props.operation.accountName}" for ${props.operation.servicePrincipal}`
1220
+ );
1221
+ return upsertDelegatedAdministratorInWorkingState({
1222
+ workingState: props.state,
1223
+ delegatedAdministrator: {
1224
+ accountId: props.operation.accountId,
1225
+ servicePrincipal: props.operation.servicePrincipal
1226
+ }
1227
+ });
1228
+ }
1229
+ if (props.operation.kind === "deregisterDelegatedAdministrator") {
1230
+ props.logger.log(
1231
+ `Deregistering delegated administrator "${props.operation.accountName}" (${props.operation.accountId}) for ${props.operation.servicePrincipal}...`
1232
+ );
1233
+ await props.organizationsClient.send(
1234
+ new DeregisterDelegatedAdministratorCommand({
1235
+ AccountId: props.operation.accountId,
1236
+ ServicePrincipal: props.operation.servicePrincipal
1237
+ })
1238
+ );
1239
+ props.logger.log(
1240
+ `Done: removed "${props.operation.accountName}" for ${props.operation.servicePrincipal}`
1241
+ );
1242
+ return removeDelegatedAdministratorFromWorkingState({
1243
+ workingState: props.state,
1244
+ accountId: props.operation.accountId,
1245
+ servicePrincipal: props.operation.servicePrincipal
1246
+ });
1247
+ }
1248
+ assertUnreachable(props.operation, "Unsupported operation kind in apply.");
913
1249
  }
914
1250
  function resolveAssignmentDependencies(props) {
915
1251
  const account = props.state.organization.accountsByName[props.accountName];
@@ -969,6 +1305,16 @@ function resolveGroupByDisplayName(props) {
969
1305
  }
970
1306
  return group;
971
1307
  }
1308
+ function resolvePolicyId(props) {
1309
+ if (props.policyId !== "__pending_creation__") return props.policyId;
1310
+ const policy = props.state.organization.policiesByName[props.policyName];
1311
+ if (policy == null) {
1312
+ throw new Error(
1313
+ `Could not resolve policy "${props.policyName}" in working state.`
1314
+ );
1315
+ }
1316
+ return policy.id;
1317
+ }
972
1318
  function resolvePermissionSetByName(props) {
973
1319
  const permissionSet = props.state.identityCenter.permissionSetsByName[props.permissionSetName];
974
1320
  if (permissionSet == null) {