@mtndev/cli 1.1.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/cjs/__chunks/VH7oDXx4.cjs +28 -0
  3. package/cjs/commands/aws/ec2/allow-ip/handler.cjs +261 -0
  4. package/cjs/commands/aws/ec2/allow-ip/handler.d.ts +6 -0
  5. package/cjs/commands/aws/ec2/allow-ip/index.cjs +25 -0
  6. package/cjs/commands/aws/ec2/allow-ip/index.d.ts +3 -0
  7. package/cjs/commands/aws/ec2/allow-ip/schema.cjs +33 -0
  8. package/cjs/commands/aws/ec2/allow-ip/schema.d.ts +33 -0
  9. package/cjs/commands/aws/ec2/allow-ip/utils.cjs +379 -0
  10. package/cjs/commands/aws/ec2/allow-ip/utils.d.ts +189 -0
  11. package/cjs/commands/aws/iam/admin-group.cjs +111 -0
  12. package/cjs/commands/aws/iam/admin-group.d.ts +55 -0
  13. package/cjs/commands/aws/iam/break-glass/handler.cjs +127 -0
  14. package/cjs/commands/aws/iam/break-glass/handler.d.ts +7 -0
  15. package/cjs/commands/aws/iam/break-glass/index.cjs +7 -0
  16. package/cjs/commands/aws/iam/break-glass/index.d.ts +2 -0
  17. package/cjs/commands/aws/iam/break-glass/schema.cjs +21 -0
  18. package/cjs/commands/aws/iam/break-glass/schema.d.ts +25 -0
  19. package/cjs/commands/aws/iam/check-admin/handler.cjs +89 -0
  20. package/cjs/commands/aws/iam/check-admin/handler.d.ts +5 -0
  21. package/cjs/commands/aws/iam/check-admin/index.cjs +7 -0
  22. package/cjs/commands/aws/iam/check-admin/index.d.ts +2 -0
  23. package/cjs/commands/aws/iam/check-admin/schema.cjs +19 -0
  24. package/cjs/commands/aws/iam/check-admin/schema.d.ts +19 -0
  25. package/cjs/commands/aws/iam/policies/s3-restrictions-deny-non-s3-services.json +20 -0
  26. package/cjs/commands/aws/iam/policies/sts-federation.json +11 -0
  27. package/cjs/commands/aws/iam/policies/user-admins-deny-list.json +175 -0
  28. package/cjs/commands/aws/iam/policies/user-admins-deny-regions-list.json +41 -0
  29. package/cjs/commands/aws/iam/policies/user-admins-self-service-iam.json +56 -0
  30. package/cjs/commands/aws/iam/policies/user-admins-write-list.json +117 -0
  31. package/cjs/commands/aws/iam/remove-admin/handler.cjs +120 -0
  32. package/cjs/commands/aws/iam/remove-admin/handler.d.ts +6 -0
  33. package/cjs/commands/aws/iam/remove-admin/index.cjs +7 -0
  34. package/cjs/commands/aws/iam/remove-admin/index.d.ts +2 -0
  35. package/cjs/commands/aws/iam/remove-admin/schema.cjs +22 -0
  36. package/cjs/commands/aws/iam/remove-admin/schema.d.ts +28 -0
  37. package/cjs/commands/aws/iam/setup-acl/handler.cjs +227 -0
  38. package/cjs/commands/aws/iam/setup-acl/handler.d.ts +6 -0
  39. package/cjs/commands/aws/iam/setup-acl/index.cjs +13 -0
  40. package/cjs/commands/aws/iam/setup-acl/index.d.ts +3 -0
  41. package/cjs/commands/aws/iam/setup-acl/schema.cjs +19 -0
  42. package/cjs/commands/aws/iam/setup-acl/schema.d.ts +24 -0
  43. package/cjs/commands/aws/iam/setup-acl/utils.cjs +305 -0
  44. package/cjs/commands/aws/iam/setup-acl/utils.d.ts +61 -0
  45. package/cjs/commands/aws/iam/users/handler.cjs +59 -0
  46. package/cjs/commands/aws/iam/users/handler.d.ts +5 -0
  47. package/cjs/commands/aws/iam/users/index.cjs +18 -0
  48. package/cjs/commands/aws/iam/users/index.d.ts +3 -0
  49. package/cjs/commands/aws/iam/users/schema.cjs +17 -0
  50. package/cjs/commands/aws/iam/users/schema.d.ts +18 -0
  51. package/cjs/commands/aws/iam/users/utils.cjs +454 -0
  52. package/cjs/commands/aws/iam/users/utils.d.ts +119 -0
  53. package/cjs/commands/aws/index.cjs +223 -0
  54. package/cjs/commands/aws/index.d.ts +14 -0
  55. package/cjs/commands/aws/route53/add-record/handler.cjs +264 -0
  56. package/cjs/commands/aws/route53/add-record/handler.d.ts +36 -0
  57. package/cjs/commands/aws/route53/add-record/index.cjs +26 -0
  58. package/cjs/commands/aws/route53/add-record/index.d.ts +3 -0
  59. package/cjs/commands/aws/route53/add-record/schema.cjs +43 -0
  60. package/cjs/commands/aws/route53/add-record/schema.d.ts +45 -0
  61. package/cjs/commands/aws/route53/add-record/utils.cjs +404 -0
  62. package/cjs/commands/aws/route53/add-record/utils.d.ts +216 -0
  63. package/cjs/commands/aws/route53/remove-record/handler.cjs +114 -0
  64. package/cjs/commands/aws/route53/remove-record/handler.d.ts +6 -0
  65. package/cjs/commands/aws/route53/remove-record/index.cjs +5 -0
  66. package/cjs/commands/aws/route53/remove-record/index.d.ts +2 -0
  67. package/cjs/commands/aws/route53/remove-record/schema.cjs +22 -0
  68. package/cjs/commands/aws/route53/remove-record/schema.d.ts +30 -0
  69. package/cjs/commands/aws/schema.cjs +19 -0
  70. package/cjs/commands/aws/schema.d.ts +13 -0
  71. package/cjs/commands/aws/ses/send-email/handler.cjs +73 -0
  72. package/cjs/commands/aws/ses/send-email/handler.d.ts +5 -0
  73. package/cjs/commands/aws/ses/send-email/index.cjs +9 -0
  74. package/cjs/commands/aws/ses/send-email/index.d.ts +3 -0
  75. package/cjs/commands/aws/ses/send-email/schema.cjs +24 -0
  76. package/cjs/commands/aws/ses/send-email/schema.d.ts +39 -0
  77. package/cjs/commands/aws/ses/send-email/utils.cjs +87 -0
  78. package/cjs/commands/aws/ses/send-email/utils.d.ts +47 -0
  79. package/cjs/commands/aws/ses/smtp-password.cjs +72 -0
  80. package/cjs/commands/aws/ses/smtp-password.d.ts +21 -0
  81. package/cjs/commands/aws/utils/exec-aws.cjs +145 -0
  82. package/cjs/commands/aws/utils/exec-aws.d.ts +79 -0
  83. package/cjs/commands/aws/utils/resolve-policy-path.cjs +15 -0
  84. package/cjs/commands/aws/utils/resolve-policy-path.d.ts +8 -0
  85. package/cjs/commands/aws/utils/resolve-profile.cjs +93 -0
  86. package/cjs/commands/aws/utils/resolve-profile.d.ts +28 -0
  87. package/cjs/commands/aws/utils/tty.cjs +54 -0
  88. package/cjs/commands/aws/utils/tty.d.ts +24 -0
  89. package/cjs/commands/db/create-readonly-user/handler.cjs +254 -0
  90. package/cjs/commands/db/create-readonly-user/handler.d.ts +5 -0
  91. package/cjs/commands/db/create-readonly-user/index.cjs +18 -0
  92. package/cjs/commands/db/create-readonly-user/index.d.ts +3 -0
  93. package/cjs/commands/db/create-readonly-user/mysql.cjs +102 -0
  94. package/cjs/commands/db/create-readonly-user/mysql.d.ts +33 -0
  95. package/cjs/commands/db/create-readonly-user/postgres.cjs +209 -0
  96. package/cjs/commands/db/create-readonly-user/postgres.d.ts +31 -0
  97. package/cjs/commands/db/create-readonly-user/schema.cjs +39 -0
  98. package/cjs/commands/db/create-readonly-user/schema.d.ts +55 -0
  99. package/cjs/commands/db/create-readonly-user/utils.cjs +160 -0
  100. package/cjs/commands/db/create-readonly-user/utils.d.ts +112 -0
  101. package/cjs/commands/db/index.cjs +46 -0
  102. package/cjs/commands/db/index.d.ts +6 -0
  103. package/cjs/commands/doppler/handler.cjs +95 -9
  104. package/cjs/commands/doppler/index.cjs +33 -41
  105. package/cjs/commands/doppler/index.d.ts +1 -0
  106. package/cjs/commands/doppler/schema.cjs +130 -6
  107. package/cjs/commands/doppler/schema.d.ts +233 -17
  108. package/cjs/commands/doppler/set-secret.cjs +378 -0
  109. package/cjs/commands/doppler/set-secret.d.ts +113 -0
  110. package/cjs/commands/doppler/utils/exec.cjs +106 -12
  111. package/cjs/commands/doppler/utils.cjs +412 -30
  112. package/cjs/commands/doppler/utils.d.ts +32 -8
  113. package/cjs/commands/icons/handler.cjs +82 -8
  114. package/cjs/commands/icons/index.cjs +15 -31
  115. package/cjs/commands/icons/schema.cjs +101 -13
  116. package/cjs/commands/icons/schema.d.ts +1 -1
  117. package/cjs/commands/icons/utils.cjs +131 -13
  118. package/cjs/commands/index.cjs +54 -82
  119. package/cjs/commands/schema.cjs +25 -8
  120. package/cjs/index.cjs +3 -4
  121. package/esm/commands/aws/ec2/allow-ip/handler.d.ts +6 -0
  122. package/esm/commands/aws/ec2/allow-ip/handler.js +258 -0
  123. package/esm/commands/aws/ec2/allow-ip/index.d.ts +3 -0
  124. package/esm/commands/aws/ec2/allow-ip/index.js +4 -0
  125. package/esm/commands/aws/ec2/allow-ip/schema.d.ts +33 -0
  126. package/esm/commands/aws/ec2/allow-ip/schema.js +29 -0
  127. package/esm/commands/aws/ec2/allow-ip/utils.d.ts +189 -0
  128. package/esm/commands/aws/ec2/allow-ip/utils.js +363 -0
  129. package/esm/commands/aws/iam/admin-group.d.ts +55 -0
  130. package/esm/commands/aws/iam/admin-group.js +104 -0
  131. package/esm/commands/aws/iam/break-glass/handler.d.ts +7 -0
  132. package/esm/commands/aws/iam/break-glass/handler.js +124 -0
  133. package/esm/commands/aws/iam/break-glass/index.d.ts +2 -0
  134. package/esm/commands/aws/iam/break-glass/index.js +4 -0
  135. package/esm/commands/aws/iam/break-glass/schema.d.ts +25 -0
  136. package/esm/commands/aws/iam/break-glass/schema.js +19 -0
  137. package/esm/commands/aws/iam/check-admin/handler.d.ts +5 -0
  138. package/esm/commands/aws/iam/check-admin/handler.js +86 -0
  139. package/esm/commands/aws/iam/check-admin/index.d.ts +2 -0
  140. package/esm/commands/aws/iam/check-admin/index.js +4 -0
  141. package/esm/commands/aws/iam/check-admin/schema.d.ts +19 -0
  142. package/esm/commands/aws/iam/check-admin/schema.js +17 -0
  143. package/esm/commands/aws/iam/policies/s3-restrictions-deny-non-s3-services.json +20 -0
  144. package/esm/commands/aws/iam/policies/sts-federation.json +11 -0
  145. package/esm/commands/aws/iam/policies/user-admins-deny-list.json +175 -0
  146. package/esm/commands/aws/iam/policies/user-admins-deny-regions-list.json +41 -0
  147. package/esm/commands/aws/iam/policies/user-admins-self-service-iam.json +56 -0
  148. package/esm/commands/aws/iam/policies/user-admins-write-list.json +117 -0
  149. package/esm/commands/aws/iam/remove-admin/handler.d.ts +6 -0
  150. package/esm/commands/aws/iam/remove-admin/handler.js +117 -0
  151. package/esm/commands/aws/iam/remove-admin/index.d.ts +2 -0
  152. package/esm/commands/aws/iam/remove-admin/index.js +4 -0
  153. package/esm/commands/aws/iam/remove-admin/schema.d.ts +28 -0
  154. package/esm/commands/aws/iam/remove-admin/schema.js +20 -0
  155. package/esm/commands/aws/iam/setup-acl/handler.d.ts +6 -0
  156. package/esm/commands/aws/iam/setup-acl/handler.js +224 -0
  157. package/esm/commands/aws/iam/setup-acl/index.d.ts +3 -0
  158. package/esm/commands/aws/iam/setup-acl/index.js +4 -0
  159. package/esm/commands/aws/iam/setup-acl/schema.d.ts +24 -0
  160. package/esm/commands/aws/iam/setup-acl/schema.js +18 -0
  161. package/esm/commands/aws/iam/setup-acl/utils.d.ts +61 -0
  162. package/esm/commands/aws/iam/setup-acl/utils.js +298 -0
  163. package/esm/commands/aws/iam/users/handler.d.ts +5 -0
  164. package/esm/commands/aws/iam/users/handler.js +56 -0
  165. package/esm/commands/aws/iam/users/index.d.ts +3 -0
  166. package/esm/commands/aws/iam/users/index.js +4 -0
  167. package/esm/commands/aws/iam/users/schema.d.ts +18 -0
  168. package/esm/commands/aws/iam/users/schema.js +16 -0
  169. package/esm/commands/aws/iam/users/utils.d.ts +119 -0
  170. package/esm/commands/aws/iam/users/utils.js +440 -0
  171. package/esm/commands/aws/index.d.ts +14 -0
  172. package/esm/commands/aws/index.js +142 -0
  173. package/esm/commands/aws/route53/add-record/handler.d.ts +36 -0
  174. package/esm/commands/aws/route53/add-record/handler.js +258 -0
  175. package/esm/commands/aws/route53/add-record/index.d.ts +3 -0
  176. package/esm/commands/aws/route53/add-record/index.js +4 -0
  177. package/esm/commands/aws/route53/add-record/schema.d.ts +45 -0
  178. package/esm/commands/aws/route53/add-record/schema.js +40 -0
  179. package/esm/commands/aws/route53/add-record/utils.d.ts +216 -0
  180. package/esm/commands/aws/route53/add-record/utils.js +389 -0
  181. package/esm/commands/aws/route53/remove-record/handler.d.ts +6 -0
  182. package/esm/commands/aws/route53/remove-record/handler.js +111 -0
  183. package/esm/commands/aws/route53/remove-record/index.d.ts +2 -0
  184. package/esm/commands/aws/route53/remove-record/index.js +3 -0
  185. package/esm/commands/aws/route53/remove-record/schema.d.ts +30 -0
  186. package/esm/commands/aws/route53/remove-record/schema.js +21 -0
  187. package/esm/commands/aws/schema.d.ts +13 -0
  188. package/esm/commands/aws/schema.js +16 -0
  189. package/esm/commands/aws/ses/send-email/handler.d.ts +5 -0
  190. package/esm/commands/aws/ses/send-email/handler.js +70 -0
  191. package/esm/commands/aws/ses/send-email/index.d.ts +3 -0
  192. package/esm/commands/aws/ses/send-email/index.js +4 -0
  193. package/esm/commands/aws/ses/send-email/schema.d.ts +39 -0
  194. package/esm/commands/aws/ses/send-email/schema.js +23 -0
  195. package/esm/commands/aws/ses/send-email/utils.d.ts +47 -0
  196. package/esm/commands/aws/ses/send-email/utils.js +84 -0
  197. package/esm/commands/aws/ses/smtp-password.d.ts +21 -0
  198. package/esm/commands/aws/ses/smtp-password.js +69 -0
  199. package/esm/commands/aws/utils/exec-aws.d.ts +79 -0
  200. package/esm/commands/aws/utils/exec-aws.js +137 -0
  201. package/esm/commands/aws/utils/resolve-policy-path.d.ts +8 -0
  202. package/esm/commands/aws/utils/resolve-policy-path.js +14 -0
  203. package/esm/commands/aws/utils/resolve-profile.d.ts +28 -0
  204. package/esm/commands/aws/utils/resolve-profile.js +88 -0
  205. package/esm/commands/aws/utils/tty.d.ts +24 -0
  206. package/esm/commands/aws/utils/tty.js +51 -0
  207. package/esm/commands/db/create-readonly-user/handler.d.ts +5 -0
  208. package/esm/commands/db/create-readonly-user/handler.js +251 -0
  209. package/esm/commands/db/create-readonly-user/index.d.ts +3 -0
  210. package/esm/commands/db/create-readonly-user/index.js +4 -0
  211. package/esm/commands/db/create-readonly-user/mysql.d.ts +33 -0
  212. package/esm/commands/db/create-readonly-user/mysql.js +98 -0
  213. package/esm/commands/db/create-readonly-user/postgres.d.ts +31 -0
  214. package/esm/commands/db/create-readonly-user/postgres.js +205 -0
  215. package/esm/commands/db/create-readonly-user/schema.d.ts +55 -0
  216. package/esm/commands/db/create-readonly-user/schema.js +35 -0
  217. package/esm/commands/db/create-readonly-user/utils.d.ts +112 -0
  218. package/esm/commands/db/create-readonly-user/utils.js +151 -0
  219. package/esm/commands/db/index.d.ts +6 -0
  220. package/esm/commands/db/index.js +31 -0
  221. package/esm/commands/doppler/handler.js +92 -9
  222. package/esm/commands/doppler/index.d.ts +1 -0
  223. package/esm/commands/doppler/index.js +6 -41
  224. package/esm/commands/doppler/schema.d.ts +233 -17
  225. package/esm/commands/doppler/schema.js +125 -7
  226. package/esm/commands/doppler/set-secret.d.ts +113 -0
  227. package/esm/commands/doppler/set-secret.js +370 -0
  228. package/esm/commands/doppler/utils/exec.js +100 -12
  229. package/esm/commands/doppler/utils.d.ts +32 -8
  230. package/esm/commands/doppler/utils.js +396 -30
  231. package/esm/commands/icons/handler.js +79 -8
  232. package/esm/commands/icons/index.js +4 -31
  233. package/esm/commands/icons/schema.d.ts +1 -1
  234. package/esm/commands/icons/schema.js +97 -15
  235. package/esm/commands/icons/utils.js +125 -13
  236. package/esm/commands/index.js +49 -78
  237. package/esm/commands/schema.js +22 -7
  238. package/esm/index.js +3 -4
  239. package/package.json +12 -2
  240. package/vitest.config.ts +11 -0
  241. package/cjs/__chunks/4GFJUCSP.cjs +0 -52
  242. package/cjs/__chunks/4SFWHCB3.cjs +0 -133
  243. package/cjs/__chunks/B2KFW7T7.cjs +0 -1
  244. package/cjs/__chunks/EMMC33QA.cjs +0 -401
  245. package/cjs/__chunks/INFOPAHN.cjs +0 -117
  246. package/cjs/__chunks/J36P6UNE.cjs +0 -75
  247. package/cjs/__chunks/NIMXXHJQ.cjs +0 -92
  248. package/cjs/__chunks/NSRFG4DF.cjs +0 -100
  249. package/cjs/__chunks/WNJ3ZYLI.cjs +0 -1
  250. package/cjs/__chunks/ZMDIOZPT.cjs +0 -22
  251. package/esm/__chunks/46HGXFME.js +0 -0
  252. package/esm/__chunks/6G4PXXKF.js +0 -75
  253. package/esm/__chunks/6L5RNR7G.js +0 -100
  254. package/esm/__chunks/FL7AILGH.js +0 -133
  255. package/esm/__chunks/HJSXC6HP.js +0 -117
  256. package/esm/__chunks/O262GK4B.js +0 -401
  257. package/esm/__chunks/O3CCA76Q.js +0 -22
  258. package/esm/__chunks/SJXQJ7RS.js +0 -92
  259. package/esm/__chunks/SNCKIAOR.js +0 -0
  260. package/esm/__chunks/X3R5PSWH.js +0 -52
@@ -0,0 +1,298 @@
1
+ import { runAws } from "../../utils/exec-aws.js";
2
+ import { resolvePolicyPath } from "../../utils/resolve-policy-path.js";
3
+ //#region src/commands/aws/iam/setup-acl/utils.js
4
+ /**
5
+ * The five ACL groups managed by setup-acl.
6
+ */
7
+ const ACL_GROUPS = [
8
+ "acl-admin-do-not-use",
9
+ "acl-iam-full-access",
10
+ "acl-power-users",
11
+ "acl-read-only",
12
+ "acl-s3-restrictions"
13
+ ];
14
+ /**
15
+ * Custom managed policies published from bundled JSON documents.
16
+ * @type {Array<{ name: string; fileName: string }>}
17
+ */
18
+ const CUSTOM_POLICIES = [
19
+ {
20
+ name: "UserAdminsWriteList",
21
+ fileName: "user-admins-write-list.json"
22
+ },
23
+ {
24
+ name: "UserAdminsDenyList",
25
+ fileName: "user-admins-deny-list.json"
26
+ },
27
+ {
28
+ name: "UserAdminsSelfServiceIAM",
29
+ fileName: "user-admins-self-service-iam.json"
30
+ },
31
+ {
32
+ name: "UserAdminsDenyRegionsList",
33
+ fileName: "user-admins-deny-regions-list.json"
34
+ },
35
+ {
36
+ name: "sts-federation",
37
+ fileName: "sts-federation.json"
38
+ },
39
+ {
40
+ name: "S3RestrictionsDenyNonS3Services",
41
+ fileName: "s3-restrictions-deny-non-s3-services.json"
42
+ }
43
+ ];
44
+ /**
45
+ * Create an IAM group if it does not already exist.
46
+ * @param {{ name: string; profile?: string; verbose?: boolean }} params
47
+ */
48
+ function ensureGroup(params) {
49
+ const { name, profile, verbose } = params;
50
+ let exists = true;
51
+ try {
52
+ runAws({
53
+ profile,
54
+ args: [
55
+ "iam",
56
+ "get-group",
57
+ "--group-name",
58
+ name
59
+ ],
60
+ verbose
61
+ });
62
+ } catch {
63
+ exists = false;
64
+ }
65
+ if (exists) {
66
+ console.log(` Group exists: ${name}`);
67
+ return;
68
+ }
69
+ console.log(` Create group: ${name}`);
70
+ runAws({
71
+ profile,
72
+ args: [
73
+ "iam",
74
+ "create-group",
75
+ "--group-name",
76
+ name,
77
+ "--path",
78
+ "/"
79
+ ],
80
+ expectJson: false,
81
+ verbose
82
+ });
83
+ }
84
+ /**
85
+ * Create or update a customer-managed policy from a bundled JSON document.
86
+ * Handles the IAM five-version limit by pruning the oldest non-default version.
87
+ * @param {{ name: string; fileName: string; accountId: string; profile?: string; verbose?: boolean }} params
88
+ */
89
+ function publishPolicy(params) {
90
+ const { name, fileName, accountId, profile, verbose } = params;
91
+ const arn = `arn:aws:iam::${accountId}:policy/${name}`;
92
+ const file = resolvePolicyPath(fileName);
93
+ let exists = true;
94
+ try {
95
+ runAws({
96
+ profile,
97
+ args: [
98
+ "iam",
99
+ "get-policy",
100
+ "--policy-arn",
101
+ arn
102
+ ],
103
+ verbose
104
+ });
105
+ } catch {
106
+ exists = false;
107
+ }
108
+ if (!exists) {
109
+ console.log(` Create policy: ${name}`);
110
+ runAws({
111
+ profile,
112
+ args: [
113
+ "iam",
114
+ "create-policy",
115
+ "--policy-name",
116
+ name,
117
+ "--policy-document",
118
+ `file://${file}`,
119
+ "--description",
120
+ `ACL: ${name}`
121
+ ],
122
+ expectJson: false,
123
+ verbose
124
+ });
125
+ return;
126
+ }
127
+ if ((Number.parseInt(runAws({
128
+ profile,
129
+ args: [
130
+ "iam",
131
+ "list-policy-versions",
132
+ "--policy-arn",
133
+ arn,
134
+ "--query",
135
+ "length(Versions[?IsDefaultVersion==`false`])",
136
+ "--output",
137
+ "text"
138
+ ],
139
+ expectJson: false,
140
+ verbose
141
+ }), 10) || 0) >= 4) {
142
+ const oldest = runAws({
143
+ profile,
144
+ args: [
145
+ "iam",
146
+ "list-policy-versions",
147
+ "--policy-arn",
148
+ arn,
149
+ "--query",
150
+ "Versions[?IsDefaultVersion==`false`] | sort_by(@, &CreateDate)[0].VersionId",
151
+ "--output",
152
+ "text"
153
+ ],
154
+ expectJson: false,
155
+ verbose
156
+ });
157
+ console.log(` Prune oldest version of ${name}: ${oldest}`);
158
+ runAws({
159
+ profile,
160
+ args: [
161
+ "iam",
162
+ "delete-policy-version",
163
+ "--policy-arn",
164
+ arn,
165
+ "--version-id",
166
+ oldest
167
+ ],
168
+ expectJson: false,
169
+ verbose
170
+ });
171
+ }
172
+ console.log(` Update policy: ${name}`);
173
+ runAws({
174
+ profile,
175
+ args: [
176
+ "iam",
177
+ "create-policy-version",
178
+ "--policy-arn",
179
+ arn,
180
+ "--policy-document",
181
+ `file://${file}`,
182
+ "--set-as-default"
183
+ ],
184
+ expectJson: false,
185
+ verbose
186
+ });
187
+ }
188
+ /**
189
+ * @param {{ group: string; arn: string; profile?: string; verbose?: boolean }} params
190
+ * @returns {boolean}
191
+ */
192
+ function isPolicyAttached(params) {
193
+ const { group, arn, profile, verbose } = params;
194
+ const out = runAws({
195
+ profile,
196
+ args: [
197
+ "iam",
198
+ "list-attached-group-policies",
199
+ "--group-name",
200
+ group,
201
+ "--query",
202
+ `AttachedPolicies[?PolicyArn=='${arn}'].PolicyArn`,
203
+ "--output",
204
+ "text"
205
+ ],
206
+ expectJson: false,
207
+ verbose
208
+ });
209
+ return Boolean(out);
210
+ }
211
+ /**
212
+ * Attach a policy to a group if not already attached.
213
+ * @param {{ group: string; arn: string; profile?: string; verbose?: boolean }} params
214
+ */
215
+ function attach(params) {
216
+ const { group, arn, profile, verbose } = params;
217
+ const policyName = arn.split("/").pop() ?? arn;
218
+ if (isPolicyAttached({
219
+ group,
220
+ arn,
221
+ profile,
222
+ verbose
223
+ })) {
224
+ console.log(` [${group}] already attached: ${policyName}`);
225
+ return;
226
+ }
227
+ console.log(` [${group}] attach: ${policyName}`);
228
+ runAws({
229
+ profile,
230
+ args: [
231
+ "iam",
232
+ "attach-group-policy",
233
+ "--group-name",
234
+ group,
235
+ "--policy-arn",
236
+ arn
237
+ ],
238
+ expectJson: false,
239
+ verbose
240
+ });
241
+ }
242
+ /**
243
+ * Detach a (legacy) policy from a group if it is currently attached.
244
+ * @param {{ group: string; arn: string; profile?: string; verbose?: boolean }} params
245
+ */
246
+ function detach(params) {
247
+ const { group, arn, profile, verbose } = params;
248
+ const policyName = arn.split("/").pop() ?? arn;
249
+ if (!isPolicyAttached({
250
+ group,
251
+ arn,
252
+ profile,
253
+ verbose
254
+ })) return;
255
+ console.log(` [${group}] detach legacy: ${policyName}`);
256
+ runAws({
257
+ profile,
258
+ args: [
259
+ "iam",
260
+ "detach-group-policy",
261
+ "--group-name",
262
+ group,
263
+ "--policy-arn",
264
+ arn
265
+ ],
266
+ expectJson: false,
267
+ verbose
268
+ });
269
+ }
270
+ /**
271
+ * Print the attached policies for each ACL group.
272
+ * @param {{ profile?: string; verbose?: boolean }} params
273
+ */
274
+ function printFinalState(params) {
275
+ const { profile, verbose } = params;
276
+ for (const group of ACL_GROUPS) {
277
+ console.log("");
278
+ console.log(`=== ${group} ===`);
279
+ const table = runAws({
280
+ profile,
281
+ args: [
282
+ "iam",
283
+ "list-attached-group-policies",
284
+ "--group-name",
285
+ group,
286
+ "--query",
287
+ "AttachedPolicies[].PolicyName",
288
+ "--output",
289
+ "table"
290
+ ],
291
+ expectJson: false,
292
+ verbose
293
+ });
294
+ console.log(table);
295
+ }
296
+ }
297
+ //#endregion
298
+ export { ACL_GROUPS, CUSTOM_POLICIES, attach, detach, ensureGroup, printFinalState, publishPolicy };
@@ -0,0 +1,5 @@
1
+ /**
2
+ * `aws iam users` handler: interactively create IAM users and assign ACL groups.
3
+ * @param {unknown} options
4
+ */
5
+ export function usersCommand(options: unknown): Promise<void>;
@@ -0,0 +1,56 @@
1
+ import { getCallerIdentity, requireCommands } from "../../utils/exec-aws.js";
2
+ import { resolveProfile } from "../../utils/resolve-profile.js";
3
+ import { usersOptionsSchema } from "./schema.js";
4
+ import { createUsersInteractive } from "./utils.js";
5
+ import chalk from "chalk";
6
+ import { ZodError } from "zod";
7
+ //#region src/commands/aws/iam/users/handler.js
8
+ /**
9
+ * `aws iam users` handler: interactively create IAM users and assign ACL groups.
10
+ * @param {unknown} options
11
+ */
12
+ async function usersCommand(options) {
13
+ try {
14
+ const { accountName, profile: profileOption, verbose } = usersOptionsSchema.parse(options);
15
+ requireCommands(["aws"]);
16
+ const profile = await resolveProfile({ profile: profileOption });
17
+ console.log(chalk.blue("\nAWS IAM user management"));
18
+ console.log("");
19
+ console.log("Caller:");
20
+ const identity = getCallerIdentity({
21
+ profile,
22
+ verbose
23
+ });
24
+ console.log(` Account: ${identity.Account}`);
25
+ console.log(` Arn: ${identity.Arn}`);
26
+ console.log("");
27
+ await createUsersInteractive({
28
+ accountName,
29
+ profile,
30
+ identity,
31
+ verbose
32
+ });
33
+ console.log("Done.");
34
+ } catch (error) {
35
+ if (error instanceof ZodError) {
36
+ console.error(chalk.red("\n❌ Invalid command options:"));
37
+ error.errors.forEach((err) => {
38
+ console.error(chalk.red(` ${err.path.join(".")}: ${err.message}`));
39
+ });
40
+ process.exit(1);
41
+ }
42
+ const verbose = options?.verbose || false;
43
+ console.error(chalk.red("\n❌ iam users failed:"));
44
+ if (error instanceof Error) {
45
+ console.error(chalk.red(` ${error.message}`));
46
+ if (verbose && error.stack) {
47
+ console.error(chalk.gray("\nStack trace:"));
48
+ console.error(chalk.gray(error.stack));
49
+ }
50
+ } else console.error(chalk.red(` ${String(error)}`));
51
+ console.error(chalk.yellow("\n💡 Requires the AWS CLI and a profile with IAM write access.\n"));
52
+ process.exit(1);
53
+ }
54
+ }
55
+ //#endregion
56
+ export { usersCommand };
@@ -0,0 +1,3 @@
1
+ export * from "./handler.js";
2
+ export * from "./schema.js";
3
+ export * from "./utils.js";
@@ -0,0 +1,4 @@
1
+ import { usersOptionsSchema } from "./schema.js";
2
+ import { buildUsername, createCliAccessKey, createUsersInteractive, ensureAclGroupsExist, ensureUser, ensureUserInGroup, inferAccountName, isValidSlug, normalizeIdentifier, normalizeSlug, parseMdUsername, roleToGroup } from "./utils.js";
3
+ import { usersCommand } from "./handler.js";
4
+ export { buildUsername, createCliAccessKey, createUsersInteractive, ensureAclGroupsExist, ensureUser, ensureUserInGroup, inferAccountName, isValidSlug, normalizeIdentifier, normalizeSlug, parseMdUsername, roleToGroup, usersCommand, usersOptionsSchema };
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Zod schema for `aws iam users` options.
3
+ */
4
+ export const usersOptionsSchema: z.ZodObject<{
5
+ accountName: z.ZodOptional<z.ZodString>;
6
+ profile: z.ZodOptional<z.ZodString>;
7
+ verbose: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
8
+ }, "strip", z.ZodTypeAny, {
9
+ verbose: boolean;
10
+ profile?: string | undefined;
11
+ accountName?: string | undefined;
12
+ }, {
13
+ profile?: string | undefined;
14
+ verbose?: boolean | undefined;
15
+ accountName?: string | undefined;
16
+ }>;
17
+ export type UsersOptions = z.infer<typeof usersOptionsSchema>;
18
+ import { z } from "zod";
@@ -0,0 +1,16 @@
1
+ import { profileField, verboseField } from "../../schema.js";
2
+ import { z } from "zod";
3
+ //#region src/commands/aws/iam/users/schema.js
4
+ /**
5
+ * Zod schema for `aws iam users` options.
6
+ */
7
+ const usersOptionsSchema = z.object({
8
+ accountName: z.string().optional().describe("AWS account slug used in md-{identifier}-{account}-{role}"),
9
+ profile: profileField,
10
+ verbose: verboseField
11
+ });
12
+ /**
13
+ * @typedef {z.infer<typeof usersOptionsSchema>} UsersOptions
14
+ */
15
+ //#endregion
16
+ export { usersOptionsSchema };
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Map a user role to its ACL group.
3
+ * @param {string} role
4
+ * @returns {string}
5
+ */
6
+ export function roleToGroup(role: string): string;
7
+ /**
8
+ * Lowercase and hyphenate a raw value into a slug.
9
+ * @param {string} value
10
+ * @returns {string}
11
+ */
12
+ export function normalizeSlug(value: string): string;
13
+ /**
14
+ * @param {string} value
15
+ * @returns {boolean}
16
+ */
17
+ export function isValidSlug(value: string): boolean;
18
+ /**
19
+ * Build the canonical IAM username.
20
+ * @param {{ identifier: string; accountName: string; role: string }} params
21
+ * @returns {string}
22
+ */
23
+ export function buildUsername(params: {
24
+ identifier: string;
25
+ accountName: string;
26
+ role: string;
27
+ }): string;
28
+ /**
29
+ * Strip md- prefix, role suffix, and account suffix from a raw identifier.
30
+ * @param {{ raw: string; accountName: string; role: string }} params
31
+ * @returns {string}
32
+ */
33
+ export function normalizeIdentifier(params: {
34
+ raw: string;
35
+ accountName: string;
36
+ role: string;
37
+ }): string;
38
+ /**
39
+ * Parse an md-{identifier}-{account}-{role} username into parts.
40
+ * Identifier is the first segment; account is everything between it and the role
41
+ * (so multi-segment account slugs still work).
42
+ * @param {string} name - Profile name or IAM user name
43
+ * @returns {{ identifier: string; accountName: string; role: string } | null}
44
+ */
45
+ export function parseMdUsername(name: string): {
46
+ identifier: string;
47
+ accountName: string;
48
+ role: string;
49
+ } | null;
50
+ /**
51
+ * Infer the AWS account slug from the caller IAM user / profile name.
52
+ * Prefers the ARN username, then the profile string.
53
+ * @param {{
54
+ * profile?: string;
55
+ * identity?: { Arn?: string };
56
+ * }} params
57
+ * @returns {string | null}
58
+ */
59
+ export function inferAccountName(params: {
60
+ profile?: string;
61
+ identity?: {
62
+ Arn?: string;
63
+ };
64
+ }): string | null;
65
+ /**
66
+ * Create the IAM user if it does not exist.
67
+ * @param {{ username: string; profile?: string; verbose?: boolean }} params
68
+ */
69
+ export function ensureUser(params: {
70
+ username: string;
71
+ profile?: string;
72
+ verbose?: boolean;
73
+ }): void;
74
+ /**
75
+ * Add the user to the group if not already a member.
76
+ * @param {{ username: string; group: string; profile?: string; verbose?: boolean }} params
77
+ */
78
+ export function ensureUserInGroup(params: {
79
+ username: string;
80
+ group: string;
81
+ profile?: string;
82
+ verbose?: boolean;
83
+ }): void;
84
+ /**
85
+ * Create a CLI access key for the user and print a one-line setup command.
86
+ * @param {{ username: string; profile?: string; verbose?: boolean }} params
87
+ * @returns {boolean} False when the user already has the maximum number of keys
88
+ */
89
+ export function createCliAccessKey(params: {
90
+ username: string;
91
+ profile?: string;
92
+ verbose?: boolean;
93
+ }): boolean;
94
+ /**
95
+ * Verify the required ACL groups exist before creating users.
96
+ * @param {{ profile?: string; verbose?: boolean }} params
97
+ * @returns {boolean}
98
+ */
99
+ export function ensureAclGroupsExist(params: {
100
+ profile?: string;
101
+ verbose?: boolean;
102
+ }): boolean;
103
+ /**
104
+ * Interactively create IAM users, assign ACL groups, and print CLI credentials.
105
+ * @param {{
106
+ * accountName?: string;
107
+ * profile?: string;
108
+ * identity?: { Arn?: string };
109
+ * verbose?: boolean;
110
+ * }} params
111
+ */
112
+ export function createUsersInteractive(params: {
113
+ accountName?: string;
114
+ profile?: string;
115
+ identity?: {
116
+ Arn?: string;
117
+ };
118
+ verbose?: boolean;
119
+ }): Promise<void>;