@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
@@ -0,0 +1,3558 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.STAGE_AUTHORITY_CROSS_ACCOUNT_MUTATION_ACTIONS = exports.STAGE_AUTHORITY_CROSS_ACCOUNT_EC2_MUTATION_ACTIONS = exports.STAGE_AUTHORITY_SST_417_EXTERNAL_AMI_OWNERS_BY_PARTITION = exports.STAGE_AUTHORITY_CLOUDCONTROL_EDGE_MUTATION_ACTIONS = exports.STAGE_AUTHORITY_SCOPE_GUARD_MUTATION_FAMILIES = exports.STAGE_AUTHORITY_WORKLOAD_IDENTITY_POLICY_ACTIONS = exports.STAGE_AUTHORITY_APPROVED_AWS_MANAGED_POLICIES = exports.STAGE_RUNTIME_REGIONAL_SERVICE_FAMILIES = exports.STAGE_AUTHORITY_LOGS_MUTATION_FAMILIES = exports.STAGE_AUTHORITY_REGIONAL_MUTATION_FAMILIES = exports.STAGE_RUNTIME_GLOBAL_ACTIONS = exports.STAGE_RUNTIME_REGIONAL_ACTIONS = exports.STAGE_AUTHORITY_ACCOUNT_SCOPED_GLOBAL_WRITE_ACTIONS = exports.STAGE_AUTHORITY_GLOBAL_WRITE_ACTIONS = exports.STAGE_AUTHORITY_UNSUPPORTED_REPLICATION_AND_TOPOLOGY_ACTIONS = exports.STAGE_AUTHORITY_WAF_EDGE_MUTATION_ACTIONS = exports.STAGE_AUTHORITY_S3_REGIONAL_MUTATION_ACTIONS = exports.STAGE_AUTHORITY_UNSCOPED_CLOUDFRONT_CREATE_ACTIONS = exports.STAGE_AUTHORITY_REGIONAL_WRITE_ACTIONS = exports.STAGE_AUTHORITY_LAMBDA_INFRASTRUCTURE_ACTIONS = exports.STAGE_AUTHORITY_KMS_INFRASTRUCTURE_ACTIONS = exports.STAGE_AUTHORITY_EC2_INFRASTRUCTURE_ACTIONS = exports.STAGE_AUTHORITY_BACKUP_INFRASTRUCTURE_ACTIONS = exports.STAGE_AUTHORITY_BROAD_REGIONAL_SERVICE_ACTIONS = exports.STAGE_AUTHORITY_EDGE_OBSERVABILITY_READ_ACTIONS = exports.STAGE_AUTHORITY_GLOBAL_READ_ACTIONS = exports.STAGE_AUTHORITY_REGIONAL_READ_ACTIONS = exports.STAGE_AUTHORITY_COST_ANOMALY_WRITE_ACTIONS = exports.STAGE_AUTHORITY_COST_ANOMALY_RESOURCE_WRITE_ACTIONS = exports.STAGE_AUTHORITY_COST_ANOMALY_CREATE_ACTIONS = exports.STAGE_AUTHORITY_COST_ANOMALY_READ_ACTIONS = exports.STAGE_AUTHORITY_KMS_ROTATION_ACTIONS = exports.STAGE_AUTHORITY_RDS_EVENT_SUBSCRIPTION_SOURCE_ACTIONS = exports.STAGE_AUTHORITY_BUDGET_MUTATION_ACTIONS = exports.STAGE_AUTHORITY_EDGE_WAF_LOG_DELIVERY_MUTATION_ACTIONS = exports.STAGE_AUTHORITY_EDGE_WAF_LOG_GROUP_ACTIONS = exports.STAGE_AUTHORITY_WAF_LOGGING_ACTIONS = exports.STAGE_AUTHORITY_CLOUDFRONT_INVALIDATION_ACTIONS = exports.STAGE_AUTHORITY_LAMBDA_DEPLOYMENT_INVOKE_ACTIONS = exports.STAGE_AUTHORITY_EVENT_ARCHIVE_RESOURCE_ACTIONS = exports.STAGE_AUTHORITY_EVENT_ARCHIVE_CREATE_ACTIONS = exports.STAGE_AUTHORITY_CLOUDFORMATION_LIFECYCLE_ACTIONS = exports.STAGE_AUTHORITY_BOUND_TEMPLATE_BODY_MINIMUM_HEADROOM = exports.STAGE_AUTHORITY_TEMPLATE_BODY_BYTE_LIMIT = exports.STAGE_AUTHORITY_MANAGED_POLICY_CHARACTER_HEADROOM = exports.STAGE_AUTHORITY_MANAGED_POLICY_CHARACTER_LIMIT = exports.STAGE_AUTHORITY_DEPLOYMENT_POLICY_KINDS = exports.STAGE_AUTHORITY_PARTITIONS = exports.STAGE_AUTHORITY_STAGES = exports.STAGE_AUTHORITY_SCHEMA_VERSION = void 0;
4
+ exports.STAGE_AUTHORITY_SERVICE_LINKED_ROLES = exports.STAGE_AUTHORITY_UNSUPPORTED_WORKFLOW_EXECUTION_ACTIONS = exports.STAGE_AUTHORITY_NON_DEPLOYMENT_ACCOUNT_AND_DATA_ACTIONS = exports.STAGE_AUTHORITY_UNREVIEWED_PERMISSION_MANAGEMENT_ACTION_PATTERNS = exports.STAGE_AUTHORITY_REVIEWED_PERMISSION_MANAGEMENT_ACTIONS = exports.STAGE_AUTHORITY_S3_BUCKET_POLICY_MUTATION_ACTIONS = exports.STAGE_AUTHORITY_KNOWN_STAGE_MUTATION_ACTIONS = exports.STAGE_AUTHORITY_UNTAGGED_DESTRUCTIVE_ACTIONS = exports.STAGE_AUTHORITY_CROSS_STAGE_DESTRUCTIVE_ACTIONS = void 0;
5
+ exports.createStageAuthorityIdentity = createStageAuthorityIdentity;
6
+ exports.canonicalStageAuthorityTemplate = canonicalStageAuthorityTemplate;
7
+ exports.digestStageAuthorityTemplate = digestStageAuthorityTemplate;
8
+ exports.assertBoundStageAuthorityTemplateFitsBodyLimit = assertBoundStageAuthorityTemplateFitsBodyLimit;
9
+ exports.createStageAuthorityPlan = createStageAuthorityPlan;
10
+ exports.createStageIamBoundaryTransformContract = createStageIamBoundaryTransformContract;
11
+ exports.installStageIamBoundaryTransforms = installStageIamBoundaryTransforms;
12
+ const node_crypto_1 = require("node:crypto");
13
+ exports.STAGE_AUTHORITY_SCHEMA_VERSION = 1;
14
+ exports.STAGE_AUTHORITY_STAGES = [
15
+ 'development',
16
+ 'staging',
17
+ 'production',
18
+ ];
19
+ exports.STAGE_AUTHORITY_PARTITIONS = [
20
+ 'aws',
21
+ 'aws-cn',
22
+ 'aws-us-gov',
23
+ ];
24
+ exports.STAGE_AUTHORITY_DEPLOYMENT_POLICY_KINDS = [
25
+ 'read',
26
+ 'regional-mutation',
27
+ 'global-iam-mutation',
28
+ 'global-resource-mutation',
29
+ 'generated-resource-mutation',
30
+ 'stage-containment',
31
+ 'permission-guardrails',
32
+ 'guardrails',
33
+ ];
34
+ exports.STAGE_AUTHORITY_MANAGED_POLICY_CHARACTER_LIMIT = 6_144;
35
+ exports.STAGE_AUTHORITY_MANAGED_POLICY_CHARACTER_HEADROOM = 200;
36
+ exports.STAGE_AUTHORITY_TEMPLATE_BODY_BYTE_LIMIT = 51_200;
37
+ exports.STAGE_AUTHORITY_BOUND_TEMPLATE_BODY_MINIMUM_HEADROOM = 1_024;
38
+ const STAGE_AUTHORITY_MAX_AWS_PRINCIPALS = 16;
39
+ const STAGE_AUTHORITY_MAX_AWS_PRINCIPAL_ARN_BYTES = 2_048;
40
+ // IAM glob syntax cannot validate hexadecimal characters. Framework task
41
+ // admission validates exact lowercase hex; this is only a bounded IAM shape.
42
+ const TASK_STAGE_IAM_SHAPE = `personal-${'?'.repeat(24)}`;
43
+ const TASK_PRINCIPAL_STAGE = '${aws:PrincipalTag/ebk:stage}';
44
+ const ACCOUNT_ID = /^\d{12}$/u;
45
+ const REGION = /^(?:(?:af|ap|ca|cn|eu|il|me|mx|sa|us)(?:-(?:gov|iso|isob|isoe|isof))?|eusc-[a-z]{2})-[a-z]+-\d$/u;
46
+ const AWS_PRINCIPAL_ARN = /^arn:(aws|aws-cn|aws-us-gov):iam::(\d{12}):role\/[A-Za-z0-9+=,.@_/-]+$/u;
47
+ const GITHUB_OIDC_PROVIDER_ARN = /^arn:(aws|aws-cn|aws-us-gov):iam::(\d{12}):oidc-provider\/token[.]actions[.]githubusercontent[.]com$/u;
48
+ const GITHUB_SUBJECT = /^repo:[A-Za-z0-9_.-]+@[1-9][0-9]{0,19}\/[A-Za-z0-9_.-]+@[1-9][0-9]{0,19}:environment:(development|staging|production)$/u;
49
+ /** Native lifecycle required by the generated machine-authorization nested
50
+ * stack. Recovery-only and stack-policy mutation APIs remain ungranted. */
51
+ exports.STAGE_AUTHORITY_CLOUDFORMATION_LIFECYCLE_ACTIONS = Object.freeze([
52
+ 'cloudformation:CreateStack',
53
+ 'cloudformation:DeleteStack',
54
+ 'cloudformation:UpdateStack',
55
+ ].sort(compareStrings));
56
+ /** EventBridge archives expose no request-tag or resource-tag IAM condition
57
+ * keys. Their lifecycle is contained by the exact canonical archive ARN and
58
+ * requested Region instead. */
59
+ exports.STAGE_AUTHORITY_EVENT_ARCHIVE_CREATE_ACTIONS = Object.freeze([
60
+ 'events:CreateArchive',
61
+ ]);
62
+ exports.STAGE_AUTHORITY_EVENT_ARCHIVE_RESOURCE_ACTIONS = Object.freeze(['events:DeleteArchive', 'events:UpdateArchive'].sort(compareStrings));
63
+ exports.STAGE_AUTHORITY_LAMBDA_DEPLOYMENT_INVOKE_ACTIONS = Object.freeze([
64
+ 'lambda:InvokeFunction',
65
+ ]);
66
+ exports.STAGE_AUTHORITY_CLOUDFRONT_INVALIDATION_ACTIONS = Object.freeze([
67
+ 'cloudfront:CreateInvalidation',
68
+ ]);
69
+ exports.STAGE_AUTHORITY_WAF_LOGGING_ACTIONS = Object.freeze([
70
+ 'wafv2:PutLoggingConfiguration',
71
+ ]);
72
+ /** SST's CloudFront-scope WAF logging component owns exactly one generated log
73
+ * group in the edge control Region. These resource-capable actions stay bound
74
+ * to that generated ARN below. */
75
+ exports.STAGE_AUTHORITY_EDGE_WAF_LOG_GROUP_ACTIONS = Object.freeze([
76
+ 'logs:CreateLogGroup',
77
+ 'logs:DeleteLogGroup',
78
+ 'logs:DeleteRetentionPolicy',
79
+ 'logs:PutRetentionPolicy',
80
+ 'logs:TagLogGroup',
81
+ 'logs:TagResource',
82
+ 'logs:UntagLogGroup',
83
+ 'logs:UntagResource',
84
+ ].sort(compareStrings));
85
+ /** CloudWatch Logs exposes these WAF delivery mutations only at account scope.
86
+ * In particular, PutResourcePolicy supports neither resource ARNs nor
87
+ * action-specific condition keys. Requested Region and reviewed generated
88
+ * source are therefore the strongest honest controls for that one exception. */
89
+ exports.STAGE_AUTHORITY_EDGE_WAF_LOG_DELIVERY_MUTATION_ACTIONS = Object.freeze([
90
+ 'logs:CreateLogDelivery',
91
+ 'logs:DeleteLogDelivery',
92
+ 'logs:PutResourcePolicy',
93
+ ].sort(compareStrings));
94
+ exports.STAGE_AUTHORITY_BUDGET_MUTATION_ACTIONS = Object.freeze(['budgets:ModifyBudget', 'budgets:TagResource', 'budgets:UntagResource'].sort(compareStrings));
95
+ exports.STAGE_AUTHORITY_RDS_EVENT_SUBSCRIPTION_SOURCE_ACTIONS = Object.freeze([
96
+ 'rds:AddSourceIdentifierToSubscription',
97
+ 'rds:RemoveSourceIdentifierFromSubscription',
98
+ ].sort(compareStrings));
99
+ exports.STAGE_AUTHORITY_KMS_ROTATION_ACTIONS = Object.freeze([
100
+ 'kms:EnableKeyRotation',
101
+ ]);
102
+ /** Commercial AWS exposes CloudFront, CloudFront-scope WAF, and edge
103
+ * certificates through us-east-1 even when the application stage is deployed
104
+ * elsewhere. This batch intentionally preserves the selected Region for
105
+ * nonstandard partitions; CloudFront is not available inside GovCloud. */
106
+ function edgeControlRegion(partition, deploymentRegion) {
107
+ return partition === 'aws' ? 'us-east-1' : deploymentRegion;
108
+ }
109
+ /** Cost Explorer creation is account-global, while existing anomaly controls
110
+ * support account-bound ARNs. These exact verbs are admitted only to the
111
+ * production stage role below. */
112
+ exports.STAGE_AUTHORITY_COST_ANOMALY_READ_ACTIONS = Object.freeze([
113
+ 'ce:GetAnomalyMonitors',
114
+ 'ce:GetAnomalySubscriptions',
115
+ 'ce:ListTagsForResource',
116
+ ].sort(compareStrings));
117
+ exports.STAGE_AUTHORITY_COST_ANOMALY_CREATE_ACTIONS = Object.freeze(['ce:CreateAnomalyMonitor', 'ce:CreateAnomalySubscription'].sort(compareStrings));
118
+ exports.STAGE_AUTHORITY_COST_ANOMALY_RESOURCE_WRITE_ACTIONS = Object.freeze([
119
+ 'ce:DeleteAnomalyMonitor',
120
+ 'ce:DeleteAnomalySubscription',
121
+ 'ce:TagResource',
122
+ 'ce:UntagResource',
123
+ 'ce:UpdateAnomalyMonitor',
124
+ 'ce:UpdateAnomalySubscription',
125
+ ].sort(compareStrings));
126
+ exports.STAGE_AUTHORITY_COST_ANOMALY_WRITE_ACTIONS = Object.freeze([
127
+ ...exports.STAGE_AUTHORITY_COST_ANOMALY_CREATE_ACTIONS,
128
+ ...exports.STAGE_AUTHORITY_COST_ANOMALY_RESOURCE_WRITE_ACTIONS,
129
+ ].sort(compareStrings));
130
+ exports.STAGE_AUTHORITY_REGIONAL_READ_ACTIONS = Object.freeze([
131
+ 'access-analyzer:Get*',
132
+ 'access-analyzer:List*',
133
+ 'acm:Describe*',
134
+ 'acm:Get*',
135
+ 'acm:List*',
136
+ 'application-autoscaling:Describe*',
137
+ 'appconfig:Get*',
138
+ 'appconfig:List*',
139
+ 'backup:Describe*',
140
+ 'backup:Get*',
141
+ 'backup:List*',
142
+ 'cloudformation:Describe*',
143
+ 'cloudformation:Get*',
144
+ 'cloudformation:List*',
145
+ 'cloudformation:ValidateTemplate',
146
+ 'cloudwatch:Describe*',
147
+ 'cloudwatch:Get*',
148
+ 'cloudwatch:List*',
149
+ 'cognito-idp:Describe*',
150
+ 'cognito-idp:Get*',
151
+ 'cognito-idp:List*',
152
+ 'dynamodb:Describe*',
153
+ 'dynamodb:Get*',
154
+ 'dynamodb:List*',
155
+ 'ec2:Describe*',
156
+ 'ec2:GetInstanceUefiData',
157
+ 'ec2:GetResourcePolicy',
158
+ 'ecr:Describe*',
159
+ 'ecr:Get*',
160
+ 'ecr:List*',
161
+ 'ecs:Describe*',
162
+ 'ecs:List*',
163
+ 'elasticloadbalancing:Describe*',
164
+ 'events:Describe*',
165
+ 'events:List*',
166
+ 'kms:Describe*',
167
+ 'kms:Get*',
168
+ 'kms:List*',
169
+ 'lambda:Get*',
170
+ 'lambda:List*',
171
+ 'logs:Describe*',
172
+ 'logs:FilterLogEvents',
173
+ 'logs:Get*',
174
+ 'logs:List*',
175
+ 'rds:Describe*',
176
+ 'rds:List*',
177
+ 'secretsmanager:Describe*',
178
+ 'secretsmanager:Get*',
179
+ 'secretsmanager:List*',
180
+ 'servicequotas:Get*',
181
+ 'servicequotas:List*',
182
+ 'servicediscovery:Get*',
183
+ 'servicediscovery:List*',
184
+ 'sns:Get*',
185
+ 'sns:List*',
186
+ 'sqs:Get*',
187
+ 'sqs:List*',
188
+ 'ssm:Describe*',
189
+ 'ssm:Get*',
190
+ 'ssm:List*',
191
+ 'states:Describe*',
192
+ 'states:List*',
193
+ ].sort(compareStrings));
194
+ exports.STAGE_AUTHORITY_GLOBAL_READ_ACTIONS = Object.freeze([
195
+ 'apigateway:GET',
196
+ 'budgets:Describe*',
197
+ 'budgets:List*',
198
+ 'budgets:ViewBudget',
199
+ 'cloudfront-keyvaluestore:DescribeKeyValueStore',
200
+ 'cloudfront-keyvaluestore:GetKey',
201
+ 'cloudfront-keyvaluestore:ListKeys',
202
+ 'cloudfront:Describe*',
203
+ 'cloudfront:Get*',
204
+ 'cloudfront:List*',
205
+ 'iam:Get*',
206
+ 'iam:List*',
207
+ 'route53:Get*',
208
+ 'route53:List*',
209
+ 's3:Get*',
210
+ 's3:List*',
211
+ 'sts:GetCallerIdentity',
212
+ 'tag:GetResources',
213
+ 'wafv2:Get*',
214
+ 'wafv2:List*',
215
+ ].sort(compareStrings));
216
+ /** CloudFront-scope WAF publishes its observability signals through the edge
217
+ * control Region. Keep this read surface exact instead of broadening every
218
+ * regional read when the application Region differs from us-east-1. */
219
+ exports.STAGE_AUTHORITY_EDGE_OBSERVABILITY_READ_ACTIONS = Object.freeze([
220
+ 'cloudwatch:GetMetricData',
221
+ 'logs:DescribeLogGroups',
222
+ 'logs:DescribeResourcePolicies',
223
+ ].sort(compareStrings));
224
+ /** A deployment role is a temporary infrastructure administrator, not a
225
+ * runtime workload identity. Routine regional services therefore use one
226
+ * stable service-family contract instead of a provider-call inventory. The
227
+ * families whose policy, protection, launch, or trust semantics need tighter
228
+ * treatment remain on the bounded action sets below. */
229
+ exports.STAGE_AUTHORITY_BROAD_REGIONAL_SERVICE_ACTIONS = Object.freeze([
230
+ 'acm:*',
231
+ 'apigateway:*',
232
+ 'appconfig:*',
233
+ 'application-autoscaling:*',
234
+ 'cloudwatch:*',
235
+ 'cognito-idp:*',
236
+ 'dynamodb:*',
237
+ 'ecr:*',
238
+ 'ecs:*',
239
+ 'elasticloadbalancing:*',
240
+ 'events:*',
241
+ 'logs:*',
242
+ 'rds:*',
243
+ 'secretsmanager:*',
244
+ 'servicediscovery:*',
245
+ 'sns:*',
246
+ 'sqs:*',
247
+ 'ssm:*',
248
+ 'states:*',
249
+ ].sort(compareStrings));
250
+ exports.STAGE_AUTHORITY_BACKUP_INFRASTRUCTURE_ACTIONS = Object.freeze([
251
+ 'backup:CreateBackupPlan',
252
+ 'backup:CreateBackupSelection',
253
+ 'backup:CreateBackupVault',
254
+ 'backup:DeleteBackupPlan',
255
+ 'backup:DeleteBackupSelection',
256
+ 'backup:DeleteBackupVault',
257
+ 'backup:StartBackupJob',
258
+ 'backup:TagResource',
259
+ 'backup:UntagResource',
260
+ 'backup:UpdateBackupPlan',
261
+ ].sort(compareStrings));
262
+ exports.STAGE_AUTHORITY_EC2_INFRASTRUCTURE_ACTIONS = Object.freeze([
263
+ 'ec2:AllocateAddress',
264
+ 'ec2:Associate*',
265
+ 'ec2:Attach*',
266
+ 'ec2:Authorize*',
267
+ 'ec2:Create*',
268
+ 'ec2:Delete*',
269
+ 'ec2:Detach*',
270
+ 'ec2:Disassociate*',
271
+ 'ec2:ImportKeyPair',
272
+ 'ec2:Modify*',
273
+ 'ec2:ReleaseAddress',
274
+ 'ec2:Replace*',
275
+ 'ec2:Revoke*',
276
+ 'ec2:RunInstances',
277
+ 'ec2:StartInstances',
278
+ 'ec2:StopInstances',
279
+ 'ec2:TerminateInstances',
280
+ 'ec2:UpdateSecurityGroupRuleDescriptions*',
281
+ ].sort(compareStrings));
282
+ exports.STAGE_AUTHORITY_KMS_INFRASTRUCTURE_ACTIONS = Object.freeze([
283
+ 'kms:CreateAlias',
284
+ 'kms:CreateKey',
285
+ 'kms:DeleteAlias',
286
+ 'kms:TagResource',
287
+ 'kms:UntagResource',
288
+ 'kms:UpdateAlias',
289
+ 'kms:UpdateKeyDescription',
290
+ ].sort(compareStrings));
291
+ /** AddPermission, RemovePermission, and InvokeFunction remain in exact
292
+ * statements so the family allow cannot bypass Lambda resource-policy and
293
+ * deployment-smoke constraints. */
294
+ exports.STAGE_AUTHORITY_LAMBDA_INFRASTRUCTURE_ACTIONS = Object.freeze([
295
+ 'lambda:Create*',
296
+ 'lambda:Delete*',
297
+ 'lambda:PublishVersion',
298
+ 'lambda:Put*',
299
+ 'lambda:TagResource',
300
+ 'lambda:UntagResource',
301
+ 'lambda:Update*',
302
+ ].sort(compareStrings));
303
+ exports.STAGE_AUTHORITY_REGIONAL_WRITE_ACTIONS = Object.freeze([
304
+ ...exports.STAGE_AUTHORITY_BACKUP_INFRASTRUCTURE_ACTIONS,
305
+ ...exports.STAGE_AUTHORITY_BROAD_REGIONAL_SERVICE_ACTIONS,
306
+ ...exports.STAGE_AUTHORITY_EC2_INFRASTRUCTURE_ACTIONS,
307
+ ...exports.STAGE_AUTHORITY_KMS_INFRASTRUCTURE_ACTIONS,
308
+ ...exports.STAGE_AUTHORITY_LAMBDA_INFRASTRUCTURE_ACTIONS,
309
+ ].sort(compareStrings));
310
+ exports.STAGE_AUTHORITY_UNSCOPED_CLOUDFRONT_CREATE_ACTIONS = Object.freeze([
311
+ 'cloudfront:CreateCachePolicy',
312
+ 'cloudfront:CreateDistribution',
313
+ 'cloudfront:CreateFunction',
314
+ 'cloudfront:CreateKeyValueStore',
315
+ 'cloudfront:CreateOriginAccessControl',
316
+ ].sort(compareStrings));
317
+ exports.STAGE_AUTHORITY_S3_REGIONAL_MUTATION_ACTIONS = Object.freeze([
318
+ 's3:AbortMultipartUpload',
319
+ 's3:DeleteBucket',
320
+ 's3:DeleteBucketPolicy',
321
+ 's3:DeleteObject',
322
+ 's3:DeleteObjectTagging',
323
+ 's3:DeleteObjectVersion',
324
+ 's3:PutBucket*',
325
+ 's3:PutEncryptionConfiguration',
326
+ 's3:PutLifecycleConfiguration',
327
+ 's3:PutObject',
328
+ 's3:PutObjectTagging',
329
+ 's3:RestoreObject',
330
+ ].sort(compareStrings));
331
+ exports.STAGE_AUTHORITY_WAF_EDGE_MUTATION_ACTIONS = Object.freeze([
332
+ 'wafv2:AssociateWebACL',
333
+ 'wafv2:Create*',
334
+ 'wafv2:Delete*',
335
+ 'wafv2:DisassociateWebACL',
336
+ 'wafv2:TagResource',
337
+ 'wafv2:UntagResource',
338
+ 'wafv2:Update*',
339
+ ].sort(compareStrings));
340
+ /** These APIs establish unsupported replicas, global resources, alternate
341
+ * database topologies, integrations, or cross-Region copies. The generated
342
+ * architecture does not use them. */
343
+ exports.STAGE_AUTHORITY_UNSUPPORTED_REPLICATION_AND_TOPOLOGY_ACTIONS = Object.freeze([
344
+ 'backup:StartCopyJob',
345
+ 'backup:UpdateRegionSettings',
346
+ 'dynamodb:AssociateTableReplica',
347
+ 'dynamodb:CreateGlobalTable',
348
+ 'dynamodb:CreateGlobalTableWitness',
349
+ 'dynamodb:CreateTableReplica',
350
+ 'dynamodb:DeleteGlobalTableWitness',
351
+ 'dynamodb:DeleteTableReplica',
352
+ 'dynamodb:UpdateGlobalTable',
353
+ 'dynamodb:UpdateGlobalTableSettings',
354
+ 'dynamodb:UpdateTableReplicaAutoScaling',
355
+ 'ecr:PutReplicationConfiguration',
356
+ 'kms:ReplicateKey',
357
+ 'kms:UpdatePrimaryRegion',
358
+ 'rds:CopyDBClusterSnapshot',
359
+ 'rds:CopyDBSnapshot',
360
+ 'rds:CreateBlueGreenDeployment',
361
+ 'rds:CreateDBInstanceReadReplica',
362
+ 'rds:CreateDBShardGroup',
363
+ 'rds:CreateGlobalCluster',
364
+ 'rds:CreateIntegration',
365
+ 'rds:CrossRegionCommunication',
366
+ 'rds:DeleteBlueGreenDeployment',
367
+ 'rds:DeleteDBShardGroup',
368
+ 'rds:DeleteGlobalCluster',
369
+ 'rds:DeleteIntegration',
370
+ 'rds:FailoverGlobalCluster',
371
+ 'rds:ModifyDBShardGroup',
372
+ 'rds:ModifyGlobalCluster',
373
+ 'rds:ModifyIntegration',
374
+ 'rds:PromoteReadReplica',
375
+ 'rds:PromoteReadReplicaDBCluster',
376
+ 'rds:RebootDBShardGroup',
377
+ 'rds:RemoveFromGlobalCluster',
378
+ 'rds:StartDBInstanceAutomatedBackupsReplication',
379
+ 'rds:StopDBInstanceAutomatedBackupsReplication',
380
+ 'rds:SwitchoverBlueGreenDeployment',
381
+ 'rds:SwitchoverGlobalCluster',
382
+ 'rds:SwitchoverReadReplica',
383
+ 's3:PutReplicationConfiguration',
384
+ 'secretsmanager:RemoveRegionsFromReplication',
385
+ 'secretsmanager:ReplicateSecretToRegions',
386
+ 'secretsmanager:StopReplicationToReplica',
387
+ ].sort(compareStrings));
388
+ exports.STAGE_AUTHORITY_GLOBAL_WRITE_ACTIONS = Object.freeze([
389
+ 'route53:ChangeResourceRecordSets',
390
+ 'route53:ChangeTagsForResource',
391
+ 'route53:CreateHealthCheck',
392
+ 'route53:DeleteHealthCheck',
393
+ 'route53:UpdateHealthCheck',
394
+ ].sort(compareStrings));
395
+ exports.STAGE_AUTHORITY_ACCOUNT_SCOPED_GLOBAL_WRITE_ACTIONS = Object.freeze([
396
+ 'cloudfront:DeleteCachePolicy',
397
+ 'cloudfront:DeleteDistribution',
398
+ 'cloudfront:DeleteFunction',
399
+ 'cloudfront:DeleteKeyValueStore',
400
+ 'cloudfront:DeleteOriginAccessControl',
401
+ 'cloudfront:PublishFunction',
402
+ 'cloudfront:TagResource',
403
+ 'cloudfront:UntagResource',
404
+ 'cloudfront:UpdateCachePolicy',
405
+ 'cloudfront:UpdateDistribution',
406
+ 'cloudfront:UpdateFunction',
407
+ 'cloudfront:UpdateKeyValueStore',
408
+ 'cloudfront:UpdateOriginAccessControl',
409
+ 'cloudfront-keyvaluestore:DeleteKey',
410
+ 'cloudfront-keyvaluestore:PutKey',
411
+ 'cloudfront-keyvaluestore:UpdateKeys',
412
+ ].sort(compareStrings));
413
+ exports.STAGE_RUNTIME_REGIONAL_ACTIONS = Object.freeze([
414
+ 'appconfig:GetLatestConfiguration',
415
+ 'appconfig:StartConfigurationSession',
416
+ 'cloudwatch:DescribeAlarms',
417
+ 'cloudwatch:PutMetricData',
418
+ 'cognito-idp:CreateUserPoolClient',
419
+ 'cognito-idp:DeleteUserPoolClient',
420
+ 'cognito-idp:DescribeUserPoolClient',
421
+ 'cognito-idp:ListUserPoolClients',
422
+ 'dynamodb:BatchGetItem',
423
+ 'dynamodb:BatchWriteItem',
424
+ 'dynamodb:ConditionCheckItem',
425
+ 'dynamodb:DeleteItem',
426
+ 'dynamodb:DescribeStream',
427
+ 'dynamodb:DescribeTable',
428
+ 'dynamodb:GetItem',
429
+ 'dynamodb:GetRecords',
430
+ 'dynamodb:GetShardIterator',
431
+ 'dynamodb:ListStreams',
432
+ 'dynamodb:PutItem',
433
+ 'dynamodb:Query',
434
+ 'dynamodb:Scan',
435
+ 'dynamodb:TransactWriteItems',
436
+ 'dynamodb:UpdateItem',
437
+ 'ec2:AssignPrivateIpAddresses',
438
+ 'ec2:CreateNetworkInterface',
439
+ 'ec2:DeleteNetworkInterface',
440
+ 'ec2:DescribeNetworkInterfaces',
441
+ 'ec2:DescribeSubnets',
442
+ 'ec2:UnassignPrivateIpAddresses',
443
+ 'ecr:BatchCheckLayerAvailability',
444
+ 'ecr:BatchGetImage',
445
+ 'ecr:GetAuthorizationToken',
446
+ 'ecr:GetDownloadUrlForLayer',
447
+ 'ecs:DescribeTasks',
448
+ 'ecs:RunTask',
449
+ 'ecs:StopTask',
450
+ 'events:DescribeRule',
451
+ 'events:PutEvents',
452
+ 'events:PutRule',
453
+ 'events:PutTargets',
454
+ 'kms:Decrypt',
455
+ 'kms:DescribeKey',
456
+ 'kms:Encrypt',
457
+ 'kms:GenerateDataKey',
458
+ 'lambda:InvokeFunction',
459
+ 'logs:CreateLogDelivery',
460
+ 'logs:CreateLogStream',
461
+ 'logs:DeleteLogDelivery',
462
+ 'logs:DescribeLogGroups',
463
+ 'logs:DescribeResourcePolicies',
464
+ 'logs:GetLogDelivery',
465
+ 'logs:ListLogDeliveries',
466
+ 'logs:PutLogEvents',
467
+ 'logs:PutResourcePolicy',
468
+ 'logs:UpdateLogDelivery',
469
+ 'rds-db:connect',
470
+ 's3:AbortMultipartUpload',
471
+ 's3:DeleteObject',
472
+ 's3:DeleteObjectVersion',
473
+ 's3:GetObject',
474
+ 's3:GetObjectVersion',
475
+ 's3:ListBucket',
476
+ 's3:ListBucketVersions',
477
+ 's3:PutObject',
478
+ 'secretsmanager:DeleteSecret',
479
+ 'secretsmanager:DescribeSecret',
480
+ 'secretsmanager:GetSecretValue',
481
+ 'secretsmanager:PutSecretValue',
482
+ 'secretsmanager:UpdateSecretVersionStage',
483
+ 'sns:Publish',
484
+ 'sqs:ChangeMessageVisibility',
485
+ 'sqs:DeleteMessage',
486
+ 'sqs:GetQueueAttributes',
487
+ 'sqs:GetQueueUrl',
488
+ 'sqs:ReceiveMessage',
489
+ 'sqs:SendMessage',
490
+ 'ssmmessages:CreateControlChannel',
491
+ 'ssmmessages:CreateDataChannel',
492
+ 'ssmmessages:OpenControlChannel',
493
+ 'ssmmessages:OpenDataChannel',
494
+ 'ssm:GetParameter',
495
+ 'ssm:GetParameters',
496
+ 'states:DescribeExecution',
497
+ 'states:SendTaskFailure',
498
+ 'states:SendTaskHeartbeat',
499
+ 'states:SendTaskSuccess',
500
+ 'states:StartExecution',
501
+ ].sort(compareStrings));
502
+ exports.STAGE_RUNTIME_GLOBAL_ACTIONS = Object.freeze(['cloudfront:CreateInvalidation'].sort(compareStrings));
503
+ exports.STAGE_AUTHORITY_REGIONAL_MUTATION_FAMILIES = Object.freeze([
504
+ ...new Set([
505
+ ...exports.STAGE_AUTHORITY_REGIONAL_WRITE_ACTIONS,
506
+ ...exports.STAGE_AUTHORITY_CLOUDFORMATION_LIFECYCLE_ACTIONS,
507
+ ]
508
+ .map((action) => `${action.split(':', 1)[0]}:*`)
509
+ .filter((family) => !['acm:*', 'cloudwatch:*', 'logs:*'].includes(family))),
510
+ 'cloudwatch:Delete*',
511
+ 'cloudwatch:Disable*',
512
+ 'cloudwatch:Enable*',
513
+ 'cloudwatch:Put*',
514
+ 'cloudwatch:Set*',
515
+ 'cloudwatch:Start*',
516
+ 'cloudwatch:Stop*',
517
+ 'cloudwatch:TagResource',
518
+ 'cloudwatch:UntagResource',
519
+ ].sort(compareStrings));
520
+ /** Logs application resources live in the deployment Region, while native WAF
521
+ * delivery resources live in the CloudFront edge control Region. The allow
522
+ * statements remain separate; this family exists only to deny mutations in a
523
+ * third Region. */
524
+ exports.STAGE_AUTHORITY_LOGS_MUTATION_FAMILIES = Object.freeze([
525
+ 'logs:Associate*',
526
+ 'logs:Cancel*',
527
+ 'logs:Create*',
528
+ 'logs:Delete*',
529
+ 'logs:Disassociate*',
530
+ 'logs:Put*',
531
+ 'logs:Start*',
532
+ 'logs:Stop*',
533
+ 'logs:Tag*',
534
+ 'logs:Untag*',
535
+ 'logs:Update*',
536
+ ].sort(compareStrings));
537
+ exports.STAGE_RUNTIME_REGIONAL_SERVICE_FAMILIES = Object.freeze([
538
+ ...new Set(exports.STAGE_RUNTIME_REGIONAL_ACTIONS.map((action) => `${action.split(':', 1)[0]}:*`)),
539
+ ].sort(compareStrings));
540
+ exports.STAGE_AUTHORITY_APPROVED_AWS_MANAGED_POLICIES = Object.freeze([
541
+ 'AmazonSSMManagedInstanceCore',
542
+ 'service-role/AmazonECSTaskExecutionRolePolicy',
543
+ 'service-role/AWSLambdaBasicDurableExecutionRolePolicy',
544
+ 'service-role/AWSLambdaBasicExecutionRole',
545
+ 'service-role/AWSLambdaVPCAccessExecutionRole',
546
+ ]);
547
+ exports.STAGE_AUTHORITY_WORKLOAD_IDENTITY_POLICY_ACTIONS = Object.freeze([
548
+ 'iam:AttachRolePolicy',
549
+ 'iam:DeleteRolePolicy',
550
+ 'iam:DetachRolePolicy',
551
+ 'iam:PutRolePolicy',
552
+ ].sort(compareStrings));
553
+ const IAM_AUTHORITY_MUTATION_ACTIONS = Object.freeze([
554
+ 'iam:AddRoleToInstanceProfile',
555
+ 'iam:AttachRolePolicy',
556
+ 'iam:CreatePolicyVersion',
557
+ 'iam:DeletePolicy',
558
+ 'iam:DeletePolicyVersion',
559
+ 'iam:DeleteRole',
560
+ 'iam:DeleteRolePermissionsBoundary',
561
+ 'iam:DeleteRolePolicy',
562
+ 'iam:DetachRolePolicy',
563
+ 'iam:PutRolePermissionsBoundary',
564
+ 'iam:PutRolePolicy',
565
+ 'iam:RemoveRoleFromInstanceProfile',
566
+ 'iam:SetDefaultPolicyVersion',
567
+ 'iam:TagPolicy',
568
+ 'iam:TagRole',
569
+ 'iam:UntagPolicy',
570
+ 'iam:UntagRole',
571
+ 'iam:UpdateAssumeRolePolicy',
572
+ 'iam:UpdateRole',
573
+ 'iam:UpdateRoleDescription',
574
+ ].sort(compareStrings));
575
+ /** Compact service-family scope guards keep mutation outside the selected AWS
576
+ * account/Region closed. They intentionally do not claim same-account stage
577
+ * isolation, because native SST owns account-shared bootstrap resources. */
578
+ exports.STAGE_AUTHORITY_SCOPE_GUARD_MUTATION_FAMILIES = Object.freeze([
579
+ ...new Set([
580
+ ...exports.STAGE_AUTHORITY_REGIONAL_MUTATION_FAMILIES,
581
+ 'acm:*',
582
+ 'apigateway:*',
583
+ 'cloudfront:*',
584
+ 'iam:*',
585
+ 'logs:*',
586
+ 'route53:*',
587
+ 's3:*',
588
+ 'wafv2:*',
589
+ ]),
590
+ ].sort(compareStrings));
591
+ exports.STAGE_AUTHORITY_CLOUDCONTROL_EDGE_MUTATION_ACTIONS = Object.freeze([
592
+ 'cloudformation:CreateResource',
593
+ 'cloudformation:DeleteResource',
594
+ 'cloudformation:UpdateResource',
595
+ ]);
596
+ /** SST 4.17.1 resolves the generated nonproduction VPC's EC2 NAT image from
597
+ * this commercial-partition fck-nat publisher. The generated development
598
+ * bastion reuses that NAT instance, while production uses managed NAT. No
599
+ * publisher is admitted in partitions where the pinned source is unproven. */
600
+ exports.STAGE_AUTHORITY_SST_417_EXTERNAL_AMI_OWNERS_BY_PARTITION = Object.freeze({
601
+ aws: Object.freeze(['568608671756']),
602
+ 'aws-cn': Object.freeze([]),
603
+ 'aws-us-gov': Object.freeze([]),
604
+ });
605
+ /** Preserve the generic cross-account guard for ordinary EC2 mutations while
606
+ * routing RunInstances through its resource-aware statements below. A service
607
+ * family wildcard would otherwise reject SST's deliberately external AMI. */
608
+ exports.STAGE_AUTHORITY_CROSS_ACCOUNT_EC2_MUTATION_ACTIONS = Object.freeze(exports.STAGE_AUTHORITY_REGIONAL_WRITE_ACTIONS.filter((action) => action.startsWith('ec2:') && action !== 'ec2:RunInstances'));
609
+ exports.STAGE_AUTHORITY_CROSS_ACCOUNT_MUTATION_ACTIONS = Object.freeze([
610
+ ...exports.STAGE_AUTHORITY_SCOPE_GUARD_MUTATION_FAMILIES.filter((action) => action !== 'ec2:*'),
611
+ ...exports.STAGE_AUTHORITY_CROSS_ACCOUNT_EC2_MUTATION_ACTIONS,
612
+ ].sort(compareStrings));
613
+ /** A deliberately narrow destructive set for same-account stage defense in
614
+ * depth. It protects named/tagged production resources without pretending the
615
+ * deployment roles form a complete IAM boundary. */
616
+ exports.STAGE_AUTHORITY_CROSS_STAGE_DESTRUCTIVE_ACTIONS = Object.freeze([
617
+ 'backup:Delete*',
618
+ 'budgets:ModifyBudget',
619
+ 'budgets:TagResource',
620
+ 'budgets:UntagResource',
621
+ 'cloudformation:DeleteStack',
622
+ 'cloudformation:UpdateStack',
623
+ 'cloudfront:CreateInvalidation',
624
+ 'cloudfront:Delete*',
625
+ 'cloudfront:PublishFunction',
626
+ 'cloudfront:TagResource',
627
+ 'cloudfront:UntagResource',
628
+ 'cloudfront:Update*',
629
+ 'cognito-idp:Delete*',
630
+ 'dynamodb:Delete*',
631
+ 'ec2:Replace*',
632
+ 'ecr:BatchDeleteImage',
633
+ 'ecr:Delete*',
634
+ 'events:DeleteArchive',
635
+ 'events:DeleteEventBus',
636
+ 'events:DeleteRule',
637
+ 'events:RemoveTargets',
638
+ 'events:UpdateArchive',
639
+ 'events:UpdateEventBus',
640
+ 'iam:Delete*',
641
+ 'kms:ScheduleKeyDeletion',
642
+ 'lambda:Delete*',
643
+ 'rds:Delete*',
644
+ 'rds:ModifyDBCluster',
645
+ 'rds:ModifyDBInstance',
646
+ 'rds:AddSourceIdentifierToSubscription',
647
+ 'rds:RemoveSourceIdentifierFromSubscription',
648
+ 's3:AbortMultipartUpload',
649
+ 's3:CreateBucket',
650
+ 's3:DeleteBucket',
651
+ 's3:DeleteBucketPolicy',
652
+ 's3:DeleteObject*',
653
+ 's3:PutBucket*',
654
+ 's3:PutObject*',
655
+ 's3:RestoreObject',
656
+ 'secretsmanager:DeleteSecret',
657
+ 'servicediscovery:DeleteNamespace',
658
+ 'sqs:DeleteQueue',
659
+ 'ssm:DeleteParameter*',
660
+ 'states:DeleteStateMachine',
661
+ 'wafv2:Delete*',
662
+ 'wafv2:DisassociateWebACL',
663
+ 'wafv2:PutLoggingConfiguration',
664
+ 'wafv2:Update*',
665
+ ].sort(compareStrings));
666
+ /** Existing-resource mutations must either retain the exact stage tag or use a
667
+ * generated stage/SST shared resource identity. Initial create/tag calls are
668
+ * governed by their request-tag or exact-resource statements instead. */
669
+ exports.STAGE_AUTHORITY_UNTAGGED_DESTRUCTIVE_ACTIONS = Object.freeze([
670
+ ...exports.STAGE_AUTHORITY_CROSS_STAGE_DESTRUCTIVE_ACTIONS.filter((action) => !action.startsWith('cloudfront:') && action !== 's3:CreateBucket'),
671
+ 'cloudfront:DeleteDistribution',
672
+ 'cloudfront:DeleteFunction',
673
+ 'cloudfront:PublishFunction',
674
+ 'cloudfront:UpdateDistribution',
675
+ 'cloudfront:UpdateFunction',
676
+ ].sort(compareStrings));
677
+ /** Operations whose target already exposes a stage tag may use the broader
678
+ * deployer contract. A known different-stage tag must still win as an explicit
679
+ * deny, including for provider calls that are not destructive by name. */
680
+ exports.STAGE_AUTHORITY_KNOWN_STAGE_MUTATION_ACTIONS = Object.freeze([
681
+ ...new Set([
682
+ ...exports.STAGE_AUTHORITY_REGIONAL_MUTATION_FAMILIES,
683
+ 'acm:*',
684
+ 'budgets:*',
685
+ 'cloudformation:*',
686
+ 'cloudfront:*',
687
+ 'iam:*',
688
+ 'logs:*',
689
+ 's3:*',
690
+ 'wafv2:*',
691
+ ]),
692
+ ].sort(compareStrings));
693
+ exports.STAGE_AUTHORITY_S3_BUCKET_POLICY_MUTATION_ACTIONS = Object.freeze(['s3:DeleteBucketPolicy', 's3:PutBucketPolicy'].sort(compareStrings));
694
+ const PRIVILEGE_CONSTRUCTION_ACTIONS = Object.freeze([
695
+ 'account:*',
696
+ 'iam:AttachGroupPolicy',
697
+ 'iam:AttachUserPolicy',
698
+ 'iam:CreateAccessKey',
699
+ 'iam:CreateGroup',
700
+ 'iam:CreateLoginProfile',
701
+ 'iam:CreatePolicy',
702
+ 'iam:CreatePolicyVersion',
703
+ 'iam:CreateUser',
704
+ 'iam:DeleteRolePermissionsBoundary',
705
+ 'iam:PutGroupPolicy',
706
+ 'iam:PutUserPermissionsBoundary',
707
+ 'iam:PutUserPolicy',
708
+ 'iam:SetDefaultPolicyVersion',
709
+ 'organizations:*',
710
+ 'sts:AssumeRole',
711
+ ].sort(compareStrings));
712
+ const RUNTIME_PRIVILEGE_ACTIONS = Object.freeze([
713
+ ...PRIVILEGE_CONSTRUCTION_ACTIONS,
714
+ 'iam:AttachRolePolicy',
715
+ 'iam:CreateInstanceProfile',
716
+ 'iam:CreateRole',
717
+ 'iam:DeleteRole',
718
+ 'iam:DeleteRolePolicy',
719
+ 'iam:DetachRolePolicy',
720
+ 'iam:PutRolePermissionsBoundary',
721
+ 'iam:PutRolePolicy',
722
+ 'iam:UpdateAssumeRolePolicy',
723
+ ].sort(compareStrings));
724
+ /** Permission-management actions that the generated lifecycle must call. Each
725
+ * exception is named exactly here and remains subject to the resource and
726
+ * condition containment statements below. */
727
+ exports.STAGE_AUTHORITY_REVIEWED_PERMISSION_MANAGEMENT_ACTIONS = Object.freeze([
728
+ 'iam:AttachRolePolicy',
729
+ 'iam:DeleteRolePolicy',
730
+ 'iam:DetachRolePolicy',
731
+ 'iam:PutRolePermissionsBoundary',
732
+ 'iam:PutRolePolicy',
733
+ 'kms:CreateGrant',
734
+ 'lambda:AddPermission',
735
+ 'lambda:RemovePermission',
736
+ 'logs:PutResourcePolicy',
737
+ 's3:DeleteBucketPolicy',
738
+ 's3:PutBucketOwnershipControls',
739
+ 's3:PutBucketPolicy',
740
+ 's3:PutBucketPublicAccessBlock',
741
+ 'sns:SetTopicAttributes',
742
+ 'sqs:SetQueueAttributes',
743
+ ].sort(compareStrings));
744
+ /** Compact deny patterns covering permission-management actions admitted by
745
+ * wildcard lifecycle grants but not named as reviewed exceptions. The focused
746
+ * oracle derives every wildcard service family from the policy and proves each
747
+ * currently admitted permission-management action is reviewed or denied, and
748
+ * that no compact pattern also captures a retained read-only action. */
749
+ exports.STAGE_AUTHORITY_UNREVIEWED_PERMISSION_MANAGEMENT_ACTION_PATTERNS = Object.freeze([
750
+ 'apigateway:*AccessAssociation',
751
+ 'apigateway:*Certificate*Domain',
752
+ 'apigateway:DeletePortalProductSharingPolicy',
753
+ 'apigateway:PutPortalProductSharingPolicy',
754
+ 'apigateway:SetWebACL',
755
+ 'apigateway:Update*Policy',
756
+ 'backup:DeleteBackupVault*Policy',
757
+ 'backup:ListIndexedRecoveryPointsForSearch',
758
+ 'backup:PutBackupVault*Policy',
759
+ 'backup:SearchRecoveryPoint',
760
+ 'cloudfront:AllowVendedLogDeliveryForResource',
761
+ 'dynamodb:DeleteResourcePolicy',
762
+ 'dynamodb:PutResourcePolicy',
763
+ 'dynamodb:UpdateAbacStatus',
764
+ 'ec2:*Appliance*NatGateway',
765
+ 'ec2:*ImageBlockPublicAccess',
766
+ 'ec2:*OdbNetworkPeering',
767
+ 'ec2:*Permission',
768
+ 'ec2:*Resources*PlacementGroup',
769
+ 'ec2:*SnapshotBlockPublicAccess',
770
+ 'ec2:DeleteResourcePolicy',
771
+ 'ec2:ModifySnapshotAttribute',
772
+ 'ec2:ModifyVpcEndpointServicePermissions',
773
+ 'ec2:PutResourcePolicy',
774
+ 'ec2:ResetSnapshotAttribute',
775
+ 'ecr:DeleteRegistryPolicy',
776
+ 'ecr:DeleteRepositoryPolicy',
777
+ 'ecr:PutRegistryPolicy',
778
+ 'ecr:SetRepositoryPolicy',
779
+ 'ecs:AllowVendedLogDeliveryForResource',
780
+ 'elasticloadbalancing:AllowVendedLogDeliveryForResource',
781
+ 'events:*Permission',
782
+ 'kms:PutKeyPolicy',
783
+ 'kms:RetireGrant',
784
+ 'kms:RevokeGrant',
785
+ 'lambda:*LayerVersionPermission',
786
+ 'lambda:*Replication',
787
+ 'lambda:DeleteResourcePolicy',
788
+ 'lambda:PutResourcePolicy',
789
+ 'logs:DeleteResourcePolicy',
790
+ 'rds:AuthorizeDBSecurityGroupIngress',
791
+ 's3:AssociateAccessGrantsIdentityCenter',
792
+ 's3:BypassGovernanceRetention',
793
+ 's3:CreateAccessGrant*',
794
+ 's3:Delete*AccessPointPolicy*',
795
+ 's3:DeleteAccessGrant*',
796
+ 's3:DissociateAccessGrantsIdentityCenter',
797
+ 's3:ObjectOwnerOverrideToBucketOwner',
798
+ 's3:Put*AccessPointPolicy*',
799
+ 's3:Put*Acl',
800
+ 's3:PutAccessGrantsInstanceResourcePolicy',
801
+ 's3:PutAccessPointPublicAccessBlock',
802
+ 's3:PutAccountPublicAccessBlock',
803
+ 's3:UpdateAccessGrantsLocation',
804
+ 'secretsmanager:DeleteResourcePolicy',
805
+ 'secretsmanager:PutResourcePolicy',
806
+ 'secretsmanager:ValidateResourcePolicy',
807
+ 'sns:*Permission',
808
+ 'sqs:*Permission',
809
+ 'ssm:*ResourcePolicy',
810
+ 'ssm:ModifyDocumentPermission',
811
+ 'wafv2:DeletePermissionPolicy',
812
+ 'wafv2:PutPermissionPolicy',
813
+ ].sort(compareStrings));
814
+ const ADDITIONAL_RESOURCE_POLICY_AND_TRUST_EXPANSION_ACTIONS = Object.freeze([
815
+ 'ec2:AcceptTransitGatewayPeeringAttachment',
816
+ 'ec2:AcceptVpcPeeringConnection',
817
+ 'ec2:CreateTransitGatewayPeeringAttachment',
818
+ 'ec2:CreateVpcEndpointServiceConfiguration',
819
+ 'ec2:CreateVpcPeeringConnection',
820
+ 'ec2:DeleteVpcEndpointServiceConfigurations',
821
+ 'ec2:ModifyImageAttribute',
822
+ 'ec2:ModifyVpcEndpointServiceConfiguration',
823
+ 'ec2:ModifyVpcPeeringConnectionOptions',
824
+ 'ecr:PutReplicationConfiguration',
825
+ 'iam:UpdateAssumeRolePolicy',
826
+ 'logs:DeleteAccountPolicy',
827
+ 'logs:DeleteDeliveryDestinationPolicy',
828
+ 'logs:PutAccountPolicy',
829
+ 'logs:PutDeliveryDestinationPolicy',
830
+ 'logs:PutDestinationPolicy',
831
+ 'rds:ModifyDBClusterSnapshotAttribute',
832
+ 'rds:ModifyDBSnapshotAttribute',
833
+ 'states:DeleteResourcePolicy',
834
+ 'states:PutResourcePolicy',
835
+ 'states:RevealSecrets',
836
+ 'states:TestState',
837
+ ].sort(compareStrings));
838
+ const RESOURCE_POLICY_AND_TRUST_EXPANSION_ACTIONS = Object.freeze([
839
+ ...exports.STAGE_AUTHORITY_UNREVIEWED_PERMISSION_MANAGEMENT_ACTION_PATTERNS,
840
+ ...ADDITIONAL_RESOURCE_POLICY_AND_TRUST_EXPANSION_ACTIONS,
841
+ ].sort(compareStrings));
842
+ /** Stable exclusions from the temporary infrastructure-administrator role.
843
+ * These are account administration, direct application data/user mutation,
844
+ * message handling, or export paths rather than native stack reconciliation.
845
+ * The generated deployed smoke retains only its four exact Cognito admin calls. */
846
+ exports.STAGE_AUTHORITY_NON_DEPLOYMENT_ACCOUNT_AND_DATA_ACTIONS = Object.freeze([
847
+ 'acm:*Acme*',
848
+ 'acm:ExportCertificate',
849
+ 'acm:PutAccountConfiguration',
850
+ 'appconfig:UpdateAccountSettings',
851
+ 'cognito-idp:AdminConfirmSignUp',
852
+ 'cognito-idp:AdminDeleteUserAttributes',
853
+ 'cognito-idp:AdminDisable*',
854
+ 'cognito-idp:AdminEnableUser',
855
+ 'cognito-idp:AdminForgetDevice',
856
+ 'cognito-idp:*Auth*',
857
+ 'cognito-idp:*Device*',
858
+ 'cognito-idp:*UserMFA*',
859
+ 'cognito-idp:AdminGetUser',
860
+ 'cognito-idp:AdminLinkProviderForUser',
861
+ 'cognito-idp:AdminList*',
862
+ 'cognito-idp:AdminRemoveUserFromGroup',
863
+ 'cognito-idp:AdminResetUserPassword',
864
+ 'cognito-idp:AdminSetUserSettings',
865
+ 'cognito-idp:AdminUpdateUserAttributes',
866
+ 'cognito-idp:AdminUserGlobalSignOut',
867
+ 'cognito-idp:ChangePassword',
868
+ 'cognito-idp:ConfirmForgotPassword',
869
+ 'cognito-idp:ConfirmSignUp',
870
+ 'cognito-idp:DeleteUser',
871
+ 'cognito-idp:DeleteUserAttributes',
872
+ 'cognito-idp:ForgotPassword',
873
+ 'cognito-idp:GetTokensFromRefreshToken',
874
+ 'cognito-idp:GetUser',
875
+ 'cognito-idp:GetUserAttributeVerificationCode',
876
+ 'cognito-idp:GlobalSignOut',
877
+ 'cognito-idp:ListUsers*',
878
+ 'cognito-idp:ResendConfirmationCode',
879
+ 'cognito-idp:RevokeToken',
880
+ 'cognito-idp:SetUser*',
881
+ 'cognito-idp:SignUp',
882
+ 'cognito-idp:UpdateUserAttributes',
883
+ 'cognito-idp:VerifySoftwareToken',
884
+ 'cognito-idp:VerifyUserAttribute',
885
+ 'dynamodb:*Item*',
886
+ 'dynamodb:ExportTableToPointInTime',
887
+ 'dynamodb:GetRecords',
888
+ 'dynamodb:GetShardIterator',
889
+ 'dynamodb:ImportTable',
890
+ 'dynamodb:PartiQL*',
891
+ 'dynamodb:PurchaseReservedCapacityOfferings',
892
+ 'dynamodb:Query',
893
+ 'dynamodb:ReadDataForReplication',
894
+ 'dynamodb:RestoreTableFrom*',
895
+ 'dynamodb:Scan',
896
+ 'dynamodb:WriteDataForReplication',
897
+ 'ecr:CreatePullThroughCacheRule',
898
+ 'ecr:CreateRepositoryCreationTemplate',
899
+ 'ecr:DeletePullThroughCacheRule',
900
+ 'ecr:DeleteRepositoryCreationTemplate',
901
+ 'ecr:DeleteSigningConfiguration',
902
+ 'ecr:PutAccountSetting',
903
+ 'ecr:PutRegistryScanningConfiguration',
904
+ 'ecr:PutSigningConfiguration',
905
+ 'ecr:UpdatePullThroughCacheRule',
906
+ 'ecr:UpdateRepositoryCreationTemplate',
907
+ 'ecs:DeleteAccountSetting',
908
+ 'ecs:ExecuteCommand',
909
+ 'ecs:PutAccountSetting',
910
+ 'ecs:PutAccountSettingDefault',
911
+ 'ecs:RunTask',
912
+ 'ecs:StartTask',
913
+ 'ecs:StopTask',
914
+ 'logs:CancelExportTask',
915
+ 'logs:CreateExportTask',
916
+ 'rds:CancelExportTask',
917
+ 'rds:ModifyCertificates',
918
+ 'rds:PurchaseReservedDBInstancesOffering',
919
+ 'rds:StartExportTask',
920
+ 'secretsmanager:CancelRotateSecret',
921
+ 'secretsmanager:RotateSecret',
922
+ 'secretsmanager:UpdateSecretVersionStage',
923
+ 'sns:*PhoneNumber*',
924
+ 'sns:*SMS*',
925
+ 'sqs:*Message*',
926
+ 'sqs:PurgeQueue',
927
+ 'ssm:CreateActivation',
928
+ 'ssm:ResumeSession',
929
+ 'ssm:SendCommand',
930
+ 'ssm:StartAutomationExecution',
931
+ 'ssm:StartChangeRequestExecution',
932
+ 'ssm:StartSession',
933
+ 'ssm:TerminateSession',
934
+ ].sort(compareStrings));
935
+ const SECRET_BATCH_VALUE_READ_ACTIONS = Object.freeze([
936
+ 'secretsmanager:BatchGetSecretValue',
937
+ ]);
938
+ const GENERATED_FOUNDATION_DATABASE_VALUE_ACTIONS = Object.freeze(['secretsmanager:GetSecretValue', 'secretsmanager:PutSecretValue'].sort(compareStrings));
939
+ const STAGE_SECRET_CONTAINER_METADATA_UPDATE_ACTIONS = Object.freeze([
940
+ 'secretsmanager:UpdateSecret',
941
+ ]);
942
+ const GENERATED_FOUNDATION_DATABASE_RECONCILIATION_ACTIONS = Object.freeze([
943
+ ...GENERATED_FOUNDATION_DATABASE_VALUE_ACTIONS,
944
+ ...STAGE_SECRET_CONTAINER_METADATA_UPDATE_ACTIONS,
945
+ ].sort(compareStrings));
946
+ const SSM_HISTORY_AND_RECURSIVE_VALUE_READ_ACTIONS = Object.freeze(['ssm:GetParameterHistory', 'ssm:GetParametersByPath'].sort(compareStrings));
947
+ const WORKFLOW_EXECUTION_MUTATION_ACTIONS = Object.freeze([
948
+ 'states:RedriveExecution',
949
+ 'states:StartExecution',
950
+ 'states:StartSyncExecution',
951
+ 'states:StopExecution',
952
+ ].sort(compareStrings));
953
+ exports.STAGE_AUTHORITY_UNSUPPORTED_WORKFLOW_EXECUTION_ACTIONS = Object.freeze([
954
+ 'states:RedriveExecution',
955
+ 'states:StartSyncExecution',
956
+ 'states:StopExecution',
957
+ ].sort(compareStrings));
958
+ const LAMBDA_INTEGRATION_PRINCIPALS = Object.freeze([
959
+ 'apigateway.amazonaws.com',
960
+ 'cloudfront.amazonaws.com',
961
+ 'events.amazonaws.com',
962
+ ].sort(compareStrings));
963
+ const REVIEWED_LAMBDA_PERMISSION_PRINCIPALS = Object.freeze([...LAMBDA_INTEGRATION_PRINCIPALS, '*'].sort(compareStrings));
964
+ exports.STAGE_AUTHORITY_SERVICE_LINKED_ROLES = Object.freeze([
965
+ Object.freeze({
966
+ path: 'ecs.amazonaws.com/AWSServiceRoleForECS',
967
+ serviceName: 'ecs.amazonaws.com',
968
+ }),
969
+ Object.freeze({
970
+ path: 'ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService',
971
+ serviceName: 'ecs.application-autoscaling.amazonaws.com',
972
+ }),
973
+ Object.freeze({
974
+ path: 'rds.amazonaws.com/AWSServiceRoleForRDS',
975
+ serviceName: 'rds.amazonaws.com',
976
+ }),
977
+ Object.freeze({
978
+ path: 'rds.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_RDSCluster',
979
+ serviceName: 'rds.application-autoscaling.amazonaws.com',
980
+ }),
981
+ Object.freeze({
982
+ path: 'wafv2.amazonaws.com/AWSServiceRoleForWAFV2Logging',
983
+ serviceName: 'wafv2.amazonaws.com',
984
+ }),
985
+ ]);
986
+ const IAM_POLICY_VERSION = '2012-10-17';
987
+ function compareStrings(left, right) {
988
+ return left < right ? -1 : left > right ? 1 : 0;
989
+ }
990
+ function githubOidcAudience(partition) {
991
+ return partition === 'aws-cn' ? 'sts.amazonaws.com.cn' : 'sts.amazonaws.com';
992
+ }
993
+ function canonicalize(value) {
994
+ if (Array.isArray(value))
995
+ return value.map(canonicalize);
996
+ if (!value || typeof value !== 'object')
997
+ return value;
998
+ return Object.fromEntries(Object.entries(value)
999
+ .sort(([left], [right]) => compareStrings(left, right))
1000
+ .map(([key, entry]) => [key, canonicalize(entry)]));
1001
+ }
1002
+ function deepFreeze(value) {
1003
+ if (!value || typeof value !== 'object' || Object.isFrozen(value)) {
1004
+ return value;
1005
+ }
1006
+ for (const entry of Object.values(value))
1007
+ deepFreeze(entry);
1008
+ return Object.freeze(value);
1009
+ }
1010
+ function policy(statements) {
1011
+ return {
1012
+ Statement: [...statements].sort((left, right) => compareStrings(left.Sid, right.Sid)),
1013
+ Version: IAM_POLICY_VERSION,
1014
+ };
1015
+ }
1016
+ function omitPolicyStatementSids(document, compactActions = false) {
1017
+ const record = document;
1018
+ const statements = record['Statement'];
1019
+ if (!Array.isArray(statements)) {
1020
+ throw new Error('Stage authority template policy statements are invalid.');
1021
+ }
1022
+ const rendered = statements.map((entry) => {
1023
+ if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
1024
+ throw new Error('Stage authority template policy statement is invalid.');
1025
+ }
1026
+ return Object.fromEntries(Object.entries(entry).filter(([key]) => key !== 'Sid'));
1027
+ });
1028
+ if (!compactActions)
1029
+ return { ...record, Statement: rendered };
1030
+ // Statements with identical effect, resources and conditions differ only in
1031
+ // their positive Action sets. Their union is exactly equivalent; NotAction
1032
+ // statements are deliberately never merged (union would change semantics).
1033
+ const scopes = new Map();
1034
+ const compacted = [];
1035
+ for (const entry of rendered) {
1036
+ if (!Array.isArray(entry['Action'])) {
1037
+ compacted.push(entry);
1038
+ continue;
1039
+ }
1040
+ const { Action, ...scope } = entry;
1041
+ const key = JSON.stringify(scope);
1042
+ const existing = scopes.get(key);
1043
+ if (existing)
1044
+ existing['Action'] = [
1045
+ ...new Set([
1046
+ ...existing['Action'],
1047
+ ...Action,
1048
+ ]),
1049
+ ].sort(compareStrings);
1050
+ else {
1051
+ scopes.set(key, entry);
1052
+ compacted.push(entry);
1053
+ }
1054
+ }
1055
+ // IAM accepts a singleton resource as either a string or a one-element
1056
+ // list. Keep the executable model as lists; shorten only the rendered JSON.
1057
+ return {
1058
+ ...record,
1059
+ Statement: compacted.map((entry) => Object.fromEntries(Object.entries(entry).map(([key, value]) => [
1060
+ key,
1061
+ ['Resource', 'NotResource'].includes(key) &&
1062
+ Array.isArray(value) &&
1063
+ value.length === 1
1064
+ ? value[0]
1065
+ : value,
1066
+ ]))),
1067
+ };
1068
+ }
1069
+ function replaceExactTemplateString(value, expected, replacement) {
1070
+ if (value === expected)
1071
+ return replacement;
1072
+ if (Array.isArray(value)) {
1073
+ return value.map((entry) => replaceExactTemplateString(entry, expected, replacement));
1074
+ }
1075
+ if (!value || typeof value !== 'object')
1076
+ return value;
1077
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [
1078
+ key,
1079
+ replaceExactTemplateString(entry, expected, replacement),
1080
+ ]));
1081
+ }
1082
+ function compactExactTemplatePolicyStrings(documents, values, compactLists = false) {
1083
+ const constants = {};
1084
+ const replacements = new Map();
1085
+ for (const value of [...new Set(values)].sort(compareStrings)) {
1086
+ const key = compactLists
1087
+ ? replacements.size.toString(36)
1088
+ : `A${replacements.size}`;
1089
+ const replacement = Object.freeze({
1090
+ 'Fn::FindInMap': Object.freeze(['A', 'V', key]),
1091
+ });
1092
+ constants[key] = value;
1093
+ replacements.set(value, replacement);
1094
+ }
1095
+ if (replacements.size === 0)
1096
+ return Object.freeze({ documents });
1097
+ let compactedDocuments = Object.fromEntries(Object.entries(documents).map(([logicalId, document]) => [
1098
+ logicalId,
1099
+ [...replacements.entries()].reduce((current, [literal, replacement]) => replaceExactTemplateString(current, literal, replacement), document),
1100
+ ]));
1101
+ if (compactLists) {
1102
+ const counts = new Map();
1103
+ const collect = (value) => {
1104
+ if (Array.isArray(value) &&
1105
+ value.every((entry) => typeof entry === 'string')) {
1106
+ const key = JSON.stringify(value);
1107
+ counts.set(key, (counts.get(key) ?? 0) + 1);
1108
+ }
1109
+ else if (Array.isArray(value))
1110
+ value.forEach(collect);
1111
+ else if (value && typeof value === 'object')
1112
+ Object.values(value).forEach(collect);
1113
+ };
1114
+ collect(compactedDocuments);
1115
+ const listReferences = new Map();
1116
+ for (const [literal, count] of [...counts].sort(([a], [b]) => compareStrings(a, b))) {
1117
+ if ((count - 1) * literal.length <= count * 36 + 24)
1118
+ continue;
1119
+ const key = (replacements.size + listReferences.size).toString(36);
1120
+ constants[key] = JSON.parse(literal);
1121
+ listReferences.set(literal, { 'Fn::FindInMap': ['A', 'V', key] });
1122
+ }
1123
+ const replaceLists = (value) => {
1124
+ if (Array.isArray(value)) {
1125
+ const reference = listReferences.get(JSON.stringify(value));
1126
+ return reference ?? value.map(replaceLists);
1127
+ }
1128
+ if (value && typeof value === 'object')
1129
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [
1130
+ key,
1131
+ replaceLists(entry),
1132
+ ]));
1133
+ return value;
1134
+ };
1135
+ compactedDocuments = replaceLists(compactedDocuments);
1136
+ // Fn::Split is resolved by CloudFormation before IAM evaluates the
1137
+ // document. Long literal lists can omit JSON's repeated quotes without
1138
+ // introducing wildcards, changing order, or changing a single permission.
1139
+ // Mapping values themselves stay literal (intrinsics are not valid there).
1140
+ const encodeLiteralLists = (value) => {
1141
+ if (Array.isArray(value)) {
1142
+ if (value.every((entry) => typeof entry === 'string' && !entry.includes(','))) {
1143
+ let encoded = { 'Fn::Split': [',', value.join(',')] };
1144
+ // Factor only a literal ARN prefix. CloudFormation expands it back
1145
+ // before IAM sees the list; IAM policy variables must stay literal.
1146
+ if (value.length > 1 &&
1147
+ value.every((entry) => entry.startsWith('arn:') && !entry.includes('${'))) {
1148
+ let prefix = value[0];
1149
+ for (const entry of value)
1150
+ while (!entry.startsWith(prefix))
1151
+ prefix = prefix.slice(0, -1);
1152
+ const factored = {
1153
+ 'Fn::Split': [
1154
+ ',',
1155
+ {
1156
+ 'Fn::Sub': [
1157
+ value
1158
+ .map((entry) => '${P}' + entry.slice(prefix.length))
1159
+ .join(','),
1160
+ { P: prefix },
1161
+ ],
1162
+ },
1163
+ ],
1164
+ };
1165
+ if (JSON.stringify(factored).length < JSON.stringify(encoded).length)
1166
+ encoded = factored;
1167
+ }
1168
+ if (JSON.stringify(encoded).length < JSON.stringify(value).length)
1169
+ return encoded;
1170
+ }
1171
+ return value.map(encodeLiteralLists);
1172
+ }
1173
+ if (value && typeof value === 'object')
1174
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [
1175
+ key,
1176
+ encodeLiteralLists(entry),
1177
+ ]));
1178
+ return value;
1179
+ };
1180
+ compactedDocuments = encodeLiteralLists(compactedDocuments);
1181
+ }
1182
+ if (compactLists) {
1183
+ const serialized = JSON.stringify(compactedDocuments);
1184
+ for (const key of Object.keys(constants)) {
1185
+ if (!serialized.includes(JSON.stringify(['A', 'V', key])))
1186
+ delete constants[key];
1187
+ }
1188
+ }
1189
+ return Object.freeze({
1190
+ documents: Object.freeze(compactedDocuments),
1191
+ // These short, template-private identifiers avoid repeating long exact
1192
+ // ARNs in policy documents. Fn::FindInMap resolves to the original literal
1193
+ // before IAM sees the policy; the executable policy model stays literal.
1194
+ mappings: Object.freeze({
1195
+ A: Object.freeze({ V: Object.freeze(constants) }),
1196
+ }),
1197
+ });
1198
+ }
1199
+ function repeatedDevelopmentPolicyStrings(documents) {
1200
+ const counts = new Map();
1201
+ const visit = (value) => {
1202
+ if (typeof value === 'string')
1203
+ counts.set(value, (counts.get(value) ?? 0) + 1);
1204
+ else if (Array.isArray(value))
1205
+ value.forEach(visit);
1206
+ else if (value && typeof value === 'object')
1207
+ Object.values(value).forEach(visit);
1208
+ };
1209
+ visit(documents);
1210
+ // Exact FindInMap substitution only; admit entries whose repeated bytes pay
1211
+ // for both the mapping and references. No IAM statement semantics change.
1212
+ return [...counts]
1213
+ .filter(([value, count]) => (count - 1) * value.length > count * 36 + 24)
1214
+ .map(([value]) => value);
1215
+ }
1216
+ function statement(input) {
1217
+ if ((input.Action === undefined) === (input.NotAction === undefined)) {
1218
+ throw new Error('Stage authority statements require exactly one Action or NotAction scope.');
1219
+ }
1220
+ if ((input.Resource === undefined) === (input.NotResource === undefined)) {
1221
+ throw new Error('Stage authority statements require exactly one Resource or NotResource scope.');
1222
+ }
1223
+ return {
1224
+ ...input,
1225
+ ...(input.Action
1226
+ ? { Action: [...input.Action].sort(compareStrings) }
1227
+ : { NotAction: [...(input.NotAction ?? [])].sort(compareStrings) }),
1228
+ ...(input.Resource
1229
+ ? { Resource: [...input.Resource].sort(compareStrings) }
1230
+ : {}),
1231
+ ...(input.NotResource
1232
+ ? { NotResource: [...input.NotResource].sort(compareStrings) }
1233
+ : {}),
1234
+ };
1235
+ }
1236
+ function requireIdentity(input) {
1237
+ const partition = input.partition ?? 'aws';
1238
+ if (!ACCOUNT_ID.test(input.accountId) ||
1239
+ !REGION.test(input.region) ||
1240
+ !exports.STAGE_AUTHORITY_STAGES.includes(input.stage) ||
1241
+ !exports.STAGE_AUTHORITY_PARTITIONS.includes(partition)) {
1242
+ throw new Error('Stage authority requires one exact account, Region, partition, and canonical stage.');
1243
+ }
1244
+ return {
1245
+ accountId: input.accountId,
1246
+ partition,
1247
+ region: input.region,
1248
+ stage: input.stage,
1249
+ };
1250
+ }
1251
+ function createStageAuthorityIdentity(input) {
1252
+ const identity = requireIdentity(input);
1253
+ const boundaryPath = `/ebk/${identity.stage}/`;
1254
+ const boundaryName = `workload-role-boundary-${identity.stage}`;
1255
+ const deploymentRolePath = `/ebk/${identity.stage}/deployment/`;
1256
+ const deploymentRoleName = `ebk-${identity.stage}-deploy`;
1257
+ const deploymentPolicyNames = Object.freeze([
1258
+ `stage-deployment-read-${identity.stage}`,
1259
+ `stage-deployment-regional-mutation-${identity.stage}`,
1260
+ `stage-deployment-global-iam-mutation-${identity.stage}`,
1261
+ `stage-deployment-global-resource-mutation-${identity.stage}`,
1262
+ `stage-deployment-generated-resource-mutation-${identity.stage}`,
1263
+ `stage-deployment-stage-containment-${identity.stage}`,
1264
+ `stage-deployment-permission-guardrails-${identity.stage}`,
1265
+ `stage-deployment-guardrails-${identity.stage}`,
1266
+ ]);
1267
+ const workloadRolePath = `/ebk/${identity.stage}/workloads/`;
1268
+ const workloadInstanceProfilePath = workloadRolePath;
1269
+ return Object.freeze({
1270
+ boundaryArn: `arn:${identity.partition}:iam::${identity.accountId}:policy${boundaryPath}${boundaryName}`,
1271
+ boundaryName,
1272
+ boundaryPath,
1273
+ deploymentPolicyArns: Object.freeze(deploymentPolicyNames.map((name) => `arn:${identity.partition}:iam::${identity.accountId}:policy${deploymentRolePath}${name}`)),
1274
+ deploymentPolicyNames,
1275
+ deploymentRoleArn: `arn:${identity.partition}:iam::${identity.accountId}:role${deploymentRolePath}${deploymentRoleName}`,
1276
+ deploymentRoleName,
1277
+ deploymentRolePath,
1278
+ stackName: `ebk-${identity.stage}-stage-authority`,
1279
+ workloadInstanceProfileArnPattern: `arn:${identity.partition}:iam::${identity.accountId}:instance-profile${workloadInstanceProfilePath}*`,
1280
+ workloadInstanceProfilePath,
1281
+ workloadRoleArnPattern: `arn:${identity.partition}:iam::${identity.accountId}:role${workloadRolePath}*`,
1282
+ workloadRolePath,
1283
+ });
1284
+ }
1285
+ function requireTrust(input, identity) {
1286
+ const principals = [...new Set(input.awsPrincipalArns ?? [])].sort(compareStrings);
1287
+ if (principals.length > STAGE_AUTHORITY_MAX_AWS_PRINCIPALS ||
1288
+ principals.some((arn) => {
1289
+ const match = AWS_PRINCIPAL_ARN.exec(arn);
1290
+ return (Buffer.byteLength(arn, 'utf8') >
1291
+ STAGE_AUTHORITY_MAX_AWS_PRINCIPAL_ARN_BYTES ||
1292
+ !match ||
1293
+ match[1] !== identity.partition);
1294
+ })) {
1295
+ throw new Error('Stage authority AWS trust must contain at most 16 bounded unique exact principal ARNs in the selected partition.');
1296
+ }
1297
+ const statements = [];
1298
+ if (principals.length > 0) {
1299
+ statements.push({
1300
+ Action: 'sts:AssumeRole',
1301
+ Effect: 'Allow',
1302
+ Principal: { AWS: principals },
1303
+ Sid: 'AssumeFromReviewedAwsPrincipals',
1304
+ });
1305
+ }
1306
+ if (input.github) {
1307
+ const match = GITHUB_OIDC_PROVIDER_ARN.exec(input.github.oidcProviderArn);
1308
+ const subjectMatch = GITHUB_SUBJECT.exec(input.github.subject);
1309
+ if (!match ||
1310
+ match[1] !== identity.partition ||
1311
+ match[2] !== identity.accountId ||
1312
+ !subjectMatch) {
1313
+ throw new Error('Stage authority GitHub trust must use the target account provider and one immutable environment subject.');
1314
+ }
1315
+ if (subjectMatch[1] !== identity.stage) {
1316
+ throw new Error('Stage authority GitHub trust environment must match the selected stage.');
1317
+ }
1318
+ statements.push({
1319
+ Action: 'sts:AssumeRoleWithWebIdentity',
1320
+ Condition: {
1321
+ StringEquals: {
1322
+ 'token.actions.githubusercontent.com:aud': githubOidcAudience(identity.partition),
1323
+ 'token.actions.githubusercontent.com:sub': input.github.subject,
1324
+ },
1325
+ },
1326
+ Effect: 'Allow',
1327
+ Principal: { Federated: input.github.oidcProviderArn },
1328
+ Sid: 'AssumeFromReviewedGithubEnvironment',
1329
+ });
1330
+ }
1331
+ if (statements.length === 0) {
1332
+ throw new Error('Stage authority requires at least one reviewed AWS or GitHub trust principal.');
1333
+ }
1334
+ return {
1335
+ Statement: statements.sort((left, right) => compareStrings(String(left['Sid']), String(right['Sid']))),
1336
+ Version: IAM_POLICY_VERSION,
1337
+ };
1338
+ }
1339
+ function runtimeBoundaryPolicy(options) {
1340
+ const statements = [
1341
+ statement({
1342
+ Action: exports.STAGE_RUNTIME_REGIONAL_ACTIONS,
1343
+ Condition: {
1344
+ StringEquals: { 'aws:RequestedRegion': options.region },
1345
+ },
1346
+ Effect: 'Allow',
1347
+ Resource: ['*'],
1348
+ Sid: 'AllowFixedRuntimeServicesInStageRegion',
1349
+ }),
1350
+ statement({
1351
+ Action: ['sts:GetCallerIdentity'],
1352
+ Effect: 'Allow',
1353
+ Resource: ['*'],
1354
+ Sid: 'AllowRuntimeCallerIdentity',
1355
+ }),
1356
+ statement({
1357
+ Action: exports.STAGE_RUNTIME_GLOBAL_ACTIONS,
1358
+ Effect: 'Allow',
1359
+ Resource: ['*'],
1360
+ Sid: 'AllowFixedRuntimeGlobalServices',
1361
+ }),
1362
+ statement({
1363
+ Action: ['iam:PassRole'],
1364
+ Condition: {
1365
+ StringEquals: {
1366
+ 'iam:PassedToService': [
1367
+ 'appconfig.amazonaws.com',
1368
+ 'ec2.amazonaws.com',
1369
+ 'ecs-tasks.amazonaws.com',
1370
+ 'lambda.amazonaws.com',
1371
+ 'states.amazonaws.com',
1372
+ ].sort(compareStrings),
1373
+ },
1374
+ },
1375
+ Effect: 'Allow',
1376
+ Resource: [options.identity.workloadRoleArnPattern],
1377
+ Sid: 'AllowRuntimePassBoundedStageRoles',
1378
+ }),
1379
+ statement({
1380
+ Action: exports.STAGE_RUNTIME_REGIONAL_SERVICE_FAMILIES,
1381
+ Condition: {
1382
+ StringNotEquals: { 'aws:RequestedRegion': options.region },
1383
+ },
1384
+ Effect: 'Deny',
1385
+ Resource: ['*'],
1386
+ Sid: 'DenyRuntimeOutsideStageRegion',
1387
+ }),
1388
+ statement({
1389
+ Action: ['*'],
1390
+ Condition: {
1391
+ Null: { 'aws:ResourceAccount': 'false' },
1392
+ StringNotEquals: { 'aws:ResourceAccount': options.accountId },
1393
+ },
1394
+ Effect: 'Deny',
1395
+ Resource: ['*'],
1396
+ Sid: 'DenyRuntimeCrossAccountResources',
1397
+ }),
1398
+ statement({
1399
+ Action: ['*'],
1400
+ Condition: {
1401
+ Null: { 'aws:ResourceTag/ebk:stage': 'false' },
1402
+ StringNotEquals: { 'aws:ResourceTag/ebk:stage': options.stage },
1403
+ },
1404
+ Effect: 'Deny',
1405
+ Resource: ['*'],
1406
+ Sid: 'DenyRuntimeKnownOtherStageResources',
1407
+ }),
1408
+ statement({
1409
+ Action: RUNTIME_PRIVILEGE_ACTIONS,
1410
+ Effect: 'Deny',
1411
+ Resource: ['*'],
1412
+ Sid: 'DenyRuntimePrivilegeConstruction',
1413
+ }),
1414
+ ];
1415
+ if (options.stage === 'development') {
1416
+ const regionalGuardIndex = statements.findIndex((entry) => entry.Sid === 'DenyRuntimeOutsideStageRegion');
1417
+ const regionalGuard = statements[regionalGuardIndex];
1418
+ if (!regionalGuard?.Action)
1419
+ throw new Error('Runtime Region guard is missing.');
1420
+ // Development has only these global runtime exceptions. Denying every
1421
+ // other action outside the Region preserves all admitted runtime calls
1422
+ // while strengthening the old service-family deny, including AppSync.
1423
+ statements[regionalGuardIndex] = statement({
1424
+ Sid: regionalGuard.Sid,
1425
+ NotAction: [
1426
+ ...exports.STAGE_RUNTIME_GLOBAL_ACTIONS,
1427
+ 'iam:PassRole',
1428
+ 'sts:GetCallerIdentity',
1429
+ ],
1430
+ Effect: 'Deny',
1431
+ Resource: ['*'],
1432
+ Condition: regionalGuard.Condition,
1433
+ });
1434
+ const privilegeGuard = statements.find((entry) => entry.Sid === 'DenyRuntimePrivilegeConstruction');
1435
+ if (!privilegeGuard?.Action)
1436
+ throw new Error('Runtime privilege guard is missing.');
1437
+ // These deny-only patterns cover every original privilege action and no
1438
+ // admitted runtime action (notably iam:PassRole). Protected stages retain
1439
+ // their byte-identical explicit inventory.
1440
+ privilegeGuard.Action = [
1441
+ 'account:*',
1442
+ 'iam:*Boundary',
1443
+ 'iam:*Policy*',
1444
+ 'iam:Create*',
1445
+ 'iam:Delete*',
1446
+ 'organizations:*',
1447
+ 'sts:AssumeRole',
1448
+ ];
1449
+ // Native SST dev uses one untagged account/Region AppSync Events API and
1450
+ // its `sst` namespace. IAM cannot isolate nested task channel paths. This
1451
+ // is a shared development control plane, not an application event bus.
1452
+ // The boundary narrows SST's appsync:* identity grant to transport only.
1453
+ statements.push(...nativeDevelopmentTransportStatements({
1454
+ accountId: options.accountId,
1455
+ partition: options.identity.boundaryArn.split(':')[1],
1456
+ region: options.region,
1457
+ initialize: false,
1458
+ }));
1459
+ const canonicalGuard = statements.find((entry) => entry.Sid === 'DenyRuntimeKnownOtherStageResources');
1460
+ if (!canonicalGuard)
1461
+ throw new Error('Runtime stage guard is missing.');
1462
+ canonicalGuard.Condition = {
1463
+ ...canonicalGuard.Condition,
1464
+ StringEquals: { 'aws:PrincipalTag/ebk:stage': 'development' },
1465
+ };
1466
+ const taskPrincipal = {
1467
+ StringLike: { 'aws:PrincipalTag/ebk:stage': TASK_STAGE_IAM_SHAPE },
1468
+ };
1469
+ const partition = options.identity.boundaryArn.split(':')[1];
1470
+ // Native Lambda creates an untagged ENI against existing Foundation
1471
+ // subnets/security groups. Neither VPCs nor existing shared ENIs are
1472
+ // exempted. Task-owned VPC topology is not generated by this contract.
1473
+ const sharedNetwork = ['subnet', 'security-group'].map((resource) => `arn:${partition}:ec2:${options.region}:${options.accountId}:${resource}/*`);
1474
+ const shared = [
1475
+ `arn:${partition}:events:${options.region}:${options.accountId}:event-bus/foundation-development-FoundationEventBusBus-*`,
1476
+ `arn:${partition}:cognito-idp:${options.region}:${options.accountId}:userpool/*`,
1477
+ ...sharedNetwork,
1478
+ ];
1479
+ const sharedActions = [
1480
+ 'ec2:CreateNetworkInterface',
1481
+ 'events:PutEvents',
1482
+ ...exports.STAGE_RUNTIME_REGIONAL_ACTIONS.filter((action) => action.startsWith('cognito-idp:')),
1483
+ ];
1484
+ statements.push(statement({
1485
+ Sid: 'DenyRuntimeMissingOrInvalidPrincipalStage',
1486
+ Action: ['*'],
1487
+ Effect: 'Deny',
1488
+ Resource: ['*'],
1489
+ Condition: {
1490
+ StringNotLike: {
1491
+ 'aws:PrincipalTag/ebk:stage': ['development', TASK_STAGE_IAM_SHAPE],
1492
+ },
1493
+ },
1494
+ }), statement({
1495
+ Sid: 'DenyTaskRuntimeOtherTaggedResources',
1496
+ Action: ['*'],
1497
+ Effect: 'Deny',
1498
+ NotResource: shared,
1499
+ Condition: {
1500
+ ...taskPrincipal,
1501
+ Null: { 'aws:ResourceTag/ebk:stage': 'false' },
1502
+ StringNotEquals: {
1503
+ 'aws:ResourceTag/ebk:stage': TASK_PRINCIPAL_STAGE,
1504
+ },
1505
+ },
1506
+ }), ...['ebk:stage', 'ebk:owner'].map((key) => statement({
1507
+ Sid: `DenyTaskRuntimeUnownedShared${key.split(':')[1]}`,
1508
+ Action: ['*'],
1509
+ Effect: 'Deny',
1510
+ Resource: shared,
1511
+ Condition: {
1512
+ StringNotEquals: {
1513
+ [`aws:ResourceTag/${key}`]: key === 'ebk:stage' ? 'development' : 'foundation',
1514
+ },
1515
+ },
1516
+ })), statement({
1517
+ Sid: 'DenyTaskRuntimeUnlinkedSharedActions',
1518
+ // The boundary is only a ceiling. Existing native link/VPC identity
1519
+ // policies still determine effective permissions. AWS's resource-type
1520
+ // contracts prevent this union from granting cross-service operations.
1521
+ // Shared guards also constrain canonical-development runtime roles to
1522
+ // generated Foundation ownership; protected stages are unchanged.
1523
+ NotAction: sharedActions,
1524
+ Effect: 'Deny',
1525
+ Resource: shared,
1526
+ }), statement({
1527
+ Sid: 'DenyRuntimeUnownedSharedNetworkWorkspace',
1528
+ Action: ['*'],
1529
+ Effect: 'Deny',
1530
+ Resource: sharedNetwork,
1531
+ Condition: {
1532
+ StringNotEquals: {
1533
+ 'aws:ResourceTag/ebk:workspace': "${aws:PrincipalTag/ebk:workspace, ''}",
1534
+ },
1535
+ },
1536
+ }));
1537
+ }
1538
+ // Tagless APIs retain their existing exact native-link identity policies;
1539
+ // this boundary does not pretend unsupported ResourceTag keys are present.
1540
+ return policy(statements);
1541
+ }
1542
+ function nativeDevelopmentTransportStatements(options) {
1543
+ const api = `arn:${options.partition}:appsync:${options.region}:${options.accountId}:apis/*`;
1544
+ const Condition = {
1545
+ StringEquals: { 'aws:RequestedRegion': options.region },
1546
+ };
1547
+ return [
1548
+ ...(options.initialize
1549
+ ? [
1550
+ statement({
1551
+ // SST supplies neither tags nor a logging role. AWS has no API-name
1552
+ // condition for CreateApi, and ListApis requires Resource: *.
1553
+ Action: ['appsync:CreateApi', 'appsync:ListApis'],
1554
+ Condition,
1555
+ Effect: 'Allow',
1556
+ Resource: ['*'],
1557
+ Sid: 'InitializeNativeDevelopmentTransport',
1558
+ }),
1559
+ ]
1560
+ : []),
1561
+ statement({
1562
+ Action: [
1563
+ 'appsync:EventConnect',
1564
+ ...(options.initialize ? ['appsync:GetApi'] : []),
1565
+ ],
1566
+ ...(options.initialize ? { Condition } : {}),
1567
+ Effect: 'Allow',
1568
+ Resource: [api],
1569
+ Sid: 'ConnectNativeDevelopmentTransport',
1570
+ }),
1571
+ statement({
1572
+ Action: [
1573
+ 'appsync:EventPublish',
1574
+ 'appsync:EventSubscribe',
1575
+ ...(options.initialize ? ['appsync:CreateChannelNamespace'] : []),
1576
+ ],
1577
+ ...(options.initialize ? { Condition } : {}),
1578
+ Effect: 'Allow',
1579
+ Resource: [`${api}/channelNamespace/sst`],
1580
+ Sid: 'UseNativeDevelopmentNamespace',
1581
+ }),
1582
+ ];
1583
+ }
1584
+ const SST_4_17_1_PHYSICAL_NAME_RANDOM_SUFFIX_LENGTH = 9;
1585
+ const FOUNDATION_ROUTER_CLOUDFRONT_FUNCTION_NAMES = [
1586
+ 'FoundationRouterCloudfrontFunctionRequest',
1587
+ 'FoundationRouterCloudfrontFunctionResponse',
1588
+ ];
1589
+ function sst4171PhysicalNamePattern(input) {
1590
+ const maximumPrefixLength = input.maximumLength - SST_4_17_1_PHYSICAL_NAME_RANDOM_SUFFIX_LENGTH;
1591
+ const stageLength = input.stage.length;
1592
+ const nameLength = input.logicalName.length;
1593
+ const prefix = nameLength + 1 >= maximumPrefixLength
1594
+ ? input.logicalName.substring(0, maximumPrefixLength)
1595
+ : nameLength + stageLength + 2 >= maximumPrefixLength
1596
+ ? `${input.stage.substring(0, maximumPrefixLength - nameLength - 1)}-${input.logicalName}`
1597
+ : `${input.application.substring(0, maximumPrefixLength - stageLength - nameLength - 2)}-${input.stage}-${input.logicalName}`;
1598
+ return `${prefix}-*`;
1599
+ }
1600
+ function generatedRouterCloudFrontFunctionResources(options, stage) {
1601
+ return FOUNDATION_ROUTER_CLOUDFRONT_FUNCTION_NAMES.map((logicalName) => `arn:${options.partition}:cloudfront::${options.accountId}:function/${sst4171PhysicalNamePattern({
1602
+ application: 'foundation',
1603
+ logicalName,
1604
+ maximumLength: 64,
1605
+ stage,
1606
+ })}`).sort(compareStrings);
1607
+ }
1608
+ /** Expand only existing task-app namespace contracts, never Foundation names. */
1609
+ function taskNamespaceResources(resources) {
1610
+ return [
1611
+ ...new Set(resources.flatMap((resource) => {
1612
+ if (/foundation|Foundation|workspace-owner|:rds:|:backup:|:wafv2:|:iam:/u.test(resource))
1613
+ return [resource];
1614
+ let task = resource;
1615
+ if (resource.includes('/sst/passphrase/')) {
1616
+ task = resource.replace(/\/development$/u, `/${TASK_STAGE_IAM_SHAPE}`);
1617
+ }
1618
+ else if (resource.includes(':parameter/*development*')) {
1619
+ // Native task state is not an arbitrary parameter containing "personal".
1620
+ return [
1621
+ resource,
1622
+ resource.replace(':parameter/*development*', `:parameter/sst/passphrase/*/${TASK_STAGE_IAM_SHAPE}`),
1623
+ ];
1624
+ }
1625
+ else {
1626
+ task = resource
1627
+ .replace(/-development-/gu, `-${TASK_STAGE_IAM_SHAPE}-`)
1628
+ .replace(/\/ebk\/development\//gu, `/ebk/${TASK_STAGE_IAM_SHAPE}/`)
1629
+ .replace(/:secret:ebk\/development\//gu, `:secret:ebk/${TASK_STAGE_IAM_SHAPE}/`)
1630
+ .replace(/:alias\/ebk-development-/gu, `:alias/ebk-${TASK_STAGE_IAM_SHAPE}-`);
1631
+ }
1632
+ return task === resource ? [resource] : [resource, task];
1633
+ })),
1634
+ ].sort(compareStrings);
1635
+ }
1636
+ function admitDevelopmentTaskNamespaces(statements) {
1637
+ const tagged = new Set([
1638
+ 'MutateFixedRegionalServiceFamilies',
1639
+ 'MutateEdgeCertificates',
1640
+ 'DenyExplicitOtherStageRequestTag',
1641
+ 'DenyKnownOtherStageResourceMutation',
1642
+ 'DescribeOnlyTaggedStageWorkflowExecutions',
1643
+ 'DenyWorkflowExecutionReadWithoutStageTag',
1644
+ 'StartOnlyTaggedStageWorkflowExecutions',
1645
+ 'CreateTaggedMachineAuthorizationStacks',
1646
+ 'MutateTaggedMachineAuthorizationStacks',
1647
+ 'CreateOnlyAwsResourceKmsGrants',
1648
+ 'EnableRotationOnStageKmsKeys',
1649
+ 'RetireOnlyTaggedNonProductionKmsKeys',
1650
+ 'InvalidateOnlyStageCloudFrontDistributions',
1651
+ 'InvokeOnlyStageLambdaFunctions',
1652
+ 'AddOnlyReviewedStageLambdaIntegrations',
1653
+ 'AddOnlyPublicStageLambdaFunctionUrlAccess',
1654
+ 'AddOnlyPublicStageLambdaFunctionUrlInvoke',
1655
+ 'RemoveOnlyStageLambdaIntegrations',
1656
+ ]);
1657
+ const named = new Set([
1658
+ 'SetOnlyStageQueueAttributes',
1659
+ 'DenyQueueAttributeMutationOutsideStage',
1660
+ 'SetOnlyStageTopicAttributes',
1661
+ 'DenyTopicAttributeMutationOutsideStage',
1662
+ 'DenyUntaggedMutationOutsideStageAndSstResources',
1663
+ 'DenyBucketPolicyMutationOutsideStageAndSstBootstrap',
1664
+ 'DenyUnapprovedSsmValueReads',
1665
+ 'DenySecretMetadataUpdateOutsideStageContainers',
1666
+ 'DenyEdgeLogGroupMutationOutsideGeneratedStageLogs',
1667
+ ]);
1668
+ for (const sid of new Set([...tagged, ...named])) {
1669
+ if (statements.filter((entry) => entry.Sid === sid).length !== 1) {
1670
+ throw new Error(`Task authority propagation requires exactly one ${sid} statement.`);
1671
+ }
1672
+ }
1673
+ for (const entry of statements) {
1674
+ if (tagged.has(entry.Sid) && entry.Condition) {
1675
+ const conditions = {};
1676
+ for (const [operator, values] of Object.entries(entry.Condition)) {
1677
+ for (const [key, value] of Object.entries(values)) {
1678
+ const taskTag = ['aws:RequestTag/ebk:stage', 'aws:ResourceTag/ebk:stage'].includes(key) && value === 'development';
1679
+ const taskOperator = taskTag
1680
+ ? operator.replace('Equals', 'Like')
1681
+ : operator;
1682
+ (conditions[taskOperator] ??= {})[key] = taskTag
1683
+ ? ['development', TASK_STAGE_IAM_SHAPE]
1684
+ : value;
1685
+ }
1686
+ }
1687
+ entry.Condition = conditions;
1688
+ }
1689
+ if (named.has(entry.Sid)) {
1690
+ if (entry.Resource)
1691
+ entry.Resource = taskNamespaceResources(entry.Resource);
1692
+ if (entry.NotResource)
1693
+ entry.NotResource = taskNamespaceResources(entry.NotResource);
1694
+ }
1695
+ }
1696
+ }
1697
+ function deploymentPolicy(options) {
1698
+ const edgeRegion = edgeControlRegion(options.partition, options.region);
1699
+ const managedPolicies = exports.STAGE_AUTHORITY_APPROVED_AWS_MANAGED_POLICIES.map((name) => `arn:${options.partition}:iam::aws:policy/${name}`);
1700
+ const productionDatabaseResources = [
1701
+ `arn:${options.partition}:rds:${options.region}:${options.accountId}:cluster:*`,
1702
+ `arn:${options.partition}:rds:${options.region}:${options.accountId}:db:*`,
1703
+ ];
1704
+ const productionRetentionResources = [
1705
+ `arn:${options.partition}:backup:${options.region}:${options.accountId}:backup-plan:*`,
1706
+ `arn:${options.partition}:backup:${options.region}:${options.accountId}:backup-vault:*`,
1707
+ `arn:${options.partition}:backup:${options.region}:${options.accountId}:recovery-point:*`,
1708
+ ];
1709
+ const productionDataExportBucketResources = [
1710
+ `arn:${options.partition}:s3:::ebk-${options.accountId}-production-*-data-export`,
1711
+ `arn:${options.partition}:s3:::ebk-${options.accountId}-production-*-data-export/*`,
1712
+ ];
1713
+ const productionDataExportAliasResources = [
1714
+ `arn:${options.partition}:kms:${options.region}:${options.accountId}:alias/ebk-production-*-data-export`,
1715
+ ];
1716
+ const stageLambdaResources = [
1717
+ `arn:${options.partition}:lambda:${options.region}:${options.accountId}:function:*`,
1718
+ ];
1719
+ const foundationNatWorkloadRoleResources = [
1720
+ `arn:${options.partition}:iam::${options.accountId}:role${options.identity.workloadRolePath}ebk-${options.stage}-foundation-nat`,
1721
+ ];
1722
+ const stageCloudFrontDistributionResources = [
1723
+ `arn:${options.partition}:cloudfront::${options.accountId}:distribution/*`,
1724
+ ];
1725
+ const stageRouterWebAclResources = [
1726
+ `arn:${options.partition}:wafv2:${edgeRegion}:${options.accountId}:global/webacl/*-${options.stage}-*/*`,
1727
+ ];
1728
+ const stageRouterCloudFrontFunctionResources = generatedRouterCloudFrontFunctionResources(options, options.stage);
1729
+ const productionRouterCloudFrontFunctionResources = generatedRouterCloudFrontFunctionResources(options, 'production');
1730
+ const stageRouterWafLogDestinationResources = [
1731
+ `arn:${options.partition}:logs:${edgeRegion}:${options.accountId}:log-group:aws-waf-logs-foundation-${options.stage}-FoundationRouter-*`,
1732
+ ];
1733
+ const generatedEdgeLogGroupMutationResources = [
1734
+ ...stageRouterWafLogDestinationResources,
1735
+ ...(options.region === edgeRegion
1736
+ ? [
1737
+ `arn:${options.partition}:logs:${options.region}:${options.accountId}:log-group:/aws/vendedlogs/apis/*-${options.stage}-*`,
1738
+ `arn:${options.partition}:logs:${options.region}:${options.accountId}:log-group:/ebk/${options.stage}/*`,
1739
+ ]
1740
+ : []),
1741
+ ].sort(compareStrings);
1742
+ const productionEventSubscriptionResources = [
1743
+ `arn:${options.partition}:rds:${options.region}:${options.accountId}:es:*`,
1744
+ ];
1745
+ const stageAccountBudgetResources = [
1746
+ `arn:${options.partition}:budgets::${options.accountId}:budget/*`,
1747
+ ];
1748
+ const stageTopicResources = [
1749
+ `arn:${options.partition}:sns:${options.region}:${options.accountId}:*-${options.stage}-*`,
1750
+ ];
1751
+ const generatedFoundationAlertTopicResources = [
1752
+ `arn:${options.partition}:sns:${options.region}:${options.accountId}:foundation-${options.stage}-FoundationAlertsTopic-*`,
1753
+ ];
1754
+ const stageQueueResources = [
1755
+ `arn:${options.partition}:sqs:${options.region}:${options.accountId}:*-${options.stage}-*`,
1756
+ ];
1757
+ const stageReadableSsmValueResources = [
1758
+ `arn:${options.partition}:ssm:${options.region}:${options.accountId}:parameter/ebk/${options.stage}/workspace-owner`,
1759
+ `arn:${options.partition}:ssm:${options.region}:${options.accountId}:parameter/ebk/${options.stage}/foundation/*`,
1760
+ `arn:${options.partition}:ssm:${options.region}:${options.accountId}:parameter/sst/bootstrap`,
1761
+ // SST 4.17.1 reads both /sst/bootstrap and /sst/bootstrap/asset on every
1762
+ // deploy; a fresh stage refuses its first Foundation deploy without the
1763
+ // asset parameter (EBK-INT-2026-078).
1764
+ `arn:${options.partition}:ssm:${options.region}:${options.accountId}:parameter/sst/bootstrap/asset`,
1765
+ `arn:${options.partition}:ssm:${options.region}:${options.accountId}:parameter/sst/passphrase/*/${options.stage}`,
1766
+ `arn:${options.partition}:ssm:${options.region}:${options.accountId}:parameter/sst/vpc/vpc-*/private-key-value`,
1767
+ ].sort(compareStrings);
1768
+ const immutableWorkspaceOwnerResources = [
1769
+ 'development',
1770
+ 'production',
1771
+ 'staging',
1772
+ ]
1773
+ .map((stage) => `arn:${options.partition}:ssm:${options.region}:${options.accountId}:parameter/ebk/${stage}/workspace-owner`)
1774
+ .sort(compareStrings);
1775
+ // SST 4.17.1 models the generated Aurora credential as a managed
1776
+ // SecretVersion. The pinned AWS provider needs PutSecretValue to create it
1777
+ // and GetSecretValue to reconcile its AWSCURRENT version during removal.
1778
+ // Keep those value operations bound to the one Foundation-owned
1779
+ // physical-name and stage-tag contract; operator/generated paths and every
1780
+ // other secret value remain explicitly outside this exception.
1781
+ const generatedFoundationDatabaseCredentialResources = [
1782
+ `arn:${options.partition}:secretsmanager:${options.region}:${options.accountId}:secret:foundation-${options.stage}-FoundationDatabaseProxySecret-*`,
1783
+ ];
1784
+ // Native providers reconcile an EBK-owned Secret container through
1785
+ // UpdateSecret regardless of whether it holds a generated database
1786
+ // credential, a machine credential, or operator-supplied material. Bind that
1787
+ // metadata lifecycle to the stable stage-owned namespace instead of
1788
+ // enumerating today's generated container purposes. UpdateSecret can itself
1789
+ // carry plaintext, so reviewed generated source, temporary deployer
1790
+ // credentials, and CloudTrail remain the honest controls. GetSecretValue and
1791
+ // PutSecretValue stay excluded from every Slice container.
1792
+ const stageOwnedSecretContainerResources = [
1793
+ `arn:${options.partition}:secretsmanager:${options.region}:${options.accountId}:secret:ebk/${options.stage}/*`,
1794
+ ];
1795
+ const stageSecretContainerMetadataUpdateResources = [
1796
+ ...generatedFoundationDatabaseCredentialResources,
1797
+ ...stageOwnedSecretContainerResources,
1798
+ ].sort(compareStrings);
1799
+ const machineAuthorizationStackResources = [
1800
+ `arn:${options.partition}:cloudformation:${options.region}:${options.accountId}:stack/*MachineAuthorization*/*`,
1801
+ ];
1802
+ const costAnomalyMonitorResources = [
1803
+ `arn:${options.partition}:ce::${options.accountId}:anomalymonitor/*`,
1804
+ ];
1805
+ const costAnomalySubscriptionResources = [
1806
+ `arn:${options.partition}:ce::${options.accountId}:anomalysubscription/*`,
1807
+ ];
1808
+ const costAnomalyResources = [
1809
+ ...costAnomalyMonitorResources,
1810
+ ...costAnomalySubscriptionResources,
1811
+ ].sort(compareStrings);
1812
+ const productionCostScope = '*/account/production';
1813
+ const eventArchiveResources = [
1814
+ `arn:${options.partition}:events:${options.region}:${options.accountId}:archive/ebk-${options.stage}-foundation-events`,
1815
+ ];
1816
+ const foundationEventBusResources = [
1817
+ `arn:${options.partition}:events:${options.region}:${options.accountId}:event-bus/foundation-${options.stage}-FoundationEventBusBus-*`,
1818
+ ];
1819
+ const stageKmsKeyResources = [
1820
+ `arn:${options.partition}:kms:${options.region}:${options.accountId}:key/*`,
1821
+ ];
1822
+ const stageKmsAliasResources = [
1823
+ `arn:${options.partition}:kms:${options.region}:${options.accountId}:alias/ebk-${options.stage}-*-data-export`,
1824
+ ];
1825
+ const stageStateMachineResources = [
1826
+ `arn:${options.partition}:states:${options.region}:${options.accountId}:stateMachine:*-${options.stage}-*`,
1827
+ ];
1828
+ // Native SST physical state-machine names are derived from Pulumi logical
1829
+ // names and do not necessarily contain the stage. Step Functions exposes the
1830
+ // state machine's resource tags while authorizing both the state machine and
1831
+ // its Standard executions, so the governed execution path uses the exact
1832
+ // account/Region namespace plus the stage tag instead of a name convention.
1833
+ const accountStateMachineResources = [
1834
+ `arn:${options.partition}:states:${options.region}:${options.accountId}:stateMachine:*`,
1835
+ ];
1836
+ const accountExecutionResources = [
1837
+ `arn:${options.partition}:states:${options.region}:${options.accountId}:execution:*:*`,
1838
+ ];
1839
+ const serviceLinkedRoleResources = exports.STAGE_AUTHORITY_SERVICE_LINKED_ROLES.map(({ path }) => `arn:${options.partition}:iam::${options.accountId}:role/aws-service-role/${path}`);
1840
+ const stageAndSharedMutationResources = [
1841
+ `arn:${options.partition}:backup:${options.region}:${options.accountId}:*:*${options.stage}*`,
1842
+ `arn:${options.partition}:budgets::${options.accountId}:budget/*`,
1843
+ ...stageRouterCloudFrontFunctionResources,
1844
+ `arn:${options.partition}:dynamodb:${options.region}:${options.accountId}:table/*-${options.stage}-*`,
1845
+ `arn:${options.partition}:ecr:${options.region}:${options.accountId}:repository/ebk/${options.stage}/*`,
1846
+ `arn:${options.partition}:events:${options.region}:${options.accountId}:archive/ebk-${options.stage}-*`,
1847
+ `arn:${options.partition}:events:${options.region}:${options.accountId}:event-bus/*-${options.stage}-*`,
1848
+ `arn:${options.partition}:events:${options.region}:${options.accountId}:rule/*-${options.stage}-*`,
1849
+ `arn:${options.partition}:iam::${options.accountId}:instance-profile/ebk/${options.stage}/workloads/*`,
1850
+ `arn:${options.partition}:iam::${options.accountId}:role/ebk/${options.stage}/workloads/*`,
1851
+ ...stageKmsAliasResources,
1852
+ `arn:${options.partition}:lambda:${options.region}:${options.accountId}:function:*-${options.stage}-*`,
1853
+ `arn:${options.partition}:rds:${options.region}:${options.accountId}:cluster:*-${options.stage}-*`,
1854
+ `arn:${options.partition}:rds:${options.region}:${options.accountId}:db:*-${options.stage}-*`,
1855
+ `arn:${options.partition}:rds:${options.region}:${options.accountId}:snapshot:*-${options.stage}-*`,
1856
+ `arn:${options.partition}:s3:::*-${options.stage}-*`,
1857
+ `arn:${options.partition}:s3:::*-${options.stage}-*/*`,
1858
+ `arn:${options.partition}:s3:::sst-asset-*`,
1859
+ `arn:${options.partition}:s3:::sst-asset-*/*`,
1860
+ `arn:${options.partition}:s3:::sst-state-*`,
1861
+ `arn:${options.partition}:s3:::sst-state-*/*`,
1862
+ `arn:${options.partition}:secretsmanager:${options.region}:${options.accountId}:secret:ebk/${options.stage}/*`,
1863
+ `arn:${options.partition}:sns:${options.region}:${options.accountId}:*-${options.stage}-*`,
1864
+ `arn:${options.partition}:sqs:${options.region}:${options.accountId}:*-${options.stage}-*`,
1865
+ `arn:${options.partition}:ssm:${options.region}:${options.accountId}:parameter/*${options.stage}*`,
1866
+ ...stageStateMachineResources,
1867
+ `arn:${options.partition}:wafv2:${edgeRegion}:${options.accountId}:global/webacl/*-${options.stage}-*/*`,
1868
+ ].sort(compareStrings);
1869
+ const namedProductionResources = [
1870
+ `arn:${options.partition}:backup:${options.region}:${options.accountId}:backup-vault:*production*`,
1871
+ `arn:${options.partition}:cloudwatch:${options.region}:${options.accountId}:alarm:*production*`,
1872
+ `arn:${options.partition}:cloudwatch::${options.accountId}:dashboard/*production*`,
1873
+ ...productionRouterCloudFrontFunctionResources,
1874
+ `arn:${options.partition}:dynamodb:${options.region}:${options.accountId}:table/*-production-*`,
1875
+ `arn:${options.partition}:ecr:${options.region}:${options.accountId}:repository/ebk/production/*`,
1876
+ `arn:${options.partition}:ecs:${options.region}:${options.accountId}:cluster/*production*`,
1877
+ `arn:${options.partition}:ecs:${options.region}:${options.accountId}:service/*production*/*`,
1878
+ `arn:${options.partition}:elasticloadbalancing:${options.region}:${options.accountId}:loadbalancer/*/*production*/*`,
1879
+ `arn:${options.partition}:elasticloadbalancing:${options.region}:${options.accountId}:targetgroup/*production*/*`,
1880
+ `arn:${options.partition}:events:${options.region}:${options.accountId}:event-bus/*-production-*`,
1881
+ `arn:${options.partition}:events:${options.region}:${options.accountId}:rule/*-production-*`,
1882
+ `arn:${options.partition}:iam::${options.accountId}:instance-profile/ebk/production/*`,
1883
+ `arn:${options.partition}:iam::${options.accountId}:policy/ebk/production/*`,
1884
+ `arn:${options.partition}:iam::${options.accountId}:role/ebk/production/*`,
1885
+ `arn:${options.partition}:kms:${options.region}:${options.accountId}:alias/ebk-production-*-data-export`,
1886
+ `arn:${options.partition}:lambda:${options.region}:${options.accountId}:function:*-production-*`,
1887
+ `arn:${options.partition}:logs:${options.region}:${options.accountId}:log-group:*production*`,
1888
+ `arn:${options.partition}:rds:${options.region}:${options.accountId}:cluster:*-production-*`,
1889
+ `arn:${options.partition}:rds:${options.region}:${options.accountId}:db:*-production-*`,
1890
+ `arn:${options.partition}:rds:${options.region}:${options.accountId}:snapshot:*-production-*`,
1891
+ `arn:${options.partition}:s3:::*-production-*`,
1892
+ `arn:${options.partition}:s3:::*-production-*/*`,
1893
+ `arn:${options.partition}:secretsmanager:${options.region}:${options.accountId}:secret:ebk/production/*`,
1894
+ `arn:${options.partition}:sns:${options.region}:${options.accountId}:*-production-*`,
1895
+ `arn:${options.partition}:sqs:${options.region}:${options.accountId}:*-production-*`,
1896
+ `arn:${options.partition}:ssm:${options.region}:${options.accountId}:parameter/*production*`,
1897
+ `arn:${options.partition}:states:${options.region}:${options.accountId}:stateMachine:*-production-*`,
1898
+ `arn:${options.partition}:wafv2:${edgeRegion}:${options.accountId}:global/webacl/*-production-*/*`,
1899
+ ].sort(compareStrings);
1900
+ const stageAndSharedSstBucketResources = [
1901
+ `arn:${options.partition}:s3:::*-${options.stage}-*`,
1902
+ `arn:${options.partition}:s3:::sst-asset-*`,
1903
+ `arn:${options.partition}:s3:::sst-state-*`,
1904
+ ].sort(compareStrings);
1905
+ const runInstancesExternalReferenceResources = [
1906
+ `arn:${options.partition}:ec2:${options.region}::image/ami-*`,
1907
+ `arn:${options.partition}:ec2:${options.region}::snapshot/snap-*`,
1908
+ ].sort(compareStrings);
1909
+ const runInstancesApprovedReferenceOwners = [
1910
+ options.accountId,
1911
+ ...(options.stage === 'production'
1912
+ ? []
1913
+ : exports.STAGE_AUTHORITY_SST_417_EXTERNAL_AMI_OWNERS_BY_PARTITION[options.partition]),
1914
+ ].sort(compareStrings);
1915
+ const statements = [
1916
+ statement({
1917
+ Action: exports.STAGE_AUTHORITY_REGIONAL_READ_ACTIONS,
1918
+ Condition: {
1919
+ StringEquals: { 'aws:RequestedRegion': options.region },
1920
+ },
1921
+ Effect: 'Allow',
1922
+ Resource: ['*'],
1923
+ Sid: 'ReadFixedRegionalServiceFamilies',
1924
+ }),
1925
+ statement({
1926
+ Action: ['acm:Describe*', 'acm:Get*', 'acm:List*'],
1927
+ Condition: {
1928
+ StringEquals: { 'aws:RequestedRegion': edgeRegion },
1929
+ },
1930
+ Effect: 'Allow',
1931
+ Resource: ['*'],
1932
+ Sid: 'ReadEdgeCertificateControlPlane',
1933
+ }),
1934
+ statement({
1935
+ Action: exports.STAGE_AUTHORITY_EDGE_OBSERVABILITY_READ_ACTIONS,
1936
+ Condition: {
1937
+ StringEquals: { 'aws:RequestedRegion': edgeRegion },
1938
+ },
1939
+ Effect: 'Allow',
1940
+ Resource: ['*'],
1941
+ Sid: 'ReadEdgeObservabilityControlPlane',
1942
+ }),
1943
+ statement({
1944
+ Action: exports.STAGE_AUTHORITY_EDGE_WAF_LOG_GROUP_ACTIONS,
1945
+ Condition: {
1946
+ StringEquals: { 'aws:RequestedRegion': edgeRegion },
1947
+ },
1948
+ Effect: 'Allow',
1949
+ Resource: stageRouterWafLogDestinationResources,
1950
+ Sid: 'ManageOnlyGeneratedEdgeWafLogGroup',
1951
+ }),
1952
+ // CloudWatch Logs models these native WAF delivery calls as account-level
1953
+ // operations. PutResourcePolicy exposes neither a resource ARN nor an
1954
+ // action-specific condition key; reviewed generated source is the control
1955
+ // for its uninspectable payload, and the request remains edge-Region-bound.
1956
+ statement({
1957
+ Action: [
1958
+ ...exports.STAGE_AUTHORITY_EDGE_WAF_LOG_DELIVERY_MUTATION_ACTIONS,
1959
+ // Cloud Control has no resource-level or TypeName condition support.
1960
+ // Use the caller's temporary session, never a service RoleArn. The
1961
+ // underlying resource operations retain the deployer's guardrails.
1962
+ ...exports.STAGE_AUTHORITY_CLOUDCONTROL_EDGE_MUTATION_ACTIONS,
1963
+ // The ordinary regional read grant already covers a same-Region
1964
+ // deployment. CloudFront still needs these exact reads at the edge
1965
+ // endpoint when application resources live elsewhere.
1966
+ ...(options.region === edgeRegion
1967
+ ? []
1968
+ : [
1969
+ 'cloudformation:DescribeType',
1970
+ 'cloudformation:GetResource',
1971
+ 'cloudformation:GetResourceRequestStatus',
1972
+ ]),
1973
+ ],
1974
+ Condition: {
1975
+ StringEquals: { 'aws:RequestedRegion': edgeRegion },
1976
+ },
1977
+ Effect: 'Allow',
1978
+ Resource: ['*'],
1979
+ Sid: 'ManageEdgeWafLogDeliveryControlPlane',
1980
+ }),
1981
+ statement({
1982
+ Action: exports.STAGE_AUTHORITY_GLOBAL_READ_ACTIONS,
1983
+ Effect: 'Allow',
1984
+ Resource: ['*'],
1985
+ Sid: 'ReadFixedGlobalServiceFamilies',
1986
+ }),
1987
+ statement({
1988
+ Action: ['states:DescribeExecution'],
1989
+ Condition: {
1990
+ StringEquals: {
1991
+ 'aws:RequestedRegion': options.region,
1992
+ 'aws:ResourceTag/ebk:stage': options.stage,
1993
+ },
1994
+ },
1995
+ Effect: 'Allow',
1996
+ Resource: accountExecutionResources,
1997
+ Sid: 'DescribeOnlyTaggedStageWorkflowExecutions',
1998
+ }),
1999
+ statement({
2000
+ Action: ['states:DescribeExecution'],
2001
+ Condition: {
2002
+ StringNotEquals: {
2003
+ 'aws:ResourceTag/ebk:stage': options.stage,
2004
+ },
2005
+ },
2006
+ Effect: 'Deny',
2007
+ Resource: accountExecutionResources,
2008
+ Sid: 'DenyWorkflowExecutionReadWithoutStageTag',
2009
+ }),
2010
+ statement({
2011
+ Action: ['states:DescribeExecution'],
2012
+ Effect: 'Deny',
2013
+ NotResource: accountExecutionResources,
2014
+ Sid: 'DenyWorkflowExecutionReadOutsideAccount',
2015
+ }),
2016
+ statement({
2017
+ Action: exports.STAGE_AUTHORITY_REGIONAL_WRITE_ACTIONS,
2018
+ Condition: {
2019
+ StringEquals: { 'aws:RequestedRegion': options.region },
2020
+ StringEqualsIfExists: {
2021
+ 'aws:RequestTag/ebk:stage': options.stage,
2022
+ 'aws:ResourceAccount': options.accountId,
2023
+ 'aws:ResourceTag/ebk:stage': options.stage,
2024
+ },
2025
+ },
2026
+ Effect: 'Allow',
2027
+ Resource: ['*'],
2028
+ Sid: 'MutateFixedRegionalServiceFamilies',
2029
+ }),
2030
+ statement({
2031
+ Action: ['acm:*'],
2032
+ Condition: {
2033
+ StringEquals: { 'aws:RequestedRegion': edgeRegion },
2034
+ StringEqualsIfExists: {
2035
+ 'aws:RequestTag/ebk:stage': options.stage,
2036
+ 'aws:ResourceAccount': options.accountId,
2037
+ 'aws:ResourceTag/ebk:stage': options.stage,
2038
+ },
2039
+ },
2040
+ Effect: 'Allow',
2041
+ Resource: ['*'],
2042
+ Sid: 'MutateEdgeCertificates',
2043
+ }),
2044
+ statement({
2045
+ Action: exports.STAGE_AUTHORITY_S3_REGIONAL_MUTATION_ACTIONS,
2046
+ Condition: {
2047
+ StringEquals: { 'aws:RequestedRegion': options.region },
2048
+ },
2049
+ Effect: 'Allow',
2050
+ Resource: ['*'],
2051
+ Sid: 'MutateStageBucketsInStageRegion',
2052
+ }),
2053
+ statement({
2054
+ Action: ['s3:CreateBucket'],
2055
+ Condition: options.region === 'us-east-1'
2056
+ ? {
2057
+ Null: { 's3:LocationConstraint': 'true' },
2058
+ StringEquals: { 'aws:RequestedRegion': options.region },
2059
+ }
2060
+ : {
2061
+ StringEquals: {
2062
+ 'aws:RequestedRegion': options.region,
2063
+ 's3:LocationConstraint': options.region,
2064
+ },
2065
+ },
2066
+ Effect: 'Allow',
2067
+ Resource: ['*'],
2068
+ Sid: 'CreateBucketOnlyInStageRegion',
2069
+ }),
2070
+ // The generated architecture does not synthesize a stable Grant resource
2071
+ // whose grantee and operation set can be enumerated here. Follow AWS KMS's
2072
+ // integrated-service contract instead: a user cannot call CreateGrant
2073
+ // directly, and the grant remains bound to this account's stage key.
2074
+ statement({
2075
+ Action: ['kms:CreateGrant'],
2076
+ Condition: {
2077
+ Bool: { 'kms:GrantIsForAWSResource': 'true' },
2078
+ StringEquals: {
2079
+ 'aws:RequestedRegion': options.region,
2080
+ 'aws:ResourceTag/ebk:stage': options.stage,
2081
+ },
2082
+ StringEqualsIfExists: {
2083
+ 'aws:ResourceAccount': options.accountId,
2084
+ },
2085
+ },
2086
+ Effect: 'Allow',
2087
+ Resource: stageKmsKeyResources,
2088
+ Sid: 'CreateOnlyAwsResourceKmsGrants',
2089
+ }),
2090
+ statement({
2091
+ Action: ['ec2:RunInstances'],
2092
+ Condition: {
2093
+ StringEquals: { 'aws:RequestedRegion': options.region },
2094
+ },
2095
+ Effect: 'Allow',
2096
+ Resource: ['*'],
2097
+ Sid: 'LaunchStageInfrastructureFromApprovedReferences',
2098
+ }),
2099
+ statement({
2100
+ Action: SECRET_BATCH_VALUE_READ_ACTIONS,
2101
+ Effect: 'Deny',
2102
+ Resource: ['*'],
2103
+ Sid: 'DenySecretsManagerBatchValueReads',
2104
+ }),
2105
+ statement({
2106
+ Action: GENERATED_FOUNDATION_DATABASE_VALUE_ACTIONS,
2107
+ Effect: 'Deny',
2108
+ NotResource: generatedFoundationDatabaseCredentialResources,
2109
+ Sid: 'DenySecretValueAccessOutsideGeneratedFoundationDatabase',
2110
+ }),
2111
+ statement({
2112
+ Action: GENERATED_FOUNDATION_DATABASE_RECONCILIATION_ACTIONS,
2113
+ Condition: {
2114
+ StringNotEquals: {
2115
+ 'aws:ResourceTag/ebk:stage': options.stage,
2116
+ },
2117
+ },
2118
+ Effect: 'Deny',
2119
+ Resource: generatedFoundationDatabaseCredentialResources,
2120
+ Sid: 'DenyGeneratedDatabaseValueAccessWithWrongStageTag',
2121
+ }),
2122
+ statement({
2123
+ Action: STAGE_SECRET_CONTAINER_METADATA_UPDATE_ACTIONS,
2124
+ Effect: 'Deny',
2125
+ NotResource: stageSecretContainerMetadataUpdateResources,
2126
+ Sid: 'DenySecretMetadataUpdateOutsideStageContainers',
2127
+ }),
2128
+ statement({
2129
+ Action: ['ssm:GetParameter', 'ssm:GetParameters'],
2130
+ Effect: 'Deny',
2131
+ NotResource: stageReadableSsmValueResources,
2132
+ Sid: 'DenyUnapprovedSsmValueReads',
2133
+ }),
2134
+ statement({
2135
+ Action: SSM_HISTORY_AND_RECURSIVE_VALUE_READ_ACTIONS,
2136
+ Effect: 'Deny',
2137
+ Resource: ['*'],
2138
+ Sid: 'DenySsmHistoryAndRecursiveValueReads',
2139
+ }),
2140
+ statement({
2141
+ Action: [
2142
+ 'ssm:AddTagsToResource',
2143
+ 'ssm:DeleteParameter',
2144
+ 'ssm:DeleteParameters',
2145
+ 'ssm:LabelParameterVersion',
2146
+ 'ssm:PutParameter',
2147
+ 'ssm:RemoveTagsFromResource',
2148
+ 'ssm:UnlabelParameterVersion',
2149
+ ],
2150
+ Effect: 'Deny',
2151
+ Resource: immutableWorkspaceOwnerResources,
2152
+ Sid: 'DenyOwnerMutation',
2153
+ }),
2154
+ statement({
2155
+ Action: exports.STAGE_AUTHORITY_NON_DEPLOYMENT_ACCOUNT_AND_DATA_ACTIONS,
2156
+ Effect: 'Deny',
2157
+ Resource: ['*'],
2158
+ Sid: 'DenyNonDeploymentControlOperations',
2159
+ }),
2160
+ statement({
2161
+ Action: WORKFLOW_EXECUTION_MUTATION_ACTIONS,
2162
+ Effect: 'Deny',
2163
+ NotResource: [
2164
+ ...accountExecutionResources,
2165
+ ...accountStateMachineResources,
2166
+ ],
2167
+ Sid: 'DenyUnscopedWorkflowExecutionMutation',
2168
+ }),
2169
+ statement({
2170
+ Action: exports.STAGE_AUTHORITY_UNSUPPORTED_WORKFLOW_EXECUTION_ACTIONS,
2171
+ Effect: 'Deny',
2172
+ Resource: ['*'],
2173
+ Sid: 'DenyUnsupportedWorkflowExecutionMutation',
2174
+ }),
2175
+ statement({
2176
+ Action: ['states:StartExecution'],
2177
+ Condition: {
2178
+ Null: { 'aws:ResourceTag/ebk:stage': 'true' },
2179
+ },
2180
+ Effect: 'Deny',
2181
+ Resource: accountStateMachineResources,
2182
+ Sid: 'DenyUntaggedWorkflowExecutionStart',
2183
+ }),
2184
+ statement({
2185
+ Action: ['states:StartExecution'],
2186
+ Condition: {
2187
+ StringEquals: {
2188
+ 'aws:RequestedRegion': options.region,
2189
+ 'aws:ResourceTag/ebk:stage': options.stage,
2190
+ },
2191
+ },
2192
+ Effect: 'Allow',
2193
+ Resource: accountStateMachineResources,
2194
+ Sid: 'StartOnlyTaggedStageWorkflowExecutions',
2195
+ }),
2196
+ statement({
2197
+ Action: ['cloudformation:CreateStack'],
2198
+ Condition: {
2199
+ StringEquals: {
2200
+ 'aws:RequestTag/ebk:stage': options.stage,
2201
+ 'aws:RequestedRegion': options.region,
2202
+ },
2203
+ },
2204
+ Effect: 'Allow',
2205
+ Resource: machineAuthorizationStackResources,
2206
+ Sid: 'CreateTaggedMachineAuthorizationStacks',
2207
+ }),
2208
+ statement({
2209
+ Action: ['cloudformation:DeleteStack', 'cloudformation:UpdateStack'],
2210
+ Condition: {
2211
+ StringEquals: {
2212
+ 'aws:RequestedRegion': options.region,
2213
+ 'aws:ResourceTag/ebk:stage': options.stage,
2214
+ },
2215
+ },
2216
+ Effect: 'Allow',
2217
+ Resource: machineAuthorizationStackResources,
2218
+ Sid: 'MutateTaggedMachineAuthorizationStacks',
2219
+ }),
2220
+ statement({
2221
+ Action: exports.STAGE_AUTHORITY_EVENT_ARCHIVE_CREATE_ACTIONS,
2222
+ Condition: {
2223
+ StringEquals: {
2224
+ 'aws:RequestedRegion': options.region,
2225
+ },
2226
+ },
2227
+ Effect: 'Allow',
2228
+ Resource: eventArchiveResources,
2229
+ Sid: 'CreateNamedFoundationEventArchive',
2230
+ }),
2231
+ statement({
2232
+ Action: exports.STAGE_AUTHORITY_EVENT_ARCHIVE_CREATE_ACTIONS,
2233
+ Condition: {
2234
+ StringEquals: {
2235
+ 'aws:RequestedRegion': options.region,
2236
+ 'aws:ResourceTag/ebk:stage': options.stage,
2237
+ },
2238
+ },
2239
+ Effect: 'Allow',
2240
+ Resource: foundationEventBusResources,
2241
+ Sid: 'CreateArchiveFromTaggedFoundationEventBus',
2242
+ }),
2243
+ statement({
2244
+ Action: exports.STAGE_AUTHORITY_EVENT_ARCHIVE_RESOURCE_ACTIONS,
2245
+ Condition: {
2246
+ StringEquals: {
2247
+ 'aws:RequestedRegion': options.region,
2248
+ },
2249
+ },
2250
+ Effect: 'Allow',
2251
+ Resource: eventArchiveResources,
2252
+ Sid: 'MutateNamedFoundationEventArchive',
2253
+ }),
2254
+ statement({
2255
+ Action: [
2256
+ ...exports.STAGE_AUTHORITY_EVENT_ARCHIVE_CREATE_ACTIONS,
2257
+ ...exports.STAGE_AUTHORITY_EVENT_ARCHIVE_RESOURCE_ACTIONS,
2258
+ ],
2259
+ Effect: 'Deny',
2260
+ NotResource: [...eventArchiveResources, ...foundationEventBusResources],
2261
+ Sid: 'DenyEventArchiveMutationOutsideGeneratedFoundationArchive',
2262
+ }),
2263
+ statement({
2264
+ Action: exports.STAGE_AUTHORITY_KMS_ROTATION_ACTIONS,
2265
+ Condition: {
2266
+ StringEquals: {
2267
+ 'aws:RequestedRegion': options.region,
2268
+ 'aws:ResourceTag/ebk:stage': options.stage,
2269
+ },
2270
+ },
2271
+ Effect: 'Allow',
2272
+ Resource: stageKmsKeyResources,
2273
+ Sid: 'EnableRotationOnStageKmsKeys',
2274
+ }),
2275
+ statement({
2276
+ Action: ['iam:CreateServiceLinkedRole'],
2277
+ Condition: {
2278
+ StringEquals: {
2279
+ 'iam:AWSServiceName': exports.STAGE_AUTHORITY_SERVICE_LINKED_ROLES.map(({ serviceName }) => serviceName),
2280
+ },
2281
+ },
2282
+ Effect: 'Allow',
2283
+ Resource: serviceLinkedRoleResources,
2284
+ Sid: 'CreateOnlyRequiredServiceLinkedRoles',
2285
+ }),
2286
+ statement({
2287
+ Action: exports.STAGE_AUTHORITY_UNSCOPED_CLOUDFRONT_CREATE_ACTIONS,
2288
+ Condition: {
2289
+ StringEquals: { 'aws:RequestedRegion': edgeRegion },
2290
+ },
2291
+ Effect: 'Allow',
2292
+ Resource: ['*'],
2293
+ Sid: 'CreateOnlyGeneratedCloudFrontResources',
2294
+ }),
2295
+ statement({
2296
+ Action: exports.STAGE_AUTHORITY_GLOBAL_WRITE_ACTIONS,
2297
+ Effect: 'Allow',
2298
+ Resource: ['*'],
2299
+ Sid: 'MutateFixedGlobalServiceFamilies',
2300
+ }),
2301
+ statement({
2302
+ Action: exports.STAGE_AUTHORITY_WAF_EDGE_MUTATION_ACTIONS,
2303
+ Condition: {
2304
+ StringEquals: { 'aws:RequestedRegion': edgeRegion },
2305
+ },
2306
+ Effect: 'Allow',
2307
+ Resource: ['*'],
2308
+ Sid: 'MutateCloudFrontScopeWafInEdgeRegion',
2309
+ }),
2310
+ statement({
2311
+ Action: ['route53:CreateHostedZone'],
2312
+ Condition: {
2313
+ Bool: { 'aws:ViaAWSService': 'true' },
2314
+ StringEquals: {
2315
+ 'aws:CalledViaLast': 'servicediscovery.amazonaws.com',
2316
+ },
2317
+ },
2318
+ Effect: 'Allow',
2319
+ Resource: ['*'],
2320
+ Sid: 'CreateOnlyCloudMapPrivateHostedZones',
2321
+ }),
2322
+ statement({
2323
+ Action: exports.STAGE_AUTHORITY_ACCOUNT_SCOPED_GLOBAL_WRITE_ACTIONS,
2324
+ Condition: {
2325
+ StringEquals: { 'aws:RequestedRegion': edgeRegion },
2326
+ },
2327
+ Effect: 'Allow',
2328
+ Resource: [
2329
+ `arn:${options.partition}:cloudfront::${options.accountId}:*/*`,
2330
+ ],
2331
+ Sid: 'MutateAccountCloudFront',
2332
+ }),
2333
+ statement({
2334
+ Action: exports.STAGE_AUTHORITY_CLOUDFRONT_INVALIDATION_ACTIONS,
2335
+ Condition: {
2336
+ StringEquals: {
2337
+ 'aws:RequestedRegion': edgeRegion,
2338
+ 'aws:ResourceTag/ebk:stage': options.stage,
2339
+ },
2340
+ },
2341
+ Effect: 'Allow',
2342
+ Resource: stageCloudFrontDistributionResources,
2343
+ Sid: 'InvalidateOnlyStageCloudFrontDistributions',
2344
+ }),
2345
+ statement({
2346
+ Action: exports.STAGE_AUTHORITY_LAMBDA_DEPLOYMENT_INVOKE_ACTIONS,
2347
+ Condition: {
2348
+ StringEquals: {
2349
+ 'aws:RequestedRegion': options.region,
2350
+ 'aws:ResourceTag/ebk:stage': options.stage,
2351
+ },
2352
+ },
2353
+ Effect: 'Allow',
2354
+ Resource: stageLambdaResources,
2355
+ Sid: 'InvokeOnlyStageLambdaFunctions',
2356
+ }),
2357
+ statement({
2358
+ Action: ['lambda:AddPermission'],
2359
+ Condition: {
2360
+ StringEquals: {
2361
+ 'aws:RequestedRegion': options.region,
2362
+ 'aws:ResourceTag/ebk:stage': options.stage,
2363
+ 'lambda:Principal': LAMBDA_INTEGRATION_PRINCIPALS,
2364
+ },
2365
+ },
2366
+ Effect: 'Allow',
2367
+ Resource: stageLambdaResources,
2368
+ Sid: 'AddOnlyReviewedStageLambdaIntegrations',
2369
+ }),
2370
+ statement({
2371
+ Action: ['lambda:AddPermission'],
2372
+ Condition: {
2373
+ StringEquals: {
2374
+ 'aws:RequestedRegion': options.region,
2375
+ 'aws:ResourceTag/ebk:stage': options.stage,
2376
+ 'lambda:FunctionUrlAuthType': 'NONE',
2377
+ 'lambda:Principal': '*',
2378
+ },
2379
+ },
2380
+ Effect: 'Allow',
2381
+ Resource: stageLambdaResources,
2382
+ Sid: 'AddOnlyPublicStageLambdaFunctionUrlAccess',
2383
+ }),
2384
+ statement({
2385
+ Action: ['lambda:AddPermission'],
2386
+ Condition: {
2387
+ // AddPermission accepts InvokedViaFunctionUrl, but Lambda does not
2388
+ // expose that request member as a caller-side authorization context.
2389
+ // The companion request is distinguishable from the public
2390
+ // InvokeFunctionUrl permission by the absence of FunctionUrlAuthType.
2391
+ Null: {
2392
+ 'lambda:FunctionUrlAuthType': 'true',
2393
+ },
2394
+ StringEquals: {
2395
+ 'aws:RequestedRegion': options.region,
2396
+ 'aws:ResourceTag/ebk:stage': options.stage,
2397
+ 'lambda:Principal': '*',
2398
+ },
2399
+ },
2400
+ Effect: 'Allow',
2401
+ Resource: stageLambdaResources,
2402
+ Sid: 'AddOnlyPublicStageLambdaFunctionUrlInvoke',
2403
+ }),
2404
+ statement({
2405
+ Action: exports.STAGE_AUTHORITY_WAF_LOGGING_ACTIONS,
2406
+ Condition: {
2407
+ ArnLike: {
2408
+ 'wafv2:LogDestinationResource': stageRouterWafLogDestinationResources,
2409
+ },
2410
+ StringEquals: {
2411
+ 'aws:RequestedRegion': edgeRegion,
2412
+ 'aws:ResourceTag/ebk:stage': options.stage,
2413
+ 'wafv2:LogScope': 'CUSTOMER',
2414
+ },
2415
+ },
2416
+ Effect: 'Allow',
2417
+ Resource: stageRouterWebAclResources,
2418
+ Sid: 'PutOnlyStageRouterWafLogging',
2419
+ }),
2420
+ statement({
2421
+ Action: ['budgets:ModifyBudget', 'budgets:TagResource'],
2422
+ Condition: {
2423
+ StringEquals: {
2424
+ 'aws:RequestTag/ebk:stage': options.stage,
2425
+ },
2426
+ },
2427
+ Effect: 'Allow',
2428
+ Resource: stageAccountBudgetResources,
2429
+ Sid: 'CreateOnlyTaggedStageAccountBudget',
2430
+ }),
2431
+ statement({
2432
+ Action: exports.STAGE_AUTHORITY_BUDGET_MUTATION_ACTIONS,
2433
+ Condition: {
2434
+ StringEquals: {
2435
+ 'aws:ResourceTag/ebk:stage': options.stage,
2436
+ },
2437
+ },
2438
+ Effect: 'Allow',
2439
+ Resource: stageAccountBudgetResources,
2440
+ Sid: 'MutateOnlyTaggedStageAccountBudget',
2441
+ }),
2442
+ statement({
2443
+ Action: exports.STAGE_AUTHORITY_RDS_EVENT_SUBSCRIPTION_SOURCE_ACTIONS,
2444
+ Condition: {
2445
+ Null: { 'aws:ResourceTag/ebk:stage': 'true' },
2446
+ },
2447
+ Effect: 'Deny',
2448
+ Resource: productionEventSubscriptionResources,
2449
+ Sid: 'DenyUnscopedDatabaseEventSubscriptionSourceMutation',
2450
+ }),
2451
+ statement({
2452
+ Action: ['lambda:RemovePermission'],
2453
+ Condition: {
2454
+ StringEquals: {
2455
+ 'aws:RequestedRegion': options.region,
2456
+ 'aws:ResourceTag/ebk:stage': options.stage,
2457
+ },
2458
+ },
2459
+ Effect: 'Allow',
2460
+ Resource: stageLambdaResources,
2461
+ Sid: 'RemoveOnlyStageLambdaIntegrations',
2462
+ }),
2463
+ statement({
2464
+ Action: ['lambda:AddPermission', 'lambda:RemovePermission'],
2465
+ Condition: {
2466
+ Null: { 'aws:ResourceTag/ebk:stage': 'true' },
2467
+ },
2468
+ Effect: 'Deny',
2469
+ Resource: ['*'],
2470
+ Sid: 'DenyUnscopedLambdaPermissions',
2471
+ }),
2472
+ statement({
2473
+ Action: ['sns:SetTopicAttributes'],
2474
+ Condition: {
2475
+ StringEquals: {
2476
+ 'aws:RequestedRegion': options.region,
2477
+ },
2478
+ },
2479
+ Effect: 'Allow',
2480
+ Resource: stageTopicResources,
2481
+ Sid: 'SetOnlyStageTopicAttributes',
2482
+ }),
2483
+ // RDS validates that the CreateEventSubscription caller can publish to
2484
+ // its destination topic. The regional service-family allow admits that
2485
+ // control-plane check; this exact deny keeps every other topic closed.
2486
+ // Runtime workloads retain their separately generated least-privilege roles.
2487
+ statement({
2488
+ Action: ['sns:Publish'],
2489
+ Effect: 'Deny',
2490
+ NotResource: generatedFoundationAlertTopicResources,
2491
+ Sid: 'DenyPublishOutsideGeneratedFoundationAlerts',
2492
+ }),
2493
+ statement({
2494
+ Action: ['sqs:SetQueueAttributes'],
2495
+ Condition: {
2496
+ StringEquals: {
2497
+ 'aws:RequestedRegion': options.region,
2498
+ },
2499
+ },
2500
+ Effect: 'Allow',
2501
+ Resource: stageQueueResources,
2502
+ Sid: 'SetOnlyStageQueueAttributes',
2503
+ }),
2504
+ statement({
2505
+ Action: ['sns:SetTopicAttributes'],
2506
+ Effect: 'Deny',
2507
+ NotResource: stageTopicResources,
2508
+ Sid: 'DenyTopicAttributeMutationOutsideStage',
2509
+ }),
2510
+ statement({
2511
+ Action: ['sqs:SetQueueAttributes'],
2512
+ Effect: 'Deny',
2513
+ NotResource: stageQueueResources,
2514
+ Sid: 'DenyQueueAttributeMutationOutsideStage',
2515
+ }),
2516
+ statement({
2517
+ Action: [
2518
+ 'iam:AddRoleToInstanceProfile',
2519
+ 'iam:CreateInstanceProfile',
2520
+ 'iam:DeleteInstanceProfile',
2521
+ 'iam:DeleteRole',
2522
+ 'iam:DeleteRolePolicy',
2523
+ 'iam:PutRolePolicy',
2524
+ 'iam:RemoveRoleFromInstanceProfile',
2525
+ 'iam:TagInstanceProfile',
2526
+ 'iam:TagRole',
2527
+ 'iam:UntagInstanceProfile',
2528
+ 'iam:UntagRole',
2529
+ 'iam:UpdateRole',
2530
+ 'iam:UpdateRoleDescription',
2531
+ ],
2532
+ Effect: 'Allow',
2533
+ Resource: [
2534
+ options.identity.workloadInstanceProfileArnPattern,
2535
+ options.identity.workloadRoleArnPattern,
2536
+ ],
2537
+ Sid: 'ManageStageWorkloadIdentities',
2538
+ }),
2539
+ statement({
2540
+ Action: ['iam:CreateRole'],
2541
+ Condition: {
2542
+ StringEquals: {
2543
+ 'iam:PermissionsBoundary': options.identity.boundaryArn,
2544
+ },
2545
+ },
2546
+ Effect: 'Allow',
2547
+ Resource: [options.identity.workloadRoleArnPattern],
2548
+ Sid: 'CreateOnlyBoundaryConstrainedStageWorkloadRoles',
2549
+ }),
2550
+ statement({
2551
+ Action: ['iam:PutRolePermissionsBoundary'],
2552
+ Condition: {
2553
+ StringEquals: {
2554
+ 'iam:PermissionsBoundary': options.identity.boundaryArn,
2555
+ },
2556
+ },
2557
+ Effect: 'Allow',
2558
+ Resource: [options.identity.workloadRoleArnPattern],
2559
+ Sid: 'ApplyExactStageRuntimeBoundary',
2560
+ }),
2561
+ statement({
2562
+ Action: ['iam:AttachRolePolicy', 'iam:DetachRolePolicy'],
2563
+ Condition: {
2564
+ ArnEquals: {
2565
+ 'iam:PermissionsBoundary': options.identity.boundaryArn,
2566
+ 'iam:PolicyARN': managedPolicies,
2567
+ },
2568
+ },
2569
+ Effect: 'Allow',
2570
+ Resource: [options.identity.workloadRoleArnPattern],
2571
+ Sid: 'AttachOnlyPinnedAwsRuntimePolicies',
2572
+ }),
2573
+ statement({
2574
+ Action: ['iam:PassRole'],
2575
+ Condition: {
2576
+ StringEquals: {
2577
+ 'iam:PassedToService': [
2578
+ 'appconfig.amazonaws.com',
2579
+ 'ec2.amazonaws.com',
2580
+ 'ecs-tasks.amazonaws.com',
2581
+ 'lambda.amazonaws.com',
2582
+ 'states.amazonaws.com',
2583
+ ].sort(compareStrings),
2584
+ },
2585
+ },
2586
+ Effect: 'Allow',
2587
+ Resource: [options.identity.workloadRoleArnPattern],
2588
+ Sid: 'PassOnlyStageWorkloadRoles',
2589
+ }),
2590
+ statement({
2591
+ Action: ['iam:PassRole'],
2592
+ Condition: {
2593
+ StringNotEquals: {
2594
+ 'iam:PassedToService': 'ec2.amazonaws.com',
2595
+ },
2596
+ },
2597
+ Effect: 'Deny',
2598
+ Resource: foundationNatWorkloadRoleResources,
2599
+ Sid: 'DenyFoundationNatRolePassOutsideEc2',
2600
+ }),
2601
+ statement({
2602
+ Action: PRIVILEGE_CONSTRUCTION_ACTIONS,
2603
+ Effect: 'Deny',
2604
+ Resource: ['*'],
2605
+ Sid: 'DenyAccountAndPrivilegeAdministration',
2606
+ }),
2607
+ statement({
2608
+ Action: RESOURCE_POLICY_AND_TRUST_EXPANSION_ACTIONS,
2609
+ Effect: 'Deny',
2610
+ Resource: ['*'],
2611
+ Sid: 'DenyUnreviewableResourcePolicyAndTrustExpansion',
2612
+ }),
2613
+ statement({
2614
+ Action: exports.STAGE_AUTHORITY_UNSUPPORTED_REPLICATION_AND_TOPOLOGY_ACTIONS,
2615
+ Effect: 'Deny',
2616
+ Resource: ['*'],
2617
+ Sid: 'DenyUnsupportedReplicationAndTopology',
2618
+ }),
2619
+ statement({
2620
+ Action: [
2621
+ 'servicediscovery:CreateHttpNamespace',
2622
+ 'servicediscovery:CreatePublicDnsNamespace',
2623
+ ],
2624
+ Effect: 'Deny',
2625
+ Resource: ['*'],
2626
+ Sid: 'DenyNonPrivateServiceDiscoveryNamespaces',
2627
+ }),
2628
+ statement({
2629
+ Action: exports.STAGE_AUTHORITY_S3_BUCKET_POLICY_MUTATION_ACTIONS,
2630
+ Effect: 'Deny',
2631
+ NotResource: stageAndSharedSstBucketResources,
2632
+ Sid: 'DenyBucketPolicyMutationOutsideStageAndSstBootstrap',
2633
+ }),
2634
+ statement({
2635
+ Action: ['lambda:AddPermission'],
2636
+ Condition: {
2637
+ StringNotEquals: {
2638
+ 'lambda:Principal': REVIEWED_LAMBDA_PERMISSION_PRINCIPALS,
2639
+ },
2640
+ },
2641
+ Effect: 'Deny',
2642
+ Resource: stageLambdaResources,
2643
+ Sid: 'DenyUnreviewedLambdaIntegrationPrincipal',
2644
+ }),
2645
+ statement({
2646
+ Action: ['budgets:UntagResource'],
2647
+ Condition: {
2648
+ 'ForAnyValue:StringEquals': {
2649
+ 'aws:TagKeys': 'ebk:stage',
2650
+ },
2651
+ },
2652
+ Effect: 'Deny',
2653
+ Resource: stageAccountBudgetResources,
2654
+ Sid: 'DenyStageAccountBudgetStageTagRemoval',
2655
+ }),
2656
+ statement({
2657
+ Action: IAM_AUTHORITY_MUTATION_ACTIONS,
2658
+ Effect: 'Deny',
2659
+ Resource: [
2660
+ options.identity.boundaryArn,
2661
+ ...options.identity.deploymentPolicyArns,
2662
+ options.identity.deploymentRoleArn,
2663
+ ],
2664
+ Sid: 'DenyStageAuthorityMutation',
2665
+ }),
2666
+ statement({
2667
+ Action: ['iam:DeleteRolePermissionsBoundary'],
2668
+ Effect: 'Deny',
2669
+ Resource: [options.identity.workloadRoleArnPattern],
2670
+ Sid: 'DenyRuntimeBoundaryRemoval',
2671
+ }),
2672
+ statement({
2673
+ Action: ['iam:UpdateAssumeRolePolicy'],
2674
+ Effect: 'Deny',
2675
+ Resource: [options.identity.workloadRoleArnPattern],
2676
+ Sid: 'DenyRuntimeTrustPolicyMutation',
2677
+ }),
2678
+ statement({
2679
+ Action: ['iam:PutRolePermissionsBoundary'],
2680
+ Condition: {
2681
+ ArnNotEquals: {
2682
+ 'iam:PermissionsBoundary': options.identity.boundaryArn,
2683
+ },
2684
+ },
2685
+ Effect: 'Deny',
2686
+ Resource: [options.identity.workloadRoleArnPattern],
2687
+ Sid: 'DenyRuntimeBoundarySubstitution',
2688
+ }),
2689
+ statement({
2690
+ Action: exports.STAGE_AUTHORITY_WORKLOAD_IDENTITY_POLICY_ACTIONS,
2691
+ Condition: {
2692
+ ArnNotEquals: {
2693
+ 'iam:PermissionsBoundary': options.identity.boundaryArn,
2694
+ },
2695
+ },
2696
+ Effect: 'Deny',
2697
+ Resource: [options.identity.workloadRoleArnPattern],
2698
+ Sid: 'DenyUnboundedStageWorkloadIdentityPolicyMutation',
2699
+ }),
2700
+ statement({
2701
+ Action: ['iam:AttachRolePolicy'],
2702
+ Condition: {
2703
+ ArnNotEquals: { 'iam:PolicyARN': managedPolicies },
2704
+ },
2705
+ Effect: 'Deny',
2706
+ Resource: [options.identity.workloadRoleArnPattern],
2707
+ Sid: 'DenyUnapprovedManagedPolicyAttachment',
2708
+ }),
2709
+ statement({
2710
+ Action: ['acm:*'],
2711
+ Condition: {
2712
+ StringNotEquals: {
2713
+ 'aws:RequestedRegion': [options.region, edgeRegion],
2714
+ },
2715
+ },
2716
+ Effect: 'Deny',
2717
+ Resource: ['*'],
2718
+ Sid: 'DenyAcmMutationOutsideStageAndEdgeRegions',
2719
+ }),
2720
+ statement({
2721
+ Action: [
2722
+ ...exports.STAGE_AUTHORITY_S3_REGIONAL_MUTATION_ACTIONS,
2723
+ 's3:CreateBucket',
2724
+ ],
2725
+ Condition: {
2726
+ StringNotEquals: { 'aws:RequestedRegion': options.region },
2727
+ },
2728
+ Effect: 'Deny',
2729
+ Resource: ['*'],
2730
+ Sid: 'DenyS3MutationOutsideStageRegion',
2731
+ }),
2732
+ statement({
2733
+ Action: [
2734
+ ...exports.STAGE_AUTHORITY_ACCOUNT_SCOPED_GLOBAL_WRITE_ACTIONS,
2735
+ ...exports.STAGE_AUTHORITY_CLOUDFRONT_INVALIDATION_ACTIONS,
2736
+ ...exports.STAGE_AUTHORITY_EDGE_WAF_LOG_DELIVERY_MUTATION_ACTIONS,
2737
+ ...exports.STAGE_AUTHORITY_UNSCOPED_CLOUDFRONT_CREATE_ACTIONS,
2738
+ ...exports.STAGE_AUTHORITY_WAF_EDGE_MUTATION_ACTIONS,
2739
+ ...exports.STAGE_AUTHORITY_WAF_LOGGING_ACTIONS,
2740
+ ],
2741
+ Condition: {
2742
+ StringNotEquals: { 'aws:RequestedRegion': edgeRegion },
2743
+ },
2744
+ Effect: 'Deny',
2745
+ Resource: ['*'],
2746
+ Sid: 'DenyEdgeControlMutationOutsideEdgeRegion',
2747
+ }),
2748
+ statement({
2749
+ Action: [
2750
+ ...exports.STAGE_AUTHORITY_REGIONAL_MUTATION_FAMILIES.filter((family) => family !== 'cloudformation:*'),
2751
+ ...exports.STAGE_AUTHORITY_CLOUDFORMATION_LIFECYCLE_ACTIONS,
2752
+ ],
2753
+ Condition: {
2754
+ StringNotEquals: { 'aws:RequestedRegion': options.region },
2755
+ },
2756
+ Effect: 'Deny',
2757
+ Resource: ['*'],
2758
+ Sid: 'DenyMutationOutsideStageRegion',
2759
+ }),
2760
+ statement({
2761
+ Action: exports.STAGE_AUTHORITY_LOGS_MUTATION_FAMILIES,
2762
+ Condition: {
2763
+ StringNotEquals: {
2764
+ 'aws:RequestedRegion': [options.region, edgeRegion],
2765
+ },
2766
+ },
2767
+ Effect: 'Deny',
2768
+ Resource: ['*'],
2769
+ Sid: 'DenyLogsMutationOutsideStageAndEdgeRegions',
2770
+ }),
2771
+ // When the application and CloudFront edge control planes share a Region,
2772
+ // RequestedRegion cannot distinguish their log groups. In that case admit
2773
+ // only the generated application and API execution-log namespaces so both
2774
+ // create-time and existing-resource lifecycle calls remain bounded.
2775
+ statement({
2776
+ Action: exports.STAGE_AUTHORITY_EDGE_WAF_LOG_GROUP_ACTIONS,
2777
+ Condition: {
2778
+ StringEquals: { 'aws:RequestedRegion': edgeRegion },
2779
+ },
2780
+ Effect: 'Deny',
2781
+ NotResource: generatedEdgeLogGroupMutationResources,
2782
+ Sid: 'DenyEdgeLogGroupMutationOutsideGeneratedStageLogs',
2783
+ }),
2784
+ statement({
2785
+ Action: exports.STAGE_AUTHORITY_CROSS_ACCOUNT_MUTATION_ACTIONS,
2786
+ Condition: {
2787
+ Null: { 'aws:ResourceAccount': 'false' },
2788
+ StringNotEquals: { 'aws:ResourceAccount': options.accountId },
2789
+ },
2790
+ Effect: 'Deny',
2791
+ Resource: ['*'],
2792
+ Sid: 'DenyCrossAccountMutationWhenResourceAccountIsKnown',
2793
+ }),
2794
+ statement({
2795
+ Action: ['ec2:RunInstances'],
2796
+ Condition: {
2797
+ Null: { 'aws:ResourceAccount': 'false' },
2798
+ StringNotEquals: { 'aws:ResourceAccount': options.accountId },
2799
+ },
2800
+ Effect: 'Deny',
2801
+ NotResource: runInstancesExternalReferenceResources,
2802
+ Sid: 'DenyCrossAccountRunInstancesTargets',
2803
+ }),
2804
+ statement({
2805
+ Action: ['ec2:RunInstances'],
2806
+ Condition: {
2807
+ StringNotEquals: {
2808
+ 'ec2:Owner': runInstancesApprovedReferenceOwners,
2809
+ },
2810
+ },
2811
+ Effect: 'Deny',
2812
+ Resource: runInstancesExternalReferenceResources,
2813
+ Sid: 'DenyRunInstancesFromUnapprovedReferenceOwners',
2814
+ }),
2815
+ statement({
2816
+ Action: exports.STAGE_AUTHORITY_KNOWN_STAGE_MUTATION_ACTIONS,
2817
+ Condition: {
2818
+ Null: { 'aws:ResourceTag/ebk:stage': 'false' },
2819
+ StringNotEquals: { 'aws:ResourceTag/ebk:stage': options.stage },
2820
+ },
2821
+ Effect: 'Deny',
2822
+ Resource: ['*'],
2823
+ Sid: 'DenyKnownOtherStageResourceMutation',
2824
+ }),
2825
+ statement({
2826
+ Action: exports.STAGE_AUTHORITY_UNTAGGED_DESTRUCTIVE_ACTIONS,
2827
+ Condition: {
2828
+ Null: { 'aws:ResourceTag/ebk:stage': 'true' },
2829
+ },
2830
+ Effect: 'Deny',
2831
+ NotResource: stageAndSharedMutationResources,
2832
+ Sid: 'DenyUntaggedMutationOutsideStageAndSstResources',
2833
+ }),
2834
+ statement({
2835
+ Action: ['*'],
2836
+ Condition: {
2837
+ Null: { 'aws:RequestTag/ebk:stage': 'false' },
2838
+ StringNotEquals: { 'aws:RequestTag/ebk:stage': options.stage },
2839
+ },
2840
+ Effect: 'Deny',
2841
+ Resource: ['*'],
2842
+ Sid: 'DenyExplicitOtherStageRequestTag',
2843
+ }),
2844
+ ];
2845
+ if (options.stage !== 'production') {
2846
+ statements.push(statement({
2847
+ Action: ['kms:ScheduleKeyDeletion'],
2848
+ Condition: {
2849
+ StringEquals: {
2850
+ 'aws:RequestedRegion': options.region,
2851
+ 'aws:ResourceTag/ebk:management': 'standard-data-export',
2852
+ 'aws:ResourceTag/ebk:stage': options.stage,
2853
+ },
2854
+ },
2855
+ Effect: 'Allow',
2856
+ Resource: stageKmsKeyResources,
2857
+ Sid: 'RetireOnlyTaggedNonProductionKmsKeys',
2858
+ }), statement({
2859
+ Action: exports.STAGE_AUTHORITY_KNOWN_STAGE_MUTATION_ACTIONS,
2860
+ Condition: {
2861
+ StringEquals: { 'aws:ResourceTag/ebk:stage': 'production' },
2862
+ },
2863
+ Effect: 'Deny',
2864
+ Resource: ['*'],
2865
+ Sid: 'DenyNonProductionAccessToProductionTaggedResources',
2866
+ }), statement({
2867
+ Action: exports.STAGE_AUTHORITY_KNOWN_STAGE_MUTATION_ACTIONS,
2868
+ Effect: 'Deny',
2869
+ Resource: namedProductionResources,
2870
+ Sid: 'DenyNonProductionAccessToNamedProductionResources',
2871
+ }), statement({
2872
+ Action: exports.STAGE_AUTHORITY_RDS_EVENT_SUBSCRIPTION_SOURCE_ACTIONS,
2873
+ Effect: 'Deny',
2874
+ Resource: ['*'],
2875
+ Sid: 'DenyNonProductionDatabaseEventSubscriptionSourceMutation',
2876
+ }));
2877
+ }
2878
+ if (options.stage === 'production') {
2879
+ statements.push(statement({
2880
+ Action: ['kms:ScheduleKeyDeletion'],
2881
+ Effect: 'Deny',
2882
+ Resource: stageKmsKeyResources,
2883
+ Sid: 'DenyProtectedProductionKmsKeyDeletion',
2884
+ }), statement({
2885
+ Action: ['kms:DeleteAlias'],
2886
+ Effect: 'Deny',
2887
+ Resource: productionDataExportAliasResources,
2888
+ Sid: 'DenyProtectedProductionDataExportAliasDeletion',
2889
+ }), statement({
2890
+ Action: [
2891
+ 's3:DeleteBucket',
2892
+ 's3:DeleteBucketPolicy',
2893
+ 's3:DeleteObject',
2894
+ 's3:DeleteObjectVersion',
2895
+ ],
2896
+ Effect: 'Deny',
2897
+ Resource: productionDataExportBucketResources,
2898
+ Sid: 'DenyProtectedProductionDataExportDeletion',
2899
+ }), statement({
2900
+ Action: exports.STAGE_AUTHORITY_RDS_EVENT_SUBSCRIPTION_SOURCE_ACTIONS,
2901
+ Condition: {
2902
+ StringEquals: {
2903
+ 'aws:RequestedRegion': options.region,
2904
+ 'aws:ResourceTag/ebk:stage': 'production',
2905
+ },
2906
+ },
2907
+ Effect: 'Allow',
2908
+ Resource: productionEventSubscriptionResources,
2909
+ Sid: 'MutateOnlyProductionDatabaseEventSubscriptionSources',
2910
+ }), statement({
2911
+ Action: exports.STAGE_AUTHORITY_COST_ANOMALY_READ_ACTIONS,
2912
+ Condition: {
2913
+ StringLike: {
2914
+ 'aws:ResourceTag/ebk:cost-scope': productionCostScope,
2915
+ },
2916
+ },
2917
+ Effect: 'Allow',
2918
+ Resource: costAnomalyResources,
2919
+ Sid: 'ReadProductionCostAnomalyControl',
2920
+ }), statement({
2921
+ Action: exports.STAGE_AUTHORITY_COST_ANOMALY_CREATE_ACTIONS,
2922
+ Condition: {
2923
+ StringEquals: {
2924
+ 'aws:RequestTag/ebk:stage': options.stage,
2925
+ },
2926
+ StringLike: {
2927
+ 'aws:RequestTag/ebk:cost-scope': productionCostScope,
2928
+ },
2929
+ },
2930
+ Effect: 'Allow',
2931
+ Resource: ['*'],
2932
+ Sid: 'CreateProductionCostAnomalyControl',
2933
+ }), statement({
2934
+ Action: exports.STAGE_AUTHORITY_COST_ANOMALY_RESOURCE_WRITE_ACTIONS,
2935
+ Condition: {
2936
+ StringLike: {
2937
+ 'aws:ResourceTag/ebk:cost-scope': productionCostScope,
2938
+ },
2939
+ },
2940
+ Effect: 'Allow',
2941
+ Resource: costAnomalyResources,
2942
+ Sid: 'MutateProductionCostAnomalyControl',
2943
+ }), statement({
2944
+ Action: ['ce:TagResource'],
2945
+ Condition: {
2946
+ Null: { 'aws:RequestTag/ebk:cost-scope': 'false' },
2947
+ StringNotLike: {
2948
+ 'aws:RequestTag/ebk:cost-scope': productionCostScope,
2949
+ },
2950
+ },
2951
+ Effect: 'Deny',
2952
+ Resource: costAnomalyResources,
2953
+ Sid: 'DenyProductionCostScopeSubstitution',
2954
+ }), statement({
2955
+ Action: ['ce:UntagResource'],
2956
+ Condition: {
2957
+ 'ForAnyValue:StringEquals': {
2958
+ 'aws:TagKeys': 'ebk:cost-scope',
2959
+ },
2960
+ },
2961
+ Effect: 'Deny',
2962
+ Resource: costAnomalyResources,
2963
+ Sid: 'DenyProductionCostScopeRemoval',
2964
+ }), statement({
2965
+ Action: [
2966
+ 'backup:DeleteRecoveryPoint',
2967
+ 'rds:DeleteDBCluster',
2968
+ 'rds:DeleteDBClusterAutomatedBackup',
2969
+ 'rds:DeleteDBInstance',
2970
+ 'rds:DeleteDBSnapshot',
2971
+ ],
2972
+ Effect: 'Deny',
2973
+ Resource: productionDatabaseResources,
2974
+ Sid: 'DenyProtectedProductionDatabaseDeletion',
2975
+ }), statement({
2976
+ Action: [
2977
+ 'backup:DeleteBackupPlan',
2978
+ 'backup:DeleteBackupSelection',
2979
+ 'backup:DeleteBackupVault',
2980
+ 'backup:DeleteRecoveryPoint',
2981
+ ],
2982
+ Effect: 'Deny',
2983
+ Resource: productionRetentionResources,
2984
+ Sid: 'DenyProtectedProductionRetentionDeletion',
2985
+ }));
2986
+ }
2987
+ if (options.stage === 'development') {
2988
+ admitDevelopmentTaskNamespaces(statements);
2989
+ const privilege = statements.find(({ Sid }) => Sid === 'DenyAccountAndPrivilegeAdministration');
2990
+ if (!privilege?.Action)
2991
+ throw new Error('Deployment privilege guard is missing.');
2992
+ privilege.Action = privilege.Action.filter((action) => action !== 'sts:AssumeRole');
2993
+ // Native SST EnvFor assumes the SSR dev-server role, not the deployment
2994
+ // identity, for local application code. Preserve every other assumption
2995
+ // deny, protected-stage policy, created-role boundary and trust control.
2996
+ // Native physical names can truncate even the component suffix for long
2997
+ // valid Slice names. Bind purpose by a generated role tag, not that suffix.
2998
+ const nativeWebRoles = [options.identity.workloadRoleArnPattern];
2999
+ statements.push(...Object.entries({
3000
+ Region: ['aws:RequestedRegion', options.region],
3001
+ Session: ['sts:RoleSessionName', 'sst-dev'],
3002
+ Purpose: ['aws:ResourceTag/ebk:dev-runtime', 'web'],
3003
+ }).map(([label, [key, value]]) => statement({
3004
+ Sid: `DenyDevAssume${label}`,
3005
+ Effect: 'Deny',
3006
+ Action: ['sts:AssumeRole'],
3007
+ Resource: nativeWebRoles,
3008
+ // Negated conditions also deny a missing key. Separate statements
3009
+ // encode OR: any invalid attribute blocks an unrelated attached Allow.
3010
+ Condition: { StringNotEquals: { [key]: value } },
3011
+ })), statement({
3012
+ Sid: 'DenyDevAssumeStage',
3013
+ Effect: 'Deny',
3014
+ Action: ['sts:AssumeRole'],
3015
+ Resource: nativeWebRoles,
3016
+ Condition: {
3017
+ StringNotLike: {
3018
+ 'aws:ResourceTag/ebk:stage': ['development', TASK_STAGE_IAM_SHAPE],
3019
+ },
3020
+ },
3021
+ }), statement({
3022
+ Sid: 'AssumeNativeDevelopmentWebRuntime',
3023
+ Effect: 'Allow',
3024
+ Action: ['sts:AssumeRole'],
3025
+ Resource: nativeWebRoles,
3026
+ Condition: {
3027
+ StringEquals: {
3028
+ 'aws:RequestedRegion': options.region,
3029
+ 'sts:RoleSessionName': 'sst-dev',
3030
+ 'aws:ResourceTag/ebk:dev-runtime': 'web',
3031
+ },
3032
+ StringLike: {
3033
+ 'aws:ResourceTag/ebk:stage': ['development', TASK_STAGE_IAM_SHAPE],
3034
+ },
3035
+ },
3036
+ }), statement({
3037
+ Sid: 'DenyAssumptionOutsideNativeDevelopmentWebRuntime',
3038
+ Effect: 'Deny',
3039
+ Action: ['sts:AssumeRole'],
3040
+ NotResource: nativeWebRoles,
3041
+ }));
3042
+ statements.push(...nativeDevelopmentTransportStatements({
3043
+ accountId: options.accountId,
3044
+ partition: options.partition,
3045
+ region: options.region,
3046
+ initialize: true,
3047
+ }));
3048
+ }
3049
+ let groups = [
3050
+ {
3051
+ kind: 'read',
3052
+ logicalId: 'StageDeploymentReadPolicy',
3053
+ sids: [
3054
+ 'DenyGeneratedDatabaseValueAccessWithWrongStageTag',
3055
+ 'DenyNonPrivateServiceDiscoveryNamespaces',
3056
+ 'DenyRuntimeBoundaryRemoval',
3057
+ 'DenySecretsManagerBatchValueReads',
3058
+ 'DenySecretValueAccessOutsideGeneratedFoundationDatabase',
3059
+ 'DenySsmHistoryAndRecursiveValueReads',
3060
+ 'DenyWorkflowExecutionReadOutsideAccount',
3061
+ 'DenyUnapprovedSsmValueReads',
3062
+ 'CreateOnlyAwsResourceKmsGrants',
3063
+ 'ManageOnlyGeneratedEdgeWafLogGroup',
3064
+ 'PutOnlyStageRouterWafLogging',
3065
+ 'ReadFixedGlobalServiceFamilies',
3066
+ 'ReadFixedRegionalServiceFamilies',
3067
+ ...(options.stage === 'development'
3068
+ ? [
3069
+ 'InitializeNativeDevelopmentTransport',
3070
+ 'ConnectNativeDevelopmentTransport',
3071
+ 'UseNativeDevelopmentNamespace',
3072
+ ]
3073
+ : []),
3074
+ 'DenyWorkflowExecutionReadWithoutStageTag',
3075
+ 'DescribeOnlyTaggedStageWorkflowExecutions',
3076
+ ...(options.stage === 'production'
3077
+ ? ['ReadProductionCostAnomalyControl']
3078
+ : []),
3079
+ ],
3080
+ },
3081
+ {
3082
+ kind: 'regional-mutation',
3083
+ logicalId: 'StageDeploymentRegionalMutationPolicy',
3084
+ sids: [
3085
+ 'CreateOnlyCloudMapPrivateHostedZones',
3086
+ 'CreateBucketOnlyInStageRegion',
3087
+ 'DenyAcmMutationOutsideStageAndEdgeRegions',
3088
+ 'DenyEdgeControlMutationOutsideEdgeRegion',
3089
+ 'DenyMutationOutsideStageRegion',
3090
+ 'DenyS3MutationOutsideStageRegion',
3091
+ 'DenySecretMetadataUpdateOutsideStageContainers',
3092
+ 'DenyUnscopedWorkflowExecutionMutation',
3093
+ 'InvokeOnlyStageLambdaFunctions',
3094
+ 'MutateEdgeCertificates',
3095
+ 'MutateFixedRegionalServiceFamilies',
3096
+ 'MutateStageBucketsInStageRegion',
3097
+ ],
3098
+ },
3099
+ {
3100
+ kind: 'global-iam-mutation',
3101
+ logicalId: 'StageDeploymentGlobalIamMutationPolicy',
3102
+ sids: [
3103
+ 'AddOnlyReviewedStageLambdaIntegrations',
3104
+ 'ApplyExactStageRuntimeBoundary',
3105
+ 'AttachOnlyPinnedAwsRuntimePolicies',
3106
+ 'CreateOnlyBoundaryConstrainedStageWorkloadRoles',
3107
+ 'DenyFoundationNatRolePassOutsideEc2',
3108
+ 'DenyQueueAttributeMutationOutsideStage',
3109
+ 'DenyStageAuthorityMutation',
3110
+ 'DenyTopicAttributeMutationOutsideStage',
3111
+ 'DenyUnscopedLambdaPermissions',
3112
+ 'ManageStageWorkloadIdentities',
3113
+ ...(options.stage === 'development'
3114
+ ? ['AssumeNativeDevelopmentWebRuntime']
3115
+ : []),
3116
+ 'PassOnlyStageWorkloadRoles',
3117
+ 'RemoveOnlyStageLambdaIntegrations',
3118
+ 'SetOnlyStageQueueAttributes',
3119
+ 'SetOnlyStageTopicAttributes',
3120
+ ],
3121
+ },
3122
+ {
3123
+ kind: 'global-resource-mutation',
3124
+ logicalId: 'StageDeploymentGlobalResourceMutationPolicy',
3125
+ sids: [
3126
+ 'DenyCrossAccountMutationWhenResourceAccountIsKnown',
3127
+ ...(options.stage === 'development'
3128
+ ? ['DenyRuntimeTrustPolicyMutation']
3129
+ : []),
3130
+ ...(options.stage === 'development'
3131
+ ? ['ReadEdgeCertificateControlPlane']
3132
+ : []),
3133
+ ...(options.stage === 'development'
3134
+ ? ['ReadEdgeObservabilityControlPlane']
3135
+ : []),
3136
+ 'DenyCrossAccountRunInstancesTargets',
3137
+ 'DenyLogsMutationOutsideStageAndEdgeRegions',
3138
+ 'DenyRunInstancesFromUnapprovedReferenceOwners',
3139
+ 'DenyUnsupportedReplicationAndTopology',
3140
+ 'LaunchStageInfrastructureFromApprovedReferences',
3141
+ 'MutateAccountCloudFront',
3142
+ 'MutateCloudFrontScopeWafInEdgeRegion',
3143
+ 'ManageEdgeWafLogDeliveryControlPlane',
3144
+ 'MutateFixedGlobalServiceFamilies',
3145
+ 'CreateOnlyTaggedStageAccountBudget',
3146
+ 'DenyStageAccountBudgetStageTagRemoval',
3147
+ 'MutateOnlyTaggedStageAccountBudget',
3148
+ ],
3149
+ },
3150
+ {
3151
+ kind: 'generated-resource-mutation',
3152
+ logicalId: 'StageDeploymentGeneratedResourceMutationPolicy',
3153
+ sids: [
3154
+ ...(options.stage === 'development'
3155
+ ? ['DenyKnownOtherStageResourceMutation']
3156
+ : []),
3157
+ 'AddOnlyPublicStageLambdaFunctionUrlAccess',
3158
+ 'AddOnlyPublicStageLambdaFunctionUrlInvoke',
3159
+ 'CreateOnlyRequiredServiceLinkedRoles',
3160
+ 'CreateArchiveFromTaggedFoundationEventBus',
3161
+ 'CreateNamedFoundationEventArchive',
3162
+ 'CreateTaggedMachineAuthorizationStacks',
3163
+ 'DenyPublishOutsideGeneratedFoundationAlerts',
3164
+ 'EnableRotationOnStageKmsKeys',
3165
+ 'InvalidateOnlyStageCloudFrontDistributions',
3166
+ 'MutateNamedFoundationEventArchive',
3167
+ 'MutateTaggedMachineAuthorizationStacks',
3168
+ 'DenyOwnerMutation',
3169
+ ...(options.stage !== 'production'
3170
+ ? ['RetireOnlyTaggedNonProductionKmsKeys']
3171
+ : []),
3172
+ 'DenyUntaggedWorkflowExecutionStart',
3173
+ 'StartOnlyTaggedStageWorkflowExecutions',
3174
+ ...(options.stage === 'production'
3175
+ ? [
3176
+ 'CreateProductionCostAnomalyControl',
3177
+ 'DenyProductionCostScopeRemoval',
3178
+ 'DenyProductionCostScopeSubstitution',
3179
+ 'MutateOnlyProductionDatabaseEventSubscriptionSources',
3180
+ 'MutateProductionCostAnomalyControl',
3181
+ ]
3182
+ : []),
3183
+ ],
3184
+ },
3185
+ {
3186
+ kind: 'stage-containment',
3187
+ logicalId: 'StageDeploymentStageContainmentPolicy',
3188
+ sids: [
3189
+ 'CreateOnlyGeneratedCloudFrontResources',
3190
+ 'DenyBucketPolicyMutationOutsideStageAndSstBootstrap',
3191
+ 'DenyEventArchiveMutationOutsideGeneratedFoundationArchive',
3192
+ 'DenyExplicitOtherStageRequestTag',
3193
+ ...(options.stage === 'development'
3194
+ ? []
3195
+ : ['DenyKnownOtherStageResourceMutation']),
3196
+ ...(options.stage !== 'production'
3197
+ ? ['DenyNonProductionDatabaseEventSubscriptionSourceMutation']
3198
+ : []),
3199
+ ...(options.stage === 'development'
3200
+ ? []
3201
+ : ['DenyRuntimeTrustPolicyMutation']),
3202
+ 'DenyUnscopedDatabaseEventSubscriptionSourceMutation',
3203
+ 'DenyUntaggedMutationOutsideStageAndSstResources',
3204
+ ],
3205
+ },
3206
+ {
3207
+ kind: 'permission-guardrails',
3208
+ logicalId: 'StageDeploymentPermissionGuardrailsPolicy',
3209
+ sids: [
3210
+ 'DenyNonDeploymentControlOperations',
3211
+ 'DenyUnboundedStageWorkloadIdentityPolicyMutation',
3212
+ 'DenyUnsupportedWorkflowExecutionMutation',
3213
+ 'DenyUnreviewableResourcePolicyAndTrustExpansion',
3214
+ ],
3215
+ },
3216
+ {
3217
+ kind: 'guardrails',
3218
+ logicalId: 'StageDeploymentGuardrailsPolicy',
3219
+ sids: [
3220
+ ...statements
3221
+ .filter((entry) => entry.Sid.startsWith('Deny') &&
3222
+ ![
3223
+ 'DenyCrossAccountMutationWhenResourceAccountIsKnown',
3224
+ 'DenyCrossAccountRunInstancesTargets',
3225
+ 'DenyEdgeControlMutationOutsideEdgeRegion',
3226
+ 'DenyAcmMutationOutsideStageAndEdgeRegions',
3227
+ 'DenyBucketPolicyMutationOutsideStageAndSstBootstrap',
3228
+ 'DenyEventArchiveMutationOutsideGeneratedFoundationArchive',
3229
+ 'DenyExplicitOtherStageRequestTag',
3230
+ 'DenyFoundationNatRolePassOutsideEc2',
3231
+ 'DenyGeneratedDatabaseValueAccessWithWrongStageTag',
3232
+ 'DenyKnownOtherStageResourceMutation',
3233
+ 'DenyLogsMutationOutsideStageAndEdgeRegions',
3234
+ 'DenyMutationOutsideStageRegion',
3235
+ 'DenyNonDeploymentControlOperations',
3236
+ 'DenyNonPrivateServiceDiscoveryNamespaces',
3237
+ 'DenyOwnerMutation',
3238
+ 'DenyNonProductionDatabaseEventSubscriptionSourceMutation',
3239
+ 'DenyProductionCostScopeRemoval',
3240
+ 'DenyProductionCostScopeSubstitution',
3241
+ 'DenyPublishOutsideGeneratedFoundationAlerts',
3242
+ 'DenyQueueAttributeMutationOutsideStage',
3243
+ 'DenyRuntimeBoundaryRemoval',
3244
+ 'DenyRuntimeTrustPolicyMutation',
3245
+ 'DenySecretsManagerBatchValueReads',
3246
+ 'DenySecretMetadataUpdateOutsideStageContainers',
3247
+ 'DenySecretValueAccessOutsideGeneratedFoundationDatabase',
3248
+ 'DenySsmHistoryAndRecursiveValueReads',
3249
+ 'DenyStageAccountBudgetStageTagRemoval',
3250
+ 'DenyStageAuthorityMutation',
3251
+ 'DenyTopicAttributeMutationOutsideStage',
3252
+ 'DenyUnapprovedSsmValueReads',
3253
+ 'DenyUnreviewableResourcePolicyAndTrustExpansion',
3254
+ 'DenyUnscopedDatabaseEventSubscriptionSourceMutation',
3255
+ 'DenyUnscopedLambdaPermissions',
3256
+ 'DenyUnboundedStageWorkloadIdentityPolicyMutation',
3257
+ 'DenyUnscopedWorkflowExecutionMutation',
3258
+ 'DenyUnsupportedWorkflowExecutionMutation',
3259
+ 'DenyUntaggedWorkflowExecutionStart',
3260
+ 'DenyUntaggedMutationOutsideStageAndSstResources',
3261
+ 'DenyWorkflowExecutionReadWithoutStageTag',
3262
+ 'DenyWorkflowExecutionReadOutsideAccount',
3263
+ 'DenyRunInstancesFromUnapprovedReferenceOwners',
3264
+ 'DenyUnsupportedReplicationAndTopology',
3265
+ 'DenyS3MutationOutsideStageRegion',
3266
+ ].includes(entry.Sid))
3267
+ .map((entry) => entry.Sid),
3268
+ ...(options.stage === 'development'
3269
+ ? []
3270
+ : ['ReadEdgeCertificateControlPlane']),
3271
+ ...(options.stage === 'development'
3272
+ ? []
3273
+ : ['ReadEdgeObservabilityControlPlane']),
3274
+ ],
3275
+ },
3276
+ ];
3277
+ if (options.stage === 'development') {
3278
+ // Co-locate equivalent scopes so rendering can union only their Action
3279
+ // sets. Every statement remains in one existing, attached policy.
3280
+ const relocation = {
3281
+ DenyRuntimeBoundarySubstitution: 'permission-guardrails',
3282
+ DenyDevAssumeRegion: 'regional-mutation',
3283
+ DenyDevAssumeSession: 'regional-mutation',
3284
+ DenyDevAssumePurpose: 'regional-mutation',
3285
+ InvokeOnlyStageLambdaFunctions: 'global-iam-mutation',
3286
+ DenyLogsMutationOutsideStageAndEdgeRegions: 'regional-mutation',
3287
+ DenyRuntimeTrustPolicyMutation: 'read',
3288
+ CreateOnlyGeneratedCloudFrontResources: 'global-resource-mutation',
3289
+ MutateStageBucketsInStageRegion: 'global-resource-mutation',
3290
+ };
3291
+ for (const sid of Object.keys(relocation)) {
3292
+ if (groups.flatMap((group) => group.sids).filter((value) => value === sid)
3293
+ .length !== 1)
3294
+ throw new Error(`Task authority compaction requires exactly one ${sid}.`);
3295
+ }
3296
+ groups = groups.map((group) => ({
3297
+ ...group,
3298
+ sids: [
3299
+ ...group.sids.filter((sid) => !relocation[sid]),
3300
+ ...Object.entries(relocation)
3301
+ .filter(([, kind]) => kind === group.kind)
3302
+ .map(([sid]) => sid),
3303
+ ],
3304
+ }));
3305
+ }
3306
+ const assigned = new Set(groups.flatMap((group) => group.sids));
3307
+ const assignmentCount = groups.reduce((total, group) => total + group.sids.length, 0);
3308
+ const unassigned = statements.filter((entry) => !assigned.has(entry.Sid));
3309
+ if (unassigned.length > 0 ||
3310
+ assigned.size !== statements.length ||
3311
+ assignmentCount !== statements.length) {
3312
+ throw new Error(`Stage authority policy groups must assign every statement exactly once; unassigned: ${unassigned.map((entry) => entry.Sid).join(', ') ||
3313
+ 'duplicate assignment'}.`);
3314
+ }
3315
+ return Object.freeze(groups.map((group, index) => {
3316
+ const document = policy(statements.filter((entry) => group.sids.includes(entry.Sid)));
3317
+ const characters = JSON.stringify(omitPolicyStatementSids(document, options.stage === 'development')).length;
3318
+ if (characters >
3319
+ exports.STAGE_AUTHORITY_MANAGED_POLICY_CHARACTER_LIMIT -
3320
+ exports.STAGE_AUTHORITY_MANAGED_POLICY_CHARACTER_HEADROOM) {
3321
+ throw new Error(`Stage authority ${group.kind} policy has ${characters} characters; it must retain ${exports.STAGE_AUTHORITY_MANAGED_POLICY_CHARACTER_HEADROOM} characters below the IAM managed-policy limit of ${exports.STAGE_AUTHORITY_MANAGED_POLICY_CHARACTER_LIMIT}.`);
3322
+ }
3323
+ const name = options.identity.deploymentPolicyNames[index];
3324
+ const arn = options.identity.deploymentPolicyArns[index];
3325
+ if (!name || !arn) {
3326
+ throw new Error(`Stage authority ${group.kind} identity is incomplete.`);
3327
+ }
3328
+ return Object.freeze({
3329
+ arn,
3330
+ document,
3331
+ kind: group.kind,
3332
+ logicalId: group.logicalId,
3333
+ name,
3334
+ });
3335
+ }));
3336
+ }
3337
+ function canonicalStageAuthorityTemplate(template) {
3338
+ return `${JSON.stringify(canonicalize(template))}\n`;
3339
+ }
3340
+ function digestStageAuthorityTemplate(template) {
3341
+ return (0, node_crypto_1.createHash)('sha256')
3342
+ .update(canonicalStageAuthorityTemplate(template), 'utf8')
3343
+ .digest('hex');
3344
+ }
3345
+ function assertBoundStageAuthorityTemplateFitsBodyLimit(template) {
3346
+ const templateBytes = Buffer.byteLength(canonicalStageAuthorityTemplate(template), 'utf8');
3347
+ if (templateBytes > exports.STAGE_AUTHORITY_TEMPLATE_BODY_BYTE_LIMIT) {
3348
+ throw new Error(`Workspace-bound stage authority template has ${templateBytes} bytes; the direct CloudFormation TemplateBody limit is ${exports.STAGE_AUTHORITY_TEMPLATE_BODY_BYTE_LIMIT}.`);
3349
+ }
3350
+ return templateBytes;
3351
+ }
3352
+ function createStageAuthorityPlan(input) {
3353
+ const target = requireIdentity(input);
3354
+ const identity = createStageAuthorityIdentity(target);
3355
+ const assumeRolePolicy = requireTrust(input, target);
3356
+ const boundary = runtimeBoundaryPolicy({
3357
+ accountId: target.accountId,
3358
+ identity,
3359
+ region: target.region,
3360
+ stage: target.stage,
3361
+ });
3362
+ const boundaryCharacters = JSON.stringify(omitPolicyStatementSids(boundary, target.stage === 'development')).length;
3363
+ if (boundaryCharacters > exports.STAGE_AUTHORITY_MANAGED_POLICY_CHARACTER_LIMIT) {
3364
+ throw new Error(`Stage runtime boundary has ${boundaryCharacters} characters; the IAM managed-policy limit is ${exports.STAGE_AUTHORITY_MANAGED_POLICY_CHARACTER_LIMIT}.`);
3365
+ }
3366
+ const deployment = deploymentPolicy({
3367
+ accountId: target.accountId,
3368
+ identity,
3369
+ partition: target.partition,
3370
+ region: target.region,
3371
+ stage: target.stage,
3372
+ });
3373
+ const renderedDeploymentPolicyDocuments = Object.fromEntries(deployment.map((entry) => {
3374
+ let document = replaceExactTemplateString(replaceExactTemplateString(omitPolicyStatementSids(entry.document, target.stage === 'development'), identity.boundaryArn, { Ref: 'StageRuntimeBoundary' }), identity.deploymentRoleArn, { 'Fn::GetAtt': ['StageDeploymentRole', 'Arn'] });
3375
+ if (entry.logicalId === 'StageDeploymentGlobalIamMutationPolicy') {
3376
+ for (const sibling of deployment) {
3377
+ if (sibling.logicalId === entry.logicalId)
3378
+ continue;
3379
+ document = replaceExactTemplateString(document, sibling.arn, {
3380
+ Ref: sibling.logicalId,
3381
+ });
3382
+ }
3383
+ }
3384
+ return [entry.logicalId, document];
3385
+ }));
3386
+ const edgeRegion = edgeControlRegion(target.partition, target.region);
3387
+ const templatePolicyDocuments = compactExactTemplatePolicyStrings({
3388
+ ...renderedDeploymentPolicyDocuments,
3389
+ StageRuntimeBoundary: omitPolicyStatementSids(boundary, target.stage === 'development'),
3390
+ }, [
3391
+ identity.workloadRoleArnPattern,
3392
+ `arn:${target.partition}:cloudformation:${target.region}:${target.accountId}:stack/*MachineAuthorization*/*`,
3393
+ `arn:${target.partition}:events:${target.region}:${target.accountId}:archive/ebk-${target.stage}-foundation-events`,
3394
+ `arn:${target.partition}:events:${target.region}:${target.accountId}:event-bus/foundation-${target.stage}-FoundationEventBusBus-*`,
3395
+ `arn:${target.partition}:lambda:${target.region}:${target.accountId}:function:*`,
3396
+ `arn:${target.partition}:logs:${edgeRegion}:${target.accountId}:log-group:aws-waf-logs-foundation-${target.stage}-FoundationRouter-*`,
3397
+ `arn:${target.partition}:secretsmanager:${target.region}:${target.accountId}:secret:foundation-${target.stage}-FoundationDatabaseProxySecret-*`,
3398
+ `arn:${target.partition}:states:${target.region}:${target.accountId}:execution:*:*`,
3399
+ ...(target.stage === 'development'
3400
+ ? repeatedDevelopmentPolicyStrings({
3401
+ ...renderedDeploymentPolicyDocuments,
3402
+ boundary,
3403
+ })
3404
+ : []),
3405
+ ], target.stage === 'development');
3406
+ const deploymentPolicyResources = Object.fromEntries(deployment.map((entry) => [
3407
+ entry.logicalId,
3408
+ {
3409
+ Properties: {
3410
+ Description: `Stable reviewed ${target.stage} ${entry.kind} deployment authority.`,
3411
+ ManagedPolicyName: entry.name,
3412
+ Path: identity.deploymentRolePath,
3413
+ // IAM statement Sids are diagnostic labels, not authority. Keep them
3414
+ // in the executable policy model while omitting them from the direct
3415
+ // CloudFormation body so every supported partition retains bounded
3416
+ // TemplateBody headroom without changing effective permissions.
3417
+ // Ref on AWS::IAM::ManagedPolicy resolves to its exact ARN. Use the
3418
+ // runtime-boundary resource identity in rendered policy documents
3419
+ // instead of repeating its long partition/account/path ARN. The
3420
+ // executable policy model retains the literal ARN for simulation;
3421
+ // this is representation-only direct-TemplateBody compaction.
3422
+ PolicyDocument: templatePolicyDocuments.documents[entry.logicalId],
3423
+ Roles: [{ Ref: 'StageDeploymentRole' }],
3424
+ },
3425
+ Type: 'AWS::IAM::ManagedPolicy',
3426
+ },
3427
+ ]));
3428
+ const template = {
3429
+ AWSTemplateFormatVersion: '2010-09-09',
3430
+ ...(templatePolicyDocuments.mappings
3431
+ ? { Mappings: templatePolicyDocuments.mappings }
3432
+ : {}),
3433
+ Outputs: {
3434
+ DeploymentRoleArn: {
3435
+ Value: { 'Fn::GetAtt': ['StageDeploymentRole', 'Arn'] },
3436
+ },
3437
+ RuntimeBoundaryArn: { Value: { Ref: 'StageRuntimeBoundary' } },
3438
+ },
3439
+ Resources: {
3440
+ ...deploymentPolicyResources,
3441
+ StageDeploymentRole: {
3442
+ Properties: {
3443
+ AssumeRolePolicyDocument: omitPolicyStatementSids(assumeRolePolicy),
3444
+ Description: `Stable Empire Builder Kit ${target.stage} deployment role.`,
3445
+ MaxSessionDuration: 3_600,
3446
+ Path: identity.deploymentRolePath,
3447
+ RoleName: identity.deploymentRoleName,
3448
+ Tags: [
3449
+ { Key: 'ebk:managed-by', Value: 'empire-builder-kit' },
3450
+ { Key: 'ebk:stage', Value: target.stage },
3451
+ ],
3452
+ },
3453
+ Type: 'AWS::IAM::Role',
3454
+ },
3455
+ StageRuntimeBoundary: {
3456
+ Properties: {
3457
+ Description: `Stable maximum permissions for ${target.stage} workload roles.`,
3458
+ ManagedPolicyName: identity.boundaryName,
3459
+ Path: identity.boundaryPath,
3460
+ PolicyDocument: templatePolicyDocuments.documents['StageRuntimeBoundary'],
3461
+ },
3462
+ Type: 'AWS::IAM::ManagedPolicy',
3463
+ },
3464
+ },
3465
+ };
3466
+ const templateBytes = Buffer.byteLength(canonicalStageAuthorityTemplate(template), 'utf8');
3467
+ if (templateBytes > exports.STAGE_AUTHORITY_TEMPLATE_BODY_BYTE_LIMIT) {
3468
+ throw new Error(`Stage authority template has ${templateBytes} bytes; the direct CloudFormation TemplateBody limit is ${exports.STAGE_AUTHORITY_TEMPLATE_BODY_BYTE_LIMIT}.`);
3469
+ }
3470
+ return deepFreeze({
3471
+ deploymentPolicies: deployment,
3472
+ digest: digestStageAuthorityTemplate(template),
3473
+ identity,
3474
+ limitations: Object.freeze({
3475
+ protectedDatabaseConfiguration: 'iam-cannot-inspect-rds-modify-request-fields-lifecycle-preflight-required',
3476
+ resourcePolicyAttributes: 'sns-and-sqs-set-attributes-can-write-resource-policies-name-account-region-containment-applies',
3477
+ sameAccountStageDeploymentIsolation: 'deployment-role-is-account-scoped-use-production-isolated-for-hard-production-boundary',
3478
+ wafLoggingResourcePolicy: 'cloudwatch-logs-put-resource-policy-has-no-resource-or-action-condition-keys-reviewed-generated-source-is-control',
3479
+ workloadTrust: 'iam-cannot-inspect-create-role-trust-reviewed-generated-source-is-control',
3480
+ }),
3481
+ runtimeBoundaryPolicy: boundary,
3482
+ schemaVersion: exports.STAGE_AUTHORITY_SCHEMA_VERSION,
3483
+ template,
3484
+ });
3485
+ }
3486
+ function createStageIamBoundaryTransformContract(input) {
3487
+ const identity = createStageAuthorityIdentity({
3488
+ ...input,
3489
+ region: 'us-east-1',
3490
+ });
3491
+ return Object.freeze({
3492
+ boundaryArn: identity.boundaryArn,
3493
+ instanceProfilePath: identity.workloadInstanceProfilePath,
3494
+ rolePath: identity.workloadRolePath,
3495
+ });
3496
+ }
3497
+ function requireTransformArgs(value, label) {
3498
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
3499
+ throw new Error(`${label} transform arguments must be an object.`);
3500
+ }
3501
+ return value;
3502
+ }
3503
+ function refuseSubstitution(existing, expected, label) {
3504
+ if (existing !== undefined && existing !== expected) {
3505
+ throw new Error(`${label} attempted to substitute stable stage authority.`);
3506
+ }
3507
+ }
3508
+ /**
3509
+ * Installs ordinary Pulumi resource transforms before generated SST components
3510
+ * are constructed. SST remains responsible for creating its roles and NAT
3511
+ * instance profiles; this helper contributes only the stable stage path and
3512
+ * permissions boundary.
3513
+ */
3514
+ function installStageIamBoundaryTransforms(input) {
3515
+ if (typeof input.registerTransform !== 'function' ||
3516
+ input.roleResource === undefined ||
3517
+ input.instanceProfileResource === undefined) {
3518
+ throw new Error('Stage IAM boundary transforms require the ordinary Pulumi role and instance-profile resource types.');
3519
+ }
3520
+ const resourceStage = input.resourceStage ?? input.stage;
3521
+ if (resourceStage !== input.stage &&
3522
+ !(input.stage === 'development' &&
3523
+ /^personal-[a-f0-9]{24}$/u.test(resourceStage))) {
3524
+ throw new Error('IAM resource stage must be canonical or the exact development task.');
3525
+ }
3526
+ const contract = createStageIamBoundaryTransformContract(input);
3527
+ input.registerTransform(input.roleResource, (value) => {
3528
+ const args = requireTransformArgs(value, 'IAM role');
3529
+ let stageTags;
3530
+ if (input.stage === 'development') {
3531
+ const tags = args.tags;
3532
+ if (tags !== undefined &&
3533
+ (!tags ||
3534
+ typeof tags !== 'object' ||
3535
+ Array.isArray(tags) ||
3536
+ ![Object.prototype, null].includes(Object.getPrototypeOf(tags)) ||
3537
+ Object.values(tags).some((value) => typeof value !== 'string'))) {
3538
+ throw new Error('IAM role stage tags must be a literal string record.');
3539
+ }
3540
+ const literalTags = (tags ?? {});
3541
+ refuseSubstitution(literalTags['ebk:stage'], resourceStage, 'IAM role stage tag');
3542
+ stageTags = { ...literalTags, 'ebk:stage': resourceStage };
3543
+ }
3544
+ refuseSubstitution(args.permissionsBoundary, contract.boundaryArn, 'IAM role permissions boundary');
3545
+ refuseSubstitution(args.path, contract.rolePath, 'IAM role path');
3546
+ if (stageTags)
3547
+ args.tags = stageTags;
3548
+ args.permissionsBoundary = contract.boundaryArn;
3549
+ args.path = contract.rolePath;
3550
+ });
3551
+ input.registerTransform(input.instanceProfileResource, (value) => {
3552
+ const args = requireTransformArgs(value, 'IAM instance profile');
3553
+ refuseSubstitution(args.path, contract.instanceProfilePath, 'IAM instance-profile path');
3554
+ args.path = contract.instanceProfilePath;
3555
+ });
3556
+ return contract;
3557
+ }
3558
+ //# sourceMappingURL=stage-authority.js.map