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

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 (115) hide show
  1. package/package.json +7 -3
  2. package/src/aws/identity.js +1 -1
  3. package/src/aws/identity.js.map +1 -1
  4. package/src/aws-authority/stage-authority.d.ts +2 -0
  5. package/src/aws-authority/stage-authority.js +152 -20
  6. package/src/aws-authority/stage-authority.js.map +1 -1
  7. package/src/cli/main.d.ts +2 -0
  8. package/src/cli/main.js +11 -0
  9. package/src/cli/main.js.map +1 -1
  10. package/src/developer-agent/workspace-inspection.js +11 -2
  11. package/src/developer-agent/workspace-inspection.js.map +1 -1
  12. package/src/executors/github-bootstrap/github-bootstrap.d.ts +1 -0
  13. package/src/executors/github-bootstrap/github-bootstrap.js +1 -0
  14. package/src/executors/github-bootstrap/github-bootstrap.js.map +1 -1
  15. package/src/executors/github-bootstrap/schema.json +7 -1
  16. package/src/executors/infrastructure-plan/infrastructure-plan.d.ts +2 -0
  17. package/src/executors/infrastructure-plan/infrastructure-plan.js +18 -1
  18. package/src/executors/infrastructure-plan/infrastructure-plan.js.map +1 -1
  19. package/src/executors/local-deploy/local-deploy.d.ts +2 -0
  20. package/src/executors/local-deploy/local-deploy.js +17 -0
  21. package/src/executors/local-deploy/local-deploy.js.map +1 -1
  22. package/src/executors/router-waf-rehearsal/router-waf-rehearsal.d.ts +2 -0
  23. package/src/executors/router-waf-rehearsal/router-waf-rehearsal.js +2 -0
  24. package/src/executors/router-waf-rehearsal/router-waf-rehearsal.js.map +1 -1
  25. package/src/executors/secret-initialize/secret-initialize.d.ts +2 -0
  26. package/src/executors/secret-initialize/secret-initialize.js +14 -0
  27. package/src/executors/secret-initialize/secret-initialize.js.map +1 -1
  28. package/src/executors/secret-metadata/secret-metadata.d.ts +2 -0
  29. package/src/executors/secret-metadata/secret-metadata.js +14 -0
  30. package/src/executors/secret-metadata/secret-metadata.js.map +1 -1
  31. package/src/executors/sst-lifecycle/run-sst-command.d.ts +2 -0
  32. package/src/executors/sst-lifecycle/run-sst-command.js +17 -2
  33. package/src/executors/sst-lifecycle/run-sst-command.js.map +1 -1
  34. package/src/foundation/provision-logical-database.js +2 -0
  35. package/src/foundation/provision-logical-database.js.map +1 -1
  36. package/src/generators/preset/generator.js +6 -1
  37. package/src/generators/preset/generator.js.map +1 -1
  38. package/src/generators/preset/schema.d.ts +3 -0
  39. package/src/generators/preset/schema.json +5 -5
  40. package/src/generators/preset/workspace-files-performance-load.js +21 -12
  41. package/src/generators/preset/workspace-files-performance-load.js.map +1 -1
  42. package/src/generators/preset/workspace-files-stage-authority.d.ts +2 -0
  43. package/src/generators/preset/workspace-files-stage-authority.js +264 -60
  44. package/src/generators/preset/workspace-files-stage-authority.js.map +1 -1
  45. package/src/generators/preset/workspace-files-thin-deploy.d.ts +6 -1
  46. package/src/generators/preset/workspace-files-thin-deploy.js +102 -36
  47. package/src/generators/preset/workspace-files-thin-deploy.js.map +1 -1
  48. package/src/generators/preset/workspace-files-thin-docs.js +26 -10
  49. package/src/generators/preset/workspace-files-thin-docs.js.map +1 -1
  50. package/src/generators/preset/workspace-files.d.ts +1 -0
  51. package/src/generators/preset/workspace-files.js +111 -493
  52. package/src/generators/preset/workspace-files.js.map +1 -1
  53. package/src/generators/repository-policy/repository-policy.js +149 -19
  54. package/src/generators/repository-policy/repository-policy.js.map +1 -1
  55. package/src/generators/repository-policy/schema.d.ts +2 -0
  56. package/src/generators/repository-policy/schema.json +11 -1
  57. package/src/generators/repository-policy/tree-policy.d.ts +3 -0
  58. package/src/generators/repository-policy/tree-policy.js +25 -0
  59. package/src/generators/repository-policy/tree-policy.js.map +1 -0
  60. package/src/generators/slice/built-in-plan-async-work-files.js +41 -0
  61. package/src/generators/slice/built-in-plan-async-work-files.js.map +1 -1
  62. package/src/generators/slice/built-in-plan-authorization-infrastructure-files.js +2 -0
  63. package/src/generators/slice/built-in-plan-authorization-infrastructure-files.js.map +1 -1
  64. package/src/generators/slice/built-in-plan-data-lifecycle-runtime-files.js +19 -0
  65. package/src/generators/slice/built-in-plan-data-lifecycle-runtime-files.js.map +1 -1
  66. package/src/generators/slice/built-in-plan-data-retention-launcher-files.js +21 -3
  67. package/src/generators/slice/built-in-plan-data-retention-launcher-files.js.map +1 -1
  68. package/src/generators/slice/built-in-plan-database-retirement-rehearsal-files.js +20 -1
  69. package/src/generators/slice/built-in-plan-database-retirement-rehearsal-files.js.map +1 -1
  70. package/src/generators/slice/built-in-plan-operations-files.js +22 -2
  71. package/src/generators/slice/built-in-plan-operations-files.js.map +1 -1
  72. package/src/generators/slice/built-in-plan-performance-files.js +60 -0
  73. package/src/generators/slice/built-in-plan-performance-files.js.map +1 -1
  74. package/src/generators/slice/built-in-plan-secret-runtime-files.js +13 -0
  75. package/src/generators/slice/built-in-plan-secret-runtime-files.js.map +1 -1
  76. package/src/generators/slice/built-in-plan-testing-files.js +20 -0
  77. package/src/generators/slice/built-in-plan-testing-files.js.map +1 -1
  78. package/src/generators/slice/slice.js +3 -3
  79. package/src/generators/slice/slice.js.map +1 -1
  80. package/src/generators/upgrade/upgrade.js +25 -28
  81. package/src/generators/upgrade/upgrade.js.map +1 -1
  82. package/src/generators/workload/performance-registration.js +4 -8
  83. package/src/generators/workload/performance-registration.js.map +1 -1
  84. package/src/git-policy/github-bootstrap.d.ts +10 -2
  85. package/src/git-policy/github-bootstrap.js +109 -13
  86. package/src/git-policy/github-bootstrap.js.map +1 -1
  87. package/src/index.d.ts +1 -0
  88. package/src/index.js +1 -0
  89. package/src/index.js.map +1 -1
  90. package/src/local-dev/tls.js +5 -1
  91. package/src/local-dev/tls.js.map +1 -1
  92. package/src/repository-policy/policy.d.ts +16 -1
  93. package/src/repository-policy/policy.js +226 -12
  94. package/src/repository-policy/policy.js.map +1 -1
  95. package/src/schemas/repository-policy-v1.json +46 -2
  96. package/src/secrets/adapters.d.ts +2 -1
  97. package/src/secrets/adapters.js +12 -2
  98. package/src/secrets/adapters.js.map +1 -1
  99. package/src/supply-chain/generated-container-release-command.js +41 -18
  100. package/src/supply-chain/generated-container-release-command.js.map +1 -1
  101. package/src/workspace-deployment/identity.d.ts +3 -0
  102. package/src/workspace-deployment/identity.js +22 -0
  103. package/src/workspace-deployment/identity.js.map +1 -0
  104. package/src/workspace-deployment/index.d.ts +3 -0
  105. package/src/workspace-deployment/index.js +7 -0
  106. package/src/workspace-deployment/index.js.map +1 -0
  107. package/src/workspace-deployment/migration-evidence.d.ts +29 -0
  108. package/src/workspace-deployment/migration-evidence.js +83 -0
  109. package/src/workspace-deployment/migration-evidence.js.map +1 -0
  110. package/src/workspace-deployment/migration.d.ts +27 -0
  111. package/src/workspace-deployment/migration.js +109 -0
  112. package/src/workspace-deployment/migration.js.map +1 -0
  113. package/src/workspace-deployment/ownership.d.ts +81 -0
  114. package/src/workspace-deployment/ownership.js +381 -0
  115. package/src/workspace-deployment/ownership.js.map +1 -0
@@ -173,6 +173,49 @@ const TOOL_VERSIONS = {
173
173
  function json(value) {
174
174
  return `${JSON.stringify(value, null, 2)}\n`;
175
175
  }
176
+ function indentWorkflowScript(source, spaces) {
177
+ const prefix = ' '.repeat(spaces);
178
+ return source
179
+ .trim()
180
+ .split('\n')
181
+ .map((line) => `${prefix}${line}`)
182
+ .join('\n');
183
+ }
184
+ function protectedSecretPolicyDerivationScript() {
185
+ return `node --input-type=module <<'NODE'
186
+ import { appendFileSync } from 'node:fs';
187
+ import {
188
+ configuredDeploymentAccountTopology,
189
+ configuredDeploymentRegion,
190
+ isActiveDeploymentStage,
191
+ readRepositoryOperatingPolicy,
192
+ } from '@empire-builder-kit/nx/repository-policy';
193
+
194
+ const output = process.env.GITHUB_OUTPUT?.trim() ?? '';
195
+ const renderedProfile = process.env.EBK_RENDERED_PROFILE?.trim() ?? '';
196
+ const stage = process.env.EBK_STAGE?.trim() ?? '';
197
+ if (!output) throw new Error('Secret workflow authority output is unavailable.');
198
+ const policy = readRepositoryOperatingPolicy(process.cwd());
199
+ if (policy.deploymentProfile !== renderedProfile) {
200
+ throw new Error('Generated and committed deployment profiles differ.');
201
+ }
202
+ if (!isActiveDeploymentStage(policy.deploymentProfile, stage)) {
203
+ throw new Error('Secret workflow stage is inactive for the committed deployment profile.');
204
+ }
205
+ const accounts = configuredDeploymentAccountTopology(
206
+ policy.deploymentProfile,
207
+ policy.deploymentAccounts,
208
+ );
209
+ const region = configuredDeploymentRegion(policy.deploymentRegion);
210
+ appendFileSync(output, [
211
+ 'deployment_region=' + region,
212
+ 'development_account_id=' + accounts.development,
213
+ 'staging_account_id=' + (accounts.staging ?? ''),
214
+ 'production_account_id=' + accounts.production,
215
+ '',
216
+ ].join('\\n'));
217
+ NODE`;
218
+ }
176
219
  function planApplicationBindingCheck() {
177
220
  return ` node - <<'NODE'
178
221
  const declared = JSON.parse(process.env.AWS_PLAN_SST_APPS_JSON ?? '');
@@ -1017,6 +1060,7 @@ const WORKSPACE_SEEDED_PATHS = new Set([
1017
1060
  'docs/git-workflow.md',
1018
1061
  'docs/repository-operating-policy.md',
1019
1062
  'docs/stage-deployment-authority.md',
1063
+ 'docs/workspace-deployment-ownership.md',
1020
1064
  'docs/work-markers.md',
1021
1065
  'ebk.repository-policy.json',
1022
1066
  ]);
@@ -1136,7 +1180,9 @@ function renderWorkspaceFiles(options) {
1136
1180
  : protectedWorkflowStageChoices;
1137
1181
  const rehearsalStage = (0, index_js_4.productionRehearsalStage)(deploymentProfile);
1138
1182
  const protectedWorkflowStageBranchCases = `${rehearsalStage}:refs/heads/develop|production:refs/heads/main`;
1139
- const initialRepositoryPolicy = (0, index_js_4.createIncubationRepositoryPolicy)(deploymentProfile);
1183
+ const workspaceDeploymentId = options.workspaceDeploymentId ??
1184
+ `ebkws-${(0, index_js_1.hashGeneratedContent)(`workspace-deployment-id:${name}`).slice(0, 32)}`;
1185
+ const initialRepositoryPolicy = (0, index_js_4.createIncubationRepositoryPolicy)(deploymentProfile, workspaceDeploymentId);
1140
1186
  initialRepositoryPolicy.deploymentAccounts = options.deploymentAccounts ?? {
1141
1187
  development: null,
1142
1188
  production: null,
@@ -7131,11 +7177,9 @@ jobs:
7131
7177
  contents: read
7132
7178
  id-token: write
7133
7179
  env:
7134
- AWS_DEPLOY_ROLE_ARN: \${{ secrets.AWS_DEPLOY_ROLE_ARN }}
7135
- AWS_EXPECTED_ACCOUNT_ID: \${{ vars.AWS_EXPECTED_ACCOUNT_ID }}
7136
- AWS_REGION: \${{ vars.AWS_REGION }}
7137
7180
  EBK_ACTION: \${{ inputs.action }}
7138
7181
  EBK_PROJECT: \${{ inputs.project }}
7182
+ EBK_RENDERED_PROFILE: ${deploymentProfile}
7139
7183
  EBK_STAGE: \${{ inputs.stage }}
7140
7184
  runs-on: ubuntu-latest
7141
7185
  steps:
@@ -7150,13 +7194,6 @@ jobs:
7150
7194
  case "$EBK_PROJECT" in
7151
7195
  ''|-*|*-|*[!a-z0-9-]*) echo 'Secret metadata project must be an exact normalized Slice name'; exit 1 ;;
7152
7196
  esac
7153
- test -n "$AWS_DEPLOY_ROLE_ARN" || { echo "$EBK_STAGE AWS_DEPLOY_ROLE_ARN is required"; exit 1; }
7154
- test -n "$AWS_EXPECTED_ACCOUNT_ID" || { echo "$EBK_STAGE AWS_EXPECTED_ACCOUNT_ID is required"; exit 1; }
7155
- test -n "$AWS_REGION" || { echo "$EBK_STAGE AWS_REGION is required"; exit 1; }
7156
- case "$AWS_DEPLOY_ROLE_ARN" in
7157
- arn:aws:iam::$AWS_EXPECTED_ACCOUNT_ID:role/*) ;;
7158
- *) echo 'Secret metadata role does not belong to the expected account'; exit 1 ;;
7159
- esac
7160
7197
  - uses: ${checkoutAction}
7161
7198
  with:
7162
7199
  persist-credentials: false
@@ -7168,14 +7205,37 @@ jobs:
7168
7205
  - run: pnpm install --frozen-lockfile --ignore-scripts --ignore-pnpmfile
7169
7206
  - name: Verify managed workspace integrity before AWS authority
7170
7207
  run: pnpm nx run ${name}:workspace-health
7208
+ - id: policy
7209
+ name: Derive committed secret metadata stage policy
7210
+ run: |
7211
+ ${indentWorkflowScript(protectedSecretPolicyDerivationScript(), 10)}
7212
+ - id: authority
7213
+ name: Derive canonical committed stage authority
7214
+ env:
7215
+ EBK_DEVELOPMENT_ACCOUNT: \${{ steps.policy.outputs.development_account_id }}
7216
+ EBK_PRODUCTION_ACCOUNT: \${{ steps.policy.outputs.production_account_id }}
7217
+ EBK_REGION: \${{ steps.policy.outputs.deployment_region }}
7218
+ EBK_STAGING_ACCOUNT: \${{ steps.policy.outputs.staging_account_id }}
7219
+ run: |
7220
+ ${indentWorkflowScript(`set -euo pipefail\n${(0, workspace_files_thin_deploy_js_1.canonicalStageAuthorityDerivationScript)()}`, 10)}
7171
7221
  - uses: ${configureAwsAction}
7172
7222
  with:
7173
- role-to-assume: \${{ secrets.AWS_DEPLOY_ROLE_ARN }}
7223
+ audience: \${{ steps.authority.outputs.audience }}
7224
+ role-to-assume: \${{ steps.authority.outputs.role_arn }}
7174
7225
  role-session-name: ebk-secret-metadata-\${{ github.run_id }}-\${{ github.run_attempt }}
7175
- aws-region: \${{ vars.AWS_REGION }}
7176
- - name: Verify assumed account
7177
- run: test "$(aws sts get-caller-identity --query Account --output text)" = "$AWS_EXPECTED_ACCOUNT_ID"
7226
+ aws-region: \${{ steps.policy.outputs.deployment_region }}
7227
+ - name: Verify exact stage authority
7228
+ env:
7229
+ AWS_DEPLOY_ROLE_ARN: \${{ steps.authority.outputs.role_arn }}
7230
+ AWS_PARTITION: \${{ steps.authority.outputs.partition }}
7231
+ EBK_POLICY_ACCOUNT_ID: \${{ steps.authority.outputs.account_id }}
7232
+ run: |
7233
+ ${indentWorkflowScript((0, workspace_files_thin_deploy_js_1.exactStageDeployerGuardScript)('Secret metadata', '$EBK_POLICY_ACCOUNT_ID'), 10)}
7178
7234
  - name: Reconcile value-blind metadata
7235
+ env:
7236
+ AWS_DEPLOY_ROLE_ARN: \${{ steps.authority.outputs.role_arn }}
7237
+ AWS_EXPECTED_ACCOUNT_ID: \${{ steps.authority.outputs.account_id }}
7238
+ AWS_REGION: \${{ steps.policy.outputs.deployment_region }}
7179
7239
  run: |
7180
7240
  args=("--stage=$EBK_STAGE" "--region=$AWS_REGION")
7181
7241
  if [ "$EBK_ACTION" = apply ]; then args+=("--apply"); fi
@@ -7220,12 +7280,10 @@ jobs:
7220
7280
  contents: read
7221
7281
  id-token: write
7222
7282
  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
7283
  EBK_ACTION: \${{ inputs.action }}
7227
7284
  EBK_LOGICAL_NAME: \${{ inputs.logical_name }}
7228
7285
  EBK_PROJECT: \${{ inputs.project }}
7286
+ EBK_RENDERED_PROFILE: ${deploymentProfile}
7229
7287
  EBK_STAGE: \${{ inputs.stage }}
7230
7288
  runs-on: ubuntu-latest
7231
7289
  steps:
@@ -7242,13 +7300,6 @@ jobs:
7242
7300
  esac
7243
7301
  [[ "$EBK_LOGICAL_NAME" =~ ^[A-Za-z][A-Za-z0-9]{0,63}$ ]] ||
7244
7302
  { 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
7303
  - uses: ${checkoutAction}
7253
7304
  with:
7254
7305
  persist-credentials: false
@@ -7260,14 +7311,37 @@ jobs:
7260
7311
  - run: pnpm install --frozen-lockfile --ignore-scripts --ignore-pnpmfile
7261
7312
  - name: Verify managed workspace integrity before AWS authority
7262
7313
  run: pnpm nx run ${name}:workspace-health
7314
+ - id: policy
7315
+ name: Derive committed secret initialize stage policy
7316
+ run: |
7317
+ ${indentWorkflowScript(protectedSecretPolicyDerivationScript(), 10)}
7318
+ - id: authority
7319
+ name: Derive canonical committed stage authority
7320
+ env:
7321
+ EBK_DEVELOPMENT_ACCOUNT: \${{ steps.policy.outputs.development_account_id }}
7322
+ EBK_PRODUCTION_ACCOUNT: \${{ steps.policy.outputs.production_account_id }}
7323
+ EBK_REGION: \${{ steps.policy.outputs.deployment_region }}
7324
+ EBK_STAGING_ACCOUNT: \${{ steps.policy.outputs.staging_account_id }}
7325
+ run: |
7326
+ ${indentWorkflowScript(`set -euo pipefail\n${(0, workspace_files_thin_deploy_js_1.canonicalStageAuthorityDerivationScript)()}`, 10)}
7263
7327
  - uses: ${configureAwsAction}
7264
7328
  with:
7265
- role-to-assume: \${{ secrets.AWS_DEPLOY_ROLE_ARN }}
7329
+ audience: \${{ steps.authority.outputs.audience }}
7330
+ role-to-assume: \${{ steps.authority.outputs.role_arn }}
7266
7331
  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"
7332
+ aws-region: \${{ steps.policy.outputs.deployment_region }}
7333
+ - name: Verify exact stage authority
7334
+ env:
7335
+ AWS_DEPLOY_ROLE_ARN: \${{ steps.authority.outputs.role_arn }}
7336
+ AWS_PARTITION: \${{ steps.authority.outputs.partition }}
7337
+ EBK_POLICY_ACCOUNT_ID: \${{ steps.authority.outputs.account_id }}
7338
+ run: |
7339
+ ${indentWorkflowScript((0, workspace_files_thin_deploy_js_1.exactStageDeployerGuardScript)('Secret initialize', '$EBK_POLICY_ACCOUNT_ID'), 10)}
7270
7340
  - name: Initialize machine-generated secret value-blind
7341
+ env:
7342
+ AWS_DEPLOY_ROLE_ARN: \${{ steps.authority.outputs.role_arn }}
7343
+ AWS_EXPECTED_ACCOUNT_ID: \${{ steps.authority.outputs.account_id }}
7344
+ AWS_REGION: \${{ steps.policy.outputs.deployment_region }}
7271
7345
  run: |
7272
7346
  args=("--logicalName=$EBK_LOGICAL_NAME" "--stage=$EBK_STAGE" "--region=$AWS_REGION")
7273
7347
  if [ "$EBK_ACTION" = apply ]; then args+=("--apply"); fi
@@ -7624,50 +7698,6 @@ export default tseslint.config(
7624
7698
  rules: { 'no-console': 'error' },
7625
7699
  },
7626
7700
  );
7627
- `,
7628
- 'README.md': `# ${name}
7629
-
7630
- This workspace was created with Empire Builder Kit v1.
7631
-
7632
- ## Start here
7633
-
7634
- 1. Review \`docs/architecture.md\`.
7635
- 2. Review the generated Foundation before deploying it.
7636
- 3. Add product slices through the Empire Builder Kit Nx plugin.
7637
- 4. Review \`docs/repository-operating-policy.md\` and \`docs/git-workflow.md\` before enabling production.
7638
- 5. Read \`AGENTS.md\` and \`docs/work-markers.md\` before assigning generated customization work to agents.
7639
-
7640
- For one-origin fleet development, initialize the workspace-pinned CLI once with
7641
- \`ebk dev configure --profile=<bounded-development-profile>\`, inspect the certificate reported
7642
- by \`ebk dev setup\`, and then explicitly approve \`ebk dev setup --trust\`. The supported v1
7643
- origin uses the complete explicit-port HTTPS URL reported at startup; optional
7644
- \`--portless\` setup is experimental. \`ebk dev doctor\` requires a real exact-host TLS
7645
- handshake for trust and connectivity readiness, and reports portless access ready
7646
- only after a live port-443 probe. Complete
7647
- \`aws sso login --profile <bounded-development-profile>\`, then start selected Slices with
7648
- \`ebk dev up billing accounts\`. The CLI derives the personal stage from the operating-system
7649
- account, reads the saved profile and Region, propagates that AWS context to child Slices, and
7650
- uses SST \`mono\` mode so agents and non-cursor-addressable terminals receive ordinary logs.
7651
- Use \`ebk dev status\`, \`ebk dev logs\`, \`ebk dev tail\`, \`ebk dev restart\`,
7652
- \`ebk dev down\`, and \`ebk dev doctor\` without supplying a stage. Setup, doctor, and the
7653
- managed root Fleet target remain internal Nx-backed implementation surfaces; \`ebk dev\` is the
7654
- framework-local development interface. For the development namespace, if the shell does not
7655
- expose workspace binaries, \`pnpm exec ebk dev ...\` only locates the workspace-pinned binary;
7656
- it is not another framework command surface. Protected Blueprint receipt review must instead
7657
- use the direct installed \`.bin/ebk blueprint verification-review\` entry documented in
7658
- \`docs/blueprints.md\`.
7659
-
7660
- Workspace creation only writes source files. It does not create or change cloud resources.
7661
-
7662
- New workspaces default to the one-account \`starter\` deployment profile. Configure the exact
7663
- shared account and Region in \`ebk.repository-policy.json\`, authenticate through IAM Identity
7664
- Center, add exact development and staging CIDRs to
7665
- \`packages/foundation/security/router-waf.json\`, and use
7666
- \`pnpm nx run ${name}:deploy-local -- --stage=development
7667
- --profile=<profile> --expectedRoleArn=<role-arn>\`. Never invoke SST directly.
7668
- For a brand-new stage with generated Product Slices, complete the documented workload-role
7669
- Foundation publication and pass \`--phase=foundation-bootstrap\` once before publishing and
7670
- deploying the complete stage.
7671
7701
  `,
7672
7702
  'docs/architecture.md': `# Workspace architecture
7673
7703
 
@@ -7690,286 +7720,6 @@ Every active canonical stage owns a separate Router/domain, Aurora cluster and m
7690
7720
  Cognito user pool, event bus, secret namespace, IAM boundary, logs, queues, ECR namespace, and
7691
7721
  stage-qualified SSM discovery contract. Discovery rejects a record for an inactive or different
7692
7722
  canonical stage.
7693
- `,
7694
- 'docs/git-workflow.md': `# Protected Git workflow
7695
-
7696
- Ordinary work starts from \`develop\` and returns through a reviewed pull request to
7697
- \`develop\`. A production promotion is exactly \`develop\` to \`main\`. After production,
7698
- review and merge the managed \`main\` to \`develop\` sync-back pull request before ordinary
7699
- work resumes.
7700
-
7701
- Both protected branches require the stable \`policy\` and \`verify\` checks, one approving
7702
- review including an approval from the committed catch-all CODEOWNER and someone other than the
7703
- most recent pusher, dismissed stale reviews, resolved conversations, and merge commits. Replace
7704
- the placeholder in \`.github/CODEOWNERS\` with a GitHub user or team that has repository access
7705
- before bootstrap. An approval from \`github-actions[bot]\` cannot satisfy the independent
7706
- code-owner gate; the Actions repository setting is needed to create the managed sync-back pull
7707
- request, not to approve it.
7708
- Direct updates, force pushes, deletion, squash merging, and rebase merging are prohibited.
7709
- GitHub rulesets, environments, and AWS IAM are the authorization boundaries; local hooks are
7710
- only defense in depth.
7711
-
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.
7717
- The committed \`productionApproval.mode\` selects one of two production authorization
7718
- contracts:
7719
-
7720
- - \`promotion-pr\` is compatible with private repositories on GitHub Team. The required
7721
- non-author CODEOWNER approval on the exact \`develop\` to \`main\` promotion pull request
7722
- is the production authorization. Merging that pull request starts production deployment;
7723
- there is no second EBK-managed environment approval or wait timer. The approver may also be
7724
- the human whose merge triggers deployment. Roll back through a reviewed revert on the
7725
- protected branches and let the resulting \`main\` push redeploy. A repository write actor who
7726
- can run Actions may also manually dispatch \`deploy\`, \`refresh\`, or \`unlock\` against the
7727
- already approved \`main\` tip without another human gate. That residual cannot introduce
7728
- unreviewed source; production \`remove\` remains separately variable-gated. Restrict write and
7729
- Actions access, audit dispatches, or select \`environment-reviewer\` when every production
7730
- action needs separate approval.
7731
- - \`environment-reviewer\` adds a separate production environment reviewer with self-review
7732
- prevention. A private repository needs GitHub Enterprise capability for this mode. Bootstrap
7733
- inspects that capability and fails closed on an unsupported plan; it never silently changes
7734
- the committed mode.
7735
-
7736
- Both modes retain required checks, a non-author CODEOWNER approval, no ruleset bypass, the
7737
- literal production environment, and its branch-scoped credentials. The base \`staging\` and
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.
7742
- Starter promotion authenticates once to the shared account and copies the exact staging digest
7743
- into a distinct production ECR repository. Dedicated
7744
- \`infrastructure-plan-<stage>\` environments gate read-only role use. Separate
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;
7747
- an independent clean audit job assumes that exact environment-subject role and verifies its
7748
- trust and complete inline policy before any repository-backed plan job may assume it. Plan-role
7749
- trust uses GitHub's immutable repository identity subject,
7750
- \`repo:<owner>@<owner-id>/<repository>@<repository-id>:environment:<environment>\`.
7751
- The audit derives it from the workflow's repository name, owner ID, repository ID, and literal
7752
- environment and refuses missing IDs or the older mutable name-only subject. Update every
7753
- adopter-owned AWS OIDC role trust to the immutable identity before protected use; never retain
7754
- both forms. Every
7755
- \`*-staging\` environment accepts only \`develop\`; every
7756
- \`*-production\` environment accepts only \`main\`; reviewer, self-review, and wait protection
7757
- matches the corresponding base stage. The credential-free \`npm-prerelease\` environment
7758
- accepts only \`main\` and contains no secrets or variables. In Team-compatible
7759
- \`promotion-pr\` mode, protected-main review plus the exact current-main tag binding is
7760
- publication authorization, so it has no reviewer or wait rule. In
7761
- \`environment-reviewer\` mode it mirrors production protection. Never add repository- or
7762
- organization-visible fallbacks for protected values. Keep repository default workflow
7763
- permissions read-only; generated jobs request only the additional permissions they need.
7764
-
7765
- \`EBK_FLEET_ORIGIN\` is the sole protected deployment and smoke origin. Read-only plan jobs
7766
- enter only their dedicated \`infrastructure-plan-<stage>\` environment; their stage-named
7767
- repository variables \`EBK_STAGING_FLEET_ORIGIN\` and
7768
- \`EBK_PRODUCTION_FLEET_ORIGIN\` remain plan inputs only. Before mutation, each
7769
- base-environment-protected deployment requires
7770
- its \`EBK_FLEET_ORIGIN\` to equal the origin retained by the plan.
7771
-
7772
- \`AWS_ASYNC_RECOVERY_ROLE_ARN\` is a separate mutation role. Trust only this
7773
- repository's exact \`async-recovery-<stage>\` GitHub OIDC subject and grant only
7774
- the recovery operations/resources declared by generated capability adapters.
7775
-
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.
7780
-
7781
- \`AWS_RELIABILITY_READ_ROLE_ARN\` is a separate read-only OIDC role. Trust only
7782
- this repository's exact \`reliability-read-<stage>\` GitHub OIDC subject.
7783
- Grant \`sts:GetCallerIdentity\`, \`cloudwatch:DescribeAlarms\`,
7784
- \`cloudwatch:DescribeAlarmHistory\`, \`cloudwatch:GetMetricData\`,
7785
- \`ecs:DescribeServices\`, and \`states:DescribeExecution\`. Scope ECS and Step
7786
- Functions resources to the reviewed Slice services, state machines, and
7787
- executions wherever IAM supports resource-level constraints. Do not grant log
7788
- reads, deployment, CloudFormation, SST, or any AWS mutation.
7789
-
7790
- The generated \`reliability-read.yml\` workflow selects the newest nonexpired
7791
- binding artifact from a successful deployed-smoke run, reconciles it to the
7792
- current successful protected deployment, and checks out that exact commit
7793
- before assuming the role. Callers choose only a bounded operation and workload;
7794
- they cannot supply the AWS account, Region, role, or binding path. The binding
7795
- allowlists exact alarm names, API ID, ECS services, and Step Functions
7796
- resources before the adapter makes a service call. Bootstrap verifies
7797
- environment-only secret placement, not the role's hidden AWS trust or
7798
- permission policy.
7799
-
7800
- The async-recovery and reliability-read jobs have job-scoped \`id-token: write\`.
7801
- They install the frozen dependency
7802
- graph with lifecycle scripts and pnpm hooks disabled before assuming AWS
7803
- authority. Immediately after the one pinned credential action, they blank the
7804
- OIDC request URL and bearer for future steps and explicitly shadow both values
7805
- empty on every later step. After bounded AWS use, they blank current AWS
7806
- credential variables before evidence upload. This withholds credentials from
7807
- later processes; it does not claim that GitHub revokes the job-level
7808
- permission.
7809
-
7810
- \`AWS_SMOKE_ROLE_ARN\` is separate from deployment authority. Trust only this
7811
- repository's GitHub OIDC subject for the matching protected environment. Grant
7812
- only run-scoped Cognito principal setup/cleanup on reviewed user-pool ARNs and
7813
- \`logs:FilterLogEvents\` on exact
7814
- \`/ebk/<stage>/<slice>/event-consumer\` log-group ARNs. Do not grant
7815
- CloudFormation, SST mutation, broad Logs query, \`GetLogEvents\`,
7816
- \`StartQuery\`, or \`logs:Unmask\`. Bootstrap verifies environment-only secret
7817
- inventory but never creates or reads the secret, materializes the role, or
7818
- attests its hidden policy.
7819
-
7820
- Run the GitHub bootstrap in report mode first. Source upgrades never alter remote GitHub
7821
- settings. Apply a reviewed report only after \`develop\` exists and the candidate's exact
7822
- \`policy\` and \`verify\` check contexts have run.
7823
-
7824
- Set \`GH_REPO=<owner>/<repository>\` and a suitable \`GH_TOKEN\`, then run
7825
- \`pnpm nx run ${name}:github-bootstrap\`. Review the deterministic report before rerunning
7826
- with \`--apply\`. The command never creates branches, credentials, secrets, or AWS resources.
7827
- Supply \`--npmPrereleaseReviewerIds=<id,...>\` only in
7828
- \`environment-reviewer\` mode when intentionally setting a distinct npm
7829
- mutation reviewer set.
7830
- Supply \`--productionReviewerIds=<id,...>\` only when committed policy selects
7831
- \`environment-reviewer\`; it is rejected in \`promotion-pr\` mode.
7832
-
7833
- Install the optional defense-in-depth pre-push hook explicitly with
7834
- \`pnpm nx run ${name}:install-git-hooks\`. It refuses to overwrite an unrelated existing hook.
7835
-
7836
- The sync-back workflow uses only \`GITHUB_TOKEN\` and never pushes or auto-merges. GitHub may
7837
- place its pull-request workflows in an approval-required state. Approve them; if no run
7838
- materializes, close and reopen the pull request as a human and then approve it.
7839
- `,
7840
- 'docs/repository-operating-policy.md': `# Repository Operating Policy
7841
-
7842
- \`ebk.repository-policy.json\` is the reviewed source of truth for deployment profile, exact
7843
- stage account IDs, deployment Region, production access, production approval, per-Slice
7844
- readiness, and the one shared production Foundation profile.
7845
- New workspaces start with production disabled and explicit Team-compatible
7846
- \`productionApproval.mode: "promotion-pr"\`. A missing approval mode or Slice entry fails
7847
- closed; no GitHub capability is allowed to choose a mode implicitly.
7848
-
7849
- Deployment profiles are proportional to operator maturity:
7850
-
7851
- - \`starter\` (default) requires one shared account, permits local development and staging
7852
- through the governed root Nx target, and reserves production for protected GitHub deployment;
7853
- - \`production-isolated\` requires one development/staging account and a distinct production
7854
- account; only production is GitHub-only; and
7855
- - \`fully-isolated\` requires three distinct accounts; staging and production are GitHub-only.
7856
-
7857
- Equal account IDs never imply shared stage resources. Router, Aurora, Cognito, events, secrets,
7858
- IAM, logs, queues, resource names, and SSM discovery remain stage-specific. Existing prerelease
7859
- repositories migrate explicitly to \`fully-isolated\`; upgrades never infer or weaken topology.
7860
- That profile-only migration retains the former authority model but stays undeployable until exact
7861
- development, staging, and production account IDs plus \`deploymentRegion\` are committed.
7862
-
7863
- The named repository modes are source-writing presets, not runtime state. Report a change
7864
- first and inspect the complete current/next policy:
7865
-
7866
- \`\`\`bash
7867
- pnpm nx g @empire-builder-kit/nx:repository-policy \\
7868
- --deploymentProfile=starter --deploymentRegion=us-east-1 \\
7869
- --developmentAccountId=111122223333 --stagingAccountId=111122223333 \\
7870
- --productionAccountId=111122223333
7871
- \`\`\`
7872
-
7873
- Apply the reviewed source change separately with \`--apply\`. This command never contacts AWS
7874
- or GitHub. Use \`--status=blocked|pilot|ready\` for explicit Slice transitions and
7875
- \`--profile=cost-optimized|standard\` for an explicit shared Foundation decision.
7876
- Use \`--productionApprovalMode=promotion-pr|environment-reviewer\` for an explicit approval
7877
- transition. This changes committed policy only; a separate bootstrap report/apply reconciles
7878
- remote GitHub settings.
7879
-
7880
- After applying exact topology, authenticate with temporary federated credentials for development
7881
- or staging and invoke
7882
- \`pnpm nx run ${name}:deploy-local -- --stage=<stage> --profile=<profile>
7883
- --expectedRoleArn=<role-arn>\`. Production runs only through the protected main-branch GitHub
7884
- workflow. Each admitted local invocation plans the complete current stage, displays the stage
7885
- summary and first material project, and requires a real TTY response of
7886
- \`approve:<action>:<stage>:<project>:<current-plan-digest>\`. A human or authorized agent may type
7887
- that acknowledgement; it is active operator control, not a claim of independent human review.
7888
- The target creates one private ten-minute capability for that project, rechecks the exact source,
7889
- artifacts, account, Region, role, stage, policy, state, and lock without a second provider preview,
7890
- consumes the capability once, and removes it on every exit path. Unattended scripts cannot approve.
7891
- Every material deploy or refresh mutates at most the first material project and ends with a
7892
- controlled non-success \`replan-required\` handoff, including the last project in the ordered stage.
7893
- Rerun the complete stage, review the new current summary, and repeat until one invocation proves
7894
- every project is semantically converged. Only that convergence invocation succeeds. A preview is
7895
- recent review and audit evidence; it is not represented as a cryptographically replayable Pulumi
7896
- transaction. A complete, unlocked deploy plan containing only provider reads with no changed
7897
- properties, replacement, failure, or unmatched risk finding is retained as observation evidence
7898
- and counts as semantically converged. The standalone project planner may still return its
7899
- conservative non-success for that drift observation; the root local transaction accepts only a
7900
- freshly emitted exact provider-read-only record from that child. Repeated reads coalesce
7901
- only when their logical ID and resource type match exactly. Any stale or ambiguous
7902
- observation fails closed; a plan with desired changes remains material and requires review. One
7903
- narrower case stays reviewable instead of becoming
7904
- drift: when an upstream Foundation apply changes only both external framework-version tag
7905
- projections (plus SST's already-bounded name hydration), the retained
7906
- external identity must match one exact non-replacing provider read in the same ordinary plan.
7907
- Missing read correlation, owned resources, other tag or property changes, incomplete tag pairs,
7908
- and provider failures remain drift and fail closed. The local target requires the exact SST v5 account bootstrap normally
7909
- created by the pinned \`ebk dev up\` path, then creates and attests only missing exact
7910
- per-project/canonical-stage state passphrases before its formal read-only plans. This passphrase
7911
- bootstrap is the only persistent pre-acknowledgement write; it creates no deployment authority
7912
- and is reported in bounded local evidence. Clean immutable source, immediate per-project plans,
7913
- migration and retention preflights, and secret-free result
7914
- evidence remain mandatory. Direct SST is forbidden.
7915
-
7916
- After an interrupted apply, use the same target with \`--action=refresh\` and the exact
7917
- phase, stage, profile, and role. It retains the same plan-summary review boundary, admits only
7918
- bounded drift-detected refresh evidence, and never turns refresh into an implicit deploy. When
7919
- the interrupted write leaves a recorded provider output unusable by the ordinary desired preview,
7920
- the plan stops without mutation. The non-writing refresh preview separates provider refresh
7921
- records from its later desired preview and cannot replace failed ordinary desired authority;
7922
- repair the recorded dependency or use the documented
7923
- operator recovery path before planning again.
7924
-
7925
- A stage-wide refresh still plans and authorizes every selected project. When one exact retained
7926
- project plan proves an absent SST state that is unlocked, complete, empty, and drift-free, the
7927
- root target records that project as a refresh no-op instead of invoking SST against a nonexistent
7928
- stage. It also retains the pinned provider's exact SSM \`ebk:framework-version\` \`tagsAll\`
7929
- normalization as a semantically inert observation after the same bounded shape
7930
- repeats following refresh. Value changes, other tags, security findings, deletes, replacements,
7931
- sensitive properties, and every other resource type remain material. Locked, incomplete, failed,
7932
- or otherwise drifted plans are never skipped.
7933
-
7934
- For a stage with no workload-role account baseline, publish the fixed Foundation-only candidate
7935
- and invoke this root target with \`--phase=foundation-bootstrap\`. After Foundation outputs exist,
7936
- publish the complete \`full-stage\` candidate and invoke the target without \`--phase\` (or with
7937
- \`--phase=full-stage\`). The bootstrap phase selects exactly Foundation; it is not an arbitrary
7938
- project filter.
7939
-
7940
- Validation requires both an explicit production approval mode and an explicit Foundation
7941
- profile. It does not infer omitted values. Use \`promotion-pr\` for a private GitHub Team
7942
- repository. Use \`environment-reviewer\` only when the repository plan can enforce a separate
7943
- environment reviewer.
7944
-
7945
- - \`blocked\` prohibits production create, update, and migration.
7946
- - \`pilot\` permits protected evidence gathering without claiming normal latency or maturity.
7947
- - \`ready\` records an adopter decision after its evidence and review; it is not inferred.
7948
- - removal and unlock remain explicit protected recovery paths so disabled policy cannot strand
7949
- resources.
7950
-
7951
- Protected production deploy and refresh validate the complete Foundation/Slice set before AWS
7952
- access. The Foundation is always ordered first. The set is derived from committed policy and
7953
- cannot be narrowed with an ad hoc project argument. The retained stage preview remains review
7954
- evidence. Immediately before each project mutation the workflow computes one fresh plan against
7955
- current state and applies it without a second redundant preview. Source, artifacts, configuration,
7956
- policy, environment, and protected identities remain exact. Provider-only read/discard observations
7957
- may appear or disappear, but any new delete, replacement, import, stateful or security change, IAM
7958
- expansion, protection reduction, or unclassified resource stops for renewed approval. After an
7959
- upstream mutation, every downstream project therefore receives a fresh independent risk decision.
7960
-
7961
- \`standard\` keeps Aurora warm at 2–16 ACU. \`cost-optimized\` keeps a smaller
7962
- 0.5–4 ACU warm floor for starter production traffic. Both keep managed NAT,
7963
- 30-day backups, deletion protection, retained data, and the protected GitHub/OIDC/AWS path.
7964
- Changing policy affects only later lifecycle requests; it never deploys or removes resources.
7965
- Changing profile requires a separate reviewed Foundation deployment and retained operational
7966
- evidence.
7967
-
7968
- \`EBK_PRODUCTION_FOUNDATION_PROFILE\` is reserved managed executor input. The lifecycle
7969
- executor derives it from validated committed policy immediately before SST and removes any
7970
- ambient shell value. Do not set it as a local, repository, organization, or environment
7971
- variable. Incubation keeps the last configured profile so protected remove and unlock can still
7972
- render existing production resources; production deploy remains disabled.
7973
7723
  `,
7974
7724
  'docs/work-markers.md': `# Agent work markers
7975
7725
 
@@ -8244,29 +7994,6 @@ must be committed, reviewable, and auditable.
8244
7994
  },
8245
7995
  },
8246
7996
  }),
8247
- 'packages/foundation/README.md': `# Standard Foundation
8248
-
8249
- This project owns the workspace-wide AWS platform for each canonical \`development\`,
8250
- \`staging\`, or \`production\` stage. It is a separate SST state boundary from product slices.
8251
- Never deploy it at a framework-derived personal stage; that consumer maps to
8252
- \`development\`.
8253
-
8254
- It provides the v1 network, routing, container compute, Postgres, identity, events,
8255
- observability, configuration, and deployment capabilities. Product slices consume its
8256
- versioned contract; they do not import files from \`infra/\`.
8257
-
8258
- Workspace creation does not deploy this project. Review \`docs/costs.md\`,
8259
- \`docs/security.md\`, and \`docs/runbooks.md\` before the first deployment.
8260
-
8261
- Set \`EBK_ROOT_DOMAIN\` before deploying when Route 53 in the target account owns a public
8262
- domain. Without it, the shared Router uses its functional provider URL.
8263
-
8264
- Before deploying development or staging, add at least one exact operator/probe CIDR to
8265
- \`security/router-waf.json\`. Production is public by default behind the same managed and
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>\`.
8269
- `,
8270
7997
  'packages/foundation/contracts/foundation.json': json({
8271
7998
  contractVersion: '1.0.0',
8272
7999
  capabilities: [
@@ -8328,7 +8055,6 @@ seeded decision record aligned with organization-specific budgets and alerts.
8328
8055
 
8329
8056
  - Development uses EC2 NAT, a development bastion, and Aurora scale-to-zero.
8330
8057
  ${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
8331
- - Production always uses managed NAT and retains protected data. Its explicit Repository
8332
8058
  Operating Policy profile selects either the standard 2-ACU Aurora floor or the
8333
8059
  cost-optimized 0.5-ACU warm floor.
8334
8060
  - ECS, EventBridge, Cognito, SNS, SSM, and CloudWatch are primarily usage-priced; logs,
@@ -8336,102 +8062,6 @@ ${deploymentProfile === 'starter' ? '' : '- Staging uses EC2 NAT and Aurora scal
8336
8062
 
8337
8063
  Run \`foundation:remove\` only for disposable stages. Production is retained and protected by
8338
8064
  the SST configuration.
8339
- `,
8340
- 'packages/foundation/docs/runbooks.md': `# Foundation runbooks
8341
-
8342
- ## Deployment
8343
-
8344
- Use Nx for every supported lifecycle action:
8345
-
8346
- - \`pnpm nx run foundation:deploy --stage=development\`
8347
- - \`pnpm nx run foundation:refresh --stage=development\`
8348
- - \`pnpm nx run foundation:unlock --stage=development\`
8349
- - \`pnpm nx run foundation:remove --stage=development\`
8350
-
8351
- Do not invoke SST lifecycle commands directly. The root \`deploy-local\` target is the governed
8352
- local path for stages admitted by the committed deployment profile. Its fixed
8353
- \`foundation-bootstrap\` phase is the only local partial-stage path and exists solely for the
8354
- documented first workload-role publication; isolated protected stages remain on the trusted
8355
- GitHub path.
8356
-
8357
- Every local invocation plans the complete selected stage but mutates at most one material
8358
- project. Type the exact current \`approve:<action>:<stage>:<project>:<plan-digest>\` challenge in a
8359
- real TTY after reviewing the displayed summary. A human or authorized agent may operate that TTY;
8360
- unattended input is refused. The acknowledgement creates one ten-minute, one-use, private
8361
- capability bound to source, artifacts, policy, environment, credentials, and current state. A
8362
- completed deploy or refresh returns the controlled non-success \`replan-required\`; rerun the
8363
- complete stage, review the new current summary, and continue one project at a time. Only a
8364
- semantically converged complete stage reports success. No upstream mutation can authorize a
8365
- downstream project. A complete, unlocked deploy plan containing only provider reads with no
8366
- changed properties, replacement, failure, or unmatched risk finding is retained as observation
8367
- evidence and counts as semantically converged. The standalone project planner may still return
8368
- its conservative non-success for that drift observation; the root local transaction accepts only
8369
- a freshly emitted exact provider-read-only record from that child. Repeated reads coalesce
8370
- only when their logical ID and resource type match exactly. Any stale or ambiguous
8371
- observation fails closed; a plan with desired changes remains material and requires review. A
8372
- material downstream plan may also retain an upstream Foundation framework-version tag advance as
8373
- observation only when both external tag
8374
- projections, the retained identity, optional bounded SST name hydration, and one non-replacing
8375
- provider read correlate exactly. Every other external property or uncorroborated read remains
8376
- drift and blocks before the TTY challenge.
8377
-
8378
- For an interrupted local apply, run the same root target with \`--action=refresh\`, review its
8379
- current provider-refresh evidence, and type the displayed TTY challenge. Before mutation the
8380
- executor writes and verifies a private state recovery point plus a secret-free digest/version
8381
- manifest. The refresh preview validates its provider and later desired-event partitions; any
8382
- ordinary preview failure or malformed post-refresh desired event remains blocked. Provider-only
8383
- observation noise is retained without claiming a replayable preview. Because refresh changes
8384
- recorded state rather than cloud resources, provider-output security and protection findings
8385
- remain explicit review requirements under the drift decision. Refresh never continues into deploy
8386
- or claims desired-state convergence: run the governed deploy target afterward and resolve every
8387
- remaining source-versus-state change. Exclude the \`.private.json\` recovery point from archives.
8388
-
8389
- The root refresh target includes every selected project in its exact reviewed plan set. It skips
8390
- the SST child only when that project's retained plan proves an absent, unlocked, complete, empty,
8391
- and drift-free state, or when the only retained difference is the pinned provider's exact repeated
8392
- SSM \`ebk:framework-version\` \`tagsAll\` normalization. It records the project as an explicit refresh no-op
8393
- in either case while retaining the observation. Value changes, other tags, security findings,
8394
- deletes, replacements, sensitive
8395
- properties, and every other resource type remain material; every other plan must execute or fail
8396
- closed.
8397
-
8398
- ## Router WAF
8399
-
8400
- Each canonical stage owns one global-scope Web ACL attached to that stage's Foundation Router.
8401
- The committed \`security/router-waf.json\` policy requires AWS Common Rule Set, Known Bad
8402
- Inputs, Amazon IP Reputation, an IP rate limit, CloudWatch metrics, and sampled requests.
8403
- Development and staging fail synthesis until their allowlists contain explicit CIDRs.
8404
- Production is public by default and may be changed to an explicit allowlist.
8405
-
8406
- For tuning, set a nonproduction stage to \`count\`, deploy and inspect sampled requests, then
8407
- return staging to \`block\` and run the live allow/deny, managed-rule, rate-limit, metric, and
8408
- sampled-request probes. Write their bounded, secret-free result to
8409
- \`security/router-waf-live-evidence.json\`, then run
8410
- \`pnpm nx run foundation:router-waf-rehearsal\`. The executor seals the exact policy digest
8411
- into \`router-waf-blocking-rehearsal.json\`. Production synthesis rejects a missing, stale, or
8412
- count-mode rehearsal. Full request logging is opt-in, blocked-only, retention-bounded, and
8413
- redacts query strings plus credential-bearing headers.
8414
-
8415
- Foundation stages are canonical. \`ebk dev\` derives a Product Slice personal
8416
- stage from the operating-system account and maps that consumer to the
8417
- development Foundation. Callers cannot select that stage. Slice preflight
8418
- reports both identities, never deploys a personal Foundation, and full mapped
8419
- personal-stage deploys fail closed.
8420
-
8421
- ## Database restore
8422
-
8423
- Production Aurora retains 30 days of automated backups; non-production retains 7 days.
8424
- Restore into a new cluster, validate application migrations and data integrity, then cut over
8425
- consumers deliberately. Never expose the Foundation master credential to a product slice.
8426
-
8427
- ## Protected database migrations
8428
-
8429
- Each database-backed Product Slice deploys a one-off Fargate migration task and
8430
- Standard Step Functions workflow into the shared cluster. The existing
8431
- environment-scoped \`AWS_DEPLOY_ROLE_ARN\` starts and observes that exact
8432
- workflow; do not create a second migration OIDC role. GitHub has no direct SQL,
8433
- database-secret-value, or \`rds-db:connect\` authority. The generated task role
8434
- connects as the Slice's no-password IAM-authenticated migrator user.
8435
8065
  `,
8436
8066
  'packages/foundation/docs/security.md': `# Foundation security contract
8437
8067
 
@@ -9199,16 +8829,7 @@ export function app() {
9199
8829
  version: '4.17.1',
9200
8830
  },
9201
8831
  policy: {
9202
- adoptedImports: [
9203
- {
9204
- authority: 'workload-role-account-baseline',
9205
- logicalId: 'FoundationVpcNatInstanceProfile',
9206
- privateIdentifierTemplate: 'ebk-{stage}-foundation-nat-profile',
9207
- recoveryRunbookRef: 'docs/workload-role-account-baseline.md',
9208
- removalBehavior: 'retain',
9209
- resourceType: 'aws:iam/instanceProfile:InstanceProfile',
9210
- },
9211
- ],
8832
+ adoptedImports: [],
9212
8833
  additiveLowRiskTypes: [
9213
8834
  'aws:cloudwatch/dashboard:Dashboard',
9214
8835
  'aws:cloudwatch/logGroup:LogGroup',
@@ -10528,7 +10149,7 @@ const decision = evaluateGitPolicy(request);
10528
10149
  process.stdout.write(JSON.stringify(decision, null, 2) + '\\n');
10529
10150
  if (!decision.allowed) process.exitCode = 1;
10530
10151
  `,
10531
- 'tools/workspace-health.mjs': `import { validateRepositoryOperatingPolicy } from '@empire-builder-kit/nx/repository-policy';
10152
+ 'tools/workspace-health.mjs': `import { readRepositoryOperatingPolicy } from '@empire-builder-kit/nx/repository-policy';
10532
10153
  import { assertWorkMarkerReport, formatWorkMarkerReport, scanWorkMarkers } from '@empire-builder-kit/nx/work-markers';
10533
10154
  import { createHash } from 'node:crypto';
10534
10155
  import { existsSync, readdirSync, readFileSync } from 'node:fs';
@@ -10591,13 +10212,7 @@ if (
10591
10212
  validateOwnership('.', workspace, 'Workspace');
10592
10213
  validateOwnership('packages/foundation', foundation, 'Foundation');
10593
10214
 
10594
- const policy = validateRepositoryOperatingPolicy(readJson('ebk.repository-policy.json'));
10595
- if (!policy.valid) {
10596
- throw new Error(
10597
- 'Repository Operating Policy is invalid:\\n' +
10598
- policy.issues.map(({ message, path }) => '- ' + path + ': ' + message).join('\\n'),
10599
- );
10600
- }
10215
+ readRepositoryOperatingPolicy(process.cwd());
10601
10216
 
10602
10217
  for (const name of readdirSync('packages')) {
10603
10218
  if (name === 'foundation') continue;
@@ -10615,7 +10230,11 @@ assertWorkMarkerReport(markerReport);
10615
10230
  process.stdout.write('Empire Builder Kit workspace source health is green.\\n');
10616
10231
  `,
10617
10232
  };
10618
- Object.assign(files, SUPPLY_CHAIN_WORKSPACE_FILE_PLAN.files, developerAgentFilePlan.files, (0, workspace_files_stage_authority_js_1.renderStageAuthorityWorkspaceFiles)({ deploymentProfile }));
10233
+ Object.assign(files, SUPPLY_CHAIN_WORKSPACE_FILE_PLAN.files, developerAgentFilePlan.files, (0, workspace_files_stage_authority_js_1.renderStageAuthorityWorkspaceFiles)({
10234
+ deploymentProfile,
10235
+ name,
10236
+ workspaceDeploymentId,
10237
+ }));
10619
10238
  Object.assign(files, (0, workspace_files_ecr_inspector_js_1.renderThinEcrInspectorWorkflow)({
10620
10239
  actionPins: {
10621
10240
  checkout: checkoutAction,
@@ -10641,7 +10260,6 @@ process.stdout.write('Empire Builder Kit workspace source health is green.\\n');
10641
10260
  name,
10642
10261
  toolVersions: {
10643
10262
  node: tool_versions_js_1.WORKSPACE_NODE_VERSION,
10644
- pnpm: tool_versions_js_1.WORKSPACE_PNPM_VERSION,
10645
10263
  sst: tool_versions_js_1.WORKSPACE_SST_VERSION,
10646
10264
  },
10647
10265
  }).files, (0, workspace_files_thin_docs_js_1.renderThinLifecycleDocumentation)({ deploymentProfile, name }));