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