@beesolve/aws-accounts 1.1.0 → 1.2.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.
- package/README.md +1 -1
- package/dist/applyLogic.js +239 -3
- package/dist/awsConfig.js +402 -23
- package/dist/cli.js +63 -26
- package/dist/commands/graveyard.js +27 -0
- package/dist/commands/remote.js +139 -38
- package/dist/commands/validate.js +45 -0
- package/dist/diff.js +255 -8
- package/dist/lambda/handler.js +8 -4
- package/dist/lambdaClient.js +5 -2
- package/dist/operations.js +83 -1
- package/dist/scanLogic.js +163 -7
- package/dist/state.js +162 -6
- package/dist-lambda/handler.mjs +647 -22
- package/dist-lambda/lambda.zip +0 -0
- package/package.json +1 -1
package/dist/awsConfig.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { readFile, unlink, writeFile } from "node:fs/promises";
|
|
3
|
-
import { join, resolve } from "node:path";
|
|
3
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
4
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
5
5
|
import { build as esbuildBuild } from "esbuild";
|
|
6
6
|
import * as v from "valibot";
|
|
@@ -36,7 +36,8 @@ const deploymentSchema = v.strictObject({
|
|
|
36
36
|
region: v.string(),
|
|
37
37
|
lambdaArn: v.string(),
|
|
38
38
|
stateBucketName: v.string(),
|
|
39
|
-
stateCacheTtlSeconds: v.number()
|
|
39
|
+
stateCacheTtlSeconds: v.number(),
|
|
40
|
+
cliVersion: v.string()
|
|
40
41
|
});
|
|
41
42
|
const awsContextSchema = v.strictObject({
|
|
42
43
|
version: nonEmptyString,
|
|
@@ -66,6 +67,17 @@ const awsConfigModelSchema = v.strictObject({
|
|
|
66
67
|
key: v.string(),
|
|
67
68
|
value: v.string()
|
|
68
69
|
})
|
|
70
|
+
),
|
|
71
|
+
alternateContacts: v.optional(
|
|
72
|
+
v.array(
|
|
73
|
+
v.strictObject({
|
|
74
|
+
contactType: v.picklist(["BILLING", "OPERATIONS", "SECURITY"]),
|
|
75
|
+
name: v.string(),
|
|
76
|
+
email: v.string(),
|
|
77
|
+
phone: v.string(),
|
|
78
|
+
title: v.optional(v.string())
|
|
79
|
+
})
|
|
80
|
+
)
|
|
69
81
|
)
|
|
70
82
|
})
|
|
71
83
|
)
|
|
@@ -107,6 +119,58 @@ const awsConfigModelSchema = v.strictObject({
|
|
|
107
119
|
user: v.optional(v.string()),
|
|
108
120
|
accounts: v.array(v.string())
|
|
109
121
|
})
|
|
122
|
+
),
|
|
123
|
+
accessControlAttributes: v.optional(
|
|
124
|
+
v.array(
|
|
125
|
+
v.strictObject({
|
|
126
|
+
key: v.string(),
|
|
127
|
+
source: v.array(v.string())
|
|
128
|
+
})
|
|
129
|
+
)
|
|
130
|
+
),
|
|
131
|
+
policies: v.optional(
|
|
132
|
+
v.strictObject({
|
|
133
|
+
serviceControlPolicies: v.optional(
|
|
134
|
+
v.array(
|
|
135
|
+
v.strictObject({
|
|
136
|
+
name: v.string(),
|
|
137
|
+
description: v.optional(v.string()),
|
|
138
|
+
content: v.record(v.string(), v.unknown()),
|
|
139
|
+
targets: v.array(v.string())
|
|
140
|
+
})
|
|
141
|
+
)
|
|
142
|
+
),
|
|
143
|
+
resourceControlPolicies: v.optional(
|
|
144
|
+
v.array(
|
|
145
|
+
v.strictObject({
|
|
146
|
+
name: v.string(),
|
|
147
|
+
description: v.optional(v.string()),
|
|
148
|
+
content: v.record(v.string(), v.unknown()),
|
|
149
|
+
targets: v.array(v.string())
|
|
150
|
+
})
|
|
151
|
+
)
|
|
152
|
+
),
|
|
153
|
+
tagPolicies: v.optional(
|
|
154
|
+
v.array(
|
|
155
|
+
v.strictObject({
|
|
156
|
+
name: v.string(),
|
|
157
|
+
description: v.optional(v.string()),
|
|
158
|
+
content: v.record(v.string(), v.unknown()),
|
|
159
|
+
targets: v.array(v.string())
|
|
160
|
+
})
|
|
161
|
+
)
|
|
162
|
+
),
|
|
163
|
+
aiServicesOptOutPolicies: v.optional(
|
|
164
|
+
v.array(
|
|
165
|
+
v.strictObject({
|
|
166
|
+
name: v.string(),
|
|
167
|
+
description: v.optional(v.string()),
|
|
168
|
+
content: v.record(v.string(), v.unknown()),
|
|
169
|
+
targets: v.array(v.string())
|
|
170
|
+
})
|
|
171
|
+
)
|
|
172
|
+
)
|
|
173
|
+
})
|
|
110
174
|
)
|
|
111
175
|
});
|
|
112
176
|
const moduleDirectoryPath = resolve(
|
|
@@ -120,11 +184,13 @@ async function writeAwsConfigFromState(props) {
|
|
|
120
184
|
state,
|
|
121
185
|
context
|
|
122
186
|
});
|
|
123
|
-
const mappedConfig = mapStateToAwsConfig({
|
|
124
|
-
|
|
125
|
-
|
|
187
|
+
const mappedConfig = mapStateToAwsConfig({ state });
|
|
188
|
+
const mergedConfig = props.existingConfig != null ? {
|
|
189
|
+
...props.existingConfig,
|
|
190
|
+
policies: props.existingConfig.policies ?? mappedConfig.policies
|
|
191
|
+
} : mappedConfig;
|
|
126
192
|
const sortedConfig = sortAwsConfigModel({
|
|
127
|
-
config:
|
|
193
|
+
config: mergedConfig
|
|
128
194
|
});
|
|
129
195
|
const nextConfigContent = renderAwsConfigTs({
|
|
130
196
|
config: sortedConfig
|
|
@@ -328,10 +394,12 @@ function mapStateToAwsConfig(props) {
|
|
|
328
394
|
`Could not map account "${account.name}" to organizational unit "${ownerOuName}".`
|
|
329
395
|
);
|
|
330
396
|
}
|
|
397
|
+
const contacts = account.alternateContacts;
|
|
331
398
|
ownerOu.accounts.push({
|
|
332
399
|
name: account.name,
|
|
333
400
|
email: account.email,
|
|
334
|
-
tags: account.tags ?? []
|
|
401
|
+
tags: account.tags ?? [],
|
|
402
|
+
alternateContacts: contacts != null && contacts.length > 0 ? contacts : void 0
|
|
335
403
|
});
|
|
336
404
|
}
|
|
337
405
|
const permissionSetByArn = toRecordByProperty(
|
|
@@ -417,6 +485,73 @@ function mapStateToAwsConfig(props) {
|
|
|
417
485
|
members.push(userName);
|
|
418
486
|
}
|
|
419
487
|
}
|
|
488
|
+
const orgPolicies = props.state.organization.policies ?? [];
|
|
489
|
+
const orgPolicyAttachments = props.state.organization.policyAttachments ?? [];
|
|
490
|
+
const ouById = toRecordByProperty(
|
|
491
|
+
props.state.organization.organizationalUnits,
|
|
492
|
+
"id"
|
|
493
|
+
);
|
|
494
|
+
const orgAccountById = toRecordByProperty(
|
|
495
|
+
props.state.organization.accounts,
|
|
496
|
+
"id"
|
|
497
|
+
);
|
|
498
|
+
function resolveTargetName(targetId, targetType) {
|
|
499
|
+
if (targetType === "ROOT") {
|
|
500
|
+
return "root";
|
|
501
|
+
}
|
|
502
|
+
if (targetType === "ORGANIZATIONAL_UNIT") {
|
|
503
|
+
return ouById[targetId]?.name ?? null;
|
|
504
|
+
}
|
|
505
|
+
if (targetType === "ACCOUNT") {
|
|
506
|
+
return orgAccountById[targetId]?.name ?? null;
|
|
507
|
+
}
|
|
508
|
+
return null;
|
|
509
|
+
}
|
|
510
|
+
const attachmentsByPolicyId = /* @__PURE__ */ new Map();
|
|
511
|
+
for (const attachment of orgPolicyAttachments) {
|
|
512
|
+
const targetName = resolveTargetName(
|
|
513
|
+
attachment.targetId,
|
|
514
|
+
attachment.targetType
|
|
515
|
+
);
|
|
516
|
+
if (targetName == null) {
|
|
517
|
+
continue;
|
|
518
|
+
}
|
|
519
|
+
const targets = attachmentsByPolicyId.get(attachment.policyId) ?? [];
|
|
520
|
+
targets.push(targetName);
|
|
521
|
+
attachmentsByPolicyId.set(attachment.policyId, targets);
|
|
522
|
+
}
|
|
523
|
+
const scps = orgPolicies.filter((p) => p.type === "SERVICE_CONTROL_POLICY").map((p) => ({
|
|
524
|
+
name: p.name,
|
|
525
|
+
description: p.description.length > 0 ? p.description : void 0,
|
|
526
|
+
content: JSON.parse(p.content),
|
|
527
|
+
targets: [...attachmentsByPolicyId.get(p.id) ?? []].sort(
|
|
528
|
+
(a, b) => a.localeCompare(b)
|
|
529
|
+
)
|
|
530
|
+
}));
|
|
531
|
+
const rcps = orgPolicies.filter((p) => p.type === "RESOURCE_CONTROL_POLICY").map((p) => ({
|
|
532
|
+
name: p.name,
|
|
533
|
+
description: p.description.length > 0 ? p.description : void 0,
|
|
534
|
+
content: JSON.parse(p.content),
|
|
535
|
+
targets: [...attachmentsByPolicyId.get(p.id) ?? []].sort(
|
|
536
|
+
(a, b) => a.localeCompare(b)
|
|
537
|
+
)
|
|
538
|
+
}));
|
|
539
|
+
const tagPolicies = orgPolicies.filter((p) => p.type === "TAG_POLICY").map((p) => ({
|
|
540
|
+
name: p.name,
|
|
541
|
+
description: p.description.length > 0 ? p.description : void 0,
|
|
542
|
+
content: JSON.parse(p.content),
|
|
543
|
+
targets: [...attachmentsByPolicyId.get(p.id) ?? []].sort(
|
|
544
|
+
(a, b) => a.localeCompare(b)
|
|
545
|
+
)
|
|
546
|
+
}));
|
|
547
|
+
const aiServicesOptOutPolicies = orgPolicies.filter((p) => p.type === "AISERVICES_OPT_OUT_POLICY").map((p) => ({
|
|
548
|
+
name: p.name,
|
|
549
|
+
description: p.description.length > 0 ? p.description : void 0,
|
|
550
|
+
content: JSON.parse(p.content),
|
|
551
|
+
targets: [...attachmentsByPolicyId.get(p.id) ?? []].sort(
|
|
552
|
+
(a, b) => a.localeCompare(b)
|
|
553
|
+
)
|
|
554
|
+
}));
|
|
420
555
|
const mapped = {
|
|
421
556
|
organizationalUnits,
|
|
422
557
|
users: props.state.identityCenter.users.map((user) => ({
|
|
@@ -447,7 +582,17 @@ function mapStateToAwsConfig(props) {
|
|
|
447
582
|
)
|
|
448
583
|
})
|
|
449
584
|
),
|
|
450
|
-
assignments: [...assignmentsByKey.values()]
|
|
585
|
+
assignments: [...assignmentsByKey.values()],
|
|
586
|
+
accessControlAttributes: props.state.identityCenter.accessControlAttributes.length > 0 ? props.state.identityCenter.accessControlAttributes.map((attr) => ({
|
|
587
|
+
key: attr.key,
|
|
588
|
+
source: [...attr.source]
|
|
589
|
+
})) : void 0,
|
|
590
|
+
policies: scps.length > 0 || rcps.length > 0 || tagPolicies.length > 0 || aiServicesOptOutPolicies.length > 0 ? {
|
|
591
|
+
serviceControlPolicies: scps.length > 0 ? scps : void 0,
|
|
592
|
+
resourceControlPolicies: rcps.length > 0 ? rcps : void 0,
|
|
593
|
+
tagPolicies: tagPolicies.length > 0 ? tagPolicies : void 0,
|
|
594
|
+
aiServicesOptOutPolicies: aiServicesOptOutPolicies.length > 0 ? aiServicesOptOutPolicies : void 0
|
|
595
|
+
} : void 0
|
|
451
596
|
};
|
|
452
597
|
assertUniqueNames({
|
|
453
598
|
values: mapped.organizationalUnits.map((ou) => ou.name),
|
|
@@ -614,7 +759,8 @@ function mapAwsConfigToState(props) {
|
|
|
614
759
|
email: account.email,
|
|
615
760
|
status: matchedAccount?.status ?? "ACTIVE",
|
|
616
761
|
parentId: ownerParentId,
|
|
617
|
-
tags: account.tags
|
|
762
|
+
tags: account.tags,
|
|
763
|
+
alternateContacts: account.alternateContacts != null && account.alternateContacts.length > 0 ? account.alternateContacts : void 0
|
|
618
764
|
});
|
|
619
765
|
mappedAccountIdByName.set(account.name, mappedId);
|
|
620
766
|
}
|
|
@@ -628,10 +774,7 @@ function mapAwsConfigToState(props) {
|
|
|
628
774
|
email: user.email
|
|
629
775
|
};
|
|
630
776
|
});
|
|
631
|
-
const mappedUserByUserName = toRecordByProperty(
|
|
632
|
-
mappedUsers,
|
|
633
|
-
"userName"
|
|
634
|
-
);
|
|
777
|
+
const mappedUserByUserName = toRecordByProperty(mappedUsers, "userName");
|
|
635
778
|
const mappedGroups = props.config.groups.map((group) => {
|
|
636
779
|
const matchedGroup = groupByDisplayName[group.displayName];
|
|
637
780
|
return {
|
|
@@ -710,13 +853,107 @@ function mapAwsConfigToState(props) {
|
|
|
710
853
|
});
|
|
711
854
|
}
|
|
712
855
|
}
|
|
856
|
+
const configPolicies = props.config.policies;
|
|
857
|
+
const allConfigPolicies = [];
|
|
858
|
+
const ouByName = toRecordByProperty(
|
|
859
|
+
props.currentState.organization.organizationalUnits,
|
|
860
|
+
"name"
|
|
861
|
+
);
|
|
862
|
+
const stateAccountByName = toRecordByProperty(
|
|
863
|
+
props.currentState.organization.accounts,
|
|
864
|
+
"name"
|
|
865
|
+
);
|
|
866
|
+
function resolveTargetId(targetName) {
|
|
867
|
+
if (targetName === "root") {
|
|
868
|
+
return {
|
|
869
|
+
targetId: props.context.organization.rootId,
|
|
870
|
+
targetType: "ROOT"
|
|
871
|
+
};
|
|
872
|
+
}
|
|
873
|
+
const ou = ouByName[targetName];
|
|
874
|
+
if (ou != null) {
|
|
875
|
+
return { targetId: ou.id, targetType: "ORGANIZATIONAL_UNIT" };
|
|
876
|
+
}
|
|
877
|
+
const acct = stateAccountByName[targetName];
|
|
878
|
+
if (acct != null) {
|
|
879
|
+
return { targetId: acct.id, targetType: "ACCOUNT" };
|
|
880
|
+
}
|
|
881
|
+
return { targetId: pendingCreationId, targetType: "ACCOUNT" };
|
|
882
|
+
}
|
|
883
|
+
for (const policy of configPolicies?.serviceControlPolicies ?? []) {
|
|
884
|
+
allConfigPolicies.push({
|
|
885
|
+
name: policy.name,
|
|
886
|
+
description: policy.description ?? "",
|
|
887
|
+
type: "SERVICE_CONTROL_POLICY",
|
|
888
|
+
content: JSON.stringify(policy.content),
|
|
889
|
+
targets: policy.targets.map((t) => resolveTargetId(t))
|
|
890
|
+
});
|
|
891
|
+
}
|
|
892
|
+
for (const policy of configPolicies?.resourceControlPolicies ?? []) {
|
|
893
|
+
allConfigPolicies.push({
|
|
894
|
+
name: policy.name,
|
|
895
|
+
description: policy.description ?? "",
|
|
896
|
+
type: "RESOURCE_CONTROL_POLICY",
|
|
897
|
+
content: JSON.stringify(policy.content),
|
|
898
|
+
targets: policy.targets.map((t) => resolveTargetId(t))
|
|
899
|
+
});
|
|
900
|
+
}
|
|
901
|
+
for (const policy of configPolicies?.tagPolicies ?? []) {
|
|
902
|
+
allConfigPolicies.push({
|
|
903
|
+
name: policy.name,
|
|
904
|
+
description: policy.description ?? "",
|
|
905
|
+
type: "TAG_POLICY",
|
|
906
|
+
content: JSON.stringify(policy.content),
|
|
907
|
+
targets: policy.targets.map((t) => resolveTargetId(t))
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
for (const policy of configPolicies?.aiServicesOptOutPolicies ?? []) {
|
|
911
|
+
allConfigPolicies.push({
|
|
912
|
+
name: policy.name,
|
|
913
|
+
description: policy.description ?? "",
|
|
914
|
+
type: "AISERVICES_OPT_OUT_POLICY",
|
|
915
|
+
content: JSON.stringify(policy.content),
|
|
916
|
+
targets: policy.targets.map((t) => resolveTargetId(t))
|
|
917
|
+
});
|
|
918
|
+
}
|
|
919
|
+
const currentPoliciesByNameAndType = new Map(
|
|
920
|
+
(props.currentState.organization.policies ?? []).map((p) => [
|
|
921
|
+
`${p.type}|${p.name}`,
|
|
922
|
+
p
|
|
923
|
+
])
|
|
924
|
+
);
|
|
925
|
+
const mappedPolicies = allConfigPolicies.map((p) => {
|
|
926
|
+
const current = currentPoliciesByNameAndType.get(`${p.type}|${p.name}`);
|
|
927
|
+
return {
|
|
928
|
+
id: current?.id ?? pendingCreationId,
|
|
929
|
+
arn: current?.arn ?? pendingCreationId,
|
|
930
|
+
name: p.name,
|
|
931
|
+
description: p.description,
|
|
932
|
+
type: p.type,
|
|
933
|
+
content: p.content
|
|
934
|
+
};
|
|
935
|
+
});
|
|
936
|
+
const mappedPolicyAttachments = [];
|
|
937
|
+
for (let i = 0; i < allConfigPolicies.length; i++) {
|
|
938
|
+
const configPolicy = allConfigPolicies[i];
|
|
939
|
+
const mappedPolicy = mappedPolicies[i];
|
|
940
|
+
for (const target of configPolicy.targets) {
|
|
941
|
+
mappedPolicyAttachments.push({
|
|
942
|
+
policyId: mappedPolicy.id,
|
|
943
|
+
targetId: target.targetId,
|
|
944
|
+
targetType: target.targetType
|
|
945
|
+
});
|
|
946
|
+
}
|
|
947
|
+
}
|
|
713
948
|
const mapped = {
|
|
714
949
|
version: props.currentState.version,
|
|
715
950
|
generatedAt: props.currentState.generatedAt,
|
|
716
951
|
organization: {
|
|
717
952
|
rootId: props.context.organization.rootId,
|
|
718
953
|
organizationalUnits: mappedOrganizationalUnits,
|
|
719
|
-
accounts: mappedAccounts
|
|
954
|
+
accounts: mappedAccounts,
|
|
955
|
+
policies: mappedPolicies,
|
|
956
|
+
policyAttachments: mappedPolicyAttachments
|
|
720
957
|
},
|
|
721
958
|
identityCenter: {
|
|
722
959
|
instanceArn: props.context.identityCenter.instanceArn,
|
|
@@ -732,7 +969,10 @@ function mapAwsConfigToState(props) {
|
|
|
732
969
|
principalId: assignment.principalId,
|
|
733
970
|
principalType: assignment.principalType,
|
|
734
971
|
roleName: createAccessRoleName(assignment)
|
|
735
|
-
}))
|
|
972
|
+
})),
|
|
973
|
+
accessControlAttributes: (props.config.accessControlAttributes ?? []).map(
|
|
974
|
+
(attr) => ({ key: attr.key, source: [...attr.source] })
|
|
975
|
+
)
|
|
736
976
|
}
|
|
737
977
|
};
|
|
738
978
|
assertUniqueNames({
|
|
@@ -761,6 +1001,28 @@ function mapAwsConfigToState(props) {
|
|
|
761
1001
|
),
|
|
762
1002
|
entityName: "permission set"
|
|
763
1003
|
});
|
|
1004
|
+
assertUniqueNames({
|
|
1005
|
+
values: (props.config.policies?.serviceControlPolicies ?? []).map(
|
|
1006
|
+
(p) => p.name
|
|
1007
|
+
),
|
|
1008
|
+
entityName: "SCP"
|
|
1009
|
+
});
|
|
1010
|
+
assertUniqueNames({
|
|
1011
|
+
values: (props.config.policies?.resourceControlPolicies ?? []).map(
|
|
1012
|
+
(p) => p.name
|
|
1013
|
+
),
|
|
1014
|
+
entityName: "RCP"
|
|
1015
|
+
});
|
|
1016
|
+
assertUniqueNames({
|
|
1017
|
+
values: (props.config.policies?.tagPolicies ?? []).map((p) => p.name),
|
|
1018
|
+
entityName: "tag policy"
|
|
1019
|
+
});
|
|
1020
|
+
assertUniqueNames({
|
|
1021
|
+
values: (props.config.policies?.aiServicesOptOutPolicies ?? []).map(
|
|
1022
|
+
(p) => p.name
|
|
1023
|
+
),
|
|
1024
|
+
entityName: "AI services opt-out policy"
|
|
1025
|
+
});
|
|
764
1026
|
return validateState(mapped);
|
|
765
1027
|
}
|
|
766
1028
|
function sortAwsConfigModel(props) {
|
|
@@ -795,9 +1057,12 @@ function sortAwsConfigModel(props) {
|
|
|
795
1057
|
for (const child of children) {
|
|
796
1058
|
orderedOrganizationalUnits.push({
|
|
797
1059
|
...child,
|
|
798
|
-
accounts: [...child.accounts].sort(
|
|
799
|
-
|
|
800
|
-
|
|
1060
|
+
accounts: [...child.accounts].sort((left, right) => left.name.localeCompare(right.name)).map((account) => ({
|
|
1061
|
+
...account,
|
|
1062
|
+
alternateContacts: account.alternateContacts == null ? void 0 : [...account.alternateContacts].sort(
|
|
1063
|
+
(a, b) => a.contactType.localeCompare(b.contactType)
|
|
1064
|
+
)
|
|
1065
|
+
}))
|
|
801
1066
|
});
|
|
802
1067
|
queue.push(child.name);
|
|
803
1068
|
}
|
|
@@ -819,7 +1084,9 @@ function sortAwsConfigModel(props) {
|
|
|
819
1084
|
awsManagedPolicies: [...permissionSet.awsManagedPolicies].sort(
|
|
820
1085
|
(left, right) => left.localeCompare(right)
|
|
821
1086
|
),
|
|
822
|
-
customerManagedPolicies: [
|
|
1087
|
+
customerManagedPolicies: [
|
|
1088
|
+
...permissionSet.customerManagedPolicies
|
|
1089
|
+
].sort(
|
|
823
1090
|
(left, right) => compareStringKeys(left.path, right.path, left.name, right.name)
|
|
824
1091
|
)
|
|
825
1092
|
})).sort((left, right) => left.name.localeCompare(right.name)),
|
|
@@ -836,7 +1103,41 @@ function sortAwsConfigModel(props) {
|
|
|
836
1103
|
return principalComparison;
|
|
837
1104
|
}
|
|
838
1105
|
return left.permissionSet.localeCompare(right.permissionSet);
|
|
839
|
-
})
|
|
1106
|
+
}),
|
|
1107
|
+
accessControlAttributes: props.config.accessControlAttributes == null ? void 0 : [...props.config.accessControlAttributes].map((attr) => ({
|
|
1108
|
+
...attr,
|
|
1109
|
+
source: [...attr.source].sort((a, b) => a.localeCompare(b))
|
|
1110
|
+
})).sort((a, b) => a.key.localeCompare(b.key)),
|
|
1111
|
+
policies: props.config.policies == null ? void 0 : {
|
|
1112
|
+
serviceControlPolicies: props.config.policies.serviceControlPolicies == null ? void 0 : [...props.config.policies.serviceControlPolicies].map((p) => ({
|
|
1113
|
+
...p,
|
|
1114
|
+
content: sortJsonRecord(p.content),
|
|
1115
|
+
targets: [...p.targets].sort(
|
|
1116
|
+
(a, b) => a.localeCompare(b)
|
|
1117
|
+
)
|
|
1118
|
+
})).sort((a, b) => a.name.localeCompare(b.name)),
|
|
1119
|
+
resourceControlPolicies: props.config.policies.resourceControlPolicies == null ? void 0 : [...props.config.policies.resourceControlPolicies].map((p) => ({
|
|
1120
|
+
...p,
|
|
1121
|
+
content: sortJsonRecord(p.content),
|
|
1122
|
+
targets: [...p.targets].sort(
|
|
1123
|
+
(a, b) => a.localeCompare(b)
|
|
1124
|
+
)
|
|
1125
|
+
})).sort((a, b) => a.name.localeCompare(b.name)),
|
|
1126
|
+
tagPolicies: props.config.policies.tagPolicies == null ? void 0 : [...props.config.policies.tagPolicies].map((p) => ({
|
|
1127
|
+
...p,
|
|
1128
|
+
content: sortJsonRecord(p.content),
|
|
1129
|
+
targets: [...p.targets].sort(
|
|
1130
|
+
(a, b) => a.localeCompare(b)
|
|
1131
|
+
)
|
|
1132
|
+
})).sort((a, b) => a.name.localeCompare(b.name)),
|
|
1133
|
+
aiServicesOptOutPolicies: props.config.policies.aiServicesOptOutPolicies == null ? void 0 : [...props.config.policies.aiServicesOptOutPolicies].map((p) => ({
|
|
1134
|
+
...p,
|
|
1135
|
+
content: sortJsonRecord(p.content),
|
|
1136
|
+
targets: [...p.targets].sort(
|
|
1137
|
+
(a, b) => a.localeCompare(b)
|
|
1138
|
+
)
|
|
1139
|
+
})).sort((a, b) => a.name.localeCompare(b.name))
|
|
1140
|
+
}
|
|
840
1141
|
};
|
|
841
1142
|
}
|
|
842
1143
|
function renderAwsConfigTs(props) {
|
|
@@ -867,7 +1168,9 @@ function renderTsValue(value, props) {
|
|
|
867
1168
|
return "null";
|
|
868
1169
|
}
|
|
869
1170
|
if (value === void 0) {
|
|
870
|
-
throw new Error(
|
|
1171
|
+
throw new Error(
|
|
1172
|
+
"Undefined values must be handled before TypeScript rendering."
|
|
1173
|
+
);
|
|
871
1174
|
}
|
|
872
1175
|
if (typeof value === "string") {
|
|
873
1176
|
return renderTsStringValue(value, props);
|
|
@@ -907,14 +1210,16 @@ ${renderedItems.map((item) => `${childIndent}${item}`).join(",\n")}
|
|
|
907
1210
|
${indent}]`;
|
|
908
1211
|
}
|
|
909
1212
|
function renderTsObject(value, props) {
|
|
910
|
-
const entries = Object.entries(value).filter(
|
|
1213
|
+
const entries = Object.entries(value).filter(
|
|
1214
|
+
([, entryValue]) => entryValue !== void 0
|
|
1215
|
+
);
|
|
911
1216
|
if (entries.length === 0) {
|
|
912
1217
|
return "{}";
|
|
913
1218
|
}
|
|
914
1219
|
const indent = " ".repeat(props.indentLevel);
|
|
915
1220
|
const childIndent = " ".repeat(props.indentLevel + 1);
|
|
916
1221
|
const renderedEntries = entries.map(([key, entryValue]) => {
|
|
917
|
-
const nextWithinInlinePolicy = props.withinInlinePolicy || key === "inlinePolicy";
|
|
1222
|
+
const nextWithinInlinePolicy = props.withinInlinePolicy || key === "inlinePolicy" || key === "content";
|
|
918
1223
|
const renderedValue = renderTsValue(entryValue, {
|
|
919
1224
|
indentLevel: props.indentLevel + 1,
|
|
920
1225
|
withinInlinePolicy: nextWithinInlinePolicy,
|
|
@@ -1035,6 +1340,17 @@ export const awsConfigSchema = v.strictObject({
|
|
|
1035
1340
|
value: v.string(),
|
|
1036
1341
|
}),
|
|
1037
1342
|
),
|
|
1343
|
+
alternateContacts: v.optional(
|
|
1344
|
+
v.array(
|
|
1345
|
+
v.strictObject({
|
|
1346
|
+
contactType: v.picklist(["BILLING", "OPERATIONS", "SECURITY"]),
|
|
1347
|
+
name: v.string(),
|
|
1348
|
+
email: v.string(),
|
|
1349
|
+
phone: v.string(),
|
|
1350
|
+
title: v.optional(v.string()),
|
|
1351
|
+
}),
|
|
1352
|
+
),
|
|
1353
|
+
),
|
|
1038
1354
|
}),
|
|
1039
1355
|
),
|
|
1040
1356
|
}),
|
|
@@ -1076,6 +1392,58 @@ export const awsConfigSchema = v.strictObject({
|
|
|
1076
1392
|
accounts: v.array(accountNameSchema),
|
|
1077
1393
|
}),
|
|
1078
1394
|
),
|
|
1395
|
+
accessControlAttributes: v.optional(
|
|
1396
|
+
v.array(
|
|
1397
|
+
v.strictObject({
|
|
1398
|
+
key: v.string(),
|
|
1399
|
+
source: v.array(v.string()),
|
|
1400
|
+
}),
|
|
1401
|
+
),
|
|
1402
|
+
),
|
|
1403
|
+
policies: v.optional(
|
|
1404
|
+
v.strictObject({
|
|
1405
|
+
serviceControlPolicies: v.optional(
|
|
1406
|
+
v.array(
|
|
1407
|
+
v.strictObject({
|
|
1408
|
+
name: v.string(),
|
|
1409
|
+
description: v.optional(v.string()),
|
|
1410
|
+
content: v.record(v.string(), v.unknown()),
|
|
1411
|
+
targets: v.array(v.union([organizationalUnitNameSchema, accountNameSchema])),
|
|
1412
|
+
}),
|
|
1413
|
+
),
|
|
1414
|
+
),
|
|
1415
|
+
resourceControlPolicies: v.optional(
|
|
1416
|
+
v.array(
|
|
1417
|
+
v.strictObject({
|
|
1418
|
+
name: v.string(),
|
|
1419
|
+
description: v.optional(v.string()),
|
|
1420
|
+
content: v.record(v.string(), v.unknown()),
|
|
1421
|
+
targets: v.array(v.union([organizationalUnitNameSchema, accountNameSchema])),
|
|
1422
|
+
}),
|
|
1423
|
+
),
|
|
1424
|
+
),
|
|
1425
|
+
tagPolicies: v.optional(
|
|
1426
|
+
v.array(
|
|
1427
|
+
v.strictObject({
|
|
1428
|
+
name: v.string(),
|
|
1429
|
+
description: v.optional(v.string()),
|
|
1430
|
+
content: v.record(v.string(), v.unknown()),
|
|
1431
|
+
targets: v.array(v.union([organizationalUnitNameSchema, accountNameSchema])),
|
|
1432
|
+
}),
|
|
1433
|
+
),
|
|
1434
|
+
),
|
|
1435
|
+
aiServicesOptOutPolicies: v.optional(
|
|
1436
|
+
v.array(
|
|
1437
|
+
v.strictObject({
|
|
1438
|
+
name: v.string(),
|
|
1439
|
+
description: v.optional(v.string()),
|
|
1440
|
+
content: v.record(v.string(), v.unknown()),
|
|
1441
|
+
targets: v.array(v.union([organizationalUnitNameSchema, accountNameSchema])),
|
|
1442
|
+
}),
|
|
1443
|
+
),
|
|
1444
|
+
),
|
|
1445
|
+
}),
|
|
1446
|
+
),
|
|
1079
1447
|
});
|
|
1080
1448
|
|
|
1081
1449
|
export type AwsConfig = v.InferOutput<typeof awsConfigSchema>;
|
|
@@ -1234,6 +1602,16 @@ async function loadAwsConfigModelFromTsFile(props) {
|
|
|
1234
1602
|
async function readAwsContextFromFile(path) {
|
|
1235
1603
|
return readAwsContextFile(path);
|
|
1236
1604
|
}
|
|
1605
|
+
async function readPackageVersion() {
|
|
1606
|
+
const thisFile = fileURLToPath(import.meta.url);
|
|
1607
|
+
const packageDir = dirname(dirname(thisFile));
|
|
1608
|
+
const raw = await readFile(join(packageDir, "package.json"), "utf8");
|
|
1609
|
+
const pkg = JSON.parse(raw);
|
|
1610
|
+
if (typeof pkg.version !== "string") {
|
|
1611
|
+
throw new Error("Could not read version from package.json.");
|
|
1612
|
+
}
|
|
1613
|
+
return pkg.version;
|
|
1614
|
+
}
|
|
1237
1615
|
async function loadAwsConfigTypesModule(props) {
|
|
1238
1616
|
const loadedModule = await loadTsModule({
|
|
1239
1617
|
modulePath: props.typesPath
|
|
@@ -1361,6 +1739,7 @@ export {
|
|
|
1361
1739
|
loadAwsConfigModelFromTsFile,
|
|
1362
1740
|
mapAwsConfigToState,
|
|
1363
1741
|
readAwsContextFromFile,
|
|
1742
|
+
readPackageVersion,
|
|
1364
1743
|
regenerateAwsConfigTypes,
|
|
1365
1744
|
regenerateTypesFromState,
|
|
1366
1745
|
writeAwsConfigFromState
|