@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,454 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_rolldown_runtime = require("../../../../__chunks/VH7oDXx4.cjs");
3
+ const require_commands_aws_utils_tty = require("../../utils/tty.cjs");
4
+ const require_commands_aws_utils_exec_aws = require("../../utils/exec-aws.cjs");
5
+ let chalk = require("chalk");
6
+ chalk = require_rolldown_runtime.__toESM(chalk, 1);
7
+ //#region src/commands/aws/iam/users/utils.js
8
+ const KNOWN_ROLES = [
9
+ "read-only",
10
+ "iam-admin",
11
+ "power-user"
12
+ ];
13
+ const REQUIRED_ACL_GROUPS = [
14
+ "acl-read-only",
15
+ "acl-iam-full-access",
16
+ "acl-power-users"
17
+ ];
18
+ /**
19
+ * Map a user role to its ACL group.
20
+ * @param {string} role
21
+ * @returns {string}
22
+ */
23
+ function roleToGroup(role) {
24
+ switch (role) {
25
+ case "read-only": return "acl-read-only";
26
+ case "iam-admin": return "acl-iam-full-access";
27
+ case "power-user": return "acl-power-users";
28
+ default: throw new Error(`Unknown role: ${role}`);
29
+ }
30
+ }
31
+ /**
32
+ * Lowercase and hyphenate a raw value into a slug.
33
+ * @param {string} value
34
+ * @returns {string}
35
+ */
36
+ function normalizeSlug(value) {
37
+ return value.toLowerCase().replace(/ /g, "-");
38
+ }
39
+ /**
40
+ * @param {string} value
41
+ * @returns {boolean}
42
+ */
43
+ function isValidSlug(value) {
44
+ return /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(value);
45
+ }
46
+ /**
47
+ * Build the canonical IAM username.
48
+ * @param {{ identifier: string; accountName: string; role: string }} params
49
+ * @returns {string}
50
+ */
51
+ function buildUsername(params) {
52
+ const { identifier, accountName, role } = params;
53
+ return `md-${identifier}-${accountName}-${role}`;
54
+ }
55
+ /**
56
+ * Strip md- prefix, role suffix, and account suffix from a raw identifier.
57
+ * @param {{ raw: string; accountName: string; role: string }} params
58
+ * @returns {string}
59
+ */
60
+ function normalizeIdentifier(params) {
61
+ const { raw, accountName, role } = params;
62
+ let identifier = normalizeSlug(raw);
63
+ if (identifier.startsWith("md-")) identifier = identifier.slice(3);
64
+ if (identifier.endsWith(`-${role}`)) identifier = identifier.slice(0, -(role.length + 1));
65
+ else for (const knownRole of KNOWN_ROLES) if (identifier.endsWith(`-${knownRole}`)) {
66
+ identifier = identifier.slice(0, -(knownRole.length + 1));
67
+ break;
68
+ }
69
+ if (identifier.endsWith(`-${accountName}`)) identifier = identifier.slice(0, -(accountName.length + 1));
70
+ return identifier;
71
+ }
72
+ /**
73
+ * Parse an md-{identifier}-{account}-{role} username into parts.
74
+ * Identifier is the first segment; account is everything between it and the role
75
+ * (so multi-segment account slugs still work).
76
+ * @param {string} name - Profile name or IAM user name
77
+ * @returns {{ identifier: string; accountName: string; role: string } | null}
78
+ */
79
+ function parseMdUsername(name) {
80
+ let value = normalizeSlug(name);
81
+ if (!value.startsWith("md-")) return null;
82
+ value = value.slice(3);
83
+ const rolesByLength = [...KNOWN_ROLES].sort((a, b) => b.length - a.length);
84
+ /** @type {string | null} */
85
+ let role = null;
86
+ for (const knownRole of rolesByLength) if (value.endsWith(`-${knownRole}`)) {
87
+ role = knownRole;
88
+ value = value.slice(0, -(knownRole.length + 1));
89
+ break;
90
+ }
91
+ if (!role) return null;
92
+ const dash = value.indexOf("-");
93
+ if (dash <= 0 || dash === value.length - 1) return null;
94
+ const identifier = value.slice(0, dash);
95
+ const accountName = value.slice(dash + 1);
96
+ if (!isValidSlug(identifier) || !isValidSlug(accountName)) return null;
97
+ return {
98
+ identifier,
99
+ accountName,
100
+ role
101
+ };
102
+ }
103
+ /**
104
+ * Infer the AWS account slug from the caller IAM user / profile name.
105
+ * Prefers the ARN username, then the profile string.
106
+ * @param {{
107
+ * profile?: string;
108
+ * identity?: { Arn?: string };
109
+ * }} params
110
+ * @returns {string | null}
111
+ */
112
+ function inferAccountName(params) {
113
+ const { profile, identity } = params;
114
+ const arn = identity?.Arn ?? "";
115
+ const username = arn.includes("/") ? arn.split("/").pop() ?? "" : "";
116
+ for (const candidate of [username, profile ?? ""]) {
117
+ if (!candidate) continue;
118
+ const parsed = parseMdUsername(candidate);
119
+ if (parsed) return parsed.accountName;
120
+ }
121
+ return null;
122
+ }
123
+ /**
124
+ * @param {{ username: string; profile?: string; verbose?: boolean }} params
125
+ * @returns {boolean}
126
+ */
127
+ function userExists(params) {
128
+ const { username, profile, verbose } = params;
129
+ try {
130
+ require_commands_aws_utils_exec_aws.runAws({
131
+ profile,
132
+ args: [
133
+ "iam",
134
+ "get-user",
135
+ "--user-name",
136
+ username
137
+ ],
138
+ verbose
139
+ });
140
+ return true;
141
+ } catch {
142
+ return false;
143
+ }
144
+ }
145
+ /**
146
+ * Create the IAM user if it does not exist.
147
+ * @param {{ username: string; profile?: string; verbose?: boolean }} params
148
+ */
149
+ function ensureUser(params) {
150
+ const { username, profile, verbose } = params;
151
+ if (userExists({
152
+ username,
153
+ profile,
154
+ verbose
155
+ })) {
156
+ console.log(` User exists: ${username}`);
157
+ return;
158
+ }
159
+ console.log(` Create user: ${username}`);
160
+ require_commands_aws_utils_exec_aws.runAws({
161
+ profile,
162
+ args: [
163
+ "iam",
164
+ "create-user",
165
+ "--user-name",
166
+ username,
167
+ "--path",
168
+ "/"
169
+ ],
170
+ verbose
171
+ });
172
+ }
173
+ /**
174
+ * Add the user to the group if not already a member.
175
+ * @param {{ username: string; group: string; profile?: string; verbose?: boolean }} params
176
+ */
177
+ function ensureUserInGroup(params) {
178
+ const { username, group, profile, verbose } = params;
179
+ if (require_commands_aws_utils_exec_aws.runAws({
180
+ profile,
181
+ args: [
182
+ "iam",
183
+ "get-group",
184
+ "--group-name",
185
+ group,
186
+ "--query",
187
+ `Users[?UserName=='${username}'].UserName`,
188
+ "--output",
189
+ "text"
190
+ ],
191
+ expectJson: false,
192
+ verbose
193
+ })) {
194
+ console.log(` Already in group: ${group}`);
195
+ return;
196
+ }
197
+ console.log(` Add to group: ${group}`);
198
+ require_commands_aws_utils_exec_aws.runAws({
199
+ profile,
200
+ args: [
201
+ "iam",
202
+ "add-user-to-group",
203
+ "--user-name",
204
+ username,
205
+ "--group-name",
206
+ group
207
+ ],
208
+ expectJson: false,
209
+ verbose
210
+ });
211
+ }
212
+ /**
213
+ * Create a CLI access key for the user and print a one-line setup command.
214
+ * @param {{ username: string; profile?: string; verbose?: boolean }} params
215
+ * @returns {boolean} False when the user already has the maximum number of keys
216
+ */
217
+ function createCliAccessKey(params) {
218
+ const { username, profile, verbose } = params;
219
+ const keyCountRaw = require_commands_aws_utils_exec_aws.runAws({
220
+ profile,
221
+ args: [
222
+ "iam",
223
+ "list-access-keys",
224
+ "--user-name",
225
+ username,
226
+ "--query",
227
+ "length(AccessKeyMetadata)",
228
+ "--output",
229
+ "text"
230
+ ],
231
+ expectJson: false,
232
+ verbose
233
+ });
234
+ if ((Number.parseInt(keyCountRaw, 10) || 0) >= 2) {
235
+ console.log(chalk.default.yellow(` WARNING: ${username} already has 2 access keys (AWS max).`));
236
+ console.log(chalk.default.yellow(" Delete an existing key before creating a new one."));
237
+ return false;
238
+ }
239
+ const [accessKeyId, secretAccessKey] = require_commands_aws_utils_exec_aws.runAws({
240
+ profile,
241
+ args: [
242
+ "iam",
243
+ "create-access-key",
244
+ "--user-name",
245
+ username,
246
+ "--query",
247
+ "AccessKey.[AccessKeyId,SecretAccessKey]",
248
+ "--output",
249
+ "text"
250
+ ],
251
+ expectJson: false,
252
+ verbose
253
+ }).split(/\s+/);
254
+ if (!accessKeyId || !secretAccessKey) throw new Error("Failed to parse the newly created access key");
255
+ const setupCmd = ` export AWS_ACCESS_KEY_ID='${accessKeyId}' AWS_SECRET_ACCESS_KEY='${secretAccessKey}' && aws-vault add ${username} --env --add-config && aws configure set aws_access_key_id "$AWS_ACCESS_KEY_ID" --profile ${username} && aws configure set aws_secret_access_key "$AWS_SECRET_ACCESS_KEY" --profile ${username} && aws configure set region us-east-1 --profile ${username}`;
256
+ console.log("");
257
+ console.log(` CLI credentials for ${username} (secret shown once — copy now):`);
258
+ console.log(" ────────────────────────────────────────────────────────────────");
259
+ console.log(" YOU MUST run the command below with a LEADING SPACE so it is not saved");
260
+ console.log(" to shell history — same idea as: TEST=\"a\" && echo $TEST");
261
+ console.log("");
262
+ console.log(setupCmd);
263
+ console.log(" ────────────────────────────────────────────────────────────────");
264
+ console.log("");
265
+ return true;
266
+ }
267
+ /**
268
+ * Verify the required ACL groups exist before creating users.
269
+ * @param {{ profile?: string; verbose?: boolean }} params
270
+ * @returns {boolean}
271
+ */
272
+ function ensureAclGroupsExist(params) {
273
+ const { profile, verbose } = params;
274
+ const missing = REQUIRED_ACL_GROUPS.filter((group) => {
275
+ try {
276
+ require_commands_aws_utils_exec_aws.runAws({
277
+ profile,
278
+ args: [
279
+ "iam",
280
+ "get-group",
281
+ "--group-name",
282
+ group
283
+ ],
284
+ verbose
285
+ });
286
+ return false;
287
+ } catch {
288
+ return true;
289
+ }
290
+ });
291
+ if (missing.length > 0) {
292
+ missing.forEach((group) => console.log(` Missing group: ${group}`));
293
+ console.log("");
294
+ console.log(" Run `mtn aws iam setup-acl` first to create ACL groups and policies.");
295
+ return false;
296
+ }
297
+ return true;
298
+ }
299
+ /**
300
+ * @param {{ accountName?: string; inferredAccountName?: string | null }} params
301
+ * @returns {Promise<string>}
302
+ */
303
+ async function promptAccountName(params) {
304
+ const { accountName, inferredAccountName } = params;
305
+ if (accountName) {
306
+ const slug = normalizeSlug(accountName);
307
+ if (isValidSlug(slug)) {
308
+ console.log(` Account name: ${slug}`);
309
+ return slug;
310
+ }
311
+ console.log(" Invalid account name option — falling back to prompt.");
312
+ }
313
+ const defaultSlug = inferredAccountName && isValidSlug(normalizeSlug(inferredAccountName)) ? normalizeSlug(inferredAccountName) : null;
314
+ for (;;) {
315
+ const hint = defaultSlug ? ` [default: ${defaultSlug}]` : " (e.g. vincent)";
316
+ const raw = await require_commands_aws_utils_tty.prompt(` AWS account name${hint} — used in md-{identifier}-{account}-{role}: `);
317
+ if (raw === "" && defaultSlug) {
318
+ console.log(` → account name: ${defaultSlug}`);
319
+ return defaultSlug;
320
+ }
321
+ const slug = normalizeSlug(raw);
322
+ if (isValidSlug(slug)) {
323
+ if (raw !== slug) console.log(` → account name: ${slug}`);
324
+ return slug;
325
+ }
326
+ console.log(" Invalid account name — use lowercase letters, numbers, and hyphens" + (defaultSlug ? ", or press Enter to accept the default." : "."));
327
+ }
328
+ }
329
+ /**
330
+ * @returns {Promise<string>}
331
+ */
332
+ async function promptRole() {
333
+ for (;;) {
334
+ console.log(" Role (username will be md-{identifier}-{account}-{role}):");
335
+ console.log(" 1) read-only → acl-read-only");
336
+ console.log(" 2) iam-admin → acl-iam-full-access");
337
+ console.log(" 3) power-user → acl-power-users");
338
+ switch (await require_commands_aws_utils_tty.prompt(" Choice [1-3]: ")) {
339
+ case "1":
340
+ case "read-only": return "read-only";
341
+ case "2":
342
+ case "iam-admin": return "iam-admin";
343
+ case "3":
344
+ case "power-user": return "power-user";
345
+ default: console.log(" Invalid choice — enter 1, 2, 3, or the role name.");
346
+ }
347
+ }
348
+ }
349
+ /**
350
+ * @param {{ accountName: string; role: string }} params
351
+ * @returns {Promise<string>}
352
+ */
353
+ async function promptIdentifier(params) {
354
+ const { accountName, role } = params;
355
+ const exampleUser = buildUsername({
356
+ identifier: "declan",
357
+ accountName,
358
+ role
359
+ });
360
+ for (;;) {
361
+ const raw = await require_commands_aws_utils_tty.prompt(` Identifier (e.g. declan, or full ${exampleUser}): `);
362
+ const lowerRaw = normalizeSlug(raw);
363
+ const identifier = normalizeIdentifier({
364
+ raw,
365
+ accountName,
366
+ role
367
+ });
368
+ if (isValidSlug(identifier)) {
369
+ if (lowerRaw !== identifier) console.log(` → parsed identifier: ${identifier}`);
370
+ return identifier;
371
+ }
372
+ console.log(" Invalid identifier — use lowercase letters, numbers, and hyphens.");
373
+ console.log(" Tip: enter just the short name (e.g. declan).");
374
+ }
375
+ }
376
+ /**
377
+ * Interactively create IAM users, assign ACL groups, and print CLI credentials.
378
+ * @param {{
379
+ * accountName?: string;
380
+ * profile?: string;
381
+ * identity?: { Arn?: string };
382
+ * verbose?: boolean;
383
+ * }} params
384
+ */
385
+ async function createUsersInteractive(params) {
386
+ const { accountName: accountNameOption, profile, identity, verbose } = params;
387
+ if (!ensureAclGroupsExist({
388
+ profile,
389
+ verbose
390
+ })) return;
391
+ console.log("");
392
+ const accountName = await promptAccountName({
393
+ accountName: accountNameOption,
394
+ inferredAccountName: inferAccountName({
395
+ profile,
396
+ identity
397
+ })
398
+ });
399
+ console.log("");
400
+ while (await require_commands_aws_utils_tty.promptYesNo({
401
+ message: " Create another user?",
402
+ defaultYes: false
403
+ })) {
404
+ console.log("");
405
+ const role = await promptRole();
406
+ const username = buildUsername({
407
+ identifier: await promptIdentifier({
408
+ accountName,
409
+ role
410
+ }),
411
+ accountName,
412
+ role
413
+ });
414
+ const group = roleToGroup(role);
415
+ console.log("");
416
+ console.log(` → user: ${username}`);
417
+ console.log(` → group: ${group}`);
418
+ console.log("");
419
+ ensureUser({
420
+ username,
421
+ profile,
422
+ verbose
423
+ });
424
+ ensureUserInGroup({
425
+ username,
426
+ group,
427
+ profile,
428
+ verbose
429
+ });
430
+ try {
431
+ createCliAccessKey({
432
+ username,
433
+ profile,
434
+ verbose
435
+ });
436
+ } catch (error) {
437
+ console.log(chalk.default.yellow(` Could not create access key: ${error instanceof Error ? error.message : String(error)}`));
438
+ }
439
+ console.log("");
440
+ }
441
+ }
442
+ //#endregion
443
+ exports.buildUsername = buildUsername;
444
+ exports.createCliAccessKey = createCliAccessKey;
445
+ exports.createUsersInteractive = createUsersInteractive;
446
+ exports.ensureAclGroupsExist = ensureAclGroupsExist;
447
+ exports.ensureUser = ensureUser;
448
+ exports.ensureUserInGroup = ensureUserInGroup;
449
+ exports.inferAccountName = inferAccountName;
450
+ exports.isValidSlug = isValidSlug;
451
+ exports.normalizeIdentifier = normalizeIdentifier;
452
+ exports.normalizeSlug = normalizeSlug;
453
+ exports.parseMdUsername = parseMdUsername;
454
+ exports.roleToGroup = roleToGroup;
@@ -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>;