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