@empire-builder-kit/nx 1.0.0-rc.4 → 1.0.0-rc.41

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 (805) hide show
  1. package/README.md +44 -10
  2. package/executors.json +21 -1
  3. package/generators.json +10 -0
  4. package/package.json +31 -7
  5. package/src/aws/child-environment.d.ts +10 -0
  6. package/src/aws/child-environment.js +77 -0
  7. package/src/aws/identity.d.ts +13 -0
  8. package/src/aws/identity.js +41 -0
  9. package/src/aws-authority/index.d.ts +2 -0
  10. package/src/aws-authority/index.js +6 -0
  11. package/src/aws-authority/lambda-policy-ordering.d.ts +38 -0
  12. package/src/aws-authority/lambda-policy-ordering.js +56 -0
  13. package/src/aws-authority/stage-authority.d.ts +248 -0
  14. package/src/aws-authority/stage-authority.js +3558 -0
  15. package/src/blueprints/external-sandbox.d.ts +1 -1
  16. package/src/blueprints/external-sandbox.js +21 -9
  17. package/src/blueprints/manifest.d.ts +1 -1
  18. package/src/blueprints/resolver.js +28 -15
  19. package/src/cli/bootstrap.d.ts +1 -1
  20. package/src/cli/deploy-runtime.d.ts +30 -0
  21. package/src/cli/deploy-runtime.js +174 -0
  22. package/src/cli/dev-command.d.ts +18 -4
  23. package/src/cli/dev-command.js +71 -0
  24. package/src/cli/main.d.ts +9 -1
  25. package/src/cli/main.js +157 -24
  26. package/src/cli/output.d.ts +1 -1
  27. package/src/cli/output.js +1 -1
  28. package/src/cli/personal-secret-runtime.d.ts +12 -0
  29. package/src/cli/personal-secret-runtime.js +18 -3
  30. package/src/cli/secret-terminal.js +1 -1
  31. package/src/container-images.d.ts +1 -1
  32. package/src/container-images.js +1 -1
  33. package/src/developer-agent/context.js +41 -9
  34. package/src/developer-agent/generator-planning.js +20 -6
  35. package/src/developer-agent/git-inspection.d.ts +6 -2
  36. package/src/developer-agent/git-inspection.js +78 -6
  37. package/src/developer-agent/model.d.ts +5 -3
  38. package/src/developer-agent/model.js +4 -4
  39. package/src/developer-agent/operation-registry.d.ts +15 -0
  40. package/src/developer-agent/operation-registry.js +342 -49
  41. package/src/developer-agent/planning.d.ts +8 -1
  42. package/src/developer-agent/planning.js +39 -16
  43. package/src/developer-agent/preview-changes.d.ts +2 -0
  44. package/src/developer-agent/preview-changes.js +14 -2
  45. package/src/developer-agent/preview-source.js +3 -0
  46. package/src/developer-agent/validation.js +25 -9
  47. package/src/developer-agent/workspace-inspection.js +60 -5
  48. package/src/executors/blueprint-trust/blueprint-trust.js +6 -0
  49. package/src/executors/deployment-plan/deployment-plan.d.ts +2 -0
  50. package/src/executors/deployment-plan/deployment-plan.js +57 -2
  51. package/src/executors/dev-doctor/dev-doctor.js +13 -6
  52. package/src/executors/dev-task-cleanup/dev-task-cleanup.d.ts +23 -0
  53. package/src/executors/dev-task-cleanup/dev-task-cleanup.js +145 -0
  54. package/src/executors/dev-task-cleanup/schema.json +9 -0
  55. package/src/executors/dev-task-cleanup/task-stack-absence.d.ts +27 -0
  56. package/src/executors/dev-task-cleanup/task-stack-absence.js +281 -0
  57. package/src/executors/dev-task-cleanup/task-stack-checkpoint.d.ts +12 -0
  58. package/src/executors/dev-task-cleanup/task-stack-checkpoint.js +92 -0
  59. package/src/executors/fleet/fleet.js +1 -1
  60. package/src/executors/foundation-preflight/foundation-preflight.d.ts +1 -0
  61. package/src/executors/foundation-preflight/foundation-preflight.js +6 -2
  62. package/src/executors/foundation-preflight/schema.json +5 -0
  63. package/src/executors/foundation-profile-preflight/foundation-profile-preflight.d.ts +13 -2
  64. package/src/executors/foundation-profile-preflight/foundation-profile-preflight.js +95 -31
  65. package/src/executors/foundation-profile-preflight/production-database-safeguard.d.ts +65 -0
  66. package/src/executors/foundation-profile-preflight/production-database-safeguard.js +223 -0
  67. package/src/executors/foundation-profile-preflight/schema.json +15 -4
  68. package/src/executors/foundation-remove-preflight/foundation-remove-preflight.d.ts +11 -1
  69. package/src/executors/foundation-remove-preflight/foundation-remove-preflight.js +70 -20
  70. package/src/executors/foundation-remove-preflight/schema.json +6 -1
  71. package/src/executors/github-bootstrap/github-bootstrap.d.ts +1 -0
  72. package/src/executors/github-bootstrap/github-bootstrap.js +3 -0
  73. package/src/executors/github-bootstrap/schema.json +7 -1
  74. package/src/executors/infrastructure-plan/infrastructure-plan.d.ts +29 -136
  75. package/src/executors/infrastructure-plan/infrastructure-plan.js +230 -3282
  76. package/src/executors/infrastructure-plan/schema.json +12 -52
  77. package/src/executors/local-deploy/federated-credential-transport.d.ts +48 -0
  78. package/src/executors/local-deploy/federated-credential-transport.js +252 -0
  79. package/src/executors/local-deploy/local-approval.d.ts +18 -0
  80. package/src/executors/local-deploy/local-approval.js +39 -0
  81. package/src/executors/local-deploy/local-deploy.d.ts +112 -0
  82. package/src/executors/local-deploy/local-deploy.js +1404 -0
  83. package/src/executors/local-deploy/schema.json +70 -0
  84. package/src/executors/refresh/refresh.js +2 -2
  85. package/src/executors/remove/remove.js +2 -2
  86. package/src/executors/router-waf-rehearsal/router-waf-rehearsal.d.ts +42 -0
  87. package/src/executors/router-waf-rehearsal/router-waf-rehearsal.js +1229 -0
  88. package/src/executors/router-waf-rehearsal/schema.json +29 -0
  89. package/src/executors/secret-initialize/schema.json +42 -0
  90. package/src/executors/secret-initialize/secret-initialize.d.ts +34 -0
  91. package/src/executors/secret-initialize/secret-initialize.js +297 -0
  92. package/src/executors/secret-metadata/schema.json +5 -0
  93. package/src/executors/secret-metadata/secret-metadata.d.ts +16 -2
  94. package/src/executors/secret-metadata/secret-metadata.js +129 -30
  95. package/src/executors/sst-lifecycle/generated-secret-retirement.d.ts +53 -0
  96. package/src/executors/sst-lifecycle/generated-secret-retirement.js +192 -0
  97. package/src/executors/sst-lifecycle/governed-native-operation.d.ts +48 -0
  98. package/src/executors/sst-lifecycle/governed-native-operation.js +163 -0
  99. package/src/executors/sst-lifecycle/logging-preflight.d.ts +5 -0
  100. package/src/executors/sst-lifecycle/logging-preflight.js +23 -13
  101. package/src/executors/sst-lifecycle/run-sst-command.d.ts +46 -6
  102. package/src/executors/sst-lifecycle/run-sst-command.js +750 -71
  103. package/src/executors/sst-lifecycle/schema.json +8 -1
  104. package/src/executors/sst-lifecycle/secret-preflight.d.ts +2 -0
  105. package/src/executors/sst-lifecycle/secret-preflight.js +13 -7
  106. package/src/executors/sst-lifecycle/sst-environment-source.d.ts +33 -0
  107. package/src/executors/sst-lifecycle/sst-environment-source.js +267 -0
  108. package/src/executors/sst-lifecycle/task-unlock.d.ts +15 -0
  109. package/src/executors/sst-lifecycle/task-unlock.js +126 -0
  110. package/src/executors/unlock/unlock.js +2 -2
  111. package/src/foundation/capability-plan.d.ts +43 -0
  112. package/src/foundation/capability-plan.js +168 -0
  113. package/src/foundation/cost-estimate.d.ts +170 -0
  114. package/src/foundation/cost-estimate.js +683 -0
  115. package/src/foundation/discovery.d.ts +14 -11
  116. package/src/foundation/discovery.js +32 -6
  117. package/src/foundation/index.d.ts +4 -0
  118. package/src/foundation/index.js +11 -0
  119. package/src/foundation/local-database-contract.d.ts +20 -0
  120. package/src/foundation/local-database-contract.js +262 -13
  121. package/src/foundation/local-private-smoke-access.d.ts +20 -0
  122. package/src/foundation/local-private-smoke-access.js +197 -0
  123. package/src/foundation/logging-preflight.js +1 -1
  124. package/src/foundation/logging.d.ts +3 -1
  125. package/src/foundation/logging.js +1 -1
  126. package/src/foundation/partial-state.d.ts +10 -0
  127. package/src/foundation/partial-state.js +21 -0
  128. package/src/foundation/preflight.js +37 -18
  129. package/src/foundation/private-smoke-access.d.ts +25 -0
  130. package/src/foundation/private-smoke-access.js +135 -0
  131. package/src/foundation/private-smoke-admission.d.ts +45 -0
  132. package/src/foundation/private-smoke-admission.js +180 -0
  133. package/src/foundation/private-smoke-control-plane.d.ts +18 -0
  134. package/src/foundation/private-smoke-control-plane.js +184 -0
  135. package/src/foundation/provision-database-bindings.d.ts +5 -0
  136. package/src/foundation/provision-database-bindings.js +41 -8
  137. package/src/foundation/provision-logical-database.js +15 -8
  138. package/src/foundation/requirements.d.ts +3 -3
  139. package/src/foundation/requirements.js +24 -12
  140. package/src/foundation/router-waf-rate-rehearsal.d.ts +97 -0
  141. package/src/foundation/router-waf-rate-rehearsal.js +210 -0
  142. package/src/foundation/router-waf.d.ts +149 -0
  143. package/src/foundation/router-waf.js +809 -0
  144. package/src/foundation/stages.d.ts +1 -0
  145. package/src/foundation/stages.js +11 -0
  146. package/src/generators/blueprint/blueprint.d.ts +5 -0
  147. package/src/generators/blueprint/blueprint.js +102 -0
  148. package/src/generators/blueprint/files.d.ts +6 -0
  149. package/src/generators/blueprint/files.js +217 -0
  150. package/src/generators/blueprint/schema.d.ts +4 -0
  151. package/src/generators/blueprint/schema.json +18 -0
  152. package/src/generators/formatting.d.ts +8 -0
  153. package/src/generators/formatting.js +141 -0
  154. package/src/generators/function/function.js +38 -17
  155. package/src/generators/logging-registry.d.ts +2 -0
  156. package/src/generators/logging-registry.js +22 -0
  157. package/src/generators/post-generation-install.js +2 -2
  158. package/src/generators/preset/dependency-overrides.d.ts +8 -0
  159. package/src/generators/preset/dependency-overrides.js +55 -0
  160. package/src/generators/preset/generator.js +43 -3
  161. package/src/generators/preset/schema.d.ts +10 -0
  162. package/src/generators/preset/schema.json +47 -0
  163. package/src/generators/preset/workspace-files-adopter-skills.d.ts +7 -0
  164. package/src/generators/preset/workspace-files-adopter-skills.js +324 -0
  165. package/src/generators/preset/workspace-files-ci-acceptance.d.ts +1 -0
  166. package/src/generators/preset/workspace-files-ci-acceptance.js +791 -0
  167. package/src/generators/preset/workspace-files-ci-install.d.ts +2 -0
  168. package/src/generators/preset/workspace-files-ci-install.js +196 -0
  169. package/src/generators/preset/workspace-files-developer-agent.d.ts +2 -0
  170. package/src/generators/preset/workspace-files-developer-agent.js +162 -44
  171. package/src/generators/preset/workspace-files-ecr-inspector.d.ts +18 -0
  172. package/src/generators/preset/workspace-files-ecr-inspector.js +298 -0
  173. package/src/generators/preset/workspace-files-foundation-workload-roles.js +5 -2
  174. package/src/generators/preset/workspace-files-performance-cost.d.ts +2 -2
  175. package/src/generators/preset/workspace-files-performance-cost.js +8 -8
  176. package/src/generators/preset/workspace-files-performance-load.d.ts +1 -1
  177. package/src/generators/preset/workspace-files-performance-load.js +39 -25
  178. package/src/generators/preset/workspace-files-shared-operation-claims.d.ts +10 -0
  179. package/src/generators/preset/workspace-files-shared-operation-claims.js +59 -0
  180. package/src/generators/preset/workspace-files-stage-authority.d.ts +6 -0
  181. package/src/generators/preset/workspace-files-stage-authority.js +529 -0
  182. package/src/generators/preset/workspace-files-thin-deploy.d.ts +65 -0
  183. package/src/generators/preset/workspace-files-thin-deploy.js +2507 -0
  184. package/src/generators/preset/workspace-files-thin-docs.d.ts +7 -0
  185. package/src/generators/preset/workspace-files-thin-docs.js +370 -0
  186. package/src/generators/preset/workspace-files-thin-release.d.ts +14 -0
  187. package/src/generators/preset/workspace-files-thin-release.js +26 -0
  188. package/src/generators/preset/workspace-files-workload-role-baseline.js +254 -42
  189. package/src/generators/preset/workspace-files.d.ts +18 -2
  190. package/src/generators/preset/workspace-files.js +1525 -609
  191. package/src/generators/repository-policy/repository-policy.js +235 -5
  192. package/src/generators/repository-policy/schema.d.ts +10 -0
  193. package/src/generators/repository-policy/schema.json +80 -4
  194. package/src/generators/repository-policy/tree-policy.d.ts +3 -0
  195. package/src/generators/repository-policy/tree-policy.js +25 -0
  196. package/src/generators/slice/built-in-plan-api-contract-files.js +49 -11
  197. package/src/generators/slice/built-in-plan-api-files.d.ts +1 -1
  198. package/src/generators/slice/built-in-plan-api-files.js +130 -414
  199. package/src/generators/slice/built-in-plan-async-work-files.js +166 -1969
  200. package/src/generators/slice/built-in-plan-authorization-files.js +102 -334
  201. package/src/generators/slice/built-in-plan-authorization-infrastructure-files.js +975 -233
  202. package/src/generators/slice/built-in-plan-authorization-storage.d.ts +3 -0
  203. package/src/generators/slice/built-in-plan-authorization-storage.js +119 -0
  204. package/src/generators/slice/built-in-plan-background-work-files.d.ts +2 -0
  205. package/src/generators/slice/built-in-plan-background-work-files.js +99 -0
  206. package/src/generators/slice/built-in-plan-data-deletion-files.js +2 -830
  207. package/src/generators/slice/built-in-plan-data-export-infrastructure-files.js +5 -31
  208. package/src/generators/slice/built-in-plan-data-files.d.ts +1 -1
  209. package/src/generators/slice/built-in-plan-data-files.js +176 -1200
  210. package/src/generators/slice/built-in-plan-data-lifecycle-files.js +53 -28
  211. package/src/generators/slice/built-in-plan-data-lifecycle-runtime-files.js +37 -2
  212. package/src/generators/slice/built-in-plan-data-retention-job-files.js +7 -2443
  213. package/src/generators/slice/built-in-plan-data-retention-launcher-files.js +50 -8
  214. package/src/generators/slice/built-in-plan-data-rights-files.js +6 -4482
  215. package/src/generators/slice/built-in-plan-database-lifecycle-files.js +44 -25
  216. package/src/generators/slice/built-in-plan-database-retirement-rehearsal-files.js +25 -2
  217. package/src/generators/slice/built-in-plan-foundation-files.d.ts +2 -1
  218. package/src/generators/slice/built-in-plan-foundation-files.js +39 -18
  219. package/src/generators/slice/built-in-plan-frontend-files.js +14 -3
  220. package/src/generators/slice/built-in-plan-infrastructure-files.d.ts +1 -1
  221. package/src/generators/slice/built-in-plan-infrastructure-files.js +933 -730
  222. package/src/generators/slice/built-in-plan-infrastructure-safety-files.js +75 -14
  223. package/src/generators/slice/built-in-plan-key-value-cleanup.d.ts +4 -0
  224. package/src/generators/slice/built-in-plan-key-value-cleanup.js +100 -0
  225. package/src/generators/slice/built-in-plan-key-value-consumer.d.ts +4 -0
  226. package/src/generators/slice/built-in-plan-key-value-consumer.js +151 -0
  227. package/src/generators/slice/built-in-plan-key-value-deletion.d.ts +2 -0
  228. package/src/generators/slice/built-in-plan-key-value-deletion.js +377 -0
  229. package/src/generators/slice/built-in-plan-key-value-delivery.d.ts +2 -0
  230. package/src/generators/slice/built-in-plan-key-value-delivery.js +137 -0
  231. package/src/generators/slice/built-in-plan-key-value-export.d.ts +2 -0
  232. package/src/generators/slice/built-in-plan-key-value-export.js +595 -0
  233. package/src/generators/slice/built-in-plan-key-value-files.d.ts +2 -0
  234. package/src/generators/slice/built-in-plan-key-value-files.js +31 -0
  235. package/src/generators/slice/built-in-plan-key-value-holds.d.ts +2 -0
  236. package/src/generators/slice/built-in-plan-key-value-holds.js +189 -0
  237. package/src/generators/slice/built-in-plan-key-value-infrastructure.d.ts +2 -0
  238. package/src/generators/slice/built-in-plan-key-value-infrastructure.js +102 -0
  239. package/src/generators/slice/built-in-plan-key-value-performance.d.ts +5 -0
  240. package/src/generators/slice/built-in-plan-key-value-performance.js +530 -0
  241. package/src/generators/slice/built-in-plan-key-value-provider.d.ts +4 -0
  242. package/src/generators/slice/built-in-plan-key-value-provider.js +366 -0
  243. package/src/generators/slice/built-in-plan-key-value-records.d.ts +3 -0
  244. package/src/generators/slice/built-in-plan-key-value-records.js +232 -0
  245. package/src/generators/slice/built-in-plan-key-value-retention-infrastructure.d.ts +2 -0
  246. package/src/generators/slice/built-in-plan-key-value-retention-infrastructure.js +103 -0
  247. package/src/generators/slice/built-in-plan-key-value-retention-job-files.d.ts +2 -0
  248. package/src/generators/slice/built-in-plan-key-value-retention-job-files.js +160 -0
  249. package/src/generators/slice/built-in-plan-key-value-retention-maintenance.d.ts +2 -0
  250. package/src/generators/slice/built-in-plan-key-value-retention-maintenance.js +329 -0
  251. package/src/generators/slice/built-in-plan-key-value-retention-worker.d.ts +2 -0
  252. package/src/generators/slice/built-in-plan-key-value-retention-worker.js +477 -0
  253. package/src/generators/slice/built-in-plan-key-value-retention.d.ts +2 -0
  254. package/src/generators/slice/built-in-plan-key-value-retention.js +184 -0
  255. package/src/generators/slice/built-in-plan-metadata-files.d.ts +1 -1
  256. package/src/generators/slice/built-in-plan-metadata-files.js +159 -29
  257. package/src/generators/slice/built-in-plan-native-runtime-authority-files.d.ts +2 -0
  258. package/src/generators/slice/built-in-plan-native-runtime-authority-files.js +324 -0
  259. package/src/generators/slice/built-in-plan-operations-files.d.ts +1 -1
  260. package/src/generators/slice/built-in-plan-operations-files.js +585 -97
  261. package/src/generators/slice/built-in-plan-performance-files.d.ts +2 -1
  262. package/src/generators/slice/built-in-plan-performance-files.js +220 -1074
  263. package/src/generators/slice/built-in-plan-project-files.js +141 -135
  264. package/src/generators/slice/built-in-plan-release-files.d.ts +1 -1
  265. package/src/generators/slice/built-in-plan-release-files.js +310 -70
  266. package/src/generators/slice/built-in-plan-reliability-files.d.ts +1 -1
  267. package/src/generators/slice/built-in-plan-reliability-files.js +283 -44
  268. package/src/generators/slice/built-in-plan-secret-runtime-files.d.ts +1 -1
  269. package/src/generators/slice/built-in-plan-secret-runtime-files.js +87 -76
  270. package/src/generators/slice/built-in-plan-shared.d.ts +4 -2
  271. package/src/generators/slice/built-in-plan-shared.js +41 -19
  272. package/src/generators/slice/built-in-plan-sql-events.d.ts +2 -0
  273. package/src/generators/slice/built-in-plan-sql-events.js +276 -0
  274. package/src/generators/slice/built-in-plan-testing-files.d.ts +1 -1
  275. package/src/generators/slice/built-in-plan-testing-files.js +304 -172
  276. package/src/generators/slice/built-in-plan-testing-persistence-event-files.d.ts +7 -0
  277. package/src/generators/slice/built-in-plan-testing-persistence-event-files.js +487 -0
  278. package/src/generators/slice/built-in-plan-testing-persistence-files.d.ts +2 -0
  279. package/src/generators/slice/built-in-plan-testing-persistence-files.js +180 -0
  280. package/src/generators/slice/built-in-plan-thin-release-files.d.ts +11 -0
  281. package/src/generators/slice/built-in-plan-thin-release-files.js +162 -0
  282. package/src/generators/slice/built-in-plan-verification-files.js +76 -2
  283. package/src/generators/slice/built-in-plan-web-files.d.ts +1 -1
  284. package/src/generators/slice/built-in-plan-web-files.js +223 -16
  285. package/src/generators/slice/built-in-plan-workload-role-files.d.ts +1 -1
  286. package/src/generators/slice/built-in-plan-workload-role-files.js +143 -279
  287. package/src/generators/slice/built-in-plan.d.ts +11 -1
  288. package/src/generators/slice/built-in-plan.js +83 -30
  289. package/src/generators/slice/data-policy-review-seed.d.ts +2 -0
  290. package/src/generators/slice/data-policy-review-seed.js +22 -0
  291. package/src/generators/slice/deployed-smoke-readiness.d.ts +2 -0
  292. package/src/generators/slice/deployed-smoke-readiness.js +214 -0
  293. package/src/generators/slice/local-source-identity.d.ts +2 -0
  294. package/src/generators/slice/local-source-identity.js +31 -0
  295. package/src/generators/slice/persistence-contract.d.ts +14 -0
  296. package/src/generators/slice/persistence-contract.js +32 -0
  297. package/src/generators/slice/slice.js +61 -50
  298. package/src/generators/sql/schema.d.ts +7 -0
  299. package/src/generators/sql/schema.json +38 -0
  300. package/src/generators/sql/sql.d.ts +6 -0
  301. package/src/generators/sql/sql.js +53 -0
  302. package/src/generators/upgrade/sql-seeded-reconciliation.d.ts +2 -0
  303. package/src/generators/upgrade/sql-seeded-reconciliation.js +170 -0
  304. package/src/generators/upgrade/upgrade.d.ts +15 -1
  305. package/src/generators/upgrade/upgrade.js +435 -44
  306. package/src/generators/workload/frozen-container.d.ts +1 -1
  307. package/src/generators/workload/performance-registration.d.ts +1 -0
  308. package/src/generators/workload/performance-registration.js +9 -11
  309. package/src/generators/workload/service-performance-files.d.ts +1 -0
  310. package/src/generators/workload/service-performance-files.js +27 -7
  311. package/src/generators/workload/workload.d.ts +1 -1
  312. package/src/generators/workload/workload.js +105 -29
  313. package/src/git-policy/action-pins.d.ts +5 -0
  314. package/src/git-policy/action-pins.js +5 -0
  315. package/src/git-policy/github-bootstrap.d.ts +48 -8
  316. package/src/git-policy/github-bootstrap.js +344 -176
  317. package/src/git-policy/routing.d.ts +7 -1
  318. package/src/git-policy/routing.js +62 -1
  319. package/src/index.d.ts +1 -0
  320. package/src/index.js +1 -0
  321. package/src/infrastructure-change/local-capability.d.ts +73 -0
  322. package/src/infrastructure-change/local-capability.js +114 -0
  323. package/src/infrastructure-change/model.d.ts +25 -4
  324. package/src/infrastructure-change/model.js +1 -0
  325. package/src/infrastructure-change/normalize.d.ts +4 -0
  326. package/src/infrastructure-change/normalize.js +47 -7
  327. package/src/infrastructure-change/plan.d.ts +30 -3
  328. package/src/infrastructure-change/plan.js +323 -13
  329. package/src/infrastructure-change/risk.d.ts +3 -1
  330. package/src/infrastructure-change/risk.js +96 -16
  331. package/src/local-dev/browser-verification.d.ts +37 -0
  332. package/src/local-dev/browser-verification.js +281 -0
  333. package/src/local-dev/contracts.d.ts +10 -1
  334. package/src/local-dev/contracts.js +114 -13
  335. package/src/local-dev/dev-command-core.js +24 -5
  336. package/src/local-dev/docker-credential-health.d.ts +14 -0
  337. package/src/local-dev/docker-credential-health.js +94 -0
  338. package/src/local-dev/environment-inspector.d.ts +7 -0
  339. package/src/local-dev/environment-inspector.js +42 -15
  340. package/src/local-dev/environment-state.js +2 -2
  341. package/src/local-dev/errors.d.ts +1 -1
  342. package/src/local-dev/errors.js +2 -0
  343. package/src/local-dev/fleet-client.js +2 -2
  344. package/src/local-dev/fleet-configuration.js +57 -25
  345. package/src/local-dev/fleet-inventory.js +58 -22
  346. package/src/local-dev/fleet-ipc.d.ts +7 -0
  347. package/src/local-dev/fleet-ipc.js +14 -2
  348. package/src/local-dev/fleet-launcher.d.ts +6 -0
  349. package/src/local-dev/fleet-launcher.js +16 -4
  350. package/src/local-dev/fleet-logs.js +50 -22
  351. package/src/local-dev/fleet-process.d.ts +20 -1
  352. package/src/local-dev/fleet-process.js +197 -41
  353. package/src/local-dev/fleet-runner-evidence.d.ts +5 -0
  354. package/src/local-dev/fleet-runner-evidence.js +56 -0
  355. package/src/local-dev/fleet-runtime.js +268 -229
  356. package/src/local-dev/fleet-session.d.ts +2 -0
  357. package/src/local-dev/fleet-session.js +28 -11
  358. package/src/local-dev/fleet-slice-runner-daemon.js +4 -0
  359. package/src/local-dev/fleet-state.d.ts +5 -2
  360. package/src/local-dev/fleet-state.js +25 -4
  361. package/src/local-dev/fleet-supervisor.d.ts +3 -0
  362. package/src/local-dev/fleet-supervisor.js +66 -11
  363. package/src/local-dev/fleet-web-start.d.ts +12 -0
  364. package/src/local-dev/fleet-web-start.js +48 -0
  365. package/src/local-dev/identity.js +3 -14
  366. package/src/local-dev/index.d.ts +1 -0
  367. package/src/local-dev/index.js +1 -0
  368. package/src/local-dev/native-completion.d.ts +9 -0
  369. package/src/local-dev/native-completion.js +130 -0
  370. package/src/local-dev/nx-workspace.d.ts +4 -2
  371. package/src/local-dev/nx-workspace.js +11 -6
  372. package/src/local-dev/personal-stage.d.ts +4 -5
  373. package/src/local-dev/personal-stage.js +6 -54
  374. package/src/local-dev/port-claims.d.ts +13 -0
  375. package/src/local-dev/port-claims.js +46 -0
  376. package/src/local-dev/ports.d.ts +14 -2
  377. package/src/local-dev/ports.js +78 -3
  378. package/src/local-dev/private-state.d.ts +11 -0
  379. package/src/local-dev/private-state.js +146 -40
  380. package/src/local-dev/process-group.d.ts +4 -0
  381. package/src/local-dev/process-group.js +29 -0
  382. package/src/local-dev/process-identity.d.ts +8 -0
  383. package/src/local-dev/process-identity.js +31 -1
  384. package/src/local-dev/proxy.js +11 -12
  385. package/src/local-dev/runtime-paths.js +1 -1
  386. package/src/local-dev/slice-claim.js +1 -1
  387. package/src/local-dev/slice-runner.d.ts +15 -6
  388. package/src/local-dev/slice-runner.js +189 -54
  389. package/src/local-dev/task-attachment.d.ts +17 -0
  390. package/src/local-dev/task-attachment.js +73 -0
  391. package/src/local-dev/task-authority.d.ts +10 -0
  392. package/src/local-dev/task-authority.js +27 -0
  393. package/src/local-dev/task-identity.d.ts +33 -0
  394. package/src/local-dev/task-identity.js +418 -0
  395. package/src/local-dev/task-native-writer.d.ts +18 -0
  396. package/src/local-dev/task-native-writer.js +329 -0
  397. package/src/local-dev/tls.js +8 -2
  398. package/src/local-dev/web-launch.d.ts +9 -0
  399. package/src/local-dev/web-launch.js +130 -0
  400. package/src/ownership/composition.d.ts +2 -1
  401. package/src/ownership/composition.js +1 -0
  402. package/src/performance/cost-collection.d.ts +1 -1
  403. package/src/performance/cost-collection.js +4 -2
  404. package/src/performance/cost-controls.d.ts +8 -4
  405. package/src/performance/cost-controls.js +39 -28
  406. package/src/performance/evidence.d.ts +1 -1
  407. package/src/performance/evidence.js +5 -3
  408. package/src/performance/load-safety.js +5 -3
  409. package/src/performance/model.d.ts +4 -4
  410. package/src/performance/model.js +4 -5
  411. package/src/performance/scenario.d.ts +22 -0
  412. package/src/performance/scenario.js +100 -92
  413. package/src/release/index.d.ts +0 -2
  414. package/src/release/index.js +0 -2
  415. package/src/release/source-authority.d.ts +5 -5
  416. package/src/release/source-authority.js +141 -124
  417. package/src/repository-policy/aurora-preflight.d.ts +1 -1
  418. package/src/repository-policy/aurora-preflight.js +4 -1
  419. package/src/repository-policy/capacity-migration.d.ts +3 -0
  420. package/src/repository-policy/capacity-migration.js +21 -0
  421. package/src/repository-policy/deployment-plan.d.ts +4 -1
  422. package/src/repository-policy/deployment-plan.js +9 -0
  423. package/src/repository-policy/foundation-profile.js +10 -1
  424. package/src/repository-policy/policy.d.ts +57 -3
  425. package/src/repository-policy/policy.js +497 -11
  426. package/src/schemas/blueprint-v1.json +5 -4
  427. package/src/schemas/foundation-requirement-v1.json +5 -4
  428. package/src/schemas/performance-policy-v1.json +3 -3
  429. package/src/schemas/repository-policy-v1.json +130 -6
  430. package/src/schemas/testing-evidence-result-v1.json +1 -1
  431. package/src/secrets/adapters.d.ts +7 -2
  432. package/src/secrets/adapters.js +34 -3
  433. package/src/secrets/aws-control-plane.d.ts +10 -1
  434. package/src/secrets/aws-control-plane.js +67 -0
  435. package/src/secrets/generated-aws-control-plane.d.ts +23 -0
  436. package/src/secrets/generated-aws-control-plane.js +259 -0
  437. package/src/secrets/metadata.js +38 -10
  438. package/src/secrets/model.d.ts +8 -1
  439. package/src/secrets/model.js +24 -3
  440. package/src/secrets/operator.d.ts +91 -3
  441. package/src/secrets/operator.js +463 -13
  442. package/src/secrets/personal-command.d.ts +18 -2
  443. package/src/secrets/personal-command.js +66 -12
  444. package/src/secrets/registry.d.ts +2 -1
  445. package/src/secrets/registry.js +18 -1
  446. package/src/secrets/verification.js +15 -2
  447. package/src/secrets/workload-access.js +10 -2
  448. package/src/sst-environment-source-format.d.ts +6 -0
  449. package/src/sst-environment-source-format.js +199 -0
  450. package/src/supply-chain/action-pins.js +61 -7
  451. package/src/supply-chain/blueprint-trust-git.js +85 -24
  452. package/src/supply-chain/blueprint-verification-authority.js +55 -3
  453. package/src/supply-chain/build-output-bounds.d.ts +2 -0
  454. package/src/supply-chain/build-output-bounds.js +12 -0
  455. package/src/supply-chain/build-output.d.ts +7 -1
  456. package/src/supply-chain/build-output.js +177 -24
  457. package/src/supply-chain/ecr-scanning.d.ts +5 -3
  458. package/src/supply-chain/ecr-scanning.js +11 -7
  459. package/src/supply-chain/ecs-deployed-image.d.ts +5 -3
  460. package/src/supply-chain/ecs-deployed-image.js +6 -4
  461. package/src/supply-chain/generated-blueprint-trust-command.js +18 -1
  462. package/src/supply-chain/generated-command.js +1 -0
  463. package/src/supply-chain/generated-container-release-command.js +1285 -124
  464. package/src/supply-chain/generated-ecr-collector-command.d.ts +0 -1
  465. package/src/supply-chain/generated-ecr-collector-command.js +200 -93
  466. package/src/supply-chain/generated-files.js +25 -14
  467. package/src/supply-chain/generated-scanner-command.js +2 -1
  468. package/src/supply-chain/index.d.ts +1 -1
  469. package/src/supply-chain/index.js +2 -1
  470. package/src/supply-chain/sbom.d.ts +1 -1
  471. package/src/supply-chain/sbom.js +30 -5
  472. package/src/supply-chain/scanner.js +3 -0
  473. package/src/testing-evidence/fixture-scope.d.ts +2 -1
  474. package/src/testing-evidence/fixture-scope.js +4 -2
  475. package/src/testing-evidence/result.d.ts +2 -1
  476. package/src/testing-evidence/result.js +18 -4
  477. package/src/workload-roles/account-baseline.d.ts +11 -0
  478. package/src/workload-roles/account-baseline.js +253 -16
  479. package/src/workload-roles/authority.d.ts +3 -1
  480. package/src/workload-roles/authority.js +48 -2
  481. package/src/workload-roles/aws-s3-state.js +27 -0
  482. package/src/workload-roles/boundary.d.ts +2 -1
  483. package/src/workload-roles/boundary.js +9 -2
  484. package/src/workload-roles/handler.js +52 -24
  485. package/src/workload-roles/index.d.ts +10 -17
  486. package/src/workload-roles/index.js +5 -18
  487. package/src/workload-roles/injection.js +1 -1
  488. package/src/workload-roles/provisioner.js +12 -4
  489. package/src/workload-roles/registration.d.ts +1 -0
  490. package/src/workload-roles/registration.js +5 -0
  491. package/src/workload-roles/stage-boundary.js +1 -1
  492. package/src/workload-roles/standard-slice.js +3 -3
  493. package/src/workspace-deployment/affected-lifecycle.d.ts +53 -0
  494. package/src/workspace-deployment/affected-lifecycle.js +84 -0
  495. package/src/workspace-deployment/identity.d.ts +3 -0
  496. package/src/workspace-deployment/identity.js +22 -0
  497. package/src/workspace-deployment/index.d.ts +4 -0
  498. package/src/workspace-deployment/index.js +8 -0
  499. package/src/workspace-deployment/migration-evidence.d.ts +29 -0
  500. package/src/workspace-deployment/migration-evidence.js +83 -0
  501. package/src/workspace-deployment/migration.d.ts +27 -0
  502. package/src/workspace-deployment/migration.js +109 -0
  503. package/src/workspace-deployment/ownership.d.ts +81 -0
  504. package/src/workspace-deployment/ownership.js +381 -0
  505. package/src/api-contract/baseline-update.js.map +0 -1
  506. package/src/api-contract/compatibility.js.map +0 -1
  507. package/src/api-contract/contract-graph.js.map +0 -1
  508. package/src/api-contract/evidence.js.map +0 -1
  509. package/src/api-contract/index.js.map +0 -1
  510. package/src/api-contract/model.fixtures.d.ts +0 -2
  511. package/src/api-contract/model.fixtures.js +0 -81
  512. package/src/api-contract/model.fixtures.js.map +0 -1
  513. package/src/api-contract/model.js.map +0 -1
  514. package/src/api-contract/rollout.js.map +0 -1
  515. package/src/authorization/compatibility.js.map +0 -1
  516. package/src/authorization/index.js.map +0 -1
  517. package/src/blueprints/execution.js.map +0 -1
  518. package/src/blueprints/external-sandbox.js.map +0 -1
  519. package/src/blueprints/index.js.map +0 -1
  520. package/src/blueprints/inputs.js.map +0 -1
  521. package/src/blueprints/manifest.js.map +0 -1
  522. package/src/blueprints/resolver.js.map +0 -1
  523. package/src/blueprints/transitions.js.map +0 -1
  524. package/src/cli/agent-command.js.map +0 -1
  525. package/src/cli/agent-runtime.js.map +0 -1
  526. package/src/cli/blueprint-authority.js.map +0 -1
  527. package/src/cli/blueprint-command.js.map +0 -1
  528. package/src/cli/bootstrap.js.map +0 -1
  529. package/src/cli/dev-command.js.map +0 -1
  530. package/src/cli/main.js.map +0 -1
  531. package/src/cli/output.js.map +0 -1
  532. package/src/cli/personal-secret-runtime.js.map +0 -1
  533. package/src/cli/secret-terminal.js.map +0 -1
  534. package/src/container-images.js.map +0 -1
  535. package/src/data-lifecycle/index.js.map +0 -1
  536. package/src/data-lifecycle/model.fixtures.d.ts +0 -2
  537. package/src/data-lifecycle/model.fixtures.js +0 -244
  538. package/src/data-lifecycle/model.fixtures.js.map +0 -1
  539. package/src/data-lifecycle/model.js.map +0 -1
  540. package/src/data-lifecycle/sensitive-artifacts.js.map +0 -1
  541. package/src/data-lifecycle/validation.js.map +0 -1
  542. package/src/database-retirement/contract.js.map +0 -1
  543. package/src/database-retirement/index.js.map +0 -1
  544. package/src/deterministic-order.js.map +0 -1
  545. package/src/developer-agent/context.js.map +0 -1
  546. package/src/developer-agent/generator-planning.js.map +0 -1
  547. package/src/developer-agent/generator-preview.js.map +0 -1
  548. package/src/developer-agent/git-inspection.js.map +0 -1
  549. package/src/developer-agent/handoff.js.map +0 -1
  550. package/src/developer-agent/index.js.map +0 -1
  551. package/src/developer-agent/model.js.map +0 -1
  552. package/src/developer-agent/operation-registry.js.map +0 -1
  553. package/src/developer-agent/ordering.js.map +0 -1
  554. package/src/developer-agent/planning.js.map +0 -1
  555. package/src/developer-agent/preview-changes.js.map +0 -1
  556. package/src/developer-agent/preview-source.js.map +0 -1
  557. package/src/developer-agent/validation.js.map +0 -1
  558. package/src/developer-agent/workspace-inspection.js.map +0 -1
  559. package/src/developer-agent/workspace-path.js.map +0 -1
  560. package/src/executors/blueprint-trust/blueprint-trust.js.map +0 -1
  561. package/src/executors/blueprint-verification/blueprint-verification.js.map +0 -1
  562. package/src/executors/deploy/deploy.js.map +0 -1
  563. package/src/executors/deployment-plan/deployment-plan.js.map +0 -1
  564. package/src/executors/dev/dev.js.map +0 -1
  565. package/src/executors/dev-doctor/dev-doctor.js.map +0 -1
  566. package/src/executors/dev-setup/dev-setup.js.map +0 -1
  567. package/src/executors/developer-context/developer-context.js.map +0 -1
  568. package/src/executors/fleet/fleet.js.map +0 -1
  569. package/src/executors/foundation-preflight/foundation-preflight.js.map +0 -1
  570. package/src/executors/foundation-profile-preflight/foundation-profile-preflight.js.map +0 -1
  571. package/src/executors/foundation-remove-preflight/foundation-remove-preflight.js.map +0 -1
  572. package/src/executors/github-bootstrap/github-bootstrap.js.map +0 -1
  573. package/src/executors/infrastructure-plan/infrastructure-plan.js.map +0 -1
  574. package/src/executors/refresh/refresh.js.map +0 -1
  575. package/src/executors/remove/remove.js.map +0 -1
  576. package/src/executors/secret-guardrails/secret-guardrails.js.map +0 -1
  577. package/src/executors/secret-metadata/secret-metadata.js.map +0 -1
  578. package/src/executors/sst-lifecycle/logging-preflight.js.map +0 -1
  579. package/src/executors/sst-lifecycle/run-sst-command.js.map +0 -1
  580. package/src/executors/sst-lifecycle/secret-preflight.js.map +0 -1
  581. package/src/executors/unlock/unlock.js.map +0 -1
  582. package/src/executors/work-markers/work-markers.js.map +0 -1
  583. package/src/foundation/discovery.js.map +0 -1
  584. package/src/foundation/index.js.map +0 -1
  585. package/src/foundation/local-database-contract.js.map +0 -1
  586. package/src/foundation/logging-preflight.js.map +0 -1
  587. package/src/foundation/logging.js.map +0 -1
  588. package/src/foundation/preflight.js.map +0 -1
  589. package/src/foundation/provision-database-bindings.js.map +0 -1
  590. package/src/foundation/provision-logical-database.js.map +0 -1
  591. package/src/foundation/requirements.js.map +0 -1
  592. package/src/foundation/router-origin-proof.js.map +0 -1
  593. package/src/foundation/stages.js.map +0 -1
  594. package/src/frontend-security/index.js.map +0 -1
  595. package/src/frontend-security/security-headers.js.map +0 -1
  596. package/src/generators/feature-registry.js.map +0 -1
  597. package/src/generators/function/function.js.map +0 -1
  598. package/src/generators/job/job.js.map +0 -1
  599. package/src/generators/logging-registry.js.map +0 -1
  600. package/src/generators/post-generation-install.js.map +0 -1
  601. package/src/generators/preset/generator.js.map +0 -1
  602. package/src/generators/preset/tool-versions.js.map +0 -1
  603. package/src/generators/preset/workspace-files-developer-agent.js.map +0 -1
  604. package/src/generators/preset/workspace-files-foundation-workload-roles.js.map +0 -1
  605. package/src/generators/preset/workspace-files-performance-cost.js.map +0 -1
  606. package/src/generators/preset/workspace-files-performance-load.js.map +0 -1
  607. package/src/generators/preset/workspace-files-workload-role-baseline.js.map +0 -1
  608. package/src/generators/preset/workspace-files.js.map +0 -1
  609. package/src/generators/repository-policy/repository-policy.js.map +0 -1
  610. package/src/generators/service/service.js.map +0 -1
  611. package/src/generators/slice/built-in-plan-api-contract-files.js.map +0 -1
  612. package/src/generators/slice/built-in-plan-api-files.js.map +0 -1
  613. package/src/generators/slice/built-in-plan-async-work-files.js.map +0 -1
  614. package/src/generators/slice/built-in-plan-authorization-files.js.map +0 -1
  615. package/src/generators/slice/built-in-plan-authorization-infrastructure-files.js.map +0 -1
  616. package/src/generators/slice/built-in-plan-data-deletion-files.js.map +0 -1
  617. package/src/generators/slice/built-in-plan-data-export-infrastructure-files.js.map +0 -1
  618. package/src/generators/slice/built-in-plan-data-files.js.map +0 -1
  619. package/src/generators/slice/built-in-plan-data-lifecycle-files.js.map +0 -1
  620. package/src/generators/slice/built-in-plan-data-lifecycle-runtime-files.js.map +0 -1
  621. package/src/generators/slice/built-in-plan-data-retention-job-files.js.map +0 -1
  622. package/src/generators/slice/built-in-plan-data-retention-launcher-files.js.map +0 -1
  623. package/src/generators/slice/built-in-plan-data-rights-files.js.map +0 -1
  624. package/src/generators/slice/built-in-plan-database-lifecycle-files.js.map +0 -1
  625. package/src/generators/slice/built-in-plan-database-retirement-rehearsal-files.js.map +0 -1
  626. package/src/generators/slice/built-in-plan-foundation-files.js.map +0 -1
  627. package/src/generators/slice/built-in-plan-frontend-files.js.map +0 -1
  628. package/src/generators/slice/built-in-plan-infrastructure-files.js.map +0 -1
  629. package/src/generators/slice/built-in-plan-infrastructure-safety-files.js.map +0 -1
  630. package/src/generators/slice/built-in-plan-metadata-files.js.map +0 -1
  631. package/src/generators/slice/built-in-plan-operations-files.js.map +0 -1
  632. package/src/generators/slice/built-in-plan-performance-files.js.map +0 -1
  633. package/src/generators/slice/built-in-plan-project-files.js.map +0 -1
  634. package/src/generators/slice/built-in-plan-release-files.js.map +0 -1
  635. package/src/generators/slice/built-in-plan-reliability-files.js.map +0 -1
  636. package/src/generators/slice/built-in-plan-secret-runtime-files.js.map +0 -1
  637. package/src/generators/slice/built-in-plan-shared.js.map +0 -1
  638. package/src/generators/slice/built-in-plan-testing-files.js.map +0 -1
  639. package/src/generators/slice/built-in-plan-verification-files.js.map +0 -1
  640. package/src/generators/slice/built-in-plan-web-files.js.map +0 -1
  641. package/src/generators/slice/built-in-plan-workload-role-files.js.map +0 -1
  642. package/src/generators/slice/built-in-plan.js.map +0 -1
  643. package/src/generators/slice/slice.js.map +0 -1
  644. package/src/generators/upgrade/upgrade.js.map +0 -1
  645. package/src/generators/workload/frozen-container.js.map +0 -1
  646. package/src/generators/workload/performance-registration.js.map +0 -1
  647. package/src/generators/workload/reliability-registration.js.map +0 -1
  648. package/src/generators/workload/service-performance-files.js.map +0 -1
  649. package/src/generators/workload/workload.js.map +0 -1
  650. package/src/git-policy/action-pins.js.map +0 -1
  651. package/src/git-policy/github-bootstrap.js.map +0 -1
  652. package/src/git-policy/index.js.map +0 -1
  653. package/src/git-policy/routing.js.map +0 -1
  654. package/src/index.js.map +0 -1
  655. package/src/infrastructure-change/convergence.js.map +0 -1
  656. package/src/infrastructure-change/drift.js.map +0 -1
  657. package/src/infrastructure-change/index.js.map +0 -1
  658. package/src/infrastructure-change/model.js.map +0 -1
  659. package/src/infrastructure-change/normalize.js.map +0 -1
  660. package/src/infrastructure-change/plan.js.map +0 -1
  661. package/src/infrastructure-change/risk.js.map +0 -1
  662. package/src/infrastructure-change/summary.js.map +0 -1
  663. package/src/local-dev/context-discovery.js.map +0 -1
  664. package/src/local-dev/contract-validation.js.map +0 -1
  665. package/src/local-dev/contracts.js.map +0 -1
  666. package/src/local-dev/control-contract.js.map +0 -1
  667. package/src/local-dev/dev-command-core.js.map +0 -1
  668. package/src/local-dev/effects.js.map +0 -1
  669. package/src/local-dev/environment-inspector.js.map +0 -1
  670. package/src/local-dev/environment-state.js.map +0 -1
  671. package/src/local-dev/errors.js.map +0 -1
  672. package/src/local-dev/fleet-client.js.map +0 -1
  673. package/src/local-dev/fleet-configuration.js.map +0 -1
  674. package/src/local-dev/fleet-inventory.js.map +0 -1
  675. package/src/local-dev/fleet-ipc.js.map +0 -1
  676. package/src/local-dev/fleet-launcher.js.map +0 -1
  677. package/src/local-dev/fleet-lock.js.map +0 -1
  678. package/src/local-dev/fleet-logs.js.map +0 -1
  679. package/src/local-dev/fleet-process.js.map +0 -1
  680. package/src/local-dev/fleet-runtime.js.map +0 -1
  681. package/src/local-dev/fleet-session.js.map +0 -1
  682. package/src/local-dev/fleet-slice-runner-daemon.js.map +0 -1
  683. package/src/local-dev/fleet-startup.js.map +0 -1
  684. package/src/local-dev/fleet-state.js.map +0 -1
  685. package/src/local-dev/fleet-supervisor-daemon.js.map +0 -1
  686. package/src/local-dev/fleet-supervisor.js.map +0 -1
  687. package/src/local-dev/gateway-daemon.js.map +0 -1
  688. package/src/local-dev/gateway.js.map +0 -1
  689. package/src/local-dev/identity.js.map +0 -1
  690. package/src/local-dev/index.js.map +0 -1
  691. package/src/local-dev/local-context.js.map +0 -1
  692. package/src/local-dev/nx-workspace.js.map +0 -1
  693. package/src/local-dev/personal-secret-ledger.js.map +0 -1
  694. package/src/local-dev/personal-stage.js.map +0 -1
  695. package/src/local-dev/portless.js.map +0 -1
  696. package/src/local-dev/ports.js.map +0 -1
  697. package/src/local-dev/private-state.js.map +0 -1
  698. package/src/local-dev/process-identity.js.map +0 -1
  699. package/src/local-dev/proxy.js.map +0 -1
  700. package/src/local-dev/runtime-paths.js.map +0 -1
  701. package/src/local-dev/secret-slice-claim.js.map +0 -1
  702. package/src/local-dev/slice-claim.js.map +0 -1
  703. package/src/local-dev/slice-runner.js.map +0 -1
  704. package/src/local-dev/tls.js.map +0 -1
  705. package/src/ownership/composition.js.map +0 -1
  706. package/src/ownership/foundation-record.js.map +0 -1
  707. package/src/ownership/hash.js.map +0 -1
  708. package/src/ownership/index.js.map +0 -1
  709. package/src/ownership/json-ownership.js.map +0 -1
  710. package/src/ownership/record.js.map +0 -1
  711. package/src/ownership/workspace-record.js.map +0 -1
  712. package/src/performance/cost-collection.js.map +0 -1
  713. package/src/performance/cost-controls.js.map +0 -1
  714. package/src/performance/evidence.js.map +0 -1
  715. package/src/performance/index.js.map +0 -1
  716. package/src/performance/load-safety.js.map +0 -1
  717. package/src/performance/model.js.map +0 -1
  718. package/src/performance/pr-artifact-budget.js.map +0 -1
  719. package/src/performance/runner.js.map +0 -1
  720. package/src/performance/scenario-endpoint.js.map +0 -1
  721. package/src/performance/scenario.js.map +0 -1
  722. package/src/performance/test-fixtures.d.ts +0 -7
  723. package/src/performance/test-fixtures.js +0 -169
  724. package/src/performance/test-fixtures.js.map +0 -1
  725. package/src/performance/unit-cost.js.map +0 -1
  726. package/src/release/index.js.map +0 -1
  727. package/src/release/lifecycle.js.map +0 -1
  728. package/src/release/manifest.js.map +0 -1
  729. package/src/release/rollout.js.map +0 -1
  730. package/src/release/source-authority.js.map +0 -1
  731. package/src/repository-policy/aurora-preflight.js.map +0 -1
  732. package/src/repository-policy/deployment-plan.js.map +0 -1
  733. package/src/repository-policy/foundation-profile.js.map +0 -1
  734. package/src/repository-policy/index.js.map +0 -1
  735. package/src/repository-policy/policy.js.map +0 -1
  736. package/src/secrets/adapters.js.map +0 -1
  737. package/src/secrets/aws-control-plane.js.map +0 -1
  738. package/src/secrets/declaration-verification.js.map +0 -1
  739. package/src/secrets/guardrails.js.map +0 -1
  740. package/src/secrets/index.js.map +0 -1
  741. package/src/secrets/metadata.js.map +0 -1
  742. package/src/secrets/model.js.map +0 -1
  743. package/src/secrets/operator.js.map +0 -1
  744. package/src/secrets/permissions.js.map +0 -1
  745. package/src/secrets/personal-command.js.map +0 -1
  746. package/src/secrets/personal-ledger.js.map +0 -1
  747. package/src/secrets/registry.js.map +0 -1
  748. package/src/secrets/verification.js.map +0 -1
  749. package/src/secrets/workload-access.js.map +0 -1
  750. package/src/supply-chain/action-pins.js.map +0 -1
  751. package/src/supply-chain/blueprint-trust-git.js.map +0 -1
  752. package/src/supply-chain/blueprint-trust-process.js.map +0 -1
  753. package/src/supply-chain/blueprint-trust.js.map +0 -1
  754. package/src/supply-chain/blueprint-verification-authority.js.map +0 -1
  755. package/src/supply-chain/blueprint-verification-execution.js.map +0 -1
  756. package/src/supply-chain/build-output.js.map +0 -1
  757. package/src/supply-chain/common.js.map +0 -1
  758. package/src/supply-chain/container-artifact-contract.js.map +0 -1
  759. package/src/supply-chain/container-release.js.map +0 -1
  760. package/src/supply-chain/ecr-applicability.js.map +0 -1
  761. package/src/supply-chain/ecr-scanning.js.map +0 -1
  762. package/src/supply-chain/ecs-deployed-image.js.map +0 -1
  763. package/src/supply-chain/errors.js.map +0 -1
  764. package/src/supply-chain/generated-blueprint-trust-command.js.map +0 -1
  765. package/src/supply-chain/generated-command.js.map +0 -1
  766. package/src/supply-chain/generated-container-release-command.js.map +0 -1
  767. package/src/supply-chain/generated-ecr-collector-command.js.map +0 -1
  768. package/src/supply-chain/generated-files.js.map +0 -1
  769. package/src/supply-chain/generated-scanner-command.js.map +0 -1
  770. package/src/supply-chain/index.js.map +0 -1
  771. package/src/supply-chain/inventory.js.map +0 -1
  772. package/src/supply-chain/license-expression.js.map +0 -1
  773. package/src/supply-chain/pnpm-toolchain-authority.js.map +0 -1
  774. package/src/supply-chain/policy.js.map +0 -1
  775. package/src/supply-chain/publication.js.map +0 -1
  776. package/src/supply-chain/sbom.js.map +0 -1
  777. package/src/supply-chain/scanner.js.map +0 -1
  778. package/src/supply-chain/vendored-source.js.map +0 -1
  779. package/src/testing-evidence/fixture-scope.js.map +0 -1
  780. package/src/testing-evidence/index.js.map +0 -1
  781. package/src/testing-evidence/quarantine.js.map +0 -1
  782. package/src/testing-evidence/result.js.map +0 -1
  783. package/src/testing-evidence/runner-adapter.js.map +0 -1
  784. package/src/testing-evidence/sensitive-artifacts.js.map +0 -1
  785. package/src/validation.js.map +0 -1
  786. package/src/work-markers/index.js.map +0 -1
  787. package/src/work-markers/work-markers.js.map +0 -1
  788. package/src/workload-roles/account-baseline.js.map +0 -1
  789. package/src/workload-roles/authority.js.map +0 -1
  790. package/src/workload-roles/aws-adapter.js.map +0 -1
  791. package/src/workload-roles/aws-internal-handler.js.map +0 -1
  792. package/src/workload-roles/aws-s3-state.js.map +0 -1
  793. package/src/workload-roles/aws-sdk-control-plane.js.map +0 -1
  794. package/src/workload-roles/boundary.js.map +0 -1
  795. package/src/workload-roles/convergence.js.map +0 -1
  796. package/src/workload-roles/effective-policy.js.map +0 -1
  797. package/src/workload-roles/handler.js.map +0 -1
  798. package/src/workload-roles/history.js.map +0 -1
  799. package/src/workload-roles/index.js.map +0 -1
  800. package/src/workload-roles/injection.js.map +0 -1
  801. package/src/workload-roles/manifest.js.map +0 -1
  802. package/src/workload-roles/provisioner.js.map +0 -1
  803. package/src/workload-roles/registration.js.map +0 -1
  804. package/src/workload-roles/stage-boundary.js.map +0 -1
  805. package/src/workload-roles/standard-slice.js.map +0 -1
@@ -1,235 +1,930 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.renderStandardSliceAuthorizationInfrastructureFiles = renderStandardSliceAuthorizationInfrastructureFiles;
4
- const MACHINE_CLIENT_PROVISIONER_SOURCE = `import boto3,datetime,json,logging,os,urllib.request
5
- from botocore.exceptions import ClientError
6
- cognito=boto3.client("cognito-idp")
7
- secrets=boto3.client("secretsmanager")
8
- logger=logging.getLogger()
9
- logger.setLevel(logging.INFO)
10
-
11
- def emit(event,level,outcome,message,error_code=None):
12
- attributes={
13
- "requestType":str(event.get("RequestType","unknown"))[:32],
4
+ /**
5
+ * Managed Node.js CloudFormation custom-resource handler. The handler string
6
+ * 'authorization/machine-client-provisioner.handler' and the custom-resource
7
+ * contract (physical id, Data keys, secret document) are unchanged from the
8
+ * retired Python provisioner; only the two owner-approved fixes differ:
9
+ * rotation refusals precede any Cognito create, and Delete acts only on the
10
+ * physical id this provisioner returns.
11
+ */
12
+ function machineClientProvisionerSource(name) {
13
+ return `import { request } from 'node:https';
14
+ import {
15
+ CognitoIdentityProviderClient,
16
+ CreateUserPoolClientCommand,
17
+ DeleteUserPoolClientCommand,
18
+ DescribeUserPoolClientCommand,
19
+ ListUserPoolClientsCommand,
20
+ } from '@aws-sdk/client-cognito-identity-provider';
21
+ import {
22
+ GetSecretValueCommand,
23
+ PutSecretValueCommand,
24
+ SecretsManagerClient,
25
+ UpdateSecretVersionStageCommand,
26
+ } from '@aws-sdk/client-secrets-manager';
27
+ import { createLogger, type Logger } from '@empire-builder-kit/runtime/logging';
28
+
29
+ /**
30
+ * AWS-internal CloudFormation custom resource for the Slice's confidential
31
+ * Cognito machine client. The client secret moves only from Cognito into the
32
+ * generated Secrets Manager container; it never reaches a response, a log
33
+ * record, or an error reason.
34
+ */
35
+ export interface MachineClientProperties {
36
+ ClientName: string;
37
+ CredentialGeneration: string;
38
+ ResourceServerIdentifier: string;
39
+ RetirePreviousGeneration: string;
40
+ Scopes: string[];
41
+ SecretArn: string;
42
+ UserPoolId: string;
43
+ }
44
+
45
+ export interface MachineClientProvisionerEvent {
46
+ LogicalResourceId: string;
47
+ PhysicalResourceId?: string;
48
+ RequestId: string;
49
+ RequestType: string;
50
+ ResourceProperties: MachineClientProperties;
51
+ ResponseURL: string;
52
+ StackId: string;
53
+ }
54
+
55
+ export interface MachineClientProvisionerDependencies {
56
+ cognito: { send(command: any): Promise<any> };
57
+ logger: Logger;
58
+ /** Resolves only after CloudFormation has accepted the response. */
59
+ respond(responseUrl: string, body: string): Promise<void>;
60
+ secrets: { send(command: any): Promise<any> };
61
+ }
62
+
63
+ interface CredentialVersion {
64
+ document: Record<string, unknown>;
65
+ versionId: string;
66
+ }
67
+
68
+ // Reasons keep the exact tokens CloudFormation showed before the Node.js
69
+ // port. Bundles are minified, so names are literals, never class names.
70
+ type ProvisioningErrorName =
71
+ | 'AttributeError'
72
+ | 'HTTPError'
73
+ | 'JSONDecodeError'
74
+ | 'KeyError'
75
+ | 'TypeError'
76
+ | 'URLError'
77
+ | 'ValueError';
78
+
79
+ const PROVISIONING_ERROR_NAMES = new Set<string>([
80
+ 'AttributeError',
81
+ 'HTTPError',
82
+ 'JSONDecodeError',
83
+ 'KeyError',
84
+ 'TypeError',
85
+ 'URLError',
86
+ 'ValueError',
87
+ ]);
88
+
89
+ class ProvisioningError extends Error {
90
+ constructor(name: ProvisioningErrorName, message: string) {
91
+ super(message);
92
+ this.name = name;
93
+ }
94
+ }
95
+
96
+ function refuse(message: string): ProvisioningError {
97
+ return new ProvisioningError('ValueError', message);
98
+ }
99
+
100
+ function errorField(error: unknown, field: '$metadata' | 'name'): unknown {
101
+ return typeof error === 'object' && error !== null
102
+ ? (error as Record<string, unknown>)[field]
103
+ : undefined;
104
+ }
105
+
106
+ function reasonFor(error: unknown): string {
107
+ const name = errorField(error, 'name');
108
+ if (typeof name === 'string' && PROVISIONING_ERROR_NAMES.has(name)) {
109
+ return name;
110
+ }
111
+ const metadata = errorField(error, '$metadata');
112
+ if (typeof metadata === 'object' && metadata !== null) return 'ClientError';
113
+ return typeof name === 'string' && /^[A-Za-z][A-Za-z0-9]{0,127}$/.test(name)
114
+ ? name
115
+ : 'Error';
116
+ }
117
+
118
+ function isNamed(error: unknown, name: string): boolean {
119
+ return errorField(error, 'name') === name;
120
+ }
121
+
122
+ /** JSON truthiness exactly as the original provisioner evaluated it. */
123
+ function present(value: unknown): boolean {
124
+ if (Array.isArray(value)) return value.length > 0;
125
+ if (typeof value === 'object' && value !== null) {
126
+ return Object.keys(value).length > 0;
127
+ }
128
+ return Boolean(value);
129
+ }
130
+
131
+ function required(record: Record<string, unknown>, key: string): unknown {
132
+ if (!(key in record)) throw new ProvisioningError('KeyError', key);
133
+ return record[key];
134
+ }
135
+
136
+ function slotOf(value: unknown): string {
137
+ if (typeof value !== 'string') {
138
+ throw new ProvisioningError(
139
+ 'AttributeError',
140
+ 'Machine credential generation is not text.',
141
+ );
142
+ }
143
+ return value.split('-', 1)[0];
144
+ }
145
+
146
+ function parseCredentialDocument(value: unknown): Record<string, unknown> {
147
+ let document: unknown;
148
+ try {
149
+ document = JSON.parse(value as string);
150
+ } catch {
151
+ throw new ProvisioningError(
152
+ 'JSONDecodeError',
153
+ 'Machine credential document is not JSON.',
154
+ );
155
+ }
156
+ if (
157
+ typeof document !== 'object' ||
158
+ document === null ||
159
+ Array.isArray(document)
160
+ ) {
161
+ throw new ProvisioningError(
162
+ 'TypeError',
163
+ 'Machine credential document is not a JSON object.',
164
+ );
165
+ }
166
+ return document as Record<string, unknown>;
167
+ }
168
+
169
+ function logDimension(value: string | undefined): string {
170
+ const normalized = (value ?? '').trim();
171
+ return normalized.length > 0 &&
172
+ normalized.length <= 128 &&
173
+ [...normalized].every((character) => {
174
+ const code = character.charCodeAt(0);
175
+ return code > 31 && code !== 127;
176
+ })
177
+ ? normalized
178
+ : 'unknown';
179
+ }
180
+
181
+ export function createMachineClientProvisioner(
182
+ dependencies: MachineClientProvisionerDependencies,
183
+ ): (event: MachineClientProvisionerEvent) => Promise<void> {
184
+ const { cognito, logger, respond, secrets } = dependencies;
185
+
186
+ async function readVersion(
187
+ secretArn: string,
188
+ stage: 'AWSCURRENT' | 'AWSPREVIOUS',
189
+ ): Promise<CredentialVersion | undefined> {
190
+ let value: Record<string, unknown>;
191
+ try {
192
+ value = await secrets.send(
193
+ new GetSecretValueCommand({ SecretId: secretArn, VersionStage: stage }),
194
+ );
195
+ } catch (error) {
196
+ if (
197
+ isNamed(error, 'ResourceNotFoundException') ||
198
+ isNamed(error, 'InvalidRequestException')
199
+ ) {
200
+ return undefined;
201
+ }
202
+ throw error;
203
+ }
204
+ const document = parseCredentialDocument(required(value, 'SecretString'));
205
+ return {
206
+ document,
207
+ versionId: required(value, 'VersionId') as string,
208
+ };
209
+ }
210
+
211
+ async function findClient(
212
+ userPoolId: string,
213
+ clientName: string,
214
+ ): Promise<Record<string, unknown> | undefined> {
215
+ let nextToken: string | undefined;
216
+ do {
217
+ const page = await cognito.send(
218
+ new ListUserPoolClientsCommand({
219
+ UserPoolId: userPoolId,
220
+ MaxResults: 60,
221
+ ...(nextToken ? { NextToken: nextToken } : {}),
222
+ }),
223
+ );
224
+ for (const summary of page.UserPoolClients ?? []) {
225
+ if (summary.ClientName === clientName) {
226
+ const described = await cognito.send(
227
+ new DescribeUserPoolClientCommand({
228
+ UserPoolId: userPoolId,
229
+ ClientId: required(summary, 'ClientId') as string,
230
+ }),
231
+ );
232
+ return required(described, 'UserPoolClient') as Record<
233
+ string,
234
+ unknown
235
+ >;
236
+ }
237
+ }
238
+ nextToken = page.NextToken;
239
+ } while (nextToken);
240
+ return undefined;
241
+ }
242
+
243
+ async function ensureClient(
244
+ properties: MachineClientProperties,
245
+ ): Promise<Record<string, unknown>> {
246
+ const client = await findClient(
247
+ properties.UserPoolId,
248
+ properties.ClientName,
249
+ );
250
+ if (client && present(client)) return client;
251
+ const created = await cognito.send(
252
+ new CreateUserPoolClientCommand({
253
+ UserPoolId: properties.UserPoolId,
254
+ ClientName: properties.ClientName,
255
+ GenerateSecret: true,
256
+ AllowedOAuthFlows: ['client_credentials'],
257
+ AllowedOAuthFlowsUserPoolClient: true,
258
+ AllowedOAuthScopes: properties.Scopes,
259
+ AccessTokenValidity: 15,
260
+ TokenValidityUnits: { AccessToken: 'minutes' },
261
+ EnableTokenRevocation: true,
262
+ PreventUserExistenceErrors: 'ENABLED',
263
+ }),
264
+ );
265
+ return required(created, 'UserPoolClient') as Record<string, unknown>;
266
+ }
267
+
268
+ async function deleteClient(
269
+ userPoolId: string,
270
+ clientId: unknown,
271
+ ): Promise<void> {
272
+ try {
273
+ await cognito.send(
274
+ new DeleteUserPoolClientCommand({
275
+ UserPoolId: userPoolId,
276
+ ClientId: clientId as string,
277
+ }),
278
+ );
279
+ } catch (error) {
280
+ if (!isNamed(error, 'ResourceNotFoundException')) throw error;
14
281
  }
15
- if error_code:
16
- attributes["errorCode"]=str(error_code)[:128]
17
- record={
18
- "attributes":attributes,
19
- "component":"machine-client-provisioner",
20
- "feature":"authorization",
21
- "level":level,
22
- "message":message,
23
- "operation":"machine-client.provision",
24
- "outcome":outcome,
25
- "requestId":str(event.get("RequestId","unknown"))[:128],
26
- "schemaVersion":1,
27
- "slice":os.environ.get("EBK_SLICE",""),
28
- "stage":os.environ.get("EBK_STAGE",""),
29
- "timestamp":datetime.datetime.now(
30
- datetime.timezone.utc
31
- ).isoformat(timespec="milliseconds").replace("+00:00","Z"),
32
- "workspace":os.environ.get("EBK_WORKSPACE",""),
282
+ }
283
+
284
+ function record(
285
+ event: MachineClientProvisionerEvent,
286
+ outcome: 'failure' | 'success',
287
+ errorCode?: string,
288
+ skipped?: string,
289
+ ): void {
290
+ const attributes: Record<string, string> = {
291
+ requestType: String(event.RequestType ?? 'unknown').slice(0, 32),
292
+ };
293
+ if (errorCode) attributes.errorCode = errorCode.slice(0, 128);
294
+ if (skipped) attributes.skipped = skipped;
295
+ const input = {
296
+ attributes,
297
+ context: {
298
+ requestId: String(event.RequestId ?? 'unknown').slice(0, 128),
299
+ },
300
+ outcome,
301
+ };
302
+ if (outcome === 'success') {
303
+ logger.info('Machine client provisioning completed.', input);
304
+ } else {
305
+ logger.error('Machine client provisioning failed.', input);
33
306
  }
34
- encoded=json.dumps(record,separators=(",",":"),sort_keys=True)
35
- if level=="ERROR":
36
- logger.error(encoded)
37
- else:
38
- logger.info(encoded)
39
-
40
- def respond(event,status,physical,data=None,reason=None):
41
- body=json.dumps({
42
- "Status":status,
43
- "Reason":reason or status,
44
- "PhysicalResourceId":physical,
45
- "StackId":event["StackId"],
46
- "RequestId":event["RequestId"],
47
- "LogicalResourceId":event["LogicalResourceId"],
48
- "NoEcho":False,
49
- "Data":data or {},
50
- }).encode()
51
- request=urllib.request.Request(
52
- event["ResponseURL"],
53
- data=body,
54
- headers={"content-type":"","content-length":str(len(body))},
55
- method="PUT",
56
- )
57
- with urllib.request.urlopen(request):
58
- pass
59
-
60
- def read_version(secret_arn,stage):
61
- try:
62
- value=secrets.get_secret_value(
63
- SecretId=secret_arn,
64
- VersionStage=stage,
65
- )
66
- document=json.loads(value["SecretString"])
67
- document["_versionId"]=value["VersionId"]
68
- return document
69
- except ClientError as error:
70
- if error.response["Error"]["Code"] in (
71
- "ResourceNotFoundException",
72
- "InvalidRequestException",
73
- ):
74
- return None
75
- raise
76
-
77
- def find_client(user_pool_id,client_name):
78
- paginator=cognito.get_paginator("list_user_pool_clients")
79
- for page in paginator.paginate(UserPoolId=user_pool_id,MaxResults=60):
80
- for summary in page.get("UserPoolClients",[]):
81
- if summary.get("ClientName")==client_name:
82
- return cognito.describe_user_pool_client(
83
- UserPoolId=user_pool_id,
84
- ClientId=summary["ClientId"],
85
- )["UserPoolClient"]
86
- return None
87
-
88
- def ensure_client(properties):
89
- client=find_client(properties["UserPoolId"],properties["ClientName"])
90
- if client:
91
- return client
92
- return cognito.create_user_pool_client(
93
- UserPoolId=properties["UserPoolId"],
94
- ClientName=properties["ClientName"],
95
- GenerateSecret=True,
96
- AllowedOAuthFlows=["client_credentials"],
97
- AllowedOAuthFlowsUserPoolClient=True,
98
- AllowedOAuthScopes=properties["Scopes"],
99
- AccessTokenValidity=15,
100
- TokenValidityUnits={"AccessToken":"minutes"},
101
- EnableTokenRevocation=True,
102
- PreventUserExistenceErrors="ENABLED",
103
- )["UserPoolClient"]
104
-
105
- def delete_client(user_pool_id,client_id):
106
- try:
107
- cognito.delete_user_pool_client(
108
- UserPoolId=user_pool_id,
109
- ClientId=client_id,
110
- )
111
- except ClientError as error:
112
- if error.response["Error"]["Code"]!="ResourceNotFoundException":
113
- raise
114
-
115
- def handler(event,context):
116
- properties=event["ResourceProperties"]
117
- physical="ebk-machine-client-"+properties["ResourceServerIdentifier"]
118
- try:
119
- current=read_version(properties["SecretArn"],"AWSCURRENT")
120
- previous=read_version(properties["SecretArn"],"AWSPREVIOUS")
121
- if event["RequestType"]=="Delete":
122
- for document in (current,previous):
123
- if document and document.get("clientId"):
124
- delete_client(properties["UserPoolId"],document["clientId"])
125
- emit(
126
- event,
127
- "INFO",
128
- "success",
129
- "Machine client provisioning completed.",
130
- )
131
- respond(event,"SUCCESS",physical)
132
- return
133
-
134
- generation=properties["CredentialGeneration"]
135
- retire=properties["RetirePreviousGeneration"]=="true"
136
- if retire and not current:
137
- raise ValueError("No current machine credential generation exists.")
138
- client=ensure_client(properties)
139
- client_id=client["ClientId"]
140
- rollback=(
141
- current
142
- and previous
143
- and current.get("generation")!=generation
144
- and previous.get("generation")==generation
145
- )
146
- if rollback:
147
- if retire:
148
- raise ValueError("Restore and prove the rollback generation before retiring the displaced generation.")
149
- if previous.get("clientId")!=client_id:
150
- raise ValueError("Rollback generation does not match its existing Cognito client.")
151
- secrets.update_secret_version_stage(
152
- SecretId=properties["SecretArn"],
153
- VersionStage="AWSCURRENT",
154
- MoveToVersionId=previous["_versionId"],
155
- RemoveFromVersionId=current["_versionId"],
156
- )
157
- current,previous=previous,current
158
- elif current and current.get("generation")!=generation:
159
- if previous:
160
- raise ValueError("Retire the previous generation before beginning another rotation.")
161
- old_slot=current["generation"].split("-",1)[0]
162
- new_slot=generation.split("-",1)[0]
163
- if old_slot==new_slot:
164
- raise ValueError("Credential generation must alternate blue and green slots.")
165
- if retire:
166
- raise ValueError("Create and prove a new generation before retiring the previous one.")
167
-
168
- if not rollback and (
169
- not current
170
- or current.get("generation")!=generation
171
- or current.get("clientId")!=client_id
172
- ):
173
- secrets.put_secret_value(
174
- SecretId=properties["SecretArn"],
175
- SecretString=json.dumps({
176
- "clientId":client_id,
177
- "clientSecret":client["ClientSecret"],
178
- "generation":generation,
179
- },separators=(",",":")),
180
- )
181
- previous=current
182
-
183
- if retire:
184
- if not previous:
185
- raise ValueError("No previous machine credential generation exists.")
186
- previous_id=previous.get("clientId")
187
- if previous_id and previous_id!=client_id:
188
- delete_client(properties["UserPoolId"],previous_id)
189
- version_id=previous.get("_versionId")
190
- if version_id:
191
- secrets.update_secret_version_stage(
192
- SecretId=properties["SecretArn"],
193
- VersionStage="AWSPREVIOUS",
194
- RemoveFromVersionId=version_id,
195
- )
196
-
197
- accepted_client_ids=[client_id]
307
+ }
308
+
309
+ async function respondTo(
310
+ event: MachineClientProvisionerEvent,
311
+ status: 'FAILED' | 'SUCCESS',
312
+ physicalResourceId: string,
313
+ data?: Record<string, string>,
314
+ reason?: string,
315
+ ): Promise<void> {
316
+ const body = JSON.stringify({
317
+ Status: status,
318
+ Reason: reason || status,
319
+ PhysicalResourceId: physicalResourceId,
320
+ StackId: event.StackId,
321
+ RequestId: event.RequestId,
322
+ LogicalResourceId: event.LogicalResourceId,
323
+ NoEcho: false,
324
+ Data: data ?? {},
325
+ });
326
+ await respond(event.ResponseURL, body);
327
+ }
328
+
329
+ return async function provisionMachineClient(event) {
330
+ const properties = event.ResourceProperties;
331
+ const physical =
332
+ 'ebk-machine-client-' + properties.ResourceServerIdentifier;
333
+ // Delete acts only on the resource this provisioner returned. Any other
334
+ // physical id is acknowledged without reading or deleting a credential.
335
+ const foreignDelete =
336
+ event.RequestType === 'Delete' && event.PhysicalResourceId !== physical;
337
+ const responsePhysicalId =
338
+ foreignDelete && event.PhysicalResourceId
339
+ ? event.PhysicalResourceId
340
+ : physical;
341
+ try {
342
+ if (foreignDelete) {
343
+ record(event, 'success', undefined, 'foreign-physical-resource-id');
344
+ await respondTo(event, 'SUCCESS', responsePhysicalId);
345
+ return;
346
+ }
347
+ const property = (key: keyof MachineClientProperties) =>
348
+ required(properties as unknown as Record<string, unknown>, key);
349
+ let current = await readVersion(
350
+ property('SecretArn') as string,
351
+ 'AWSCURRENT',
352
+ );
353
+ let previous = await readVersion(
354
+ property('SecretArn') as string,
355
+ 'AWSPREVIOUS',
356
+ );
357
+ if (event.RequestType === 'Delete') {
358
+ for (const version of [current, previous]) {
359
+ if (version && present(version.document.clientId)) {
360
+ await deleteClient(
361
+ properties.UserPoolId,
362
+ version.document.clientId,
363
+ );
364
+ }
365
+ }
366
+ record(event, 'success');
367
+ await respondTo(event, 'SUCCESS', responsePhysicalId);
368
+ return;
369
+ }
370
+
371
+ const generation = property('CredentialGeneration');
372
+ const retire = property('RetirePreviousGeneration') === 'true';
373
+ if (retire && !current) {
374
+ throw refuse('No current machine credential generation exists.');
375
+ }
376
+ const rollbackFrom =
377
+ current &&
378
+ previous &&
379
+ current.document.generation !== generation &&
380
+ previous.document.generation === generation
381
+ ? { current, previous }
382
+ : undefined;
383
+ // Every rotation refusal precedes the first Cognito call, so a refused
384
+ // deployment never creates an orphaned client.
385
+ if (rollbackFrom) {
386
+ if (retire) {
387
+ throw refuse(
388
+ 'Restore and prove the rollback generation before retiring the displaced generation.',
389
+ );
390
+ }
391
+ } else if (current && current.document.generation !== generation) {
392
+ if (previous) {
393
+ throw refuse(
394
+ 'Retire the previous generation before beginning another rotation.',
395
+ );
396
+ }
198
397
  if (
199
- not retire
200
- and previous
201
- and previous.get("clientId")
202
- and previous["clientId"]!=client_id
203
- ):
204
- accepted_client_ids.append(previous["clientId"])
205
- emit(
206
- event,
207
- "INFO",
208
- "success",
209
- "Machine client provisioning completed.",
210
- )
211
- respond(event,"SUCCESS",physical,{
212
- "AcceptedClientIdsJson":json.dumps(
213
- accepted_client_ids,
214
- separators=(",",":"),
215
- ),
216
- "ClientId":client_id,
217
- })
218
- except Exception as error:
219
- emit(
220
- event,
221
- "ERROR",
222
- "failure",
223
- "Machine client provisioning failed.",
224
- type(error).__name__,
225
- )
226
- respond(event,"FAILED",physical,reason=type(error).__name__)
398
+ slotOf(required(current.document, 'generation')) ===
399
+ slotOf(generation)
400
+ ) {
401
+ throw refuse(
402
+ 'Credential generation must alternate blue and green slots.',
403
+ );
404
+ }
405
+ if (retire) {
406
+ throw refuse(
407
+ 'Create and prove a new generation before retiring the previous one.',
408
+ );
409
+ }
410
+ }
411
+
412
+ // A rollback reuses the displaced client and never creates one.
413
+ const client = rollbackFrom
414
+ ? await findClient(properties.UserPoolId, properties.ClientName)
415
+ : await ensureClient(properties);
416
+ const clientId = client ? required(client, 'ClientId') : undefined;
417
+ if (rollbackFrom) {
418
+ if (!client || rollbackFrom.previous.document.clientId !== clientId) {
419
+ throw refuse(
420
+ 'Rollback generation does not match its existing Cognito client.',
421
+ );
422
+ }
423
+ await secrets.send(
424
+ new UpdateSecretVersionStageCommand({
425
+ SecretId: properties.SecretArn,
426
+ VersionStage: 'AWSCURRENT',
427
+ MoveToVersionId: rollbackFrom.previous.versionId,
428
+ RemoveFromVersionId: rollbackFrom.current.versionId,
429
+ }),
430
+ );
431
+ current = rollbackFrom.previous;
432
+ previous = rollbackFrom.current;
433
+ }
434
+
435
+ if (
436
+ !rollbackFrom &&
437
+ (!current ||
438
+ current.document.generation !== generation ||
439
+ current.document.clientId !== clientId)
440
+ ) {
441
+ await secrets.send(
442
+ new PutSecretValueCommand({
443
+ SecretId: properties.SecretArn,
444
+ SecretString: JSON.stringify({
445
+ clientId,
446
+ clientSecret: required(client ?? {}, 'ClientSecret'),
447
+ generation,
448
+ }),
449
+ }),
450
+ );
451
+ previous = current;
452
+ }
453
+
454
+ if (retire) {
455
+ if (!previous) {
456
+ throw refuse('No previous machine credential generation exists.');
457
+ }
458
+ const previousId = previous.document.clientId;
459
+ if (present(previousId) && previousId !== clientId) {
460
+ await deleteClient(properties.UserPoolId, previousId);
461
+ }
462
+ if (present(previous.versionId)) {
463
+ await secrets.send(
464
+ new UpdateSecretVersionStageCommand({
465
+ SecretId: properties.SecretArn,
466
+ VersionStage: 'AWSPREVIOUS',
467
+ RemoveFromVersionId: previous.versionId,
468
+ }),
469
+ );
470
+ }
471
+ }
472
+
473
+ const acceptedClientIds: unknown[] = [clientId];
474
+ if (
475
+ !retire &&
476
+ previous &&
477
+ present(previous.document.clientId) &&
478
+ previous.document.clientId !== clientId
479
+ ) {
480
+ acceptedClientIds.push(previous.document.clientId);
481
+ }
482
+ record(event, 'success');
483
+ await respondTo(event, 'SUCCESS', responsePhysicalId, {
484
+ AcceptedClientIdsJson: JSON.stringify(acceptedClientIds),
485
+ ClientId: clientId as string,
486
+ });
487
+ } catch (error) {
488
+ const reason = reasonFor(error);
489
+ record(event, 'failure', reason);
490
+ await respondTo(event, 'FAILED', responsePhysicalId, undefined, reason);
491
+ }
492
+ };
493
+ }
494
+
495
+ /** PUTs the presigned CloudFormation response and waits for acceptance. */
496
+ export function putCloudFormationResponse(
497
+ responseUrl: string,
498
+ body: string,
499
+ ): Promise<void> {
500
+ return new Promise((resolve, reject) => {
501
+ const outgoing = request(
502
+ responseUrl,
503
+ {
504
+ // Like urllib, never pool the socket: a connection kept across a
505
+ // frozen Lambda environment can be dead when the next request thaws.
506
+ headers: {
507
+ connection: 'close',
508
+ 'content-length': String(Buffer.byteLength(body)),
509
+ 'content-type': '',
510
+ },
511
+ method: 'PUT',
512
+ },
513
+ (response) => {
514
+ response.on('error', () =>
515
+ reject(new ProvisioningError('URLError', 'Response stream failed.')),
516
+ );
517
+ response.on('end', () => {
518
+ const status = response.statusCode ?? 0;
519
+ if (status >= 200 && status < 300) resolve();
520
+ else {
521
+ reject(
522
+ new ProvisioningError(
523
+ 'HTTPError',
524
+ 'CloudFormation rejected the response with HTTP ' +
525
+ status +
526
+ '.',
527
+ ),
528
+ );
529
+ }
530
+ });
531
+ response.resume();
532
+ },
533
+ );
534
+ outgoing.on('error', () =>
535
+ reject(new ProvisioningError('URLError', 'Response delivery failed.')),
536
+ );
537
+ outgoing.end(body);
538
+ });
539
+ }
540
+
541
+ const logger = createLogger({
542
+ component: 'machine-client-provisioner',
543
+ feature: 'authorization',
544
+ operation: 'machine-client.provision',
545
+ slice: '${name}',
546
+ stage: logDimension(process.env.EBK_STAGE),
547
+ workspace: logDimension(process.env.EBK_WORKSPACE),
548
+ });
549
+
550
+ export const handler = createMachineClientProvisioner({
551
+ cognito: new CognitoIdentityProviderClient({}),
552
+ logger,
553
+ respond: putCloudFormationResponse,
554
+ secrets: new SecretsManagerClient({}),
555
+ });
556
+ `;
557
+ }
558
+ function machineClientProvisionerSpec(name) {
559
+ return `import {
560
+ CreateUserPoolClientCommand,
561
+ DeleteUserPoolClientCommand,
562
+ DescribeUserPoolClientCommand,
563
+ ListUserPoolClientsCommand,
564
+ } from '@aws-sdk/client-cognito-identity-provider';
565
+ import {
566
+ GetSecretValueCommand,
567
+ PutSecretValueCommand,
568
+ UpdateSecretVersionStageCommand,
569
+ } from '@aws-sdk/client-secrets-manager';
570
+ import {
571
+ createLogger,
572
+ type LogEntry,
573
+ } from '@empire-builder-kit/runtime/logging';
574
+ import { describe, expect, it } from 'vitest';
575
+ import {
576
+ createMachineClientProvisioner,
577
+ type MachineClientProvisionerEvent,
578
+ } from './machine-client-provisioner.js';
579
+
580
+ const POOL = 'pool-1';
581
+ const SECRET = 'arn:aws:secretsmanager:region:account:secret:machine-client';
582
+ const SLICE = '${name}';
583
+ const PHYSICAL = 'ebk-machine-client-' + SLICE + '-development';
584
+
585
+ class MemoryAws {
586
+ readonly calls: string[] = [];
587
+ readonly clients = new Map<string, { name: string; secret: string }>();
588
+ readonly logs: LogEntry[] = [];
589
+ readonly responses: Array<Record<string, unknown>> = [];
590
+ readonly versions: Array<{ id: string; stages: string[]; value: string }> =
591
+ [];
592
+ private created = 0;
593
+
594
+ readonly cognito = {
595
+ send: async (command: unknown) => {
596
+ if (command instanceof ListUserPoolClientsCommand) {
597
+ this.calls.push('ListUserPoolClients');
598
+ return {
599
+ UserPoolClients: [...this.clients].map(([id, client]) => ({
600
+ ClientId: id,
601
+ ClientName: client.name,
602
+ })),
603
+ };
604
+ }
605
+ if (command instanceof DescribeUserPoolClientCommand) {
606
+ this.calls.push('DescribeUserPoolClient');
607
+ const id = command.input.ClientId ?? '';
608
+ const client = this.clients.get(id);
609
+ return {
610
+ UserPoolClient: { ClientId: id, ClientSecret: client?.secret },
611
+ };
612
+ }
613
+ if (command instanceof CreateUserPoolClientCommand) {
614
+ this.calls.push('CreateUserPoolClient');
615
+ this.created += 1;
616
+ const id = 'client-' + this.created;
617
+ const secret = 'never-log-secret-' + this.created;
618
+ this.clients.set(id, { name: command.input.ClientName ?? '', secret });
619
+ return { UserPoolClient: { ClientId: id, ClientSecret: secret } };
620
+ }
621
+ if (command instanceof DeleteUserPoolClientCommand) {
622
+ this.calls.push('DeleteUserPoolClient:' + command.input.ClientId);
623
+ this.clients.delete(command.input.ClientId ?? '');
624
+ return {};
625
+ }
626
+ throw new Error('Unexpected Cognito command.');
627
+ },
628
+ };
629
+
630
+ readonly secrets = {
631
+ send: async (command: unknown) => {
632
+ if (command instanceof GetSecretValueCommand) {
633
+ const stage = command.input.VersionStage ?? '';
634
+ this.calls.push('GetSecretValue:' + stage);
635
+ const version = this.versions.find(({ stages }) =>
636
+ stages.includes(stage),
637
+ );
638
+ if (!version) {
639
+ throw Object.assign(new Error('absent'), {
640
+ $metadata: {},
641
+ name: 'ResourceNotFoundException',
642
+ });
643
+ }
644
+ return { SecretString: version.value, VersionId: version.id };
645
+ }
646
+ if (command instanceof PutSecretValueCommand) {
647
+ this.calls.push('PutSecretValue');
648
+ this.label('AWSPREVIOUS');
649
+ for (const version of this.versions) {
650
+ if (version.stages.includes('AWSCURRENT')) {
651
+ version.stages = ['AWSPREVIOUS'];
652
+ }
653
+ }
654
+ this.versions.push({
655
+ id: 'v' + (this.versions.length + 1),
656
+ stages: ['AWSCURRENT'],
657
+ value: command.input.SecretString ?? '',
658
+ });
659
+ return {};
660
+ }
661
+ if (command instanceof UpdateSecretVersionStageCommand) {
662
+ const { MoveToVersionId, RemoveFromVersionId, VersionStage } =
663
+ command.input;
664
+ this.calls.push(
665
+ 'UpdateSecretVersionStage:' +
666
+ VersionStage +
667
+ ':' +
668
+ (MoveToVersionId ?? '-') +
669
+ ':' +
670
+ RemoveFromVersionId,
671
+ );
672
+ if (VersionStage === 'AWSCURRENT') {
673
+ this.label('AWSPREVIOUS');
674
+ this.version(RemoveFromVersionId).stages = ['AWSPREVIOUS'];
675
+ this.version(MoveToVersionId).stages = ['AWSCURRENT'];
676
+ } else {
677
+ this.label(VersionStage ?? '');
678
+ }
679
+ return {};
680
+ }
681
+ throw new Error('Unexpected Secrets Manager command.');
682
+ },
683
+ };
684
+
685
+ readonly logger = createLogger({
686
+ component: 'machine-client-provisioner',
687
+ feature: 'authorization',
688
+ operation: 'machine-client.provision',
689
+ sink: (entry) => this.logs.push(entry as LogEntry),
690
+ slice: SLICE,
691
+ stage: 'development',
692
+ workspace: 'fixture',
693
+ });
694
+
695
+ private label(stage: string) {
696
+ for (const version of this.versions) {
697
+ version.stages = version.stages.filter((label) => label !== stage);
698
+ }
699
+ }
700
+
701
+ private version(id: string | undefined) {
702
+ const version = this.versions.find((candidate) => candidate.id === id);
703
+ if (!version) throw new Error('Unknown secret version.');
704
+ return version;
705
+ }
706
+
707
+ async invoke(
708
+ requestType: 'Create' | 'Delete' | 'Update',
709
+ generation: string,
710
+ options: { physicalResourceId?: string; retire?: boolean } = {},
711
+ ) {
712
+ this.calls.length = 0;
713
+ let release!: () => void;
714
+ let settled = false;
715
+ const provision = createMachineClientProvisioner({
716
+ cognito: this.cognito,
717
+ logger: this.logger,
718
+ respond: (_url, body) => {
719
+ this.responses.push(JSON.parse(body));
720
+ return new Promise<void>((resolve) => {
721
+ release = resolve;
722
+ });
723
+ },
724
+ secrets: this.secrets,
725
+ });
726
+ const event: MachineClientProvisionerEvent = {
727
+ LogicalResourceId: 'MachineClient',
728
+ PhysicalResourceId:
729
+ requestType === 'Create'
730
+ ? undefined
731
+ : (options.physicalResourceId ?? PHYSICAL),
732
+ RequestId: 'request-' + (this.responses.length + 1),
733
+ RequestType: requestType,
734
+ ResourceProperties: {
735
+ ClientName: SLICE + '-machine-development-' + generation,
736
+ CredentialGeneration: generation,
737
+ ResourceServerIdentifier: SLICE + '-development',
738
+ RetirePreviousGeneration: options.retire ? 'true' : 'false',
739
+ Scopes: [SLICE + '-development/proof-read'],
740
+ SecretArn: SECRET,
741
+ UserPoolId: POOL,
742
+ },
743
+ ResponseURL: 'https://cloudformation-response.invalid/response',
744
+ StackId: 'stack-1',
745
+ };
746
+ const expected = this.responses.length + 1;
747
+ const running = provision(event).then(() => {
748
+ settled = true;
749
+ });
750
+ for (let turn = 0; this.responses.length < expected && turn < 100; turn++) {
751
+ await new Promise((resolve) => setImmediate(resolve));
752
+ }
753
+ expect(this.responses).toHaveLength(expected);
754
+ // CloudFormation must have the response before the handler may finish.
755
+ expect(settled).toBe(false);
756
+ release();
757
+ await running;
758
+ return this.responses[expected - 1];
759
+ }
760
+
761
+ current() {
762
+ return JSON.parse(
763
+ this.versions.find(({ stages }) => stages.includes('AWSCURRENT'))
764
+ ?.value ?? 'null',
765
+ );
766
+ }
767
+ }
768
+
769
+ describe('generated machine-client provisioner', () => {
770
+ it('creates, replays, rotates, retires, and deletes with exact outputs', async () => {
771
+ const aws = new MemoryAws();
772
+
773
+ const created = await aws.invoke('Create', 'blue-1');
774
+ expect(created).toMatchObject({
775
+ Data: { AcceptedClientIdsJson: '["client-1"]', ClientId: 'client-1' },
776
+ PhysicalResourceId: PHYSICAL,
777
+ Status: 'SUCCESS',
778
+ });
779
+ expect(aws.versions[0].value).toBe(
780
+ '{"clientId":"client-1","clientSecret":"never-log-secret-1","generation":"blue-1"}',
781
+ );
782
+
783
+ const replay = await aws.invoke('Update', 'blue-1');
784
+ expect(aws.calls).toEqual([
785
+ 'GetSecretValue:AWSCURRENT',
786
+ 'GetSecretValue:AWSPREVIOUS',
787
+ 'ListUserPoolClients',
788
+ 'DescribeUserPoolClient',
789
+ ]);
790
+ expect(replay.Data).toEqual(created.Data);
791
+
792
+ const rotated = await aws.invoke('Update', 'green-2');
793
+ expect(rotated.Data).toEqual({
794
+ AcceptedClientIdsJson: '["client-2","client-1"]',
795
+ ClientId: 'client-2',
796
+ });
797
+ expect((await aws.invoke('Update', 'green-2')).Data).toEqual(rotated.Data);
798
+
799
+ const retired = await aws.invoke('Update', 'green-2', { retire: true });
800
+ expect(aws.calls).toContain('DeleteUserPoolClient:client-1');
801
+ expect(aws.calls.at(-1)).toBe('UpdateSecretVersionStage:AWSPREVIOUS:-:v1');
802
+ expect(retired.Data).toEqual({
803
+ AcceptedClientIdsJson: '["client-2"]',
804
+ ClientId: 'client-2',
805
+ });
806
+
807
+ expect(await aws.invoke('Delete', 'green-2')).toMatchObject({
808
+ Data: {},
809
+ Status: 'SUCCESS',
810
+ });
811
+ expect(aws.calls).toContain('DeleteUserPoolClient:client-2');
812
+ expect(aws.clients.size).toBe(0);
813
+
814
+ const serialized = JSON.stringify([aws.logs, aws.responses]);
815
+ expect(serialized).not.toContain('never-log-secret');
816
+ expect(
817
+ aws.logs.every(
818
+ ({ component }) => component === 'machine-client-provisioner',
819
+ ),
820
+ ).toBe(true);
821
+ });
822
+
823
+ it('rolls back to the displaced generation without writing a secret', async () => {
824
+ const aws = new MemoryAws();
825
+ await aws.invoke('Create', 'blue-1');
826
+ await aws.invoke('Update', 'green-2');
827
+
828
+ const restored = await aws.invoke('Update', 'blue-1');
829
+ expect(aws.calls).toEqual([
830
+ 'GetSecretValue:AWSCURRENT',
831
+ 'GetSecretValue:AWSPREVIOUS',
832
+ 'ListUserPoolClients',
833
+ 'DescribeUserPoolClient',
834
+ 'UpdateSecretVersionStage:AWSCURRENT:v1:v2',
835
+ ]);
836
+ expect(restored.Data).toEqual({
837
+ AcceptedClientIdsJson: '["client-1","client-2"]',
838
+ ClientId: 'client-1',
839
+ });
840
+ expect(aws.current().generation).toBe('blue-1');
841
+ });
842
+
843
+ it('refuses unsafe rotations before creating any Cognito client', async () => {
844
+ const aws = new MemoryAws();
845
+ await aws.invoke('Create', 'blue-1');
846
+
847
+ for (const [generation, retire] of [
848
+ ['blue-3', false],
849
+ ['green-2', true],
850
+ ] as const) {
851
+ const refused = await aws.invoke('Update', generation, { retire });
852
+ expect(refused).toMatchObject({ Reason: 'ValueError', Status: 'FAILED' });
853
+ expect(aws.calls).toEqual([
854
+ 'GetSecretValue:AWSCURRENT',
855
+ 'GetSecretValue:AWSPREVIOUS',
856
+ ]);
857
+ }
858
+ await aws.invoke('Update', 'green-2');
859
+ expect(await aws.invoke('Update', 'blue-3')).toMatchObject({
860
+ Reason: 'ValueError',
861
+ Status: 'FAILED',
862
+ });
863
+ expect(aws.calls).not.toContain('CreateUserPoolClient');
864
+ expect(aws.clients.size).toBe(2);
865
+ expect(aws.logs.at(-1)).toMatchObject({
866
+ attributes: { errorCode: 'ValueError', requestType: 'Update' },
867
+ level: 'ERROR',
868
+ outcome: 'failure',
869
+ });
870
+ });
871
+
872
+ it('acknowledges a Delete for another physical id without touching a client', async () => {
873
+ const aws = new MemoryAws();
874
+ await aws.invoke('Create', 'blue-1');
875
+
876
+ const foreign = await aws.invoke('Delete', 'blue-1', {
877
+ physicalResourceId: 'replaced-resource',
878
+ });
879
+ expect(foreign).toMatchObject({
880
+ PhysicalResourceId: 'replaced-resource',
881
+ Status: 'SUCCESS',
882
+ });
883
+ expect(aws.calls).toEqual([]);
884
+ expect(aws.clients.size).toBe(1);
885
+ });
886
+ });
227
887
  `;
888
+ }
228
889
  /** @internal */
229
890
  function renderStandardSliceAuthorizationInfrastructureFiles(name, pascalName) {
230
891
  return {
231
- 'authorization/machine-client-provisioner.py': MACHINE_CLIENT_PROVISIONER_SOURCE,
892
+ 'authorization/machine-client-provisioner.ts': machineClientProvisionerSource(name),
893
+ 'authorization/machine-client-provisioner.spec.ts': machineClientProvisionerSpec(name),
894
+ 'authorization/groups.mjs': `/** Exact physical Cognito identities; product policy keeps its logical roles. */
895
+ export function sliceAuthorizationGroupNames(stage) {
896
+ if (['development', 'staging', 'production'].includes(stage)) {
897
+ return { admin: '${name}-admin', testWriter: '${name}-test-writer' };
898
+ }
899
+ if (!/^personal-[a-f0-9]{24}$/.test(stage)) {
900
+ throw new Error('Slice authorization requires a canonical or exact task stage.');
901
+ }
902
+ return {
903
+ admin: '${name}-' + stage + '-admin',
904
+ testWriter: '${name}-' + stage + '-test-writer',
905
+ };
906
+ }
907
+
908
+ export function sliceAuthorizationRoles(stage, roles) {
909
+ const groups = sliceAuthorizationGroupNames(stage);
910
+ if (groups.admin === '${name}-admin') return [...roles];
911
+ // Canonical claims must not grant task authority. Never strip a foreign
912
+ // task suffix: only this task's exact physical names become logical roles.
913
+ return roles
914
+ .filter((role) => role !== '${name}-admin' && role !== '${name}-test-writer')
915
+ .map((role) => role === groups.admin
916
+ ? '${name}-admin'
917
+ : role === groups.testWriter ? '${name}-test-writer' : role);
918
+ }
919
+ `,
920
+ 'authorization/groups.d.mts': `export function sliceAuthorizationGroupNames(stage: string): {
921
+ admin: string;
922
+ testWriter: string;
923
+ };
924
+ export function sliceAuthorizationRoles(stage: string, roles: readonly string[]): string[];
925
+ `,
232
926
  'infra/authorization.ts': `import { createHash } from 'node:crypto';
927
+ import { sliceAuthorizationGroupNames } from '../authorization/groups.mjs';
233
928
 
234
929
  const MACHINE_AUTHORIZATION_SCOPE_NAMES = [
235
930
  'delegation-use',
@@ -326,6 +1021,7 @@ export function createStandardSliceMachineAuthorization(
326
1021
  options.credentialGeneration,
327
1022
  );
328
1023
  const resourceServerIdentifier = '${name}-' + $app.stage;
1024
+ const groups = sliceAuthorizationGroupNames($app.stage);
329
1025
  const template = {
330
1026
  AWSTemplateFormatVersion: '2010-09-09',
331
1027
  Description:
@@ -351,7 +1047,7 @@ export function createStandardSliceMachineAuthorization(
351
1047
  Properties: {
352
1048
  Description:
353
1049
  'Direct human recovery and non-author review authority for ${name}.',
354
- GroupName: '${name}-admin',
1050
+ GroupName: groups.admin,
355
1051
  Precedence: 10,
356
1052
  UserPoolId: { Ref: 'UserPoolId' },
357
1053
  },
@@ -361,7 +1057,7 @@ export function createStandardSliceMachineAuthorization(
361
1057
  Properties: {
362
1058
  Description:
363
1059
  'Run-scoped synthetic-write authority for ${name} deployed proof.',
364
- GroupName: '${name}-test-writer',
1060
+ GroupName: groups.testWriter,
365
1061
  Precedence: 20,
366
1062
  UserPoolId: { Ref: 'UserPoolId' },
367
1063
  },
@@ -373,8 +1069,10 @@ export function createStandardSliceMachineAuthorization(
373
1069
  'EBK generated ${name} confidential machine-client credential.',
374
1070
  Name: { Ref: 'SecretName' },
375
1071
  Tags: [
1072
+ { Key: 'ebk:managed-by', Value: 'empire-builder-kit' },
376
1073
  { Key: 'ebk:management', Value: 'generated-machine-credential' },
377
1074
  { Key: 'ebk:slice', Value: '${name}' },
1075
+ { Key: 'ebk:stage', Value: $app.stage },
378
1076
  { Key: 'sst:stage', Value: $app.stage },
379
1077
  ],
380
1078
  },
@@ -459,6 +1157,10 @@ export function createStandardSliceMachineAuthorization(
459
1157
  '/${name}/authorization/machine-client',
460
1158
  UserPoolId: options.userPoolId,
461
1159
  },
1160
+ tags: {
1161
+ 'ebk:managed-by': 'empire-builder-kit',
1162
+ 'ebk:stage': $app.stage,
1163
+ },
462
1164
  templateBody: JSON.stringify(template),
463
1165
  },
464
1166
  );
@@ -522,37 +1224,77 @@ line.
522
1224
 
523
1225
  ## Begin an overlap
524
1226
 
525
- 1. Read the current non-secret generation from the protected deployment
526
- configuration.
1227
+ 1. Read the current non-secret generation: the value last deployed with
1228
+ \`EBK_MACHINE_CREDENTIAL_GENERATION\`, or \`blue-1\` if the stage was never
1229
+ rotated. The proof result in step 5 reports it as \`credentialGeneration\`.
527
1230
  2. Select the other slot and a new positive generation number, for example
528
1231
  \`blue-1\` to \`green-2\`.
529
1232
  3. Set \`EBK_MACHINE_CREDENTIAL_GENERATION\` to that generation and leave
530
1233
  \`EBK_MACHINE_RETIRE_PREVIOUS_GENERATION\` unset.
531
- 4. Deploy through the Slice's Nx \`deploy\` target. The AWS-internal
532
- provisioner creates the replacement client and moves its credential to
533
- \`AWSCURRENT\`; the former credential remains \`AWSPREVIOUS\` and its Cognito
534
- client remains valid during the overlap.
1234
+ 4. Deploy the Slice through the governed root lifecycle with that variable
1235
+ in the same shell, for example:
1236
+
1237
+ \`\`\`bash
1238
+ EBK_MACHINE_CREDENTIAL_GENERATION=green-2 ebk deploy development <slice> \\
1239
+ --profile=<profile> --expectedRoleArn=<role-arn>
1240
+ \`\`\`
1241
+
1242
+ A local \`nx run <slice>:deploy\` is refused outside that lifecycle. The
1243
+ AWS-internal provisioner creates the replacement client and moves its
1244
+ credential to \`AWSCURRENT\`; the former credential remains \`AWSPREVIOUS\`
1245
+ and its Cognito client remains valid during the overlap.
535
1246
  5. Prove the server-side token-minting journey reads \`AWSCURRENT\`, obtains a
536
1247
  bounded access token, and completes its narrow capability smoke. Evidence
537
1248
  may contain the client ID, generation, scope names, and outcome, but never a
538
- secret or access token.
1249
+ secret or access token. Read that result from the Slice's deployed
1250
+ machine-authorization proof function, which no EBK command invokes yet: it
1251
+ must return \`outcome\` \`success\`, \`probeStatus\` 200, and the new
1252
+ \`credentialGeneration\`.
1253
+
1254
+ Every deploy of the Slice reads these variables, and an omitted
1255
+ \`EBK_MACHINE_CREDENTIAL_GENERATION\` requests \`blue-1\`. Keep it set to the
1256
+ current generation for every later deploy of that stage; otherwise the
1257
+ provisioner rolls back to \`blue-1\`, refuses the deploy, or begins an
1258
+ unplanned rotation. Local and workflow deploys of one stage must request the
1259
+ same generation.
539
1260
 
540
1261
  ## Retire the previous generation
541
1262
 
542
1263
  Only after the new generation is proved, set
543
1264
  \`EBK_MACHINE_RETIRE_PREVIOUS_GENERATION=true\` and deploy the same generation
544
- again through Nx. The AWS-internal provisioner deletes the previous Cognito
1265
+ again the same way. The AWS-internal provisioner deletes the previous Cognito
545
1266
  client and removes its \`AWSPREVIOUS\` label without returning either
546
1267
  credential. Clear the retirement flag after the successful deploy.
547
1268
 
548
- If the replacement cannot mint and use a token, restore the prior deployment
549
- configuration before retirement. The provisioner recognizes that exact
1269
+ If the replacement cannot mint and use a token, deploy the prior generation
1270
+ again before retirement. The provisioner recognizes that exact
550
1271
  \`AWSPREVIOUS\` generation, atomically promotes it back to \`AWSCURRENT\`, and
551
1272
  keeps the failed replacement as the new rollback generation. Prove the restored
552
1273
  generation before retiring anything. Never retire in the same deployment that
553
1274
  creates a generation, reuse the current color for a new generation, invoke SST
554
1275
  directly, or use the interactive operator-secret commands for this
555
1276
  provider-generated credential.
1277
+
1278
+ ## Rotate through the protected Deploy workflow
1279
+
1280
+ The generated protected Deploy workflow reads both variables from the
1281
+ deploying stage's GitHub environment, such as \`staging\` or \`production\`,
1282
+ and passes each to its deployment only when it is set. Set them as variables
1283
+ of that environment, never at repository or organization scope; the GitHub
1284
+ bootstrap report refuses those scopes. Before it assumes any AWS role, the
1285
+ workflow refuses a generation other than \`blue-N\` or \`green-N\`, a
1286
+ retirement flag other than \`true\` or \`false\`, a retirement without an
1287
+ explicit generation, and a retirement deploy in \`affected\` scope.
1288
+
1289
+ 1. Set \`EBK_MACHINE_CREDENTIAL_GENERATION\` in the stage's environment to the
1290
+ new generation and run the protected Deploy for that stage with
1291
+ \`lifecycle\` \`full\`. The default \`affected\` scope skips a Slice whose
1292
+ source is unchanged, so it would not rotate.
1293
+ 2. Prove the new generation as in step 5 of "Begin an overlap".
1294
+ 3. Set \`EBK_MACHINE_RETIRE_PREVIOUS_GENERATION\` to \`true\` in the same
1295
+ environment and run the protected Deploy again with \`lifecycle\` \`full\`.
1296
+ 4. After that deploy succeeds, delete the retirement variable or set it to
1297
+ \`false\`. Keep the generation variable at the current generation.
556
1298
  `,
557
1299
  };
558
1300
  }