@empire-builder-kit/nx 1.0.0-rc.30 → 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.
- package/executors.json +8 -3
- package/package.json +14 -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 +240 -0
- package/src/aws-authority/stage-authority.js +2968 -0
- package/src/aws-authority/stage-authority.js.map +1 -0
- package/src/cli/main.d.ts +2 -0
- package/src/cli/main.js +11 -0
- package/src/cli/main.js.map +1 -1
- 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/developer-agent/workspace-inspection.js +11 -2
- package/src/developer-agent/workspace-inspection.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/github-bootstrap/github-bootstrap.d.ts +1 -0
- package/src/executors/github-bootstrap/github-bootstrap.js +1 -0
- package/src/executors/github-bootstrap/github-bootstrap.js.map +1 -1
- package/src/executors/github-bootstrap/schema.json +7 -1
- package/src/executors/infrastructure-plan/infrastructure-plan.d.ts +27 -369
- package/src/executors/infrastructure-plan/infrastructure-plan.js +237 -5470
- 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 +60 -43
- package/src/executors/local-deploy/local-deploy.js +955 -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 +27 -1
- package/src/executors/router-waf-rehearsal/router-waf-rehearsal.js +907 -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 +32 -0
- package/src/executors/secret-initialize/secret-initialize.js +243 -0
- package/src/executors/secret-initialize/secret-initialize.js.map +1 -0
- package/src/executors/secret-metadata/secret-metadata.d.ts +4 -1
- package/src/executors/secret-metadata/secret-metadata.js +76 -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 +27 -7
- package/src/executors/sst-lifecycle/run-sst-command.js +474 -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/provision-logical-database.js +2 -0
- package/src/foundation/provision-logical-database.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 +28 -8
- package/src/generators/preset/generator.js.map +1 -1
- package/src/generators/preset/schema.d.ts +3 -0
- package/src/generators/preset/schema.json +5 -5
- 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 +29 -24
- package/src/generators/preset/workspace-files-performance-load.js.map +1 -1
- package/src/generators/preset/workspace-files-stage-authority.d.ts +6 -0
- package/src/generators/preset/workspace-files-stage-authority.js +479 -0
- package/src/generators/preset/workspace-files-stage-authority.js.map +1 -0
- package/src/generators/preset/workspace-files-thin-deploy.d.ts +40 -0
- package/src/generators/preset/workspace-files-thin-deploy.js +1500 -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 +240 -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 +2 -1
- package/src/generators/preset/workspace-files.js +448 -680
- package/src/generators/preset/workspace-files.js.map +1 -1
- package/src/generators/repository-policy/repository-policy.js +149 -19
- package/src/generators/repository-policy/repository-policy.js.map +1 -1
- package/src/generators/repository-policy/schema.d.ts +2 -0
- package/src/generators/repository-policy/schema.json +11 -1
- package/src/generators/repository-policy/tree-policy.d.ts +3 -0
- package/src/generators/repository-policy/tree-policy.js +25 -0
- package/src/generators/repository-policy/tree-policy.js.map +1 -0
- 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-async-work-files.js +41 -0
- package/src/generators/slice/built-in-plan-async-work-files.js.map +1 -1
- package/src/generators/slice/built-in-plan-authorization-infrastructure-files.js +6 -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-data-lifecycle-runtime-files.js +19 -0
- package/src/generators/slice/built-in-plan-data-lifecycle-runtime-files.js.map +1 -1
- package/src/generators/slice/built-in-plan-data-retention-launcher-files.js +21 -3
- package/src/generators/slice/built-in-plan-data-retention-launcher-files.js.map +1 -1
- package/src/generators/slice/built-in-plan-database-retirement-rehearsal-files.js +20 -1
- package/src/generators/slice/built-in-plan-database-retirement-rehearsal-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 +65 -51
- package/src/generators/slice/built-in-plan-operations-files.js.map +1 -1
- package/src/generators/slice/built-in-plan-performance-files.js +97 -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 +87 -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 +94 -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 +30 -32
- package/src/generators/slice/slice.js.map +1 -1
- package/src/generators/upgrade/upgrade.d.ts +1 -1
- package/src/generators/upgrade/upgrade.js +200 -48
- 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 +9 -11
- 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 +28 -7
- package/src/git-policy/github-bootstrap.js +205 -163
- package/src/git-policy/github-bootstrap.js.map +1 -1
- package/src/index.d.ts +1 -0
- package/src/index.js +1 -0
- package/src/index.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/local-dev/tls.js +5 -1
- package/src/local-dev/tls.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 +21 -2
- package/src/repository-policy/policy.js +290 -25
- package/src/repository-policy/policy.js.map +1 -1
- package/src/schemas/performance-policy-v1.json +3 -1
- package/src/schemas/repository-policy-v1.json +46 -2
- package/src/secrets/adapters.d.ts +7 -2
- package/src/secrets/adapters.js +34 -3
- 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 +849 -44
- 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
- package/src/workspace-deployment/identity.d.ts +3 -0
- package/src/workspace-deployment/identity.js +22 -0
- package/src/workspace-deployment/identity.js.map +1 -0
- package/src/workspace-deployment/index.d.ts +3 -0
- package/src/workspace-deployment/index.js +7 -0
- package/src/workspace-deployment/index.js.map +1 -0
- package/src/workspace-deployment/migration-evidence.d.ts +29 -0
- package/src/workspace-deployment/migration-evidence.js +83 -0
- package/src/workspace-deployment/migration-evidence.js.map +1 -0
- package/src/workspace-deployment/migration.d.ts +27 -0
- package/src/workspace-deployment/migration.js +109 -0
- package/src/workspace-deployment/migration.js.map +1 -0
- package/src/workspace-deployment/ownership.d.ts +81 -0
- package/src/workspace-deployment/ownership.js +381 -0
- package/src/workspace-deployment/ownership.js.map +1 -0
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.assertGovernedAwsLifecyclePlatform = assertGovernedAwsLifecyclePlatform;
|
|
4
|
+
exports.runGovernedChildProcess = runGovernedChildProcess;
|
|
3
5
|
exports.createSstChildEnvironment = createSstChildEnvironment;
|
|
4
6
|
exports.assertSafeSstForwardedArguments = assertSafeSstForwardedArguments;
|
|
5
7
|
exports.resolveSstDevMode = resolveSstDevMode;
|
|
@@ -10,13 +12,19 @@ exports.runSstLifecyclePreflights = runSstLifecyclePreflights;
|
|
|
10
12
|
exports.runSstCommand = runSstCommand;
|
|
11
13
|
const devkit_1 = require("@nx/devkit");
|
|
12
14
|
const node_child_process_1 = require("node:child_process");
|
|
15
|
+
const node_fs_1 = require("node:fs");
|
|
13
16
|
const node_path_1 = require("node:path");
|
|
17
|
+
const index_js_1 = require("../../aws-authority/index.js");
|
|
18
|
+
const child_environment_js_1 = require("../../aws/child-environment.js");
|
|
19
|
+
const identity_js_1 = require("../../aws/identity.js");
|
|
14
20
|
const stages_js_1 = require("../../foundation/stages.js");
|
|
15
21
|
const personal_stage_js_1 = require("../../local-dev/personal-stage.js");
|
|
16
|
-
const
|
|
17
|
-
const index_js_2 = require("../../
|
|
18
|
-
const
|
|
22
|
+
const federated_credential_transport_js_1 = require("../local-deploy/federated-credential-transport.js");
|
|
23
|
+
const index_js_2 = require("../../repository-policy/index.js");
|
|
24
|
+
const index_js_3 = require("../../workspace-deployment/index.js");
|
|
25
|
+
const index_js_4 = require("../../work-markers/index.js");
|
|
19
26
|
const secret_preflight_js_1 = require("./secret-preflight.js");
|
|
27
|
+
const generated_secret_retirement_js_1 = require("./generated-secret-retirement.js");
|
|
20
28
|
const sst_environment_source_js_1 = require("./sst-environment-source.js");
|
|
21
29
|
const GOVERNED_STAGES = new Set(['development', 'staging', 'production']);
|
|
22
30
|
const DEPLOYMENT_STAGES = new Set(['development', 'staging', 'production']);
|
|
@@ -30,6 +38,274 @@ const RESERVED_FORWARDED_OPTIONS = new Set([
|
|
|
30
38
|
const SST_DEV_MODES = new Set(['basic', 'mono']);
|
|
31
39
|
const AWS_REGION_PATTERN = /^[a-z]{2}(?:-gov)?-[a-z]+-\d$/;
|
|
32
40
|
const AWS_ROLE_ARN_PATTERN = /^arn:(aws|aws-us-gov|aws-cn):iam::\d{12}:role\/[A-Za-z0-9+=,.@_/-]{1,512}$/;
|
|
41
|
+
const MAX_CALLER_IDENTITY_BYTES = 1024 * 1024;
|
|
42
|
+
const SST_SIGNAL_GRACE_PERIOD_MS = 10_000;
|
|
43
|
+
const SST_SIGNAL_KILL_WAIT_MS = 5_000;
|
|
44
|
+
const SST_PROCESS_GROUP_POLL_MS = 25;
|
|
45
|
+
const GOVERNED_PROCESS_GROUP_ENV = 'EBK_GOVERNED_PROCESS_GROUP';
|
|
46
|
+
function assertGovernedAwsLifecyclePlatform(platform = process.platform) {
|
|
47
|
+
if (platform === 'win32') {
|
|
48
|
+
throw new Error('Governed AWS infrastructure lifecycle is unavailable on native Windows; use macOS, Linux, or WSL2. Native Windows remains supported for local development and verification.');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function isMissingProcessError(error) {
|
|
52
|
+
return (typeof error === 'object' &&
|
|
53
|
+
error !== null &&
|
|
54
|
+
'code' in error &&
|
|
55
|
+
error.code === 'ESRCH');
|
|
56
|
+
}
|
|
57
|
+
function exactWindowsSystemRoot() {
|
|
58
|
+
const values = new Set(Object.entries(process.env)
|
|
59
|
+
.filter(([name, value]) => name.toLowerCase() === 'systemroot' &&
|
|
60
|
+
typeof value === 'string' &&
|
|
61
|
+
value.length > 0)
|
|
62
|
+
.map(([, value]) => value));
|
|
63
|
+
if (values.size !== 1) {
|
|
64
|
+
throw new Error('Workspace SST tree cleanup requires exact SystemRoot.');
|
|
65
|
+
}
|
|
66
|
+
const systemRoot = values.values().next().value;
|
|
67
|
+
if (typeof systemRoot !== 'string' ||
|
|
68
|
+
!(0, node_path_1.isAbsolute)(systemRoot) ||
|
|
69
|
+
/[\0\r\n"]/u.test(systemRoot)) {
|
|
70
|
+
throw new Error('Workspace SST tree cleanup has an unsafe SystemRoot.');
|
|
71
|
+
}
|
|
72
|
+
return systemRoot;
|
|
73
|
+
}
|
|
74
|
+
function exactWindowsTaskkill() {
|
|
75
|
+
const systemRoot = exactWindowsSystemRoot();
|
|
76
|
+
const requested = (0, node_path_1.join)(systemRoot, 'System32', 'taskkill.exe');
|
|
77
|
+
const metadata = (0, node_fs_1.lstatSync)(requested);
|
|
78
|
+
const canonical = (0, node_fs_1.realpathSync)(requested);
|
|
79
|
+
if (metadata.isSymbolicLink() ||
|
|
80
|
+
!metadata.isFile() ||
|
|
81
|
+
canonical.toLowerCase() !== requested.toLowerCase()) {
|
|
82
|
+
throw new Error('Workspace SST taskkill authority is not exact.');
|
|
83
|
+
}
|
|
84
|
+
return { executable: canonical, systemRoot };
|
|
85
|
+
}
|
|
86
|
+
function signalExactGovernedProcessTree(child, signal) {
|
|
87
|
+
const pid = child.pid;
|
|
88
|
+
if (typeof pid !== 'number' || !Number.isSafeInteger(pid) || pid <= 0) {
|
|
89
|
+
throw new Error('Workspace SST child has no exact process identity.');
|
|
90
|
+
}
|
|
91
|
+
if (process.platform === 'win32') {
|
|
92
|
+
const taskkill = exactWindowsTaskkill();
|
|
93
|
+
const terminated = (0, node_child_process_1.spawnSync)(taskkill.executable, ['/pid', String(pid), '/t', '/f'], {
|
|
94
|
+
env: { SystemRoot: taskkill.systemRoot },
|
|
95
|
+
shell: false,
|
|
96
|
+
stdio: 'ignore',
|
|
97
|
+
timeout: 15_000,
|
|
98
|
+
windowsHide: true,
|
|
99
|
+
});
|
|
100
|
+
if ((terminated.error || terminated.signal || terminated.status !== 0) &&
|
|
101
|
+
child.exitCode === null &&
|
|
102
|
+
child.signalCode === null) {
|
|
103
|
+
throw new Error('Workspace SST process-tree termination failed.');
|
|
104
|
+
}
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
process.kill(-pid, signal);
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
if (!isMissingProcessError(error))
|
|
112
|
+
throw error;
|
|
113
|
+
if (child.exitCode === null && child.signalCode === null) {
|
|
114
|
+
child.kill(signal);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function exactGovernedProcessTreeExists(pid) {
|
|
119
|
+
if (process.platform === 'win32')
|
|
120
|
+
return false;
|
|
121
|
+
try {
|
|
122
|
+
process.kill(-pid, 0);
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
if (isMissingProcessError(error))
|
|
127
|
+
return false;
|
|
128
|
+
throw error;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
async function waitForExactGovernedProcessTreeExit(pid, deadline = Date.now() + SST_SIGNAL_GRACE_PERIOD_MS + SST_SIGNAL_KILL_WAIT_MS) {
|
|
132
|
+
while (exactGovernedProcessTreeExists(pid)) {
|
|
133
|
+
if (Date.now() >= deadline) {
|
|
134
|
+
throw new Error('Workspace SST process tree did not stop within the bounded deadline.');
|
|
135
|
+
}
|
|
136
|
+
await new Promise((resolveWait) => setTimeout(resolveWait, SST_PROCESS_GROUP_POLL_MS));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async function waitForGovernedChildSettlement(childSettled, deadline) {
|
|
140
|
+
const remaining = deadline - Date.now();
|
|
141
|
+
if (remaining <= 0) {
|
|
142
|
+
throw new Error('Workspace SST child did not stop within the bounded deadline.');
|
|
143
|
+
}
|
|
144
|
+
let timeout;
|
|
145
|
+
try {
|
|
146
|
+
await Promise.race([
|
|
147
|
+
childSettled,
|
|
148
|
+
new Promise((_resolve, reject) => {
|
|
149
|
+
timeout = setTimeout(() => reject(new Error('Workspace SST child did not stop within the bounded deadline.')), remaining);
|
|
150
|
+
}),
|
|
151
|
+
]);
|
|
152
|
+
}
|
|
153
|
+
finally {
|
|
154
|
+
if (timeout)
|
|
155
|
+
clearTimeout(timeout);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
async function terminateRetainedGovernedProcessGroup(pid) {
|
|
159
|
+
if (process.platform === 'win32' || !exactGovernedProcessTreeExists(pid)) {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
const deadline = Date.now() + SST_SIGNAL_GRACE_PERIOD_MS + SST_SIGNAL_KILL_WAIT_MS;
|
|
163
|
+
try {
|
|
164
|
+
process.kill(-pid, 'SIGTERM');
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
if (!isMissingProcessError(error))
|
|
168
|
+
throw error;
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
const escalation = setTimeout(() => {
|
|
172
|
+
try {
|
|
173
|
+
process.kill(-pid, 'SIGKILL');
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
if (!isMissingProcessError(error)) {
|
|
177
|
+
process.stderr.write('Governed descendant process-tree escalation failed.\n');
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}, SST_SIGNAL_GRACE_PERIOD_MS);
|
|
181
|
+
try {
|
|
182
|
+
await waitForExactGovernedProcessTreeExit(pid, deadline);
|
|
183
|
+
}
|
|
184
|
+
finally {
|
|
185
|
+
clearTimeout(escalation);
|
|
186
|
+
}
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
async function stopExactGovernedProcessTree(child, signal, childSettled, isSettled, ownsProcessGroup = true) {
|
|
190
|
+
const pid = child.pid;
|
|
191
|
+
const deadline = Date.now() + SST_SIGNAL_GRACE_PERIOD_MS + SST_SIGNAL_KILL_WAIT_MS;
|
|
192
|
+
if (process.platform === 'win32' || ownsProcessGroup) {
|
|
193
|
+
signalExactGovernedProcessTree(child, signal);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
child.kill(signal);
|
|
197
|
+
}
|
|
198
|
+
let escalationError;
|
|
199
|
+
const escalation = setTimeout(() => {
|
|
200
|
+
try {
|
|
201
|
+
if (!isSettled() ||
|
|
202
|
+
(ownsProcessGroup && pid && exactGovernedProcessTreeExists(pid))) {
|
|
203
|
+
if (process.platform === 'win32' || ownsProcessGroup) {
|
|
204
|
+
signalExactGovernedProcessTree(child, 'SIGKILL');
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
child.kill('SIGKILL');
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
escalationError = error;
|
|
213
|
+
}
|
|
214
|
+
}, SST_SIGNAL_GRACE_PERIOD_MS);
|
|
215
|
+
try {
|
|
216
|
+
await waitForGovernedChildSettlement(childSettled, deadline);
|
|
217
|
+
if (ownsProcessGroup && pid && process.platform !== 'win32') {
|
|
218
|
+
await waitForExactGovernedProcessTreeExit(pid, deadline);
|
|
219
|
+
}
|
|
220
|
+
if (escalationError)
|
|
221
|
+
throw escalationError;
|
|
222
|
+
}
|
|
223
|
+
finally {
|
|
224
|
+
clearTimeout(escalation);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
/** Run one exact shell-free child as an owned process tree. The returned
|
|
228
|
+
* promise settles only after child teardown and the bounded caller-supplied
|
|
229
|
+
* close reconciliation complete. */
|
|
230
|
+
function runGovernedChildProcess(input) {
|
|
231
|
+
return new Promise((resolveChildRun) => {
|
|
232
|
+
const environment = { ...input.environment };
|
|
233
|
+
for (const name of Object.keys(environment)) {
|
|
234
|
+
if (name.toUpperCase() === GOVERNED_PROCESS_GROUP_ENV) {
|
|
235
|
+
delete environment[name];
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
if (process.platform !== 'win32') {
|
|
239
|
+
environment[GOVERNED_PROCESS_GROUP_ENV] = '1';
|
|
240
|
+
}
|
|
241
|
+
const child = (input.spawnChild ?? node_child_process_1.spawn)(input.executable, [...input.args], {
|
|
242
|
+
cwd: input.cwd,
|
|
243
|
+
detached: process.platform !== 'win32',
|
|
244
|
+
env: environment,
|
|
245
|
+
shell: false,
|
|
246
|
+
stdio: 'inherit',
|
|
247
|
+
});
|
|
248
|
+
let finishing = false;
|
|
249
|
+
let settled = false;
|
|
250
|
+
let spawnError;
|
|
251
|
+
let unregisterSignalCleanup = () => undefined;
|
|
252
|
+
let resolveChildSettled = () => undefined;
|
|
253
|
+
const childSettled = new Promise((resolveChild) => {
|
|
254
|
+
resolveChildSettled = resolveChild;
|
|
255
|
+
});
|
|
256
|
+
const finish = async (status, signal) => {
|
|
257
|
+
if (finishing)
|
|
258
|
+
return;
|
|
259
|
+
finishing = true;
|
|
260
|
+
const result = {
|
|
261
|
+
...(spawnError ? { error: spawnError } : {}),
|
|
262
|
+
signal,
|
|
263
|
+
status,
|
|
264
|
+
};
|
|
265
|
+
if (!(0, federated_credential_transport_js_1.governedSignalCleanupInProgress)() && child.pid) {
|
|
266
|
+
try {
|
|
267
|
+
if (await terminateRetainedGovernedProcessGroup(child.pid)) {
|
|
268
|
+
result.error ??= new Error('Governed child exited before its exact descendant process tree stopped.');
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
catch (error) {
|
|
272
|
+
result.error =
|
|
273
|
+
error instanceof Error
|
|
274
|
+
? error
|
|
275
|
+
: new Error('Governed child descendant process-tree reconciliation failed.');
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
try {
|
|
279
|
+
await input.afterClose?.(result);
|
|
280
|
+
}
|
|
281
|
+
catch (error) {
|
|
282
|
+
result.error =
|
|
283
|
+
error instanceof Error
|
|
284
|
+
? error
|
|
285
|
+
: new Error('Governed child close reconciliation failed.');
|
|
286
|
+
}
|
|
287
|
+
settled = true;
|
|
288
|
+
unregisterSignalCleanup();
|
|
289
|
+
resolveChildSettled();
|
|
290
|
+
resolveChildRun(result);
|
|
291
|
+
};
|
|
292
|
+
unregisterSignalCleanup = (0, federated_credential_transport_js_1.registerGovernedSignalCleanup)((signal) => stopExactGovernedProcessTree(child, signal, childSettled, () => settled), 100);
|
|
293
|
+
child.once('error', (error) => {
|
|
294
|
+
spawnError = error;
|
|
295
|
+
void finish(null, null);
|
|
296
|
+
});
|
|
297
|
+
child.once('close', (status, signal) => {
|
|
298
|
+
void finish(status, signal);
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
function partitionForRegion(region) {
|
|
303
|
+
if (region.startsWith('cn-'))
|
|
304
|
+
return 'aws-cn';
|
|
305
|
+
if (region.startsWith('us-gov-'))
|
|
306
|
+
return 'aws-us-gov';
|
|
307
|
+
return 'aws';
|
|
308
|
+
}
|
|
33
309
|
function captureSstEnvironmentSource(context) {
|
|
34
310
|
const projectName = context.projectName;
|
|
35
311
|
const configured = projectName
|
|
@@ -45,24 +321,62 @@ function captureSstEnvironmentSource(context) {
|
|
|
45
321
|
workspaceRoot: context.root,
|
|
46
322
|
});
|
|
47
323
|
}
|
|
48
|
-
function
|
|
324
|
+
function requiresSourceReconciliation(command, stage) {
|
|
49
325
|
return (GOVERNED_STAGES.has(stage) &&
|
|
50
326
|
(command === 'deploy' || command === 'refresh' || command === 'remove'));
|
|
51
327
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
328
|
+
function isGovernedLocalCommand(command) {
|
|
329
|
+
return (command === 'deploy' ||
|
|
330
|
+
command === 'refresh' ||
|
|
331
|
+
command === 'remove' ||
|
|
332
|
+
command === 'unlock');
|
|
55
333
|
}
|
|
56
|
-
async function authorizeLocalUnlock(options, invocation) {
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
334
|
+
async function authorizeLocalUnlock(options, invocation, environment = process.env) {
|
|
335
|
+
const expectedAccount = invocation.environment.AWS_EXPECTED_ACCOUNT_ID?.trim() ?? '';
|
|
336
|
+
const expectedRoleArn = invocation.environment.EBK_EXPECTED_DEPLOYMENT_ROLE_ARN?.trim() ?? '';
|
|
337
|
+
if (!/^\d{12}$/.test(expectedAccount) || !expectedRoleArn) {
|
|
338
|
+
throw new Error('Local unlock requires one exact committed account and temporary assumed role.');
|
|
339
|
+
}
|
|
340
|
+
const ambientExpectedAccount = environment.AWS_EXPECTED_ACCOUNT_ID?.trim();
|
|
341
|
+
if (ambientExpectedAccount && ambientExpectedAccount !== expectedAccount) {
|
|
342
|
+
throw new Error('Ambient AWS_EXPECTED_ACCOUNT_ID does not match committed deployment topology.');
|
|
343
|
+
}
|
|
344
|
+
const result = (0, node_child_process_1.spawnSync)('aws', [
|
|
345
|
+
'sts',
|
|
346
|
+
'get-caller-identity',
|
|
347
|
+
'--endpoint-url',
|
|
348
|
+
(0, identity_js_1.canonicalStsEndpoint)(invocation.environment.AWS_REGION?.trim() ?? ''),
|
|
349
|
+
'--output',
|
|
350
|
+
'json',
|
|
351
|
+
...(options.profile ? ['--profile', options.profile] : []),
|
|
352
|
+
], {
|
|
353
|
+
cwd: invocation.cwd,
|
|
354
|
+
encoding: 'utf8',
|
|
355
|
+
env: createSstChildEnvironment(environment, invocation.environment),
|
|
356
|
+
maxBuffer: MAX_CALLER_IDENTITY_BYTES,
|
|
357
|
+
shell: false,
|
|
358
|
+
windowsHide: true,
|
|
61
359
|
});
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
360
|
+
if (result.error || result.status !== 0 || result.signal) {
|
|
361
|
+
throw new Error('Local unlock AWS caller identity could not be verified.');
|
|
362
|
+
}
|
|
363
|
+
let caller;
|
|
364
|
+
try {
|
|
365
|
+
caller = JSON.parse(result.stdout);
|
|
366
|
+
}
|
|
367
|
+
catch {
|
|
368
|
+
throw new Error('Local unlock AWS caller identity is not valid JSON.');
|
|
369
|
+
}
|
|
370
|
+
if (!caller ||
|
|
371
|
+
typeof caller !== 'object' ||
|
|
372
|
+
Array.isArray(caller) ||
|
|
373
|
+
!('Account' in caller) ||
|
|
374
|
+
!('Arn' in caller) ||
|
|
375
|
+
caller.Account !== expectedAccount ||
|
|
376
|
+
typeof caller.Arn !== 'string' ||
|
|
377
|
+
!(0, identity_js_1.matchesExpectedAssumedRoleArn)(expectedAccount, caller.Arn, expectedRoleArn)) {
|
|
378
|
+
throw new Error('Local unlock AWS caller does not match the committed account and exact temporary assumed role.');
|
|
379
|
+
}
|
|
66
380
|
}
|
|
67
381
|
function projectKind(context) {
|
|
68
382
|
if (!context.projectName) {
|
|
@@ -77,18 +391,21 @@ function projectKind(context) {
|
|
|
77
391
|
return foundation ? 'foundation' : 'slice';
|
|
78
392
|
}
|
|
79
393
|
function createSstChildEnvironment(ambient, invocation) {
|
|
80
|
-
const
|
|
394
|
+
const stageSanitized = (0, personal_stage_js_1.isFrameworkPersonalStage)(invocation.EBK_CONSUMER_STAGE)
|
|
81
395
|
? (0, personal_stage_js_1.createPersonalDevelopmentEnvironment)(invocation.EBK_CONSUMER_STAGE, ambient)
|
|
82
396
|
: (0, personal_stage_js_1.stripAmbientStageAuthority)(ambient);
|
|
397
|
+
const sanitized = (0, child_environment_js_1.sanitizeGovernedAwsChildEnvironment)(stageSanitized, {
|
|
398
|
+
preserveVerifiedGithubCredentials: stageSanitized.GITHUB_ACTIONS === 'true',
|
|
399
|
+
});
|
|
83
400
|
delete sanitized.EBK_PRODUCTION_FOUNDATION_PROFILE;
|
|
84
401
|
delete sanitized.EBK_LOCAL_MUTATION_CAPABILITY_NONCE;
|
|
85
402
|
delete sanitized.EBK_LOCAL_MUTATION_CAPABILITY_PATH;
|
|
403
|
+
delete sanitized.EBK_GITHUB_JOB_WORKFLOW_REF;
|
|
404
|
+
delete sanitized.EBK_NX_STAGE_LIFECYCLE;
|
|
86
405
|
// Nx injects task identity, target, hash, terminal, cache, and invocation
|
|
87
|
-
// metadata into every executor process.
|
|
88
|
-
//
|
|
89
|
-
//
|
|
90
|
-
// infrastructure inputs. Never let them reach SST, where build tools can
|
|
91
|
-
// persist ambient environment values into deployment archives.
|
|
406
|
+
// metadata into every executor process. Those values describe orchestration,
|
|
407
|
+
// not desired infrastructure. Never let them reach SST, where build tools
|
|
408
|
+
// can persist ambient environment values into deployment archives.
|
|
92
409
|
for (const name of Object.keys(sanitized)) {
|
|
93
410
|
if (name.startsWith('NX_') || name === 'LERNA_PACKAGE_NAME') {
|
|
94
411
|
delete sanitized[name];
|
|
@@ -124,19 +441,33 @@ function assertSstLifecyclePolicy(command, stage, environment = process.env, dep
|
|
|
124
441
|
if (command === 'dev') {
|
|
125
442
|
throw new Error(`SST dev is not permitted for protected stage ${stage}.`);
|
|
126
443
|
}
|
|
127
|
-
if (
|
|
444
|
+
if (command === 'remove' &&
|
|
445
|
+
stage === 'production' &&
|
|
446
|
+
environment.EBK_ALLOW_PRODUCTION_REMOVE !== 'true') {
|
|
447
|
+
throw new Error('Production removal requires EBK_ALLOW_PRODUCTION_REMOVE=true in the governed production environment.');
|
|
448
|
+
}
|
|
449
|
+
if (!(0, index_js_2.requiresGithubDeployment)(deploymentProfile, stage) &&
|
|
128
450
|
environment.GITHUB_ACTIONS !== 'true') {
|
|
129
451
|
return;
|
|
130
452
|
}
|
|
131
453
|
const repository = environment.GITHUB_REPOSITORY;
|
|
132
|
-
const expectedBranch = stage === '
|
|
454
|
+
const expectedBranch = stage === 'production' ? 'main' : 'develop';
|
|
133
455
|
const expectedRef = `refs/heads/${expectedBranch}`;
|
|
134
|
-
const
|
|
456
|
+
const expectedCalledWorkflowRef = repository
|
|
135
457
|
? `${repository}/.github/workflows/deploy.yml@${expectedRef}`
|
|
136
458
|
: undefined;
|
|
137
459
|
const eventName = environment.GITHUB_EVENT_NAME;
|
|
138
460
|
const allowedEvent = eventName === 'workflow_dispatch' ||
|
|
139
|
-
(eventName === 'push' &&
|
|
461
|
+
(eventName === 'push' &&
|
|
462
|
+
command === 'deploy' &&
|
|
463
|
+
deploymentProfile !== 'starter');
|
|
464
|
+
const expectedCallerWorkflowRef = eventName === 'push'
|
|
465
|
+
? repository
|
|
466
|
+
? `${repository}/.github/workflows/ci.yml@${expectedRef}`
|
|
467
|
+
: undefined
|
|
468
|
+
: eventName === 'workflow_dispatch'
|
|
469
|
+
? expectedCalledWorkflowRef
|
|
470
|
+
: undefined;
|
|
140
471
|
// These GitHub-provided values are a fail-closed provenance consistency
|
|
141
472
|
// check, not a credential boundary: a local process can spoof them. Actual
|
|
142
473
|
// protected-stage authority comes from environment-scoped OIDC role access
|
|
@@ -146,14 +477,10 @@ function assertSstLifecyclePolicy(command, stage, environment = process.env, dep
|
|
|
146
477
|
environment.GITHUB_ACTIONS === 'true' &&
|
|
147
478
|
allowedEvent &&
|
|
148
479
|
environment.GITHUB_REF === expectedRef &&
|
|
149
|
-
environment.GITHUB_WORKFLOW_REF ===
|
|
480
|
+
environment.GITHUB_WORKFLOW_REF === expectedCallerWorkflowRef &&
|
|
481
|
+
environment.EBK_GITHUB_JOB_WORKFLOW_REF === expectedCalledWorkflowRef;
|
|
150
482
|
if (!workflowProvenanceMatches) {
|
|
151
|
-
throw new Error(`SST ${command} for protected stage ${stage} must run from the ${expectedBranch}-branch deploy
|
|
152
|
-
}
|
|
153
|
-
if (command === 'remove' &&
|
|
154
|
-
stage === 'production' &&
|
|
155
|
-
environment.EBK_ALLOW_PRODUCTION_REMOVE !== 'true') {
|
|
156
|
-
throw new Error('Production removal requires EBK_ALLOW_PRODUCTION_REMOVE=true in the protected production environment.');
|
|
483
|
+
throw new Error(`SST ${command} for protected stage ${stage} must run from the exact ${expectedBranch}-branch caller and reusable deploy workflows; isolated-profile pushes may run only deploy and other lifecycle actions require workflow_dispatch.`);
|
|
157
484
|
}
|
|
158
485
|
}
|
|
159
486
|
function resolveSstLifecycleStages(options, environment = process.env) {
|
|
@@ -222,19 +549,23 @@ function buildSstCommandInvocation(command, options, context, environment = proc
|
|
|
222
549
|
stages.mapped) {
|
|
223
550
|
throw new Error(`Full deploy is not permitted for mapped personal stage ${stages.consumerStage}. Use ebk dev against the ${stages.foundationStage} Foundation.`);
|
|
224
551
|
}
|
|
225
|
-
const operatingPolicy =
|
|
226
|
-
(
|
|
227
|
-
command === '
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
552
|
+
const operatingPolicy = command === 'dev' ||
|
|
553
|
+
(DEPLOYMENT_STAGES.has(stages.consumerStage) &&
|
|
554
|
+
(command === 'deploy' ||
|
|
555
|
+
command === 'refresh' ||
|
|
556
|
+
command === 'remove' ||
|
|
557
|
+
command === 'unlock'))
|
|
558
|
+
? (0, index_js_2.readRepositoryOperatingPolicy)(context.root)
|
|
231
559
|
: undefined;
|
|
232
560
|
assertSstLifecyclePolicy(command, stages.consumerStage, environment, operatingPolicy?.deploymentProfile);
|
|
233
|
-
const
|
|
234
|
-
?
|
|
561
|
+
const authorityStage = command === 'dev'
|
|
562
|
+
? 'development'
|
|
563
|
+
: stages.consumerStage;
|
|
564
|
+
const deploymentAccount = operatingPolicy
|
|
565
|
+
? (0, index_js_2.configuredDeploymentAccountForStage)(operatingPolicy.deploymentProfile, operatingPolicy.deploymentAccounts, authorityStage)
|
|
235
566
|
: undefined;
|
|
236
567
|
const deploymentRegion = operatingPolicy
|
|
237
|
-
? (0,
|
|
568
|
+
? (0, index_js_2.configuredDeploymentRegion)(operatingPolicy.deploymentRegion)
|
|
238
569
|
: undefined;
|
|
239
570
|
if (deploymentRegion &&
|
|
240
571
|
options.region?.trim() &&
|
|
@@ -245,6 +576,22 @@ function buildSstCommandInvocation(command, options, context, environment = proc
|
|
|
245
576
|
!AWS_ROLE_ARN_PATTERN.test(options.expectedRoleArn.trim())) {
|
|
246
577
|
throw new Error('SST lifecycle expectedRoleArn must be one exact IAM role ARN.');
|
|
247
578
|
}
|
|
579
|
+
const committedRoleArn = operatingPolicy &&
|
|
580
|
+
deploymentAccount &&
|
|
581
|
+
deploymentRegion &&
|
|
582
|
+
isGovernedLocalCommand(command)
|
|
583
|
+
? (0, index_js_1.createStageAuthorityIdentity)({
|
|
584
|
+
accountId: deploymentAccount,
|
|
585
|
+
partition: partitionForRegion(deploymentRegion),
|
|
586
|
+
region: deploymentRegion,
|
|
587
|
+
stage: authorityStage,
|
|
588
|
+
}).deploymentRoleArn
|
|
589
|
+
: undefined;
|
|
590
|
+
if (committedRoleArn &&
|
|
591
|
+
options.expectedRoleArn?.trim() &&
|
|
592
|
+
options.expectedRoleArn.trim() !== committedRoleArn) {
|
|
593
|
+
throw new Error(`SST ${command} requires the exact committed ${authorityStage} stage authority role ${committedRoleArn}.`);
|
|
594
|
+
}
|
|
248
595
|
const profile = options.profile?.trim();
|
|
249
596
|
if (options.profile !== undefined &&
|
|
250
597
|
(!profile || profile !== options.profile || profile.length > 128)) {
|
|
@@ -252,21 +599,24 @@ function buildSstCommandInvocation(command, options, context, environment = proc
|
|
|
252
599
|
}
|
|
253
600
|
if (operatingPolicy &&
|
|
254
601
|
environment.GITHUB_ACTIONS !== 'true' &&
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
602
|
+
command === 'deploy' &&
|
|
603
|
+
environment.EBK_NX_STAGE_LIFECYCLE !== 'local') {
|
|
604
|
+
throw new Error(`Local deploy for ${stages.consumerStage} must be invoked by the governed root stage lifecycle (EBK_NX_STAGE_LIFECYCLE=local).`);
|
|
605
|
+
}
|
|
606
|
+
if (operatingPolicy &&
|
|
607
|
+
environment.GITHUB_ACTIONS !== 'true' &&
|
|
608
|
+
isGovernedLocalCommand(command) &&
|
|
259
609
|
!options.expectedRoleArn?.trim()) {
|
|
260
610
|
throw new Error(`Local ${command} for ${stages.consumerStage} requires --expectedRoleArn for one temporary assumed-role session.`);
|
|
261
611
|
}
|
|
262
612
|
if (GOVERNED_STAGES.has(stages.consumerStage) &&
|
|
263
613
|
(command === 'deploy' || command === 'refresh')) {
|
|
264
|
-
(0,
|
|
265
|
-
protectedPromotion:
|
|
614
|
+
(0, index_js_4.assertWorkMarkerReport)((0, index_js_4.scanWorkMarkers)(context.root), {
|
|
615
|
+
protectedPromotion: stages.consumerStage !== 'development',
|
|
266
616
|
});
|
|
267
617
|
}
|
|
268
618
|
const policyDecision = stages.consumerStage === 'production'
|
|
269
|
-
? (0,
|
|
619
|
+
? (0, index_js_2.assertRepositoryPolicyRequest)(context.root, {
|
|
270
620
|
action: command,
|
|
271
621
|
projects: [
|
|
272
622
|
{
|
|
@@ -278,6 +628,8 @@ function buildSstCommandInvocation(command, options, context, environment = proc
|
|
|
278
628
|
})
|
|
279
629
|
: undefined;
|
|
280
630
|
const args = [command, '--stage', stages.consumerStage];
|
|
631
|
+
if (command === 'refresh')
|
|
632
|
+
args.push('--yes');
|
|
281
633
|
if (options.target) {
|
|
282
634
|
args.push('--target', options.target);
|
|
283
635
|
}
|
|
@@ -297,9 +649,9 @@ function buildSstCommandInvocation(command, options, context, environment = proc
|
|
|
297
649
|
],
|
|
298
650
|
cwd,
|
|
299
651
|
environment: {
|
|
300
|
-
...(
|
|
652
|
+
...(deploymentAccount
|
|
301
653
|
? {
|
|
302
|
-
AWS_EXPECTED_ACCOUNT_ID:
|
|
654
|
+
AWS_EXPECTED_ACCOUNT_ID: deploymentAccount,
|
|
303
655
|
}
|
|
304
656
|
: {}),
|
|
305
657
|
...(profile ? { AWS_PROFILE: profile } : {}),
|
|
@@ -309,9 +661,9 @@ function buildSstCommandInvocation(command, options, context, environment = proc
|
|
|
309
661
|
? { AWS_REGION: options.region.trim() }
|
|
310
662
|
: {}),
|
|
311
663
|
EBK_CONSUMER_STAGE: stages.consumerStage,
|
|
312
|
-
...(options.expectedRoleArn?.trim()
|
|
664
|
+
...((committedRoleArn ?? options.expectedRoleArn?.trim())
|
|
313
665
|
? {
|
|
314
|
-
EBK_EXPECTED_DEPLOYMENT_ROLE_ARN: options.expectedRoleArn
|
|
666
|
+
EBK_EXPECTED_DEPLOYMENT_ROLE_ARN: committedRoleArn ?? options.expectedRoleArn?.trim(),
|
|
315
667
|
}
|
|
316
668
|
: {}),
|
|
317
669
|
EBK_FOUNDATION_STAGE: stages.foundationStage,
|
|
@@ -324,35 +676,47 @@ function buildSstCommandInvocation(command, options, context, environment = proc
|
|
|
324
676
|
executable: process.execPath,
|
|
325
677
|
};
|
|
326
678
|
}
|
|
327
|
-
async function runSstLifecyclePreflights(command, options, context, invocation, dependencies = {}) {
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
679
|
+
async function runSstLifecyclePreflights(command, options, context, invocation, dependencies = {}, environment = process.env) {
|
|
680
|
+
const stage = command === 'dev'
|
|
681
|
+
? 'development'
|
|
682
|
+
: invocation.environment.EBK_CONSUMER_STAGE;
|
|
683
|
+
await (dependencies.ownership ?? index_js_3.assertWorkspaceStageOwnershipForWorkspace)(context.root, stage, {
|
|
684
|
+
...(environment.AWS_CONFIG_FILE
|
|
685
|
+
? { configFilepath: environment.AWS_CONFIG_FILE }
|
|
686
|
+
: {}),
|
|
687
|
+
...(environment.AWS_SHARED_CREDENTIALS_FILE
|
|
688
|
+
? { credentialsFilepath: environment.AWS_SHARED_CREDENTIALS_FILE }
|
|
689
|
+
: {}),
|
|
690
|
+
...(invocation.environment.AWS_PROFILE
|
|
691
|
+
? { profile: invocation.environment.AWS_PROFILE }
|
|
692
|
+
: {}),
|
|
693
|
+
});
|
|
331
694
|
if (command === 'deploy') {
|
|
332
695
|
await (dependencies.secrets ?? secret_preflight_js_1.preflightSliceSecretMetadata)(options, context, invocation);
|
|
333
696
|
}
|
|
334
697
|
if (command === 'unlock' &&
|
|
335
698
|
invocation.environment.EBK_EXPECTED_DEPLOYMENT_ROLE_ARN) {
|
|
336
|
-
await (dependencies.unlockAuthorization ?? authorizeLocalUnlock)(options, invocation);
|
|
337
|
-
}
|
|
338
|
-
if (requiresInfrastructureBinding(command, invocation.environment.EBK_CONSUMER_STAGE)) {
|
|
339
|
-
await (dependencies.infrastructureAuthorization ??
|
|
340
|
-
authorizeInfrastructureMutation)(command, options, context, invocation);
|
|
699
|
+
await (dependencies.unlockAuthorization ?? authorizeLocalUnlock)(options, invocation, environment);
|
|
341
700
|
}
|
|
342
701
|
}
|
|
343
702
|
async function runSstCommand(command, options, context, dependencies = {}) {
|
|
703
|
+
if (command !== 'dev') {
|
|
704
|
+
assertGovernedAwsLifecyclePlatform(dependencies.platform);
|
|
705
|
+
}
|
|
706
|
+
const environment = dependencies.environment ?? process.env;
|
|
707
|
+
const joinsGovernedProcessGroup = process.platform !== 'win32' &&
|
|
708
|
+
environment[GOVERNED_PROCESS_GROUP_ENV] === '1';
|
|
344
709
|
let invocation;
|
|
345
710
|
let environmentSource;
|
|
346
711
|
try {
|
|
347
|
-
invocation = buildSstCommandInvocation(command, options, context);
|
|
348
|
-
if (
|
|
349
|
-
//
|
|
350
|
-
//
|
|
351
|
-
//
|
|
352
|
-
// nor the mutation child can become the restoration baseline.
|
|
712
|
+
invocation = buildSstCommandInvocation(command, options, context, environment);
|
|
713
|
+
if (requiresSourceReconciliation(command, invocation.environment.EBK_CONSUMER_STAGE)) {
|
|
714
|
+
// Native SST can rewrite its generated environment declaration. Capture
|
|
715
|
+
// committed tool-owned source before the child so successful and failed
|
|
716
|
+
// lifecycle commands restore the repository exactly.
|
|
353
717
|
environmentSource = captureSstEnvironmentSource(context);
|
|
354
718
|
}
|
|
355
|
-
await runSstLifecyclePreflights(command, options, context, invocation, dependencies);
|
|
719
|
+
await runSstLifecyclePreflights(command, options, context, invocation, dependencies, environment);
|
|
356
720
|
if (environmentSource)
|
|
357
721
|
(0, sst_environment_source_js_1.reconcileSstEnvironmentSourceTree)(environmentSource);
|
|
358
722
|
}
|
|
@@ -378,22 +742,52 @@ async function runSstCommand(command, options, context, dependencies = {}) {
|
|
|
378
742
|
return new Promise((resolve) => {
|
|
379
743
|
const child = (dependencies.spawnChild ?? node_child_process_1.spawn)(invocation.executable, invocation.args, {
|
|
380
744
|
cwd: invocation.cwd,
|
|
381
|
-
|
|
745
|
+
detached: process.platform !== 'win32' && !joinsGovernedProcessGroup,
|
|
746
|
+
env: createSstChildEnvironment(environment, invocation.environment),
|
|
382
747
|
shell: false,
|
|
383
748
|
stdio: 'inherit',
|
|
384
749
|
});
|
|
385
750
|
let settled = false;
|
|
751
|
+
let unregisterSignalCleanup = () => undefined;
|
|
752
|
+
let resolveChildSettled = () => undefined;
|
|
753
|
+
const childSettled = new Promise((resolveChild) => {
|
|
754
|
+
resolveChildSettled = resolveChild;
|
|
755
|
+
});
|
|
386
756
|
const settle = (success) => {
|
|
387
757
|
if (settled)
|
|
388
758
|
return;
|
|
389
759
|
settled = true;
|
|
760
|
+
unregisterSignalCleanup();
|
|
761
|
+
resolveChildSettled();
|
|
390
762
|
resolve({ success });
|
|
391
763
|
};
|
|
764
|
+
unregisterSignalCleanup = (0, federated_credential_transport_js_1.registerGovernedSignalCleanup)((signal) => {
|
|
765
|
+
if (settled)
|
|
766
|
+
return;
|
|
767
|
+
return stopExactGovernedProcessTree(child, signal, childSettled, () => settled, !joinsGovernedProcessGroup);
|
|
768
|
+
}, 100);
|
|
392
769
|
child.on('error', (error) => {
|
|
393
770
|
devkit_1.logger.error(`Failed to start workspace SST: ${error.message}`);
|
|
394
771
|
settle(false);
|
|
395
772
|
});
|
|
396
773
|
child.on('close', async (code, signal) => {
|
|
774
|
+
if (settled)
|
|
775
|
+
return;
|
|
776
|
+
let retainedProcessTree = false;
|
|
777
|
+
if (!(0, federated_credential_transport_js_1.governedSignalCleanupInProgress)() &&
|
|
778
|
+
!joinsGovernedProcessGroup &&
|
|
779
|
+
child.pid) {
|
|
780
|
+
try {
|
|
781
|
+
retainedProcessTree = await terminateRetainedGovernedProcessGroup(child.pid);
|
|
782
|
+
}
|
|
783
|
+
catch (error) {
|
|
784
|
+
retainedProcessTree = true;
|
|
785
|
+
devkit_1.logger.error(`Failed to stop retained SST descendant process tree: ${error instanceof Error ? error.message : String(error)}`);
|
|
786
|
+
}
|
|
787
|
+
if (retainedProcessTree) {
|
|
788
|
+
devkit_1.logger.error('SST exited before its exact descendant process tree stopped.');
|
|
789
|
+
}
|
|
790
|
+
}
|
|
397
791
|
if (code !== 0) {
|
|
398
792
|
devkit_1.logger.error(signal
|
|
399
793
|
? `SST ${command} terminated with signal ${signal}.`
|
|
@@ -412,30 +806,21 @@ async function runSstCommand(command, options, context, dependencies = {}) {
|
|
|
412
806
|
devkit_1.logger.error(`Failed to restore SST tool-owned source: ${error instanceof Error ? error.message : String(error)}`);
|
|
413
807
|
}
|
|
414
808
|
}
|
|
415
|
-
const applySucceeded = code === 0 && sourceRestored;
|
|
416
|
-
|
|
809
|
+
const applySucceeded = code === 0 && sourceRestored && !retainedProcessTree;
|
|
810
|
+
let generatedSecretRetirementSucceeded = true;
|
|
811
|
+
if (applySucceeded &&
|
|
812
|
+
command === 'remove' &&
|
|
813
|
+
projectKind(context) === 'slice') {
|
|
417
814
|
try {
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
if (!mutationEvidenceRetained) {
|
|
421
|
-
devkit_1.logger.error(`SST ${command} did not retain valid infrastructure mutation evidence.`);
|
|
422
|
-
}
|
|
423
|
-
// A deploy retains apply-complete-unverified as a successful handoff
|
|
424
|
-
// to deployed smoke. It is not terminal convergence; the protected
|
|
425
|
-
// finalizer consumes the exact alarm, data, and journey evidence.
|
|
426
|
-
// Convergence remains the fail-closed authority for governed
|
|
427
|
-
// mutations. A child failure remains failed even if refresh wrote a
|
|
428
|
-
// newer state snapshot; that condition is retained as recovery
|
|
429
|
-
// evidence and cannot be upgraded into accepted success.
|
|
430
|
-
settle(sourceRestored && mutationEvidenceRetained && applySucceeded);
|
|
815
|
+
await (dependencies.generatedSecretRetirement ??
|
|
816
|
+
generated_secret_retirement_js_1.retireGeneratedSecretsAfterSliceRemove)(options, context, invocation, { environment });
|
|
431
817
|
}
|
|
432
818
|
catch (error) {
|
|
433
|
-
|
|
434
|
-
|
|
819
|
+
generatedSecretRetirementSucceeded = false;
|
|
820
|
+
devkit_1.logger.error(`Generated stage-secret retirement failed after native Slice removal: ${error instanceof Error ? error.message : String(error)}`);
|
|
435
821
|
}
|
|
436
|
-
return;
|
|
437
822
|
}
|
|
438
|
-
settle(applySucceeded);
|
|
823
|
+
settle(applySucceeded && generatedSecretRetirementSucceeded);
|
|
439
824
|
});
|
|
440
825
|
});
|
|
441
826
|
}
|