@empire-builder-kit/nx 1.0.0-rc.30 → 1.0.0-rc.31

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 (261) hide show
  1. package/executors.json +8 -3
  2. package/package.json +10 -7
  3. package/src/aws/child-environment.d.ts +10 -0
  4. package/src/aws/child-environment.js +77 -0
  5. package/src/aws/child-environment.js.map +1 -0
  6. package/src/aws/identity.d.ts +13 -0
  7. package/src/aws/identity.js +41 -0
  8. package/src/aws/identity.js.map +1 -0
  9. package/src/aws-authority/index.d.ts +1 -0
  10. package/src/aws-authority/index.js +5 -0
  11. package/src/aws-authority/index.js.map +1 -0
  12. package/src/aws-authority/stage-authority.d.ts +238 -0
  13. package/src/aws-authority/stage-authority.js +2836 -0
  14. package/src/aws-authority/stage-authority.js.map +1 -0
  15. package/src/developer-agent/generator-planning.js +4 -4
  16. package/src/developer-agent/generator-planning.js.map +1 -1
  17. package/src/developer-agent/operation-registry.js +14 -6
  18. package/src/developer-agent/operation-registry.js.map +1 -1
  19. package/src/executors/deployment-plan/deployment-plan.js +1 -1
  20. package/src/executors/deployment-plan/deployment-plan.js.map +1 -1
  21. package/src/executors/foundation-preflight/foundation-preflight.d.ts +0 -1
  22. package/src/executors/foundation-preflight/foundation-preflight.js.map +1 -1
  23. package/src/executors/foundation-preflight/schema.json +0 -5
  24. package/src/executors/foundation-profile-preflight/foundation-profile-preflight.d.ts +12 -3
  25. package/src/executors/foundation-profile-preflight/foundation-profile-preflight.js +95 -32
  26. package/src/executors/foundation-profile-preflight/foundation-profile-preflight.js.map +1 -1
  27. package/src/executors/foundation-profile-preflight/production-database-safeguard.d.ts +64 -0
  28. package/src/executors/foundation-profile-preflight/production-database-safeguard.js +221 -0
  29. package/src/executors/foundation-profile-preflight/production-database-safeguard.js.map +1 -0
  30. package/src/executors/foundation-profile-preflight/schema.json +1 -6
  31. package/src/executors/foundation-remove-preflight/foundation-remove-preflight.d.ts +11 -1
  32. package/src/executors/foundation-remove-preflight/foundation-remove-preflight.js +44 -21
  33. package/src/executors/foundation-remove-preflight/foundation-remove-preflight.js.map +1 -1
  34. package/src/executors/foundation-remove-preflight/schema.json +6 -1
  35. package/src/executors/infrastructure-plan/infrastructure-plan.d.ts +25 -369
  36. package/src/executors/infrastructure-plan/infrastructure-plan.js +222 -5472
  37. package/src/executors/infrastructure-plan/infrastructure-plan.js.map +1 -1
  38. package/src/executors/infrastructure-plan/schema.json +8 -64
  39. package/src/executors/local-deploy/federated-credential-transport.d.ts +48 -0
  40. package/src/executors/local-deploy/federated-credential-transport.js +252 -0
  41. package/src/executors/local-deploy/federated-credential-transport.js.map +1 -0
  42. package/src/executors/local-deploy/local-approval.d.ts +4 -9
  43. package/src/executors/local-deploy/local-approval.js +3 -7
  44. package/src/executors/local-deploy/local-approval.js.map +1 -1
  45. package/src/executors/local-deploy/local-deploy.d.ts +58 -43
  46. package/src/executors/local-deploy/local-deploy.js +938 -804
  47. package/src/executors/local-deploy/local-deploy.js.map +1 -1
  48. package/src/executors/local-deploy/schema.json +3 -20
  49. package/src/executors/refresh/refresh.js +2 -2
  50. package/src/executors/refresh/refresh.js.map +1 -1
  51. package/src/executors/remove/remove.js +2 -2
  52. package/src/executors/remove/remove.js.map +1 -1
  53. package/src/executors/router-waf-rehearsal/router-waf-rehearsal.d.ts +25 -1
  54. package/src/executors/router-waf-rehearsal/router-waf-rehearsal.js +905 -22
  55. package/src/executors/router-waf-rehearsal/router-waf-rehearsal.js.map +1 -1
  56. package/src/executors/router-waf-rehearsal/schema.json +17 -2
  57. package/src/executors/secret-initialize/schema.json +42 -0
  58. package/src/executors/secret-initialize/secret-initialize.d.ts +30 -0
  59. package/src/executors/secret-initialize/secret-initialize.js +229 -0
  60. package/src/executors/secret-initialize/secret-initialize.js.map +1 -0
  61. package/src/executors/secret-metadata/secret-metadata.d.ts +2 -1
  62. package/src/executors/secret-metadata/secret-metadata.js +62 -29
  63. package/src/executors/secret-metadata/secret-metadata.js.map +1 -1
  64. package/src/executors/sst-lifecycle/generated-secret-retirement.d.ts +53 -0
  65. package/src/executors/sst-lifecycle/generated-secret-retirement.js +192 -0
  66. package/src/executors/sst-lifecycle/generated-secret-retirement.js.map +1 -0
  67. package/src/executors/sst-lifecycle/governed-native-operation.d.ts +46 -0
  68. package/src/executors/sst-lifecycle/governed-native-operation.js +153 -0
  69. package/src/executors/sst-lifecycle/governed-native-operation.js.map +1 -0
  70. package/src/executors/sst-lifecycle/run-sst-command.d.ts +25 -7
  71. package/src/executors/sst-lifecycle/run-sst-command.js +459 -89
  72. package/src/executors/sst-lifecycle/run-sst-command.js.map +1 -1
  73. package/src/executors/sst-lifecycle/schema.json +0 -5
  74. package/src/executors/sst-lifecycle/secret-preflight.d.ts +2 -0
  75. package/src/executors/sst-lifecycle/secret-preflight.js +13 -7
  76. package/src/executors/sst-lifecycle/secret-preflight.js.map +1 -1
  77. package/src/executors/unlock/unlock.js +2 -2
  78. package/src/executors/unlock/unlock.js.map +1 -1
  79. package/src/foundation/router-waf-rate-rehearsal.d.ts +97 -0
  80. package/src/foundation/router-waf-rate-rehearsal.js +210 -0
  81. package/src/foundation/router-waf-rate-rehearsal.js.map +1 -0
  82. package/src/foundation/router-waf.d.ts +59 -9
  83. package/src/foundation/router-waf.js +427 -32
  84. package/src/foundation/router-waf.js.map +1 -1
  85. package/src/foundation/stages.d.ts +1 -0
  86. package/src/foundation/stages.js +11 -0
  87. package/src/foundation/stages.js.map +1 -1
  88. package/src/generators/formatting.d.ts +8 -0
  89. package/src/generators/formatting.js +118 -0
  90. package/src/generators/formatting.js.map +1 -0
  91. package/src/generators/function/function.js +37 -17
  92. package/src/generators/function/function.js.map +1 -1
  93. package/src/generators/post-generation-install.js +2 -2
  94. package/src/generators/post-generation-install.js.map +1 -1
  95. package/src/generators/preset/generator.js +22 -7
  96. package/src/generators/preset/generator.js.map +1 -1
  97. package/src/generators/preset/workspace-files-developer-agent.js +15 -7
  98. package/src/generators/preset/workspace-files-developer-agent.js.map +1 -1
  99. package/src/generators/preset/workspace-files-ecr-inspector.d.ts +18 -0
  100. package/src/generators/preset/workspace-files-ecr-inspector.js +298 -0
  101. package/src/generators/preset/workspace-files-ecr-inspector.js.map +1 -0
  102. package/src/generators/preset/workspace-files-performance-cost.d.ts +2 -2
  103. package/src/generators/preset/workspace-files-performance-cost.js +8 -8
  104. package/src/generators/preset/workspace-files-performance-cost.js.map +1 -1
  105. package/src/generators/preset/workspace-files-performance-load.d.ts +1 -1
  106. package/src/generators/preset/workspace-files-performance-load.js +8 -12
  107. package/src/generators/preset/workspace-files-performance-load.js.map +1 -1
  108. package/src/generators/preset/workspace-files-stage-authority.d.ts +4 -0
  109. package/src/generators/preset/workspace-files-stage-authority.js +275 -0
  110. package/src/generators/preset/workspace-files-stage-authority.js.map +1 -0
  111. package/src/generators/preset/workspace-files-thin-deploy.d.ts +35 -0
  112. package/src/generators/preset/workspace-files-thin-deploy.js +1434 -0
  113. package/src/generators/preset/workspace-files-thin-deploy.js.map +1 -0
  114. package/src/generators/preset/workspace-files-thin-docs.d.ts +5 -0
  115. package/src/generators/preset/workspace-files-thin-docs.js +224 -0
  116. package/src/generators/preset/workspace-files-thin-docs.js.map +1 -0
  117. package/src/generators/preset/workspace-files-thin-release.d.ts +14 -0
  118. package/src/generators/preset/workspace-files-thin-release.js +26 -0
  119. package/src/generators/preset/workspace-files-thin-release.js.map +1 -0
  120. package/src/generators/preset/workspace-files.d.ts +1 -1
  121. package/src/generators/preset/workspace-files.js +373 -223
  122. package/src/generators/preset/workspace-files.js.map +1 -1
  123. package/src/generators/slice/built-in-plan-api-files.js +1 -0
  124. package/src/generators/slice/built-in-plan-api-files.js.map +1 -1
  125. package/src/generators/slice/built-in-plan-authorization-infrastructure-files.js +4 -0
  126. package/src/generators/slice/built-in-plan-authorization-infrastructure-files.js.map +1 -1
  127. package/src/generators/slice/built-in-plan-data-export-infrastructure-files.js +5 -31
  128. package/src/generators/slice/built-in-plan-data-export-infrastructure-files.js.map +1 -1
  129. package/src/generators/slice/built-in-plan-data-files.d.ts +1 -1
  130. package/src/generators/slice/built-in-plan-data-files.js +89 -30
  131. package/src/generators/slice/built-in-plan-data-files.js.map +1 -1
  132. package/src/generators/slice/built-in-plan-foundation-files.js +3 -5
  133. package/src/generators/slice/built-in-plan-foundation-files.js.map +1 -1
  134. package/src/generators/slice/built-in-plan-frontend-files.js +5 -1
  135. package/src/generators/slice/built-in-plan-frontend-files.js.map +1 -1
  136. package/src/generators/slice/built-in-plan-infrastructure-files.d.ts +1 -1
  137. package/src/generators/slice/built-in-plan-infrastructure-files.js +199 -188
  138. package/src/generators/slice/built-in-plan-infrastructure-files.js.map +1 -1
  139. package/src/generators/slice/built-in-plan-metadata-files.js +13 -0
  140. package/src/generators/slice/built-in-plan-metadata-files.js.map +1 -1
  141. package/src/generators/slice/built-in-plan-native-runtime-authority-files.d.ts +2 -0
  142. package/src/generators/slice/built-in-plan-native-runtime-authority-files.js +307 -0
  143. package/src/generators/slice/built-in-plan-native-runtime-authority-files.js.map +1 -0
  144. package/src/generators/slice/built-in-plan-operations-files.js +43 -49
  145. package/src/generators/slice/built-in-plan-operations-files.js.map +1 -1
  146. package/src/generators/slice/built-in-plan-performance-files.js +37 -19
  147. package/src/generators/slice/built-in-plan-performance-files.js.map +1 -1
  148. package/src/generators/slice/built-in-plan-project-files.js +9 -68
  149. package/src/generators/slice/built-in-plan-project-files.js.map +1 -1
  150. package/src/generators/slice/built-in-plan-secret-runtime-files.d.ts +1 -1
  151. package/src/generators/slice/built-in-plan-secret-runtime-files.js +74 -76
  152. package/src/generators/slice/built-in-plan-secret-runtime-files.js.map +1 -1
  153. package/src/generators/slice/built-in-plan-testing-files.js +74 -47
  154. package/src/generators/slice/built-in-plan-testing-files.js.map +1 -1
  155. package/src/generators/slice/built-in-plan-thin-release-files.d.ts +11 -0
  156. package/src/generators/slice/built-in-plan-thin-release-files.js +129 -0
  157. package/src/generators/slice/built-in-plan-thin-release-files.js.map +1 -0
  158. package/src/generators/slice/built-in-plan-verification-files.js +6 -2
  159. package/src/generators/slice/built-in-plan-verification-files.js.map +1 -1
  160. package/src/generators/slice/built-in-plan-web-files.js +4 -2
  161. package/src/generators/slice/built-in-plan-web-files.js.map +1 -1
  162. package/src/generators/slice/built-in-plan-workload-role-files.js +26 -4
  163. package/src/generators/slice/built-in-plan-workload-role-files.js.map +1 -1
  164. package/src/generators/slice/built-in-plan.d.ts +1 -0
  165. package/src/generators/slice/built-in-plan.js +28 -11
  166. package/src/generators/slice/built-in-plan.js.map +1 -1
  167. package/src/generators/slice/slice.js +27 -29
  168. package/src/generators/slice/slice.js.map +1 -1
  169. package/src/generators/upgrade/upgrade.d.ts +1 -1
  170. package/src/generators/upgrade/upgrade.js +224 -69
  171. package/src/generators/upgrade/upgrade.js.map +1 -1
  172. package/src/generators/workload/performance-registration.d.ts +1 -0
  173. package/src/generators/workload/performance-registration.js +6 -4
  174. package/src/generators/workload/performance-registration.js.map +1 -1
  175. package/src/generators/workload/service-performance-files.d.ts +1 -0
  176. package/src/generators/workload/service-performance-files.js +27 -7
  177. package/src/generators/workload/service-performance-files.js.map +1 -1
  178. package/src/generators/workload/workload.d.ts +1 -1
  179. package/src/generators/workload/workload.js +55 -28
  180. package/src/generators/workload/workload.js.map +1 -1
  181. package/src/git-policy/github-bootstrap.d.ts +19 -6
  182. package/src/git-policy/github-bootstrap.js +103 -157
  183. package/src/git-policy/github-bootstrap.js.map +1 -1
  184. package/src/local-dev/private-state.d.ts +3 -0
  185. package/src/local-dev/private-state.js +17 -5
  186. package/src/local-dev/private-state.js.map +1 -1
  187. package/src/performance/cost-collection.d.ts +1 -1
  188. package/src/performance/cost-collection.js +4 -2
  189. package/src/performance/cost-collection.js.map +1 -1
  190. package/src/performance/cost-controls.d.ts +3 -1
  191. package/src/performance/cost-controls.js +9 -4
  192. package/src/performance/cost-controls.js.map +1 -1
  193. package/src/performance/evidence.d.ts +1 -1
  194. package/src/performance/evidence.js +5 -3
  195. package/src/performance/evidence.js.map +1 -1
  196. package/src/performance/load-safety.js +5 -3
  197. package/src/performance/load-safety.js.map +1 -1
  198. package/src/performance/model.d.ts +2 -2
  199. package/src/performance/model.js +4 -3
  200. package/src/performance/model.js.map +1 -1
  201. package/src/release/index.d.ts +0 -2
  202. package/src/release/index.js +0 -2
  203. package/src/release/index.js.map +1 -1
  204. package/src/release/source-authority.d.ts +4 -5
  205. package/src/release/source-authority.js +13 -123
  206. package/src/release/source-authority.js.map +1 -1
  207. package/src/repository-policy/aurora-preflight.d.ts +1 -1
  208. package/src/repository-policy/aurora-preflight.js +4 -1
  209. package/src/repository-policy/aurora-preflight.js.map +1 -1
  210. package/src/repository-policy/policy.d.ts +5 -1
  211. package/src/repository-policy/policy.js +64 -13
  212. package/src/repository-policy/policy.js.map +1 -1
  213. package/src/schemas/performance-policy-v1.json +3 -1
  214. package/src/secrets/adapters.d.ts +5 -1
  215. package/src/secrets/adapters.js +22 -1
  216. package/src/secrets/adapters.js.map +1 -1
  217. package/src/secrets/aws-control-plane.d.ts +10 -1
  218. package/src/secrets/aws-control-plane.js +67 -0
  219. package/src/secrets/aws-control-plane.js.map +1 -1
  220. package/src/secrets/generated-aws-control-plane.d.ts +23 -0
  221. package/src/secrets/generated-aws-control-plane.js +259 -0
  222. package/src/secrets/generated-aws-control-plane.js.map +1 -0
  223. package/src/secrets/metadata.js +38 -10
  224. package/src/secrets/metadata.js.map +1 -1
  225. package/src/secrets/model.d.ts +8 -1
  226. package/src/secrets/model.js +24 -3
  227. package/src/secrets/model.js.map +1 -1
  228. package/src/secrets/operator.d.ts +89 -3
  229. package/src/secrets/operator.js +422 -9
  230. package/src/secrets/operator.js.map +1 -1
  231. package/src/secrets/registry.d.ts +2 -1
  232. package/src/secrets/registry.js +18 -1
  233. package/src/secrets/registry.js.map +1 -1
  234. package/src/secrets/workload-access.js +10 -2
  235. package/src/secrets/workload-access.js.map +1 -1
  236. package/src/supply-chain/action-pins.js +61 -7
  237. package/src/supply-chain/action-pins.js.map +1 -1
  238. package/src/supply-chain/build-output-bounds.d.ts +2 -0
  239. package/src/supply-chain/build-output-bounds.js +12 -0
  240. package/src/supply-chain/build-output-bounds.js.map +1 -0
  241. package/src/supply-chain/build-output.js +2 -4
  242. package/src/supply-chain/build-output.js.map +1 -1
  243. package/src/supply-chain/ecr-scanning.d.ts +5 -3
  244. package/src/supply-chain/ecr-scanning.js +11 -7
  245. package/src/supply-chain/ecr-scanning.js.map +1 -1
  246. package/src/supply-chain/ecs-deployed-image.d.ts +5 -3
  247. package/src/supply-chain/ecs-deployed-image.js +6 -4
  248. package/src/supply-chain/ecs-deployed-image.js.map +1 -1
  249. package/src/supply-chain/generated-container-release-command.js +816 -34
  250. package/src/supply-chain/generated-container-release-command.js.map +1 -1
  251. package/src/supply-chain/generated-ecr-collector-command.d.ts +0 -1
  252. package/src/supply-chain/generated-ecr-collector-command.js +188 -91
  253. package/src/supply-chain/generated-ecr-collector-command.js.map +1 -1
  254. package/src/supply-chain/generated-files.js +4 -3
  255. package/src/supply-chain/generated-files.js.map +1 -1
  256. package/src/supply-chain/index.d.ts +1 -1
  257. package/src/supply-chain/index.js +2 -1
  258. package/src/supply-chain/index.js.map +1 -1
  259. package/src/workload-roles/index.d.ts +10 -17
  260. package/src/workload-roles/index.js +5 -18
  261. package/src/workload-roles/index.js.map +1 -1
@@ -17,10 +17,11 @@ const deterministic_order_js_1 = require("../../deterministic-order.js");
17
17
  const tool_versions_js_1 = require("./tool-versions.js");
18
18
  const workspace_files_developer_agent_js_1 = require("./workspace-files-developer-agent.js");
19
19
  const workspace_files_ci_acceptance_js_1 = require("./workspace-files-ci-acceptance.js");
20
- const workspace_files_foundation_workload_roles_js_1 = require("./workspace-files-foundation-workload-roles.js");
21
- const workspace_files_performance_cost_js_1 = require("./workspace-files-performance-cost.js");
22
- const workspace_files_performance_load_js_1 = require("./workspace-files-performance-load.js");
23
- const workspace_files_workload_role_baseline_js_1 = require("./workspace-files-workload-role-baseline.js");
20
+ const workspace_files_ecr_inspector_js_1 = require("./workspace-files-ecr-inspector.js");
21
+ const workspace_files_thin_deploy_js_1 = require("./workspace-files-thin-deploy.js");
22
+ const workspace_files_thin_docs_js_1 = require("./workspace-files-thin-docs.js");
23
+ const workspace_files_thin_release_js_1 = require("./workspace-files-thin-release.js");
24
+ const workspace_files_stage_authority_js_1 = require("./workspace-files-stage-authority.js");
24
25
  const GENERATED_CREDENTIAL_SHAPE_PATTERNS = `[${sensitive_patterns_1.CREDENTIAL_SHAPE_DEFINITIONS.map(({ pattern }) => `new RegExp(${JSON.stringify(pattern.source)}, ${JSON.stringify(pattern.flags)})`).join(',')}]`;
25
26
  const GENERATED_RELEASE_ROLLOUT_PLAN_ID_PATTERN = JSON.stringify(index_js_5.RELEASE_ROLLOUT_PLAN_ID_PATTERN_SOURCE);
26
27
  exports.BLUEPRINT_TRUST_AUTHORITY_PATH = 'tools/blueprint-trust-check.mjs';
@@ -1015,6 +1016,7 @@ const WORKSPACE_SEEDED_PATHS = new Set([
1015
1016
  'docs/architecture.md',
1016
1017
  'docs/git-workflow.md',
1017
1018
  'docs/repository-operating-policy.md',
1019
+ 'docs/stage-deployment-authority.md',
1018
1020
  'docs/work-markers.md',
1019
1021
  'ebk.repository-policy.json',
1020
1022
  ]);
@@ -1042,14 +1044,13 @@ exports.WORKSPACE_PROJECT_MANAGED_JSON_POINTERS = [
1042
1044
  '/targets/dev-setup',
1043
1045
  '/targets/github-bootstrap',
1044
1046
  '/targets/install-git-hooks',
1047
+ '/targets/stage-authority-render',
1045
1048
  '/targets/supply-chain-check',
1046
1049
  '/targets/supply-chain-check-protected',
1047
1050
  '/targets/supply-chain-scan',
1048
1051
  '/targets/verify',
1049
1052
  '/targets/verify-proposed',
1050
1053
  '/targets/work-markers',
1051
- '/targets/workload-role-candidate-report',
1052
- '/targets/workload-role-provisioner-build',
1053
1054
  '/targets/workspace-health',
1054
1055
  ];
1055
1056
  const FOUNDATION_SEEDED_PATHS = new Set([
@@ -1124,6 +1125,17 @@ function createWorkspaceOwnership(files, frameworkVersion) {
1124
1125
  function renderWorkspaceFiles(options) {
1125
1126
  const { frameworkVersion, name } = options;
1126
1127
  const deploymentProfile = options.deploymentProfile ?? 'starter';
1128
+ const activeStages = (0, index_js_4.activeDeploymentStages)(deploymentProfile);
1129
+ const protectedWorkflowStageChoices = deploymentProfile === 'starter'
1130
+ ? 'development, production'
1131
+ : deploymentProfile === 'production-isolated'
1132
+ ? 'production'
1133
+ : 'staging, production';
1134
+ const ecrInspectorWorkflowStageChoices = deploymentProfile === 'starter'
1135
+ ? 'production'
1136
+ : protectedWorkflowStageChoices;
1137
+ const rehearsalStage = (0, index_js_4.productionRehearsalStage)(deploymentProfile);
1138
+ const protectedWorkflowStageBranchCases = `${rehearsalStage}:refs/heads/develop|production:refs/heads/main`;
1127
1139
  const initialRepositoryPolicy = (0, index_js_4.createIncubationRepositoryPolicy)(deploymentProfile);
1128
1140
  initialRepositoryPolicy.deploymentAccounts = options.deploymentAccounts ?? {
1129
1141
  development: null,
@@ -1367,6 +1379,7 @@ jobs:
1367
1379
  include-hidden-files: true
1368
1380
  retention-days: 30
1369
1381
  path: .ebk/evidence/release-candidate
1382
+ ${(0, workspace_files_thin_deploy_js_1.renderThinDeployVerifyCaller)(deploymentProfile)}
1370
1383
  `,
1371
1384
  '.github/workflows/deploy.yml': `name: Deploy
1372
1385
 
@@ -3876,7 +3889,7 @@ on:
3876
3889
  description: Exact protected deployment stage
3877
3890
  required: true
3878
3891
  type: choice
3879
- options: [staging, production]
3892
+ options: [${ecrInspectorWorkflowStageChoices}]
3880
3893
  deployment_commit:
3881
3894
  description: Exact successful protected deployment commit
3882
3895
  required: true
@@ -3885,8 +3898,8 @@ on:
3885
3898
  description: Exact successful Deploy workflow run ID
3886
3899
  required: true
3887
3900
  type: string
3888
- release_artifact_name:
3889
- description: Exact release-evidence artifact from that run
3901
+ deployment_receipt_artifact_name:
3902
+ description: Exact deployment-receipt artifact from that run
3890
3903
  required: true
3891
3904
  type: string
3892
3905
  slice:
@@ -3940,7 +3953,7 @@ jobs:
3940
3953
  EBK_DEPLOYMENT_ARN: \${{ inputs.deployment_arn }}
3941
3954
  EBK_DEPLOYMENT_KIND: \${{ inputs.deployment_kind }}
3942
3955
  EBK_DEPLOY_RUN_ID: \${{ inputs.deploy_run_id }}
3943
- EBK_RELEASE_ARTIFACT_NAME: \${{ inputs.release_artifact_name }}
3956
+ EBK_DEPLOYMENT_RECEIPT_ARTIFACT_NAME: \${{ inputs.deployment_receipt_artifact_name }}
3944
3957
  EBK_SLICE: \${{ inputs.slice }}
3945
3958
  EBK_DEPLOYMENT_COMMIT: \${{ inputs.deployment_commit }}
3946
3959
  EBK_STAGE: \${{ inputs.stage }}
@@ -3963,10 +3976,10 @@ jobs:
3963
3976
  esac
3964
3977
  expected_branch=develop
3965
3978
  if [ "$EBK_STAGE" = production ]; then expected_branch=main; fi
3966
- expected_artifact="release-evidence-$EBK_STAGE-$EBK_DEPLOY_RUN_ID-"
3967
- case "$EBK_RELEASE_ARTIFACT_NAME" in
3968
- "$expected_artifact"*) attempt="\${EBK_RELEASE_ARTIFACT_NAME#"$expected_artifact"}" ;;
3969
- *) echo 'Release evidence artifact does not bind the exact deploy run'; exit 1 ;;
3979
+ expected_artifact="deployment-receipt-$EBK_STAGE-$EBK_DEPLOY_RUN_ID-"
3980
+ case "$EBK_DEPLOYMENT_RECEIPT_ARTIFACT_NAME" in
3981
+ "$expected_artifact"*) attempt="\${EBK_DEPLOYMENT_RECEIPT_ARTIFACT_NAME#"$expected_artifact"}" ;;
3982
+ *) echo 'Deployment receipt artifact does not bind the exact deploy run'; exit 1 ;;
3970
3983
  esac
3971
3984
  case "$attempt" in
3972
3985
  ''|0*|*[!0-9]*) echo 'Release evidence artifact has an invalid run attempt'; exit 1 ;;
@@ -3979,7 +3992,7 @@ jobs:
3979
3992
  test "$(printf '%s' "$run" | jq -r .path)" = ".github/workflows/deploy.yml" ||
3980
3993
  { echo 'Deploy run is not the exact successful protected source authority'; exit 1; }
3981
3994
  artifacts="$(gh api "/repos/$GH_REPO/actions/runs/$EBK_DEPLOY_RUN_ID/artifacts?per_page=100")"
3982
- count="$(printf '%s' "$artifacts" | jq --arg name "$EBK_RELEASE_ARTIFACT_NAME" \
3995
+ count="$(printf '%s' "$artifacts" | jq --arg name "$EBK_DEPLOYMENT_RECEIPT_ARTIFACT_NAME" \
3983
3996
  '[.artifacts[] | select(.name == $name and .expired == false)] | length')"
3984
3997
  test "$count" = 1 ||
3985
3998
  { echo 'Exact unexpired release evidence artifact is absent or ambiguous'; exit 1; }
@@ -3996,7 +4009,7 @@ jobs:
3996
4009
  - uses: ${downloadArtifactAction}
3997
4010
  with:
3998
4011
  github-token: \${{ github.token }}
3999
- name: \${{ inputs.release_artifact_name }}
4012
+ name: \${{ inputs.deployment_receipt_artifact_name }}
4000
4013
  path: .
4001
4014
  run-id: \${{ inputs.deploy_run_id }}
4002
4015
  - uses: ${pnpmAction}
@@ -4103,7 +4116,7 @@ jobs:
4103
4116
  { encoding: "utf8" },
4104
4117
  ).trim()
4105
4118
  ) fail("Production deployment tree differs from its reviewed release source.");
4106
- } else if (stage !== "staging") {
4119
+ } else if (stage !== "${rehearsalStage}") {
4107
4120
  fail("Protected release stage is invalid.");
4108
4121
  }
4109
4122
  const productionKeys = [
@@ -4159,7 +4172,7 @@ jobs:
4159
4172
  !digest.test(binding.candidateDigest ?? "") ||
4160
4173
  (stage === "production" &&
4161
4174
  !digest.test(binding.lifecycleDigest ?? "")) ||
4162
- (stage === "staging" && binding.stage !== stage) ||
4175
+ (stage === "${rehearsalStage}" && binding.stage !== stage) ||
4163
4176
  binding.runId !== process.env.EBK_DEPLOY_RUN_ID ||
4164
4177
  binding.runAttempt !== process.env.EBK_DEPLOY_RUN_ATTEMPT ||
4165
4178
  binding.workflow !== expectedWorkflow
@@ -4238,7 +4251,7 @@ on:
4238
4251
  description: Protected deployed stage
4239
4252
  required: true
4240
4253
  type: choice
4241
- options: [staging, production]
4254
+ options: [${protectedWorkflowStageChoices}]
4242
4255
  project:
4243
4256
  description: Exact Product Slice project
4244
4257
  required: true
@@ -4338,7 +4351,7 @@ jobs:
4338
4351
  EBK_REPORT_RUN_ID: \${{ inputs.report_run_id }}
4339
4352
  run: |
4340
4353
  case "$EBK_STAGE:$EBK_PROTECTED_REF" in
4341
- staging:refs/heads/develop|production:refs/heads/main) ;;
4354
+ ${protectedWorkflowStageBranchCases}) ;;
4342
4355
  *) echo 'Async recovery stage does not match its protected branch'; exit 1 ;;
4343
4356
  esac
4344
4357
  case "$EBK_PROJECT" in
@@ -5190,27 +5203,26 @@ jobs:
5190
5203
  );
5191
5204
  NODE
5192
5205
  - id: classify
5193
- name: Require one successful staging deployment job
5206
+ name: Require one successful thin staging deployment job
5194
5207
  env:
5195
5208
  EBK_DEPLOYMENT_PROFILE: \${{ steps.profile.outputs.profile }}
5196
5209
  EBK_DEPLOYMENT_RUN_ID: \${{ github.event.workflow_run.id }}
5197
5210
  GH_TOKEN: \${{ github.token }}
5198
5211
  GH_REPO: \${{ github.repository }}
5199
5212
  run: |
5213
+ if [ "$EBK_DEPLOYMENT_PROFILE" = starter ]; then
5214
+ echo 'deployed=false' >> "$GITHUB_OUTPUT"
5215
+ exit 0
5216
+ fi
5200
5217
  jobs="$(gh api \
5201
5218
  "/repos/$GH_REPO/actions/runs/$EBK_DEPLOYMENT_RUN_ID/jobs?filter=latest&per_page=100")"
5202
- apply_count="$(printf '%s' "$jobs" | jq \
5203
- '[.jobs[] | select(.name | startswith("${stagingApplyJobPrefix}")) | select(.conclusion == "success")] | length')"
5204
- route_success_count="$(printf '%s' "$jobs" | jq \
5205
- '[.jobs[] | select(.name == "${protectedDeploymentRouteJobName}" and .conclusion == "success")] | length')"
5206
- route_skipped_count="$(printf '%s' "$jobs" | jq \
5207
- '[.jobs[] | select(.name == "${protectedDeploymentRouteJobName}" and .conclusion == "skipped")] | length')"
5208
- case "$apply_count:$route_success_count:$route_skipped_count:$EBK_DEPLOYMENT_PROFILE" in
5209
- 1:1:0:*) echo 'deployed=true' >> "$GITHUB_OUTPUT" ;;
5210
- 0:0:1:*) echo 'deployed=false' >> "$GITHUB_OUTPUT" ;;
5211
- 0:1:0:starter) echo 'deployed=false' >> "$GITHUB_OUTPUT" ;;
5212
- *) echo 'Deploy route and staging application evidence disagree'; exit 1 ;;
5213
- esac
5219
+ execute_count="$(printf '%s' "$jobs" | jq \
5220
+ '[.jobs[] | select(.name == "native deploy staging" and .conclusion == "success")] | length')"
5221
+ [ "$execute_count" = 1 ] || {
5222
+ echo 'Deploy must contain exactly one successful thin staging execution'
5223
+ exit 1
5224
+ }
5225
+ echo 'deployed=true' >> "$GITHUB_OUTPUT"
5214
5226
 
5215
5227
  plan:
5216
5228
  needs: deployment-classification
@@ -7093,7 +7105,7 @@ on:
7093
7105
  description: Protected stage
7094
7106
  required: true
7095
7107
  type: choice
7096
- options: [staging, production]
7108
+ options: [${protectedWorkflowStageChoices}]
7097
7109
  project:
7098
7110
  description: Exact Product Slice project
7099
7111
  required: true
@@ -7132,7 +7144,7 @@ jobs:
7132
7144
  EBK_PROTECTED_REF: \${{ github.ref }}
7133
7145
  run: |
7134
7146
  case "$EBK_STAGE:$EBK_PROTECTED_REF" in
7135
- staging:refs/heads/develop|production:refs/heads/main) ;;
7147
+ ${protectedWorkflowStageBranchCases}) ;;
7136
7148
  *) echo 'Secret metadata stage does not match the protected branch'; exit 1 ;;
7137
7149
  esac
7138
7150
  case "$EBK_PROJECT" in
@@ -7168,6 +7180,98 @@ jobs:
7168
7180
  args=("--stage=$EBK_STAGE" "--region=$AWS_REGION")
7169
7181
  if [ "$EBK_ACTION" = apply ]; then args+=("--apply"); fi
7170
7182
  pnpm nx run "$EBK_PROJECT:secret-metadata" -- "\${args[@]}"
7183
+ `,
7184
+ '.github/workflows/secret-initialize.yml': `name: Secret initialize
7185
+
7186
+ on:
7187
+ workflow_dispatch:
7188
+ inputs:
7189
+ stage:
7190
+ description: Protected stage
7191
+ required: true
7192
+ type: choice
7193
+ options: [${protectedWorkflowStageChoices}]
7194
+ project:
7195
+ description: Exact Product Slice project
7196
+ required: true
7197
+ type: string
7198
+ logical_name:
7199
+ description: Exact machine-generated secret logical name
7200
+ required: true
7201
+ type: string
7202
+ action:
7203
+ description: Value-blind initialization action
7204
+ required: true
7205
+ default: report
7206
+ type: choice
7207
+ options: [report, apply]
7208
+
7209
+ concurrency:
7210
+ group: secret-initialize-\${{ inputs.stage }}-\${{ inputs.project }}-\${{ inputs.logical_name }}
7211
+ cancel-in-progress: false
7212
+
7213
+ permissions:
7214
+ contents: read
7215
+
7216
+ jobs:
7217
+ initialize:
7218
+ environment: \${{ inputs.stage }}
7219
+ permissions:
7220
+ contents: read
7221
+ id-token: write
7222
+ env:
7223
+ AWS_DEPLOY_ROLE_ARN: \${{ secrets.AWS_DEPLOY_ROLE_ARN }}
7224
+ AWS_EXPECTED_ACCOUNT_ID: \${{ vars.AWS_EXPECTED_ACCOUNT_ID }}
7225
+ AWS_REGION: \${{ vars.AWS_REGION }}
7226
+ EBK_ACTION: \${{ inputs.action }}
7227
+ EBK_LOGICAL_NAME: \${{ inputs.logical_name }}
7228
+ EBK_PROJECT: \${{ inputs.project }}
7229
+ EBK_STAGE: \${{ inputs.stage }}
7230
+ runs-on: ubuntu-latest
7231
+ steps:
7232
+ - name: Validate protected request
7233
+ env:
7234
+ EBK_PROTECTED_REF: \${{ github.ref }}
7235
+ run: |
7236
+ case "$EBK_STAGE:$EBK_PROTECTED_REF" in
7237
+ ${protectedWorkflowStageBranchCases}) ;;
7238
+ *) echo 'Secret initialize stage does not match the protected branch'; exit 1 ;;
7239
+ esac
7240
+ case "$EBK_PROJECT" in
7241
+ ''|-*|*-|*[!a-z0-9-]*) echo 'Secret initialize project must be an exact normalized Slice name'; exit 1 ;;
7242
+ esac
7243
+ [[ "$EBK_LOGICAL_NAME" =~ ^[A-Za-z][A-Za-z0-9]{0,63}$ ]] ||
7244
+ { echo 'Secret initialize logical name is invalid'; exit 1; }
7245
+ test -n "$AWS_DEPLOY_ROLE_ARN" || { echo "$EBK_STAGE AWS_DEPLOY_ROLE_ARN is required"; exit 1; }
7246
+ test -n "$AWS_EXPECTED_ACCOUNT_ID" || { echo "$EBK_STAGE AWS_EXPECTED_ACCOUNT_ID is required"; exit 1; }
7247
+ test -n "$AWS_REGION" || { echo "$EBK_STAGE AWS_REGION is required"; exit 1; }
7248
+ case "$AWS_DEPLOY_ROLE_ARN" in
7249
+ arn:aws:iam::$AWS_EXPECTED_ACCOUNT_ID:role/*) ;;
7250
+ *) echo 'Secret initialize role does not belong to the expected account'; exit 1 ;;
7251
+ esac
7252
+ - uses: ${checkoutAction}
7253
+ with:
7254
+ persist-credentials: false
7255
+ - uses: ${pnpmAction}
7256
+ - uses: ${setupNodeAction}
7257
+ with:
7258
+ node-version: ${tool_versions_js_1.WORKSPACE_NODE_VERSION}
7259
+ cache: pnpm
7260
+ - run: pnpm install --frozen-lockfile --ignore-scripts --ignore-pnpmfile
7261
+ - name: Verify managed workspace integrity before AWS authority
7262
+ run: pnpm nx run ${name}:workspace-health
7263
+ - uses: ${configureAwsAction}
7264
+ with:
7265
+ role-to-assume: \${{ secrets.AWS_DEPLOY_ROLE_ARN }}
7266
+ role-session-name: ebk-secret-initialize-\${{ github.run_id }}-\${{ github.run_attempt }}
7267
+ aws-region: \${{ vars.AWS_REGION }}
7268
+ - name: Verify assumed account
7269
+ run: test "$(aws sts get-caller-identity --query Account --output text)" = "$AWS_EXPECTED_ACCOUNT_ID"
7270
+ - name: Initialize machine-generated secret value-blind
7271
+ run: |
7272
+ args=("--logicalName=$EBK_LOGICAL_NAME" "--stage=$EBK_STAGE" "--region=$AWS_REGION")
7273
+ if [ "$EBK_ACTION" = apply ]; then args+=("--apply"); fi
7274
+ pnpm nx run "$EBK_PROJECT:secret-initialize" -- "\${args[@]}"
7171
7275
  `,
7172
7276
  '.github/workflows/sync-back.yml': `name: Sync protected main history
7173
7277
 
@@ -7457,9 +7561,10 @@ infrastructure or protected deployment policy. Preserve the ownership boundary r
7457
7561
  \`.ebk/ownership.json\`: managed files belong to EBK, seeded files are generated starting
7458
7562
  points that adopters may change, and unrecorded files are adopter-owned.
7459
7563
 
7460
- Secret values are a human-only TTY ceremony. Agents and CI must never invoke
7461
- \`ebk secret set\` or \`ebk secret remove\`; they may use only value-blind
7462
- metadata, status, and verification commands.
7564
+ Human-supplied secret values are a human-only TTY ceremony. Agents and CI must
7565
+ never invoke \`ebk secret set\` or \`ebk secret remove\`. They may use
7566
+ value-blind metadata, status, verification, and the exact generated-secret
7567
+ initializer, which accepts and returns no plaintext value.
7463
7568
 
7464
7569
  ## Work markers
7465
7570
 
@@ -7576,14 +7681,15 @@ The Standard Foundation lives at \`packages/foundation\`. Product slices live be
7576
7681
  \`packages/<slice-name>\` and consume versioned Foundation contracts instead of importing
7577
7682
  Foundation implementation files.
7578
7683
 
7579
- Canonical consumer stages use the matching \`development\`, \`staging\`, or \`production\`
7580
- Foundation. Framework-derived personal stages may use only the \`development\`
7581
- Foundation; generic preview stages are unsupported.
7684
+ This workspace's \`${deploymentProfile}\` profile activates only:
7685
+ ${activeStages.join(', ')}. Each active canonical consumer stage uses the matching Foundation.
7686
+ Inactive canonical stages are rejected. Framework-derived personal stages may use only the
7687
+ \`development\` Foundation; generic preview stages are unsupported.
7582
7688
 
7583
- The committed deployment profile changes account and local/GitHub authority only. Every
7584
- canonical stage always owns a separate Router/domain, Aurora cluster and migration history,
7689
+ Every active canonical stage owns a separate Router/domain, Aurora cluster and migration history,
7585
7690
  Cognito user pool, event bus, secret namespace, IAM boundary, logs, queues, ECR namespace, and
7586
- stage-qualified SSM discovery contract. Discovery rejects a record for another canonical stage.
7691
+ stage-qualified SSM discovery contract. Discovery rejects a record for an inactive or different
7692
+ canonical stage.
7587
7693
  `,
7588
7694
  'docs/git-workflow.md': `# Protected Git workflow
7589
7695
 
@@ -7603,10 +7709,11 @@ Direct updates, force pushes, deletion, squash merging, and rebase merging are p
7603
7709
  GitHub rulesets, environments, and AWS IAM are the authorization boundaries; local hooks are
7604
7710
  only defense in depth.
7605
7711
 
7606
- The \`staging\` environment accepts only \`develop\`; \`production\` accepts only \`main\`.
7607
- These workflows exist for every deployment profile. The staging workflow is optional for
7608
- \`starter\`, whose governed local Nx target may deploy development and staging. Production is
7609
- GitHub-only for every profile; \`fully-isolated\` also requires GitHub for staging.
7712
+ The rehearsal environment accepts only \`develop\`; \`production\` accepts only \`main\`.
7713
+ For \`starter\`, development is the rehearsal stage and GitHub deployment is optional for both
7714
+ development and production. For isolated profiles, staging is the rehearsal stage;
7715
+ \`production-isolated\` requires GitHub for production and \`fully-isolated\` requires GitHub
7716
+ for staging and production.
7610
7717
  The committed \`productionApproval.mode\` selects one of two production authorization
7611
7718
  contracts:
7612
7719
 
@@ -7628,15 +7735,15 @@ contracts:
7628
7735
 
7629
7736
  Both modes retain required checks, a non-author CODEOWNER approval, no ruleset bypass, the
7630
7737
  literal production environment, and its branch-scoped credentials. The base \`staging\` and
7631
- \`production\` environments own deployment, smoke, and ECR evidence roles plus their
7632
- variables; isolated profiles also keep the staging-registry promotion pull role in production.
7738
+ \`production\` environments own deployment and smoke authority plus their variables; isolated
7739
+ profiles also keep the staging-registry promotion pull role in production. Read-only container
7740
+ evidence uses only \`ecr-inspector-<stage>\`, which owns the exact evidence role and must trust
7741
+ that dedicated immutable repository/environment subject rather than the base stage subject.
7633
7742
  Starter promotion authenticates once to the shared account and copies the exact staging digest
7634
7743
  into a distinct production ECR repository. Dedicated
7635
7744
  \`infrastructure-plan-<stage>\` environments gate read-only role use. Separate
7636
- \`async-recovery-<stage>\`, \`performance-aggregate-<stage>\`,
7637
- \`performance-cost-<stage>\`, \`performance-load-<stage>\`, and
7638
- \`reliability-read-<stage>\` environments own only the role and variables required by that
7639
- capability. Infrastructure-plan jobs use a repository-variable read-only role/input inventory;
7745
+ \`async-recovery-<stage>\` and \`reliability-read-<stage>\` environments own only the role and
7746
+ variables required by that capability. Infrastructure-plan jobs use a repository-variable read-only role/input inventory;
7640
7747
  an independent clean audit job assumes that exact environment-subject role and verifies its
7641
7748
  trust and complete inline policy before any repository-backed plan job may assume it. Plan-role
7642
7749
  trust uses GitHub's immutable repository identity subject,
@@ -7666,64 +7773,10 @@ its \`EBK_FLEET_ORIGIN\` to equal the origin retained by the plan.
7666
7773
  repository's exact \`async-recovery-<stage>\` GitHub OIDC subject and grant only
7667
7774
  the recovery operations/resources declared by generated capability adapters.
7668
7775
 
7669
- \`AWS_PERFORMANCE_LOAD_ROLE_ARN\` is a separate read-only OIDC role. Trust only
7670
- this repository's exact \`performance-load-<stage>\` GitHub OIDC subject.
7671
- Set that environment's \`EBK_PERFORMANCE_ORIGINS_JSON\` to a JSON object that
7672
- maps every reviewed Slice to the exact \`performanceEndpoint\` emitted by its
7673
- current deployment; never copy the map to repository scope or substitute the
7674
- fleet web origin. The workflow selects only its requested Slice, and the
7675
- committed load plan must name that same origin and exact reserved Slice path.
7676
- Grant \`sts:GetCallerIdentity\` and \`secretsmanager:GetSecretValue\` only on
7677
- \`arn:<partition>:secretsmanager:<region>:<account>:secret:ebk/<stage>/<slice>/*\` for
7678
- reviewed Slices. Do not grant secret writes, deployment, CloudFormation, SST,
7679
- or CloudWatch Logs access. The protected workflow never logs or uploads HMAC
7680
- material and removes its new job-scoped 0600 file after cleanup.
7681
- Bootstrap verifies environment-only secret placement, not the role's hidden
7682
- AWS trust or permission policy.
7683
-
7684
- \`AWS_PERFORMANCE_AGGREGATE_ROLE_ARN\` is a separate adopter-owned read-only
7685
- OIDC role. Trust only this repository's exact
7686
- \`performance-aggregate-<stage>\` GitHub OIDC subject. Grant
7687
- \`sts:GetCallerIdentity\` plus only the exact data-read actions and resource
7688
- ARNs required by the adopted \`performance/aggregate-count-provider.ts\`.
7689
- Do not grant writes, deployment, CloudFormation, SST, IAM, Cost Explorer, or
7690
- unrelated data access. The generated workflow validates the protected Deploy
7691
- artifact before role assumption, verifies the STS account and environment
7692
- Region, withholds the OIDC bearer, and clears the AWS session before artifact
7693
- retention. Bootstrap verifies environment-only secret placement, not the
7694
- role's hidden AWS trust or least-privilege permission policy.
7695
-
7696
- \`AWS_PERFORMANCE_COST_ROLE_ARN\` is a separate read-only OIDC role. Trust only
7697
- this repository's exact \`performance-cost-<stage>\` GitHub OIDC subject.
7698
- Grant only \`sts:GetCallerIdentity\`, \`ce:ListCostAllocationTags\`, and
7699
- \`ce:GetCostAndUsage\`; Cost Explorer
7700
- queries are account-global, while the retained evidence still binds the
7701
- selected resource Region. Do not grant budget, anomaly-monitor, tag, billing,
7702
- deployment, CloudFormation, SST, or other mutation authority. Bootstrap verifies
7703
- environment-only secret placement, not the role's hidden AWS trust or
7704
- permission policy.
7705
-
7706
- The framework manages
7707
- \`.github/workflows/performance-aggregate-counts.yml\`, its exact Deploy
7708
- binding, evidence wrapper, artifact name, and canonical schema. The seeded
7709
- \`performance/aggregate-count-provider.ts\` remains adopter-owned and fails
7710
- closed until it returns only the reviewed business counts and provider request
7711
- reference. The provider runs only with the dedicated aggregate-read role after
7712
- the framework validates the exact protected release and STS account. The
7713
- workflow binds those untrusted counts to the environment-owned account/Region,
7714
- closed period, exact current protected release, Slice, stage, and workspace
7715
- and records the dedicated OIDC access mode and adopter-owned least-privilege
7716
- read contract before it emits the single
7717
- \`aggregate-count-<stage>-<slice>-<run>-<attempt>\` artifact. The framework
7718
- does not invent counts or copy them from request-level dimensions.
7719
-
7720
- \`performance-cost-actual.yml\` treats supplied run IDs and artifact names only
7721
- as selectors. Before OIDC it queries GitHub for the fixed aggregate workflow
7722
- and generated \`Deploy\` workflow runs, requiring the same repository,
7723
- candidate, protected branch, successful conclusion, allowed event, exact
7724
- workflow name/path, and one exact nonexpired artifact. It derives the compact
7725
- performance release binding from that Deploy artifact and separately verifies
7726
- the independently approved aggregate-count and release-binding byte digests.
7776
+ The preview-era performance aggregate, cost, and load workflow renderers remain available to
7777
+ framework maintainers, but RC.31 no longer emits their stale release-manifest-bound workflows
7778
+ or GitHub environments by default. Reintroducing them requires an explicit capability contract
7779
+ bound to the thin deployment receipt rather than the removed preview/replay lifecycle.
7727
7780
 
7728
7781
  \`AWS_RELIABILITY_READ_ROLE_ARN\` is a separate read-only OIDC role. Trust only
7729
7782
  this repository's exact \`reliability-read-<stage>\` GitHub OIDC subject.
@@ -7744,8 +7797,8 @@ resources before the adapter makes a service call. Bootstrap verifies
7744
7797
  environment-only secret placement, not the role's hidden AWS trust or
7745
7798
  permission policy.
7746
7799
 
7747
- The async-recovery, performance-load, performance-cost, and reliability-read
7748
- jobs have job-scoped \`id-token: write\`. They install the frozen dependency
7800
+ The async-recovery and reliability-read jobs have job-scoped \`id-token: write\`.
7801
+ They install the frozen dependency
7749
7802
  graph with lifecycle scripts and pnpm hooks disabled before assuming AWS
7750
7803
  authority. Immediately after the one pinned credential action, they blank the
7751
7804
  OIDC request URL and bearer for future steps and explicitly shadow both values
@@ -8135,8 +8188,18 @@ must be committed, reviewable, and auditable.
8135
8188
  executor: 'nx:run-commands',
8136
8189
  options: { command: 'node tools/install-ebk-hooks.mjs' },
8137
8190
  },
8191
+ 'stage-authority-render': {
8192
+ cache: false,
8193
+ executor: 'nx:run-commands',
8194
+ outputs: ['{workspaceRoot}/.ebk/authority/{args.stage}/*'],
8195
+ options: {
8196
+ command: 'node tools/stage-authority-render.mjs',
8197
+ forwardAllArgs: true,
8198
+ },
8199
+ },
8138
8200
  'deploy-local': {
8139
8201
  cache: false,
8202
+ dependsOn: ['workspace-health'],
8140
8203
  executor: '@empire-builder-kit/nx:local-deploy',
8141
8204
  options: {
8142
8205
  stage: 'development',
@@ -8165,19 +8228,6 @@ must be committed, reviewable, and auditable.
8165
8228
  executor: '@empire-builder-kit/nx:work-markers',
8166
8229
  options: {},
8167
8230
  },
8168
- 'workload-role-candidate-report': {
8169
- executor: 'nx:run-commands',
8170
- options: {
8171
- command: 'node tools/workload-role-baseline/report-candidate-bundle.mjs',
8172
- forwardAllArgs: true,
8173
- },
8174
- },
8175
- 'workload-role-provisioner-build': {
8176
- executor: 'nx:run-commands',
8177
- options: {
8178
- command: 'node tools/workload-role-baseline/build.mjs',
8179
- },
8180
- },
8181
8231
  verify: {
8182
8232
  dependsOn: ['blueprint-trust-check', 'supply-chain-check'],
8183
8233
  executor: 'nx:run-commands',
@@ -8213,7 +8263,9 @@ domain. Without it, the shared Router uses its functional provider URL.
8213
8263
 
8214
8264
  Before deploying development or staging, add at least one exact operator/probe CIDR to
8215
8265
  \`security/router-waf.json\`. Production is public by default behind the same managed and
8216
- rate-limiting baseline; select its allowlist mode explicitly when required.
8266
+ rate-limiting baseline; select its allowlist mode explicitly when required. Rehearse the
8267
+ resolved ${(0, index_js_4.productionRehearsalStage)(deploymentProfile)} stage with
8268
+ \`pnpm nx run foundation:router-waf-rehearsal -- --probeUrl=https://<router>/<slice>/api/health --profile=<temporary-profile>\`.
8217
8269
  `,
8218
8270
  'packages/foundation/contracts/foundation.json': json({
8219
8271
  contractVersion: '1.0.0',
@@ -8243,11 +8295,15 @@ rate-limiting baseline; select its allowlist mode explicitly when required.
8243
8295
  dataRetention: 'retained',
8244
8296
  nat: 'ec2',
8245
8297
  },
8246
- staging: {
8247
- aurora: 'scale-to-zero',
8248
- dataRetention: 'retained',
8249
- nat: 'ec2',
8250
- },
8298
+ ...(deploymentProfile === 'starter'
8299
+ ? {}
8300
+ : {
8301
+ staging: {
8302
+ aurora: 'scale-to-zero',
8303
+ dataRetention: 'retained',
8304
+ nat: 'ec2',
8305
+ },
8306
+ }),
8251
8307
  production: {
8252
8308
  aurora: 'repository-policy',
8253
8309
  dataRetention: 'retained-and-protected',
@@ -8271,7 +8327,7 @@ The machine-readable stage inventory is \`../contracts/costs.json\`; keep this
8271
8327
  seeded decision record aligned with organization-specific budgets and alerts.
8272
8328
 
8273
8329
  - Development uses EC2 NAT, a development bastion, and Aurora scale-to-zero.
8274
- - Staging uses EC2 NAT and Aurora scale-to-zero by default.
8330
+ ${deploymentProfile === 'starter' ? '' : '- Staging uses EC2 NAT and Aurora scale-to-zero by default.\n'}- Production always uses managed NAT and retains protected data. Its explicit Repository
8275
8331
  - Production always uses managed NAT and retains protected data. Its explicit Repository
8276
8332
  Operating Policy profile selects either the standard 2-ACU Aurora floor or the
8277
8333
  cost-optimized 0.5-ACU warm floor.
@@ -8392,7 +8448,7 @@ connects as the Slice's no-password IAM-authenticated migrator user.
8392
8448
  - Every stage's CloudFront Router has its own global Web ACL. The baseline always includes AWS
8393
8449
  Common Rule Set, Known Bad Inputs, Amazon IP Reputation, rate blocking, CloudWatch metrics,
8394
8450
  and sampled requests. Nonproduction is allowlisted by default. Production is public by
8395
- default, but cannot deploy until the exact policy has passed a staging blocking rehearsal.
8451
+ default, but cannot deploy until the exact policy has passed a ${rehearsalStage} blocking rehearsal.
8396
8452
  - Full WAF request logging is disabled by default. Enabling it keeps blocked requests only,
8397
8453
  uses bounded retention, and redacts query strings, cookies, authorization, and API keys.
8398
8454
 
@@ -8433,6 +8489,7 @@ import {
8433
8489
  foundationSsmPath,
8434
8490
  normalizeRouterWafPolicy,
8435
8491
  reconcileRouterWafBlockingRehearsal,
8492
+ routerWafContractDigest,
8436
8493
  type FoundationSsmKey,
8437
8494
  } from '@empire-builder-kit/nx/foundation';
8438
8495
  import {
@@ -8440,12 +8497,19 @@ import {
8440
8497
  FOUNDATION_AURORA_ENGINE_VERSION,
8441
8498
  productionFoundationProfileContract,
8442
8499
  } from '@empire-builder-kit/nx/repository-policy';
8500
+ import { installStageIamBoundaryTransforms } from '@empire-builder-kit/nx/aws-authority';
8501
+ import { createStageAuthorityIdentity } from '@empire-builder-kit/nx/aws-authority';
8502
+ import {
8503
+ configuredDeploymentAccountForStage,
8504
+ configuredDeploymentRegion,
8505
+ productionRehearsalStage,
8506
+ } from '@empire-builder-kit/nx/repository-policy';
8443
8507
  import { createFoundationAccountCostControlPlan } from '@empire-builder-kit/nx/performance';
8444
8508
  import accountCostPolicy from '../performance/account-cost-policy.json';
8445
8509
  import routerWafBlockingRehearsal from '../security/router-waf-blocking-rehearsal.json';
8446
8510
  import routerWafLiveEvidence from '../security/router-waf-live-evidence.json';
8447
8511
  import routerWafPolicy from '../security/router-waf.json';
8448
- import type { FoundationWorkloadRolePreflight } from './workload-roles/preflight.js';
8512
+ import repositoryPolicy from '../../../ebk.repository-policy.json';
8449
8513
 
8450
8514
  function identityDomainPrefix(stage: string, accountId: string): string {
8451
8515
  if (!/^\\d{12}$/.test(accountId)) {
@@ -8479,14 +8543,7 @@ function publishFoundation(values: Record<FoundationSsmKey, any>) {
8479
8543
  );
8480
8544
  }
8481
8545
 
8482
- export function foundation(
8483
- workloadRoles?: FoundationWorkloadRolePreflight,
8484
- ) {
8485
- if (!$dev && !workloadRoles) {
8486
- throw new Error(
8487
- 'Protected Foundation workload-role preflight must complete before infrastructure construction.',
8488
- );
8489
- }
8546
+ export function foundation() {
8490
8547
  const isProduction = $app.stage === 'production';
8491
8548
  const isStaging = $app.stage === 'staging';
8492
8549
  const rootDomain = process.env.EBK_ROOT_DOMAIN?.trim();
@@ -8497,40 +8554,63 @@ export function foundation(
8497
8554
  : undefined;
8498
8555
  const natMode = productionConfiguration?.contract.nat ?? 'ec2';
8499
8556
  const normalizedRouterWafPolicy = normalizeRouterWafPolicy(routerWafPolicy);
8557
+ if (repositoryPolicy.deploymentProfile !== normalizedRouterWafPolicy.deploymentProfile) {
8558
+ throw new Error('Router WAF policy profile differs from committed repository policy.');
8559
+ }
8560
+ const rehearsalStage = productionRehearsalStage(normalizedRouterWafPolicy.deploymentProfile);
8561
+ const rehearsalAccount = configuredDeploymentAccountForStage(
8562
+ normalizedRouterWafPolicy.deploymentProfile,
8563
+ repositoryPolicy.deploymentAccounts,
8564
+ rehearsalStage,
8565
+ );
8566
+ const rehearsalRegion = configuredDeploymentRegion(repositoryPolicy.deploymentRegion);
8567
+ const rehearsalRoleArn = createStageAuthorityIdentity({
8568
+ accountId: rehearsalAccount,
8569
+ partition: rehearsalRegion.startsWith('us-gov-') ? 'aws-us-gov' : 'aws',
8570
+ region: rehearsalRegion,
8571
+ stage: rehearsalStage,
8572
+ }).deploymentRoleArn;
8500
8573
  const wafPlan = createRouterWafStagePlan({
8501
8574
  policy: normalizedRouterWafPolicy,
8502
8575
  rehearsal: isProduction
8503
8576
  ? reconcileRouterWafBlockingRehearsal({
8504
8577
  evidence: routerWafLiveEvidence,
8578
+ expected: {
8579
+ accountId: rehearsalAccount,
8580
+ deploymentRoleArn: rehearsalRoleArn,
8581
+ region: rehearsalRegion,
8582
+ stage: rehearsalStage,
8583
+ wafContractDigest: routerWafContractDigest(normalizedRouterWafPolicy),
8584
+ workspace: '${name}',
8585
+ },
8505
8586
  policy: normalizedRouterWafPolicy,
8506
8587
  receipt: routerWafBlockingRehearsal,
8507
8588
  })
8508
8589
  : null,
8509
8590
  stage: $app.stage,
8510
8591
  });
8511
- const natBinding = workloadRoles?.bindings.nat;
8512
- if (natMode === 'ec2' && natBinding) {
8513
- $transform(
8514
- aws.iam.InstanceProfile,
8515
- (args: any, opts: any, logicalName: string) => {
8516
- if (logicalName !== 'FoundationVpcNatInstanceProfile') return;
8517
- args.name = natBinding.instanceProfileName;
8518
- args.role = natBinding.roleName;
8519
- opts.import = natBinding.instanceProfileName;
8520
- opts.ignoreChanges = [
8521
- ...new Set([...(opts.ignoreChanges ?? []), 'tags', 'tagsAll']),
8522
- ];
8523
- },
8592
+ const deploymentAccount = process.env.AWS_EXPECTED_ACCOUNT_ID?.trim() ?? '';
8593
+ if (!/^\\d{12}$/.test(deploymentAccount)) {
8594
+ throw new Error(
8595
+ 'Foundation deployment requires the exact committed AWS account before infrastructure construction.',
8524
8596
  );
8525
8597
  }
8598
+ installStageIamBoundaryTransforms({
8599
+ accountId: deploymentAccount,
8600
+ instanceProfileResource: aws.iam.InstanceProfile,
8601
+ registerTransform: $transform,
8602
+ roleResource: aws.iam.Role,
8603
+ stage: ($dev ? 'development' : $app.stage) as
8604
+ | 'development'
8605
+ | 'staging'
8606
+ | 'production',
8607
+ });
8526
8608
 
8527
8609
  const vpc = new sst.aws.Vpc('FoundationVpc', {
8528
8610
  az: 2,
8529
8611
  bastion: $app.stage === 'development',
8530
8612
  nat:
8531
- natMode === 'ec2'
8532
- ? (natBinding?.vpc.nat ?? 'ec2')
8533
- : 'managed',
8613
+ natMode === 'ec2' ? 'ec2' : 'managed',
8534
8614
  });
8535
8615
  const cluster = new sst.aws.Cluster('FoundationCluster', { vpc });
8536
8616
  const router = new sst.aws.Router('FoundationRouter', {
@@ -8559,6 +8639,13 @@ export function foundation(
8559
8639
  'Foundation Router must attach its exact global Web ACL.',
8560
8640
  );
8561
8641
  }
8642
+ args.tags = {
8643
+ ...(args.tags ?? {}),
8644
+ 'ebk:managed-by': 'empire-builder-kit',
8645
+ 'ebk:owner': 'foundation',
8646
+ 'ebk:stage': wafPlan.stage,
8647
+ 'ebk:workspace': '${name}',
8648
+ };
8562
8649
  },
8563
8650
  waf(args: any, opts: any) {
8564
8651
  if (args.scope !== 'CLOUDFRONT') {
@@ -8576,8 +8663,11 @@ export function foundation(
8576
8663
  name: 'foundation-' + wafPlan.stage + '-router-ipv4-allowlist',
8577
8664
  scope: 'CLOUDFRONT',
8578
8665
  tags: {
8666
+ 'ebk:managed-by': 'empire-builder-kit',
8667
+ 'ebk:owner': 'foundation',
8579
8668
  'ebk:policy-digest': wafPlan.policyDigest,
8580
8669
  'ebk:stage': wafPlan.stage,
8670
+ 'ebk:workspace': '${name}',
8581
8671
  },
8582
8672
  },
8583
8673
  { provider: opts.provider },
@@ -8592,8 +8682,11 @@ export function foundation(
8592
8682
  name: 'foundation-' + wafPlan.stage + '-router-ipv6-allowlist',
8593
8683
  scope: 'CLOUDFRONT',
8594
8684
  tags: {
8685
+ 'ebk:managed-by': 'empire-builder-kit',
8686
+ 'ebk:owner': 'foundation',
8595
8687
  'ebk:policy-digest': wafPlan.policyDigest,
8596
8688
  'ebk:stage': wafPlan.stage,
8689
+ 'ebk:workspace': '${name}',
8597
8690
  },
8598
8691
  },
8599
8692
  { provider: opts.provider },
@@ -8604,8 +8697,11 @@ export function foundation(
8604
8697
  args.scope = 'CLOUDFRONT';
8605
8698
  args.tags = {
8606
8699
  ...(args.tags ?? {}),
8700
+ 'ebk:managed-by': 'empire-builder-kit',
8701
+ 'ebk:owner': 'foundation',
8607
8702
  'ebk:policy-digest': wafPlan.policyDigest,
8608
8703
  'ebk:stage': wafPlan.stage,
8704
+ 'ebk:workspace': '${name}',
8609
8705
  };
8610
8706
  args.visibilityConfig = {
8611
8707
  cloudwatchMetricsEnabled: true,
@@ -8709,6 +8805,7 @@ export function foundation(
8709
8805
  const accountCostControl = createFoundationAccountCostControlPlan({
8710
8806
  evaluatedAt: new Date().toISOString(),
8711
8807
  policy: accountCostPolicy,
8808
+ rehearsalStage: '${rehearsalStage}',
8712
8809
  region: process.env.AWS_REGION,
8713
8810
  stage: $app.stage,
8714
8811
  workspace: '${name}',
@@ -9013,15 +9110,9 @@ export function foundation(
9013
9110
  }
9014
9111
  `,
9015
9112
  'packages/foundation/infra/index.ts': `import { foundation } from './foundation.js';
9016
- import type { FoundationWorkloadRolePreflight } from './workload-roles/preflight.js';
9017
9113
 
9018
- export function app(workloadRoles?: FoundationWorkloadRolePreflight) {
9019
- const resources = foundation(workloadRoles);
9020
- return {
9021
- ...resources,
9022
- workloadRoleManifestDigest:
9023
- workloadRoles?.registry.manifestDigest ?? 'local-dev-ephemeral',
9024
- };
9114
+ export function app() {
9115
+ return foundation();
9025
9116
  }
9026
9117
  `,
9027
9118
  'packages/foundation/performance/account-cost-policy.json': json({
@@ -9036,6 +9127,7 @@ export function app(workloadRoles?: FoundationWorkloadRolePreflight) {
9036
9127
  workspace: name,
9037
9128
  }),
9038
9129
  'packages/foundation/security/router-waf.json': json({
9130
+ deploymentProfile,
9039
9131
  kind: 'ebk-router-waf-policy',
9040
9132
  logging: {
9041
9133
  enabled: false,
@@ -9054,21 +9146,25 @@ export function app(workloadRoles?: FoundationWorkloadRolePreflight) {
9054
9146
  allowedCidrs: [],
9055
9147
  mode: 'block',
9056
9148
  },
9057
- staging: {
9058
- access: 'allowlist',
9059
- allowedCidrs: [],
9060
- mode: 'block',
9061
- },
9149
+ ...(deploymentProfile === 'starter'
9150
+ ? {}
9151
+ : {
9152
+ staging: {
9153
+ access: 'allowlist',
9154
+ allowedCidrs: [],
9155
+ mode: 'block',
9156
+ },
9157
+ }),
9062
9158
  },
9063
9159
  }),
9064
9160
  'packages/foundation/security/router-waf-blocking-rehearsal.json': json({
9065
9161
  kind: 'ebk-router-waf-blocking-rehearsal',
9066
- schemaVersion: 1,
9162
+ schemaVersion: 4,
9067
9163
  status: 'pending',
9068
9164
  }),
9069
9165
  'packages/foundation/security/router-waf-live-evidence.json': json({
9070
9166
  kind: 'ebk-router-waf-live-evidence',
9071
- schemaVersion: 1,
9167
+ schemaVersion: 4,
9072
9168
  status: 'pending',
9073
9169
  }),
9074
9170
  'packages/foundation/configuration/declarations.json': json({
@@ -9222,10 +9318,6 @@ export function app(workloadRoles?: FoundationWorkloadRolePreflight) {
9222
9318
  'verify',
9223
9319
  { target: 'profile-preflight', params: 'forward' },
9224
9320
  ],
9225
- outputs: [
9226
- `{projectRoot}/.ebk/evidence/infrastructure-convergence.json`,
9227
- `{projectRoot}/.ebk/evidence/infrastructure-mutation-binding.json`,
9228
- ],
9229
9321
  options: {
9230
9322
  cwd: 'packages/foundation',
9231
9323
  stage: 'development',
@@ -9242,15 +9334,7 @@ export function app(workloadRoles?: FoundationWorkloadRolePreflight) {
9242
9334
  'infrastructure-plan': {
9243
9335
  cache: false,
9244
9336
  executor: '@empire-builder-kit/nx:infrastructure-plan',
9245
- outputs: [
9246
- `{projectRoot}/.ebk/evidence/infrastructure-plan-authorization.json`,
9247
- `{projectRoot}/.ebk/evidence/infrastructure-plan-command.json`,
9248
- `{projectRoot}/.ebk/evidence/infrastructure-plan.private-stderr.txt`,
9249
- `{projectRoot}/.ebk/evidence/infrastructure-plan.raw.json`,
9250
- `{projectRoot}/.ebk/evidence/infrastructure-plan.json`,
9251
- ],
9252
9337
  options: {
9253
- action: 'deploy',
9254
9338
  cwd: 'packages/foundation',
9255
9339
  stage: 'development',
9256
9340
  stageMode: 'foundation',
@@ -9259,10 +9343,6 @@ export function app(workloadRoles?: FoundationWorkloadRolePreflight) {
9259
9343
  refresh: {
9260
9344
  executor: '@empire-builder-kit/nx:refresh',
9261
9345
  dependsOn: [{ target: 'profile-preflight', params: 'forward' }],
9262
- outputs: [
9263
- `{projectRoot}/.ebk/evidence/infrastructure-convergence.json`,
9264
- `{projectRoot}/.ebk/evidence/infrastructure-mutation-binding.json`,
9265
- ],
9266
9346
  options: {
9267
9347
  cwd: 'packages/foundation',
9268
9348
  stage: 'development',
@@ -9272,10 +9352,6 @@ export function app(workloadRoles?: FoundationWorkloadRolePreflight) {
9272
9352
  remove: {
9273
9353
  executor: '@empire-builder-kit/nx:remove',
9274
9354
  dependsOn: [{ target: 'remove-preflight', params: 'forward' }],
9275
- outputs: [
9276
- `{projectRoot}/.ebk/evidence/infrastructure-convergence.json`,
9277
- `{projectRoot}/.ebk/evidence/infrastructure-mutation-binding.json`,
9278
- ],
9279
9355
  options: {
9280
9356
  cwd: 'packages/foundation',
9281
9357
  stage: 'development',
@@ -9325,9 +9401,17 @@ export function app(workloadRoles?: FoundationWorkloadRolePreflight) {
9325
9401
  'packages/foundation/scripts/verify-foundation.mjs': `import { readFileSync } from 'node:fs';
9326
9402
 
9327
9403
  import {
9404
+ normalizeRouterWafBlockingRehearsal,
9328
9405
  normalizeRouterWafPolicy,
9329
9406
  reconcileRouterWafBlockingRehearsal,
9407
+ routerWafContractDigest,
9330
9408
  } from '@empire-builder-kit/nx/foundation';
9409
+ import { createStageAuthorityIdentity } from '@empire-builder-kit/nx/aws-authority';
9410
+ import {
9411
+ configuredDeploymentAccountForStage,
9412
+ configuredDeploymentRegion,
9413
+ productionRehearsalStage,
9414
+ } from '@empire-builder-kit/nx/repository-policy';
9331
9415
 
9332
9416
  const descriptor = JSON.parse(
9333
9417
  readFileSync(new URL('../contracts/foundation.json', import.meta.url), 'utf8'),
@@ -9352,25 +9436,54 @@ const routerWafPolicy = normalizeRouterWafPolicy(
9352
9436
  ),
9353
9437
  ),
9354
9438
  );
9355
- reconcileRouterWafBlockingRehearsal({
9356
- evidence: JSON.parse(
9357
- readFileSync(
9358
- new URL('../security/router-waf-live-evidence.json', import.meta.url),
9359
- 'utf8',
9439
+ const repositoryPolicy = JSON.parse(
9440
+ readFileSync(new URL('../../../ebk.repository-policy.json', import.meta.url), 'utf8'),
9441
+ );
9442
+ const workspaceManifest = JSON.parse(
9443
+ readFileSync(new URL('../../../package.json', import.meta.url), 'utf8'),
9444
+ );
9445
+ const rehearsalReceipt = JSON.parse(
9446
+ readFileSync(
9447
+ new URL(
9448
+ '../security/router-waf-blocking-rehearsal.json',
9449
+ import.meta.url,
9360
9450
  ),
9451
+ 'utf8',
9361
9452
  ),
9362
- policy: routerWafPolicy,
9363
- receipt:
9364
- JSON.parse(
9365
- readFileSync(
9366
- new URL(
9367
- '../security/router-waf-blocking-rehearsal.json',
9368
- import.meta.url,
9453
+ );
9454
+ const normalizedRehearsal = normalizeRouterWafBlockingRehearsal(rehearsalReceipt);
9455
+ if (normalizedRehearsal) {
9456
+ const rehearsalStage = productionRehearsalStage(repositoryPolicy.deploymentProfile);
9457
+ const rehearsalAccount = configuredDeploymentAccountForStage(
9458
+ repositoryPolicy.deploymentProfile,
9459
+ repositoryPolicy.deploymentAccounts,
9460
+ rehearsalStage,
9461
+ );
9462
+ const rehearsalRegion = configuredDeploymentRegion(repositoryPolicy.deploymentRegion);
9463
+ reconcileRouterWafBlockingRehearsal({
9464
+ evidence: JSON.parse(
9465
+ readFileSync(
9466
+ new URL('../security/router-waf-live-evidence.json', import.meta.url),
9467
+ 'utf8',
9369
9468
  ),
9370
- 'utf8',
9371
9469
  ),
9372
- ),
9373
- });
9470
+ expected: {
9471
+ accountId: rehearsalAccount,
9472
+ deploymentRoleArn: createStageAuthorityIdentity({
9473
+ accountId: rehearsalAccount,
9474
+ partition: rehearsalRegion.startsWith('us-gov-') ? 'aws-us-gov' : 'aws',
9475
+ region: rehearsalRegion,
9476
+ stage: rehearsalStage,
9477
+ }).deploymentRoleArn,
9478
+ region: rehearsalRegion,
9479
+ stage: rehearsalStage,
9480
+ wafContractDigest: routerWafContractDigest(routerWafPolicy),
9481
+ workspace: workspaceManifest.name,
9482
+ },
9483
+ policy: routerWafPolicy,
9484
+ receipt: normalizedRehearsal,
9485
+ });
9486
+ }
9374
9487
  const expectedCapabilities = [
9375
9488
  'network',
9376
9489
  'routing',
@@ -9387,8 +9500,10 @@ if (descriptor.contractVersion !== '1.0.0') {
9387
9500
  throw new Error('Foundation contractVersion must be 1.0.0.');
9388
9501
  }
9389
9502
  if (
9503
+ JSON.stringify(Object.keys(routerWafPolicy.stages).sort()) !==
9504
+ JSON.stringify(${JSON.stringify([...activeStages].sort())}) ||
9390
9505
  routerWafPolicy.stages.development.access !== 'allowlist' ||
9391
- routerWafPolicy.stages.staging.access !== 'allowlist' ||
9506
+ ${deploymentProfile !== 'starter' ? "routerWafPolicy.stages.staging?.access !== 'allowlist' ||" : ''}
9392
9507
  routerWafPolicy.stages.production.mode !== 'block'
9393
9508
  ) {
9394
9509
  throw new Error('Foundation Router WAF stage defaults are invalid.');
@@ -9403,7 +9518,8 @@ if (
9403
9518
  costs.productionProfiles?.standard?.aurora?.min !== '2 ACU' ||
9404
9519
  costs.productionProfiles?.['cost-optimized']?.aurora?.min !== '0.5 ACU' ||
9405
9520
  !costs.stages?.development ||
9406
- !costs.stages?.staging ||
9521
+ JSON.stringify(Object.keys(costs.stages ?? {}).sort()) !==
9522
+ JSON.stringify(${JSON.stringify([...activeStages].sort())}) ||
9407
9523
  costs.stages?.production?.dataRetention !== 'retained-and-protected'
9408
9524
  ) {
9409
9525
  throw new Error('Foundation cost manifest does not match the v1 stage contract.');
@@ -9443,9 +9559,9 @@ export {};
9443
9559
  export default $config({
9444
9560
  app(input: { stage?: string } | undefined) {
9445
9561
  const stage = input?.stage ?? 'development';
9446
- if (!['development', 'staging', 'production'].includes(stage)) {
9562
+ if (!new Set<string>(${JSON.stringify(activeStages)}).has(stage)) {
9447
9563
  throw new Error(
9448
- 'Foundation stage ' + stage + ' is not canonical. Use development, staging, or production.',
9564
+ 'Foundation stage ' + stage + ' is inactive for the ${deploymentProfile} deployment profile.',
9449
9565
  );
9450
9566
  }
9451
9567
  const production = stage === 'production';
@@ -9477,15 +9593,8 @@ export default $config({
9477
9593
  };
9478
9594
  },
9479
9595
  async run() {
9480
- const workloadRoles = $dev
9481
- ? undefined
9482
- : await import(
9483
- './infra/workload-roles/preflight.js'
9484
- ).then(({ preflightFoundationWorkloadRoles }) =>
9485
- preflightFoundationWorkloadRoles($app.stage),
9486
- );
9487
9596
  const { app } = await import('./infra/index.js');
9488
- return app(workloadRoles);
9597
+ return app();
9489
9598
  },
9490
9599
  });
9491
9600
  `,
@@ -10506,7 +10615,48 @@ assertWorkMarkerReport(markerReport);
10506
10615
  process.stdout.write('Empire Builder Kit workspace source health is green.\\n');
10507
10616
  `,
10508
10617
  };
10509
- Object.assign(files, SUPPLY_CHAIN_WORKSPACE_FILE_PLAN.files, (0, workspace_files_performance_cost_js_1.renderProtectedPerformanceCostWorkflow)(), (0, workspace_files_performance_cost_js_1.renderProtectedAggregateCountWorkflow)(), (0, workspace_files_performance_load_js_1.renderProtectedPerformanceLoadWorkflowPlan)('workspace').files, developerAgentFilePlan.files, (0, workspace_files_foundation_workload_roles_js_1.renderFoundationWorkloadRoleFiles)(), (0, workspace_files_workload_role_baseline_js_1.renderWorkspaceWorkloadRoleBaselineFiles)({ name }));
10618
+ Object.assign(files, SUPPLY_CHAIN_WORKSPACE_FILE_PLAN.files, developerAgentFilePlan.files, (0, workspace_files_stage_authority_js_1.renderStageAuthorityWorkspaceFiles)({ deploymentProfile }));
10619
+ Object.assign(files, (0, workspace_files_ecr_inspector_js_1.renderThinEcrInspectorWorkflow)({
10620
+ actionPins: {
10621
+ checkout: checkoutAction,
10622
+ configureAwsCredentials: configureAwsAction,
10623
+ downloadArtifact: downloadArtifactAction,
10624
+ pnpmSetup: pnpmAction,
10625
+ setupNode: setupNodeAction,
10626
+ uploadArtifact: uploadArtifactAction,
10627
+ },
10628
+ deploymentProfile,
10629
+ name,
10630
+ nodeVersion: tool_versions_js_1.WORKSPACE_NODE_VERSION,
10631
+ }), (0, workspace_files_thin_deploy_js_1.renderThinDeployWorkflowFilePlan)({
10632
+ actionPins: {
10633
+ checkout: checkoutAction,
10634
+ configureAwsCredentials: configureAwsAction,
10635
+ downloadArtifact: downloadArtifactAction,
10636
+ pnpmSetup: pnpmAction,
10637
+ setupNode: setupNodeAction,
10638
+ uploadArtifact: uploadArtifactAction,
10639
+ },
10640
+ deploymentProfile,
10641
+ name,
10642
+ toolVersions: {
10643
+ node: tool_versions_js_1.WORKSPACE_NODE_VERSION,
10644
+ pnpm: tool_versions_js_1.WORKSPACE_PNPM_VERSION,
10645
+ sst: tool_versions_js_1.WORKSPACE_SST_VERSION,
10646
+ },
10647
+ }).files, (0, workspace_files_thin_docs_js_1.renderThinLifecycleDocumentation)({ deploymentProfile, name }));
10648
+ const thinReleaseWorkflowPlan = (0, workspace_files_thin_release_js_1.renderThinReleaseWorkflowPlan)();
10649
+ Object.assign(files, thinReleaseWorkflowPlan.files);
10650
+ for (const obsoletePath of [
10651
+ ...thinReleaseWorkflowPlan.obsoletePaths,
10652
+ '.github/workflows/performance-aggregate-counts.yml',
10653
+ '.github/workflows/performance-cost-actual.yml',
10654
+ '.github/workflows/performance-load.yml',
10655
+ 'packages/foundation/operations/infrastructure-change.json',
10656
+ 'tools/ebk-infrastructure-plan-summary.mjs',
10657
+ ]) {
10658
+ delete files[obsoletePath];
10659
+ }
10510
10660
  for (const [path, source] of Object.entries(files)) {
10511
10661
  if (/^\.github\/workflows\/[^/]+\.ya?ml$/u.test(path)) {
10512
10662
  files[path] = isolateOidcTokenBeforeAwsAuthority(source, configureAwsAction);