@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.
- package/executors.json +8 -3
- package/package.json +10 -7
- package/src/aws/child-environment.d.ts +10 -0
- package/src/aws/child-environment.js +77 -0
- package/src/aws/child-environment.js.map +1 -0
- package/src/aws/identity.d.ts +13 -0
- package/src/aws/identity.js +41 -0
- package/src/aws/identity.js.map +1 -0
- package/src/aws-authority/index.d.ts +1 -0
- package/src/aws-authority/index.js +5 -0
- package/src/aws-authority/index.js.map +1 -0
- package/src/aws-authority/stage-authority.d.ts +238 -0
- package/src/aws-authority/stage-authority.js +2836 -0
- package/src/aws-authority/stage-authority.js.map +1 -0
- package/src/developer-agent/generator-planning.js +4 -4
- package/src/developer-agent/generator-planning.js.map +1 -1
- package/src/developer-agent/operation-registry.js +14 -6
- package/src/developer-agent/operation-registry.js.map +1 -1
- package/src/executors/deployment-plan/deployment-plan.js +1 -1
- package/src/executors/deployment-plan/deployment-plan.js.map +1 -1
- package/src/executors/foundation-preflight/foundation-preflight.d.ts +0 -1
- package/src/executors/foundation-preflight/foundation-preflight.js.map +1 -1
- package/src/executors/foundation-preflight/schema.json +0 -5
- package/src/executors/foundation-profile-preflight/foundation-profile-preflight.d.ts +12 -3
- package/src/executors/foundation-profile-preflight/foundation-profile-preflight.js +95 -32
- package/src/executors/foundation-profile-preflight/foundation-profile-preflight.js.map +1 -1
- package/src/executors/foundation-profile-preflight/production-database-safeguard.d.ts +64 -0
- package/src/executors/foundation-profile-preflight/production-database-safeguard.js +221 -0
- package/src/executors/foundation-profile-preflight/production-database-safeguard.js.map +1 -0
- package/src/executors/foundation-profile-preflight/schema.json +1 -6
- package/src/executors/foundation-remove-preflight/foundation-remove-preflight.d.ts +11 -1
- package/src/executors/foundation-remove-preflight/foundation-remove-preflight.js +44 -21
- package/src/executors/foundation-remove-preflight/foundation-remove-preflight.js.map +1 -1
- package/src/executors/foundation-remove-preflight/schema.json +6 -1
- package/src/executors/infrastructure-plan/infrastructure-plan.d.ts +25 -369
- package/src/executors/infrastructure-plan/infrastructure-plan.js +222 -5472
- package/src/executors/infrastructure-plan/infrastructure-plan.js.map +1 -1
- package/src/executors/infrastructure-plan/schema.json +8 -64
- package/src/executors/local-deploy/federated-credential-transport.d.ts +48 -0
- package/src/executors/local-deploy/federated-credential-transport.js +252 -0
- package/src/executors/local-deploy/federated-credential-transport.js.map +1 -0
- package/src/executors/local-deploy/local-approval.d.ts +4 -9
- package/src/executors/local-deploy/local-approval.js +3 -7
- package/src/executors/local-deploy/local-approval.js.map +1 -1
- package/src/executors/local-deploy/local-deploy.d.ts +58 -43
- package/src/executors/local-deploy/local-deploy.js +938 -804
- package/src/executors/local-deploy/local-deploy.js.map +1 -1
- package/src/executors/local-deploy/schema.json +3 -20
- package/src/executors/refresh/refresh.js +2 -2
- package/src/executors/refresh/refresh.js.map +1 -1
- package/src/executors/remove/remove.js +2 -2
- package/src/executors/remove/remove.js.map +1 -1
- package/src/executors/router-waf-rehearsal/router-waf-rehearsal.d.ts +25 -1
- package/src/executors/router-waf-rehearsal/router-waf-rehearsal.js +905 -22
- package/src/executors/router-waf-rehearsal/router-waf-rehearsal.js.map +1 -1
- package/src/executors/router-waf-rehearsal/schema.json +17 -2
- package/src/executors/secret-initialize/schema.json +42 -0
- package/src/executors/secret-initialize/secret-initialize.d.ts +30 -0
- package/src/executors/secret-initialize/secret-initialize.js +229 -0
- package/src/executors/secret-initialize/secret-initialize.js.map +1 -0
- package/src/executors/secret-metadata/secret-metadata.d.ts +2 -1
- package/src/executors/secret-metadata/secret-metadata.js +62 -29
- package/src/executors/secret-metadata/secret-metadata.js.map +1 -1
- package/src/executors/sst-lifecycle/generated-secret-retirement.d.ts +53 -0
- package/src/executors/sst-lifecycle/generated-secret-retirement.js +192 -0
- package/src/executors/sst-lifecycle/generated-secret-retirement.js.map +1 -0
- package/src/executors/sst-lifecycle/governed-native-operation.d.ts +46 -0
- package/src/executors/sst-lifecycle/governed-native-operation.js +153 -0
- package/src/executors/sst-lifecycle/governed-native-operation.js.map +1 -0
- package/src/executors/sst-lifecycle/run-sst-command.d.ts +25 -7
- package/src/executors/sst-lifecycle/run-sst-command.js +459 -89
- package/src/executors/sst-lifecycle/run-sst-command.js.map +1 -1
- package/src/executors/sst-lifecycle/schema.json +0 -5
- package/src/executors/sst-lifecycle/secret-preflight.d.ts +2 -0
- package/src/executors/sst-lifecycle/secret-preflight.js +13 -7
- package/src/executors/sst-lifecycle/secret-preflight.js.map +1 -1
- package/src/executors/unlock/unlock.js +2 -2
- package/src/executors/unlock/unlock.js.map +1 -1
- package/src/foundation/router-waf-rate-rehearsal.d.ts +97 -0
- package/src/foundation/router-waf-rate-rehearsal.js +210 -0
- package/src/foundation/router-waf-rate-rehearsal.js.map +1 -0
- package/src/foundation/router-waf.d.ts +59 -9
- package/src/foundation/router-waf.js +427 -32
- package/src/foundation/router-waf.js.map +1 -1
- package/src/foundation/stages.d.ts +1 -0
- package/src/foundation/stages.js +11 -0
- package/src/foundation/stages.js.map +1 -1
- package/src/generators/formatting.d.ts +8 -0
- package/src/generators/formatting.js +118 -0
- package/src/generators/formatting.js.map +1 -0
- package/src/generators/function/function.js +37 -17
- package/src/generators/function/function.js.map +1 -1
- package/src/generators/post-generation-install.js +2 -2
- package/src/generators/post-generation-install.js.map +1 -1
- package/src/generators/preset/generator.js +22 -7
- package/src/generators/preset/generator.js.map +1 -1
- package/src/generators/preset/workspace-files-developer-agent.js +15 -7
- package/src/generators/preset/workspace-files-developer-agent.js.map +1 -1
- package/src/generators/preset/workspace-files-ecr-inspector.d.ts +18 -0
- package/src/generators/preset/workspace-files-ecr-inspector.js +298 -0
- package/src/generators/preset/workspace-files-ecr-inspector.js.map +1 -0
- package/src/generators/preset/workspace-files-performance-cost.d.ts +2 -2
- package/src/generators/preset/workspace-files-performance-cost.js +8 -8
- package/src/generators/preset/workspace-files-performance-cost.js.map +1 -1
- package/src/generators/preset/workspace-files-performance-load.d.ts +1 -1
- package/src/generators/preset/workspace-files-performance-load.js +8 -12
- package/src/generators/preset/workspace-files-performance-load.js.map +1 -1
- package/src/generators/preset/workspace-files-stage-authority.d.ts +4 -0
- package/src/generators/preset/workspace-files-stage-authority.js +275 -0
- package/src/generators/preset/workspace-files-stage-authority.js.map +1 -0
- package/src/generators/preset/workspace-files-thin-deploy.d.ts +35 -0
- package/src/generators/preset/workspace-files-thin-deploy.js +1434 -0
- package/src/generators/preset/workspace-files-thin-deploy.js.map +1 -0
- package/src/generators/preset/workspace-files-thin-docs.d.ts +5 -0
- package/src/generators/preset/workspace-files-thin-docs.js +224 -0
- package/src/generators/preset/workspace-files-thin-docs.js.map +1 -0
- package/src/generators/preset/workspace-files-thin-release.d.ts +14 -0
- package/src/generators/preset/workspace-files-thin-release.js +26 -0
- package/src/generators/preset/workspace-files-thin-release.js.map +1 -0
- package/src/generators/preset/workspace-files.d.ts +1 -1
- package/src/generators/preset/workspace-files.js +373 -223
- package/src/generators/preset/workspace-files.js.map +1 -1
- package/src/generators/slice/built-in-plan-api-files.js +1 -0
- package/src/generators/slice/built-in-plan-api-files.js.map +1 -1
- package/src/generators/slice/built-in-plan-authorization-infrastructure-files.js +4 -0
- package/src/generators/slice/built-in-plan-authorization-infrastructure-files.js.map +1 -1
- package/src/generators/slice/built-in-plan-data-export-infrastructure-files.js +5 -31
- package/src/generators/slice/built-in-plan-data-export-infrastructure-files.js.map +1 -1
- package/src/generators/slice/built-in-plan-data-files.d.ts +1 -1
- package/src/generators/slice/built-in-plan-data-files.js +89 -30
- package/src/generators/slice/built-in-plan-data-files.js.map +1 -1
- package/src/generators/slice/built-in-plan-foundation-files.js +3 -5
- package/src/generators/slice/built-in-plan-foundation-files.js.map +1 -1
- package/src/generators/slice/built-in-plan-frontend-files.js +5 -1
- package/src/generators/slice/built-in-plan-frontend-files.js.map +1 -1
- package/src/generators/slice/built-in-plan-infrastructure-files.d.ts +1 -1
- package/src/generators/slice/built-in-plan-infrastructure-files.js +199 -188
- package/src/generators/slice/built-in-plan-infrastructure-files.js.map +1 -1
- package/src/generators/slice/built-in-plan-metadata-files.js +13 -0
- package/src/generators/slice/built-in-plan-metadata-files.js.map +1 -1
- package/src/generators/slice/built-in-plan-native-runtime-authority-files.d.ts +2 -0
- package/src/generators/slice/built-in-plan-native-runtime-authority-files.js +307 -0
- package/src/generators/slice/built-in-plan-native-runtime-authority-files.js.map +1 -0
- package/src/generators/slice/built-in-plan-operations-files.js +43 -49
- package/src/generators/slice/built-in-plan-operations-files.js.map +1 -1
- package/src/generators/slice/built-in-plan-performance-files.js +37 -19
- package/src/generators/slice/built-in-plan-performance-files.js.map +1 -1
- package/src/generators/slice/built-in-plan-project-files.js +9 -68
- package/src/generators/slice/built-in-plan-project-files.js.map +1 -1
- package/src/generators/slice/built-in-plan-secret-runtime-files.d.ts +1 -1
- package/src/generators/slice/built-in-plan-secret-runtime-files.js +74 -76
- package/src/generators/slice/built-in-plan-secret-runtime-files.js.map +1 -1
- package/src/generators/slice/built-in-plan-testing-files.js +74 -47
- package/src/generators/slice/built-in-plan-testing-files.js.map +1 -1
- package/src/generators/slice/built-in-plan-thin-release-files.d.ts +11 -0
- package/src/generators/slice/built-in-plan-thin-release-files.js +129 -0
- package/src/generators/slice/built-in-plan-thin-release-files.js.map +1 -0
- package/src/generators/slice/built-in-plan-verification-files.js +6 -2
- package/src/generators/slice/built-in-plan-verification-files.js.map +1 -1
- package/src/generators/slice/built-in-plan-web-files.js +4 -2
- package/src/generators/slice/built-in-plan-web-files.js.map +1 -1
- package/src/generators/slice/built-in-plan-workload-role-files.js +26 -4
- package/src/generators/slice/built-in-plan-workload-role-files.js.map +1 -1
- package/src/generators/slice/built-in-plan.d.ts +1 -0
- package/src/generators/slice/built-in-plan.js +28 -11
- package/src/generators/slice/built-in-plan.js.map +1 -1
- package/src/generators/slice/slice.js +27 -29
- package/src/generators/slice/slice.js.map +1 -1
- package/src/generators/upgrade/upgrade.d.ts +1 -1
- package/src/generators/upgrade/upgrade.js +224 -69
- package/src/generators/upgrade/upgrade.js.map +1 -1
- package/src/generators/workload/performance-registration.d.ts +1 -0
- package/src/generators/workload/performance-registration.js +6 -4
- package/src/generators/workload/performance-registration.js.map +1 -1
- package/src/generators/workload/service-performance-files.d.ts +1 -0
- package/src/generators/workload/service-performance-files.js +27 -7
- package/src/generators/workload/service-performance-files.js.map +1 -1
- package/src/generators/workload/workload.d.ts +1 -1
- package/src/generators/workload/workload.js +55 -28
- package/src/generators/workload/workload.js.map +1 -1
- package/src/git-policy/github-bootstrap.d.ts +19 -6
- package/src/git-policy/github-bootstrap.js +103 -157
- package/src/git-policy/github-bootstrap.js.map +1 -1
- package/src/local-dev/private-state.d.ts +3 -0
- package/src/local-dev/private-state.js +17 -5
- package/src/local-dev/private-state.js.map +1 -1
- package/src/performance/cost-collection.d.ts +1 -1
- package/src/performance/cost-collection.js +4 -2
- package/src/performance/cost-collection.js.map +1 -1
- package/src/performance/cost-controls.d.ts +3 -1
- package/src/performance/cost-controls.js +9 -4
- package/src/performance/cost-controls.js.map +1 -1
- package/src/performance/evidence.d.ts +1 -1
- package/src/performance/evidence.js +5 -3
- package/src/performance/evidence.js.map +1 -1
- package/src/performance/load-safety.js +5 -3
- package/src/performance/load-safety.js.map +1 -1
- package/src/performance/model.d.ts +2 -2
- package/src/performance/model.js +4 -3
- package/src/performance/model.js.map +1 -1
- package/src/release/index.d.ts +0 -2
- package/src/release/index.js +0 -2
- package/src/release/index.js.map +1 -1
- package/src/release/source-authority.d.ts +4 -5
- package/src/release/source-authority.js +13 -123
- package/src/release/source-authority.js.map +1 -1
- package/src/repository-policy/aurora-preflight.d.ts +1 -1
- package/src/repository-policy/aurora-preflight.js +4 -1
- package/src/repository-policy/aurora-preflight.js.map +1 -1
- package/src/repository-policy/policy.d.ts +5 -1
- package/src/repository-policy/policy.js +64 -13
- package/src/repository-policy/policy.js.map +1 -1
- package/src/schemas/performance-policy-v1.json +3 -1
- package/src/secrets/adapters.d.ts +5 -1
- package/src/secrets/adapters.js +22 -1
- package/src/secrets/adapters.js.map +1 -1
- package/src/secrets/aws-control-plane.d.ts +10 -1
- package/src/secrets/aws-control-plane.js +67 -0
- package/src/secrets/aws-control-plane.js.map +1 -1
- package/src/secrets/generated-aws-control-plane.d.ts +23 -0
- package/src/secrets/generated-aws-control-plane.js +259 -0
- package/src/secrets/generated-aws-control-plane.js.map +1 -0
- package/src/secrets/metadata.js +38 -10
- package/src/secrets/metadata.js.map +1 -1
- package/src/secrets/model.d.ts +8 -1
- package/src/secrets/model.js +24 -3
- package/src/secrets/model.js.map +1 -1
- package/src/secrets/operator.d.ts +89 -3
- package/src/secrets/operator.js +422 -9
- package/src/secrets/operator.js.map +1 -1
- package/src/secrets/registry.d.ts +2 -1
- package/src/secrets/registry.js +18 -1
- package/src/secrets/registry.js.map +1 -1
- package/src/secrets/workload-access.js +10 -2
- package/src/secrets/workload-access.js.map +1 -1
- package/src/supply-chain/action-pins.js +61 -7
- package/src/supply-chain/action-pins.js.map +1 -1
- package/src/supply-chain/build-output-bounds.d.ts +2 -0
- package/src/supply-chain/build-output-bounds.js +12 -0
- package/src/supply-chain/build-output-bounds.js.map +1 -0
- package/src/supply-chain/build-output.js +2 -4
- package/src/supply-chain/build-output.js.map +1 -1
- package/src/supply-chain/ecr-scanning.d.ts +5 -3
- package/src/supply-chain/ecr-scanning.js +11 -7
- package/src/supply-chain/ecr-scanning.js.map +1 -1
- package/src/supply-chain/ecs-deployed-image.d.ts +5 -3
- package/src/supply-chain/ecs-deployed-image.js +6 -4
- package/src/supply-chain/ecs-deployed-image.js.map +1 -1
- package/src/supply-chain/generated-container-release-command.js +816 -34
- package/src/supply-chain/generated-container-release-command.js.map +1 -1
- package/src/supply-chain/generated-ecr-collector-command.d.ts +0 -1
- package/src/supply-chain/generated-ecr-collector-command.js +188 -91
- package/src/supply-chain/generated-ecr-collector-command.js.map +1 -1
- package/src/supply-chain/generated-files.js +4 -3
- package/src/supply-chain/generated-files.js.map +1 -1
- package/src/supply-chain/index.d.ts +1 -1
- package/src/supply-chain/index.js +2 -1
- package/src/supply-chain/index.js.map +1 -1
- package/src/workload-roles/index.d.ts +10 -17
- package/src/workload-roles/index.js +5 -18
- 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
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const
|
|
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: [
|
|
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
|
-
|
|
3889
|
-
description: Exact
|
|
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
|
-
|
|
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="
|
|
3967
|
-
case "$
|
|
3968
|
-
"$expected_artifact"*) attempt="\${
|
|
3969
|
-
*) echo '
|
|
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 "$
|
|
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.
|
|
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 !== "
|
|
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 === "
|
|
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: [
|
|
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
|
-
|
|
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
|
-
|
|
5203
|
-
'[.jobs[] | select(.name
|
|
5204
|
-
|
|
5205
|
-
'
|
|
5206
|
-
|
|
5207
|
-
|
|
5208
|
-
|
|
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: [
|
|
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
|
-
|
|
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
|
-
|
|
7461
|
-
\`ebk secret set\` or \`ebk secret remove
|
|
7462
|
-
metadata, status, and
|
|
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
|
-
|
|
7580
|
-
|
|
7581
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
7607
|
-
|
|
7608
|
-
|
|
7609
|
-
|
|
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
|
|
7632
|
-
|
|
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
|
|
7637
|
-
|
|
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
|
-
|
|
7670
|
-
|
|
7671
|
-
|
|
7672
|
-
|
|
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
|
|
7748
|
-
|
|
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
|
-
|
|
8247
|
-
|
|
8248
|
-
|
|
8249
|
-
|
|
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
|
|
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
|
|
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
|
|
8512
|
-
if (
|
|
8513
|
-
|
|
8514
|
-
|
|
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(
|
|
9019
|
-
|
|
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
|
-
|
|
9058
|
-
|
|
9059
|
-
|
|
9060
|
-
|
|
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:
|
|
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:
|
|
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
|
-
|
|
9356
|
-
|
|
9357
|
-
|
|
9358
|
-
|
|
9359
|
-
|
|
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
|
-
|
|
9363
|
-
|
|
9364
|
-
|
|
9365
|
-
|
|
9366
|
-
|
|
9367
|
-
|
|
9368
|
-
|
|
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
|
|
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
|
-
|
|
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 (!
|
|
9562
|
+
if (!new Set<string>(${JSON.stringify(activeStages)}).has(stage)) {
|
|
9447
9563
|
throw new Error(
|
|
9448
|
-
'Foundation stage ' + stage + ' is
|
|
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(
|
|
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,
|
|
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);
|