@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
|
@@ -5,6 +5,64 @@ exports.renderContainerReleaseCommand = renderContainerReleaseCommand;
|
|
|
5
5
|
const generated_ecr_collector_command_js_1 = require("./generated-ecr-collector-command.js");
|
|
6
6
|
const safe_reference_1 = require("@empire-builder-kit/runtime/safe-reference");
|
|
7
7
|
exports.CRANE_VERSION = '0.21.7';
|
|
8
|
+
const WINDOWS_HARDEN_PRIVATE_ACL = String.raw `
|
|
9
|
+
$ErrorActionPreference = 'Stop'
|
|
10
|
+
$path = $env:EBK_PRIVATE_PATH
|
|
11
|
+
$kind = $env:EBK_PRIVATE_KIND
|
|
12
|
+
$identity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
|
|
13
|
+
if ($kind -eq 'directory') {
|
|
14
|
+
$info = [System.IO.DirectoryInfo]::new($path)
|
|
15
|
+
} else {
|
|
16
|
+
$info = [System.IO.FileInfo]::new($path)
|
|
17
|
+
}
|
|
18
|
+
$acl = $info.GetAccessControl()
|
|
19
|
+
$acl.SetAccessRuleProtection($true, $false)
|
|
20
|
+
foreach ($rule in @($acl.Access)) {
|
|
21
|
+
[void]$acl.RemoveAccessRuleSpecific($rule)
|
|
22
|
+
}
|
|
23
|
+
$rights = [System.Security.AccessControl.FileSystemRights]::FullControl
|
|
24
|
+
$type = [System.Security.AccessControl.AccessControlType]::Allow
|
|
25
|
+
if ($kind -eq 'directory') {
|
|
26
|
+
$inheritance = [System.Security.AccessControl.InheritanceFlags]'ContainerInherit,ObjectInherit'
|
|
27
|
+
$propagation = [System.Security.AccessControl.PropagationFlags]::None
|
|
28
|
+
$rule = [System.Security.AccessControl.FileSystemAccessRule]::new(
|
|
29
|
+
$identity.User, $rights, $inheritance, $propagation, $type
|
|
30
|
+
)
|
|
31
|
+
} else {
|
|
32
|
+
$rule = [System.Security.AccessControl.FileSystemAccessRule]::new(
|
|
33
|
+
$identity.User, $rights, $type
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
$acl.AddAccessRule($rule)
|
|
37
|
+
$info.SetAccessControl($acl)
|
|
38
|
+
`;
|
|
39
|
+
const WINDOWS_ASSERT_PRIVATE_ACL = String.raw `
|
|
40
|
+
$ErrorActionPreference = 'Stop'
|
|
41
|
+
$path = $env:EBK_PRIVATE_PATH
|
|
42
|
+
$kind = $env:EBK_PRIVATE_KIND
|
|
43
|
+
$identity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
|
|
44
|
+
if ($kind -eq 'directory') {
|
|
45
|
+
$info = [System.IO.DirectoryInfo]::new($path)
|
|
46
|
+
} else {
|
|
47
|
+
$info = [System.IO.FileInfo]::new($path)
|
|
48
|
+
}
|
|
49
|
+
$acl = $info.GetAccessControl()
|
|
50
|
+
if (-not $acl.AreAccessRulesProtected) {
|
|
51
|
+
throw 'ACL inheritance is enabled.'
|
|
52
|
+
}
|
|
53
|
+
$allowRules = @($acl.Access | Where-Object {
|
|
54
|
+
$_.AccessControlType -eq [System.Security.AccessControl.AccessControlType]::Allow
|
|
55
|
+
})
|
|
56
|
+
$unsafeRules = @($allowRules | Where-Object {
|
|
57
|
+
$_.IdentityReference.Translate([System.Security.Principal.SecurityIdentifier]).Value -ne $identity.User.Value
|
|
58
|
+
})
|
|
59
|
+
$selfRules = @($allowRules | Where-Object {
|
|
60
|
+
$_.IdentityReference.Translate([System.Security.Principal.SecurityIdentifier]).Value -eq $identity.User.Value
|
|
61
|
+
})
|
|
62
|
+
if ($unsafeRules.Count -ne 0 -or $selfRules.Count -eq 0) {
|
|
63
|
+
throw 'ACL grants access beyond the current user or omits the current user.'
|
|
64
|
+
}
|
|
65
|
+
`;
|
|
8
66
|
exports.CRANE_RELEASES = Object.freeze({
|
|
9
67
|
'darwin-arm64': {
|
|
10
68
|
archiveFormat: 'tar-gzip',
|
|
@@ -59,8 +117,8 @@ function renderContainerReleaseCommand(options = {}) {
|
|
|
59
117
|
!/^\d+\.\d+\.\d+$/.test(craneVersion)) {
|
|
60
118
|
throw new Error('The generated container release configuration is invalid.');
|
|
61
119
|
}
|
|
62
|
-
return `import { createHash } from 'node:crypto';
|
|
63
|
-
import { execFileSync, spawnSync } from 'node:child_process';
|
|
120
|
+
return `import { createHash, randomBytes } from 'node:crypto';
|
|
121
|
+
import { execFileSync, spawn, spawnSync } from 'node:child_process';
|
|
64
122
|
import {
|
|
65
123
|
chmodSync,
|
|
66
124
|
existsSync,
|
|
@@ -71,10 +129,11 @@ import {
|
|
|
71
129
|
realpathSync,
|
|
72
130
|
readdirSync,
|
|
73
131
|
rmSync,
|
|
132
|
+
unlinkSync,
|
|
74
133
|
writeFileSync,
|
|
75
134
|
} from 'node:fs';
|
|
76
135
|
import { basename, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
77
|
-
import { tmpdir } from 'node:os';
|
|
136
|
+
import { platform as hostOperatingSystem, tmpdir } from 'node:os';
|
|
78
137
|
import {
|
|
79
138
|
CONTAINER_NATIVE_LIFECYCLE_PROOFS,
|
|
80
139
|
CONTAINER_RELEASE_PLATFORMS,
|
|
@@ -82,6 +141,7 @@ import {
|
|
|
82
141
|
createContainerNativeRunProof,
|
|
83
142
|
createContainerPlatformEvidence,
|
|
84
143
|
createContainerReleaseBinding,
|
|
144
|
+
hasSensitiveSupplyChainShape,
|
|
85
145
|
resolveContainerReleaseArtifact,
|
|
86
146
|
supplyChainDigest,
|
|
87
147
|
validateContainerArtifactIdentity,
|
|
@@ -95,6 +155,8 @@ const SYFT_VERSION = ${JSON.stringify(syftVersion)};
|
|
|
95
155
|
const SYFT_RELEASES = Object.freeze(${JSON.stringify(releases)});
|
|
96
156
|
const CRANE_VERSION = ${JSON.stringify(craneVersion)};
|
|
97
157
|
const CRANE_RELEASES = Object.freeze(${JSON.stringify(craneReleases)});
|
|
158
|
+
const WINDOWS_HARDEN_PRIVATE_ACL = ${JSON.stringify(WINDOWS_HARDEN_PRIVATE_ACL)};
|
|
159
|
+
const WINDOWS_ASSERT_PRIVATE_ACL = ${JSON.stringify(WINDOWS_ASSERT_PRIVATE_ACL)};
|
|
98
160
|
const SHA256 = /^[a-f0-9]{64}$/;
|
|
99
161
|
const IMAGE_DIGEST = /^sha256:[a-f0-9]{64}$/;
|
|
100
162
|
const COMMIT = /^(?:[a-f0-9]{40}|[a-f0-9]{64})$/;
|
|
@@ -144,23 +206,43 @@ const packageRegistryInput =
|
|
|
144
206
|
const localFederated =
|
|
145
207
|
process.env.GITHUB_ACTIONS !== 'true' &&
|
|
146
208
|
process.env.EBK_LOCAL_DEPLOYMENT_MODE === 'federated';
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
209
|
+
const localRunId = process.env.EBK_LOCAL_CONTAINER_RUN_ID?.trim() ?? '';
|
|
210
|
+
const policy = JSON.parse(
|
|
211
|
+
readFileSync(join(repositoryRoot, 'ebk.repository-policy.json'), 'utf8'),
|
|
212
|
+
);
|
|
213
|
+
const selectedDeploymentProfile =
|
|
214
|
+
process.env.EBK_DEPLOYMENT_PROFILE?.trim() ?? '';
|
|
215
|
+
const activeStages = {
|
|
216
|
+
starter: ['development', 'production'],
|
|
217
|
+
'production-isolated': ['development', 'staging', 'production'],
|
|
218
|
+
'fully-isolated': ['development', 'staging', 'production'],
|
|
219
|
+
}[policy.deploymentProfile];
|
|
220
|
+
const locallyAdmittedStages = {
|
|
221
|
+
starter: ['development', 'production'],
|
|
222
|
+
'production-isolated': ['development', 'staging'],
|
|
223
|
+
'fully-isolated': ['development'],
|
|
224
|
+
}[policy.deploymentProfile];
|
|
225
|
+
if (
|
|
226
|
+
selectedDeploymentProfile !== policy.deploymentProfile ||
|
|
227
|
+
!activeStages ||
|
|
228
|
+
!activeStages.includes(stage) ||
|
|
229
|
+
policy.deploymentAccounts?.[stage] !== accountId ||
|
|
230
|
+
policy.deploymentRegion !== region
|
|
231
|
+
) {
|
|
232
|
+
throw new Error(
|
|
233
|
+
'Container release requires the exact committed profile, active stage, account, and Region.',
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
if (
|
|
237
|
+
localFederated &&
|
|
238
|
+
(!locallyAdmittedStages || !locallyAdmittedStages.includes(stage))
|
|
239
|
+
) {
|
|
240
|
+
throw new Error(
|
|
241
|
+
'Local container release requires one of the committed profile locally admitted stages.',
|
|
150
242
|
);
|
|
151
|
-
if (
|
|
152
|
-
policy.deploymentProfile !== 'starter' ||
|
|
153
|
-
stage === 'production' ||
|
|
154
|
-
policy.deploymentAccounts?.[stage] !== accountId ||
|
|
155
|
-
policy.deploymentRegion !== region
|
|
156
|
-
) {
|
|
157
|
-
throw new Error(
|
|
158
|
-
'Local container release requires a locally admitted exact starter deployment target; production requires protected GitHub authority.',
|
|
159
|
-
);
|
|
160
|
-
}
|
|
161
243
|
}
|
|
162
244
|
const runId = localFederated
|
|
163
|
-
?
|
|
245
|
+
? localRunId
|
|
164
246
|
: process.env.GITHUB_RUN_ID?.trim() ?? '';
|
|
165
247
|
const runAttempt = localFederated
|
|
166
248
|
? '1'
|
|
@@ -359,12 +441,657 @@ const execute = (command, args, label, options = {}) => {
|
|
|
359
441
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
360
442
|
});
|
|
361
443
|
} catch (error) {
|
|
444
|
+
if (options.failureDiagnostics === 'bounded-closure') {
|
|
445
|
+
const diagnosticStream = (value) => {
|
|
446
|
+
const raw = value === undefined || value === null ? '' : String(value);
|
|
447
|
+
if (raw.length === 0) return '[empty]';
|
|
448
|
+
if (hasSensitiveSupplyChainShape(raw)) {
|
|
449
|
+
return '[redacted-sensitive-output]';
|
|
450
|
+
}
|
|
451
|
+
const bytes = Buffer.from(raw, 'utf8');
|
|
452
|
+
const truncated = bytes.byteLength > 1_024;
|
|
453
|
+
const tail = truncated
|
|
454
|
+
? bytes.subarray(bytes.byteLength - 1_024).toString('utf8')
|
|
455
|
+
: raw;
|
|
456
|
+
return JSON.stringify((truncated ? '[truncated]\\n' : '') + tail);
|
|
457
|
+
};
|
|
458
|
+
const status = Number.isSafeInteger(error?.status)
|
|
459
|
+
? String(error.status)
|
|
460
|
+
: 'unavailable';
|
|
461
|
+
const signal =
|
|
462
|
+
typeof error?.signal === 'string' && /^[A-Z0-9]+$/.test(error.signal)
|
|
463
|
+
? error.signal
|
|
464
|
+
: 'none';
|
|
465
|
+
throw new Error(
|
|
466
|
+
label +
|
|
467
|
+
' failed without complete evidence: ' +
|
|
468
|
+
'status=' +
|
|
469
|
+
status +
|
|
470
|
+
'; signal=' +
|
|
471
|
+
signal +
|
|
472
|
+
'; stdout=' +
|
|
473
|
+
diagnosticStream(error?.stdout) +
|
|
474
|
+
'; stderr=' +
|
|
475
|
+
diagnosticStream(error?.stderr),
|
|
476
|
+
);
|
|
477
|
+
}
|
|
362
478
|
throw new Error(
|
|
363
479
|
label + ' failed without complete evidence: ' +
|
|
364
480
|
String(error?.stderr ?? error?.message ?? error).slice(0, 2_000),
|
|
365
481
|
);
|
|
366
482
|
}
|
|
367
483
|
};
|
|
484
|
+
let releaseBuilder;
|
|
485
|
+
let releaseBuildChild;
|
|
486
|
+
let releaseBuildStopPromise;
|
|
487
|
+
let releaseBuilderSignal;
|
|
488
|
+
const releaseBuilderSignalHandlers = new Map();
|
|
489
|
+
const releaseToolTemporaryDirectories = new Set();
|
|
490
|
+
const yieldToReleaseSignals = () =>
|
|
491
|
+
new Promise((resolve) => setImmediate(resolve));
|
|
492
|
+
const stopExactReleaseBuildChild = async (signal = 'SIGTERM') => {
|
|
493
|
+
if (releaseBuildStopPromise) return releaseBuildStopPromise;
|
|
494
|
+
const observed = releaseBuildChild;
|
|
495
|
+
if (!observed) return;
|
|
496
|
+
releaseBuildStopPromise = (async () => {
|
|
497
|
+
const child = observed.child;
|
|
498
|
+
if (hostOperatingSystem() === 'win32') {
|
|
499
|
+
const taskkill = join(process.env.SystemRoot ?? '', 'System32', 'taskkill.exe');
|
|
500
|
+
if (!isAbsolute(taskkill) || !existsSync(taskkill) || realpathSync(taskkill) !== taskkill) {
|
|
501
|
+
throw new Error('Exact Windows Buildx cleanup requires canonical SystemRoot.');
|
|
502
|
+
}
|
|
503
|
+
const stopped = spawnSync(
|
|
504
|
+
taskkill,
|
|
505
|
+
['/PID', String(child.pid), '/T', '/F'],
|
|
506
|
+
{
|
|
507
|
+
cwd: repositoryRoot,
|
|
508
|
+
encoding: 'utf8',
|
|
509
|
+
env: process.env,
|
|
510
|
+
maxBuffer: 1024 * 1024,
|
|
511
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
512
|
+
windowsHide: true,
|
|
513
|
+
},
|
|
514
|
+
);
|
|
515
|
+
if (
|
|
516
|
+
child.exitCode === null &&
|
|
517
|
+
(stopped.error || stopped.signal || stopped.status !== 0)
|
|
518
|
+
) {
|
|
519
|
+
throw new Error('Exact Windows Buildx process-tree cleanup failed.');
|
|
520
|
+
}
|
|
521
|
+
} else if (child.pid) {
|
|
522
|
+
try {
|
|
523
|
+
process.kill(-child.pid, signal);
|
|
524
|
+
} catch (error) {
|
|
525
|
+
if (error?.code !== 'ESRCH') throw error;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
if (child.exitCode === null) {
|
|
529
|
+
const closed = await Promise.race([
|
|
530
|
+
observed.close.then(() => true),
|
|
531
|
+
new Promise((resolve) => setTimeout(() => resolve(false), 5_000)),
|
|
532
|
+
]);
|
|
533
|
+
if (!closed && hostOperatingSystem() !== 'win32' && child.pid) {
|
|
534
|
+
try {
|
|
535
|
+
process.kill(-child.pid, 'SIGKILL');
|
|
536
|
+
} catch (error) {
|
|
537
|
+
if (error?.code !== 'ESRCH') throw error;
|
|
538
|
+
}
|
|
539
|
+
const killed = await Promise.race([
|
|
540
|
+
observed.close.then(() => true),
|
|
541
|
+
new Promise((resolve) => setTimeout(() => resolve(false), 5_000)),
|
|
542
|
+
]);
|
|
543
|
+
if (!killed) {
|
|
544
|
+
throw new Error('Exact Buildx process group did not terminate.');
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
})().finally(() => {
|
|
549
|
+
if (releaseBuildChild === observed) releaseBuildChild = undefined;
|
|
550
|
+
releaseBuildStopPromise = undefined;
|
|
551
|
+
});
|
|
552
|
+
return releaseBuildStopPromise;
|
|
553
|
+
};
|
|
554
|
+
const executeObservedBuildx = async (args, label) => {
|
|
555
|
+
if (releaseBuildChild) {
|
|
556
|
+
throw new Error('Only one invocation-owned Buildx child may run at a time.');
|
|
557
|
+
}
|
|
558
|
+
const child = spawn('docker', args, {
|
|
559
|
+
cwd: repositoryRoot,
|
|
560
|
+
detached: hostOperatingSystem() !== 'win32',
|
|
561
|
+
env: process.env,
|
|
562
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
563
|
+
windowsHide: true,
|
|
564
|
+
});
|
|
565
|
+
const stdout = [];
|
|
566
|
+
const stderr = [];
|
|
567
|
+
let outputBytes = 0;
|
|
568
|
+
const retain = (chunks, stream, chunk) => {
|
|
569
|
+
outputBytes += chunk.byteLength;
|
|
570
|
+
if (outputBytes > MAX_OUTPUT_BYTES) {
|
|
571
|
+
void stopExactReleaseBuildChild('SIGTERM');
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
chunks.push(chunk);
|
|
575
|
+
stream.write(chunk);
|
|
576
|
+
};
|
|
577
|
+
child.stdout.on('data', (chunk) => retain(stdout, process.stdout, chunk));
|
|
578
|
+
child.stderr.on('data', (chunk) => retain(stderr, process.stderr, chunk));
|
|
579
|
+
const close = new Promise((resolve) => {
|
|
580
|
+
child.once('error', (error) => resolve({ error }));
|
|
581
|
+
child.once('close', (status, signal) => resolve({ signal, status }));
|
|
582
|
+
});
|
|
583
|
+
releaseBuildChild = { child, close };
|
|
584
|
+
const result = await close;
|
|
585
|
+
await stopExactReleaseBuildChild();
|
|
586
|
+
if (
|
|
587
|
+
outputBytes > MAX_OUTPUT_BYTES ||
|
|
588
|
+
result.error ||
|
|
589
|
+
result.signal ||
|
|
590
|
+
result.status !== 0
|
|
591
|
+
) {
|
|
592
|
+
throw new Error(
|
|
593
|
+
label + ' failed without complete evidence: ' +
|
|
594
|
+
Buffer.concat(stderr).toString('utf8').slice(-2_000),
|
|
595
|
+
);
|
|
596
|
+
}
|
|
597
|
+
return Buffer.concat(stdout).toString('utf8');
|
|
598
|
+
};
|
|
599
|
+
const runWindowsPrivateAcl = (script, path, kind) => {
|
|
600
|
+
const systemRoot = process.env.SystemRoot;
|
|
601
|
+
if (!systemRoot || !isAbsolute(systemRoot)) {
|
|
602
|
+
throw new Error('Windows private-path hardening requires an absolute SystemRoot.');
|
|
603
|
+
}
|
|
604
|
+
const powershell = join(
|
|
605
|
+
systemRoot,
|
|
606
|
+
'System32',
|
|
607
|
+
'WindowsPowerShell',
|
|
608
|
+
'v1.0',
|
|
609
|
+
'powershell.exe',
|
|
610
|
+
);
|
|
611
|
+
const result = spawnSync(
|
|
612
|
+
powershell,
|
|
613
|
+
[
|
|
614
|
+
'-NoLogo',
|
|
615
|
+
'-NoProfile',
|
|
616
|
+
'-NonInteractive',
|
|
617
|
+
'-EncodedCommand',
|
|
618
|
+
Buffer.from(script, 'utf16le').toString('base64'),
|
|
619
|
+
],
|
|
620
|
+
{
|
|
621
|
+
cwd: repositoryRoot,
|
|
622
|
+
encoding: 'utf8',
|
|
623
|
+
env: {
|
|
624
|
+
...process.env,
|
|
625
|
+
EBK_PRIVATE_KIND: kind,
|
|
626
|
+
EBK_PRIVATE_PATH: path,
|
|
627
|
+
},
|
|
628
|
+
maxBuffer: 1024 * 1024,
|
|
629
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
630
|
+
timeout: 15_000,
|
|
631
|
+
windowsHide: true,
|
|
632
|
+
},
|
|
633
|
+
);
|
|
634
|
+
if (result.error || result.signal || result.status !== 0) {
|
|
635
|
+
throw new Error(
|
|
636
|
+
'Windows private-path ACL operation failed closed: ' +
|
|
637
|
+
String(result.stderr || result.error?.message || result.signal || result.status)
|
|
638
|
+
.slice(-2_000),
|
|
639
|
+
);
|
|
640
|
+
}
|
|
641
|
+
};
|
|
642
|
+
const assertPrivateReleaseBuilderPathIdentity = (path, kind) => {
|
|
643
|
+
const metadata = lstatSync(path);
|
|
644
|
+
if (
|
|
645
|
+
metadata.isSymbolicLink() ||
|
|
646
|
+
(kind === 'directory' ? !metadata.isDirectory() : !metadata.isFile()) ||
|
|
647
|
+
realpathSync(path) !== path
|
|
648
|
+
) {
|
|
649
|
+
throw new Error(
|
|
650
|
+
'Container-release builder ownership path failed canonical type validation.',
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
return metadata;
|
|
654
|
+
};
|
|
655
|
+
const assertPrivateReleaseBuilderPath = (path, kind) => {
|
|
656
|
+
const metadata = assertPrivateReleaseBuilderPathIdentity(path, kind);
|
|
657
|
+
if (hostOperatingSystem() === 'win32') {
|
|
658
|
+
runWindowsPrivateAcl(WINDOWS_ASSERT_PRIVATE_ACL, path, kind);
|
|
659
|
+
return metadata;
|
|
660
|
+
}
|
|
661
|
+
const expectedMode = kind === 'directory' ? 0o700 : 0o600;
|
|
662
|
+
if (
|
|
663
|
+
(metadata.mode & 0o777) !== expectedMode ||
|
|
664
|
+
(typeof process.getuid === 'function' && metadata.uid !== process.getuid())
|
|
665
|
+
) {
|
|
666
|
+
throw new Error(
|
|
667
|
+
'Container-release builder ownership path is not current-user private.',
|
|
668
|
+
);
|
|
669
|
+
}
|
|
670
|
+
return metadata;
|
|
671
|
+
};
|
|
672
|
+
const hardenPrivateReleaseBuilderPath = (path, kind) => {
|
|
673
|
+
assertPrivateReleaseBuilderPathIdentity(path, kind);
|
|
674
|
+
if (hostOperatingSystem() === 'win32') {
|
|
675
|
+
runWindowsPrivateAcl(WINDOWS_HARDEN_PRIVATE_ACL, path, kind);
|
|
676
|
+
} else {
|
|
677
|
+
chmodSync(path, kind === 'directory' ? 0o700 : 0o600);
|
|
678
|
+
}
|
|
679
|
+
return assertPrivateReleaseBuilderPath(path, kind);
|
|
680
|
+
};
|
|
681
|
+
const assertCanonicalAncestorsBeforeCreate = (requested) => {
|
|
682
|
+
const requestedRelative = relative(repositoryRoot, requested);
|
|
683
|
+
if (
|
|
684
|
+
requestedRelative === '' ||
|
|
685
|
+
requestedRelative === '..' ||
|
|
686
|
+
requestedRelative.startsWith('..' + sep) ||
|
|
687
|
+
isAbsolute(requestedRelative)
|
|
688
|
+
) {
|
|
689
|
+
throw new Error('Container-release builder ownership path escapes its repository.');
|
|
690
|
+
}
|
|
691
|
+
let cursor = repositoryRoot;
|
|
692
|
+
for (const segment of requestedRelative.split(sep)) {
|
|
693
|
+
cursor = join(cursor, segment);
|
|
694
|
+
if (!existsSync(cursor)) break;
|
|
695
|
+
const metadata = lstatSync(cursor);
|
|
696
|
+
if (metadata.isSymbolicLink() || realpathSync(cursor) !== cursor) {
|
|
697
|
+
throw new Error(
|
|
698
|
+
'Container-release builder ownership path has a symbolic or noncanonical ancestor.',
|
|
699
|
+
);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
};
|
|
703
|
+
const releaseBuilderLeaseRoot = () => {
|
|
704
|
+
const requested = resolve(
|
|
705
|
+
repositoryRoot,
|
|
706
|
+
'.ebk/cache/container-release-builders',
|
|
707
|
+
);
|
|
708
|
+
assertCanonicalAncestorsBeforeCreate(requested);
|
|
709
|
+
mkdirSync(requested, { mode: 0o700, recursive: true });
|
|
710
|
+
hardenPrivateReleaseBuilderPath(requested, 'directory');
|
|
711
|
+
const canonical = realpathSync(requested);
|
|
712
|
+
if (canonical !== requested) {
|
|
713
|
+
throw new Error(
|
|
714
|
+
'Container-release builder leases require one repository-private owned directory.',
|
|
715
|
+
);
|
|
716
|
+
}
|
|
717
|
+
return canonical;
|
|
718
|
+
};
|
|
719
|
+
const readReleaseBuilderLease = (leasePath, expectedName) => {
|
|
720
|
+
const metadata = assertPrivateReleaseBuilderPath(leasePath, 'file');
|
|
721
|
+
if (
|
|
722
|
+
metadata.nlink !== 1 ||
|
|
723
|
+
metadata.size < 2 ||
|
|
724
|
+
metadata.size > 16 * 1024
|
|
725
|
+
) {
|
|
726
|
+
throw new Error('Container-release builder lease is not one private file.');
|
|
727
|
+
}
|
|
728
|
+
let lease;
|
|
729
|
+
try {
|
|
730
|
+
lease = JSON.parse(readFileSync(leasePath, 'utf8'));
|
|
731
|
+
} catch {
|
|
732
|
+
throw new Error('Container-release builder lease is invalid JSON.');
|
|
733
|
+
}
|
|
734
|
+
const keys = Object.keys(lease ?? {}).sort();
|
|
735
|
+
if (
|
|
736
|
+
JSON.stringify(keys) !==
|
|
737
|
+
JSON.stringify([
|
|
738
|
+
'builder',
|
|
739
|
+
'cleanup',
|
|
740
|
+
'createdAt',
|
|
741
|
+
'driver',
|
|
742
|
+
'kind',
|
|
743
|
+
'ownerPid',
|
|
744
|
+
'schemaVersion',
|
|
745
|
+
]) ||
|
|
746
|
+
lease.kind !== 'ebk-container-release-builder-lease' ||
|
|
747
|
+
lease.schemaVersion !== 1 ||
|
|
748
|
+
lease.builder !== expectedName ||
|
|
749
|
+
!/^ebk-release-[a-f0-9]{32}$/.test(lease.builder) ||
|
|
750
|
+
lease.driver !== 'docker-container' ||
|
|
751
|
+
JSON.stringify(lease.cleanup) !==
|
|
752
|
+
JSON.stringify(['docker', 'buildx', 'rm', lease.builder]) ||
|
|
753
|
+
!Number.isSafeInteger(lease.ownerPid) ||
|
|
754
|
+
lease.ownerPid <= 0 ||
|
|
755
|
+
!Number.isFinite(Date.parse(lease.createdAt)) ||
|
|
756
|
+
new Date(lease.createdAt).toISOString() !== lease.createdAt
|
|
757
|
+
) {
|
|
758
|
+
throw new Error('Container-release builder lease has an invalid identity.');
|
|
759
|
+
}
|
|
760
|
+
return lease;
|
|
761
|
+
};
|
|
762
|
+
const removeReleaseBuilderSignalHandlers = () => {
|
|
763
|
+
for (const [signal, handler] of releaseBuilderSignalHandlers) {
|
|
764
|
+
process.removeListener(signal, handler);
|
|
765
|
+
}
|
|
766
|
+
releaseBuilderSignalHandlers.clear();
|
|
767
|
+
};
|
|
768
|
+
const ensureReleaseBuilderSignalHandlers = () => {
|
|
769
|
+
if (releaseBuilderSignalHandlers.size > 0) return;
|
|
770
|
+
for (const signal of ['SIGINT', 'SIGTERM']) {
|
|
771
|
+
const handler = () => void handleReleaseBuilderSignal(signal);
|
|
772
|
+
releaseBuilderSignalHandlers.set(signal, handler);
|
|
773
|
+
process.on(signal, handler);
|
|
774
|
+
}
|
|
775
|
+
};
|
|
776
|
+
const removeReleaseBuilderSignalHandlersWhenIdle = () => {
|
|
777
|
+
if (!releaseBuilder && releaseToolTemporaryDirectories.size === 0) {
|
|
778
|
+
removeReleaseBuilderSignalHandlers();
|
|
779
|
+
}
|
|
780
|
+
};
|
|
781
|
+
const createReleaseToolTemporaryDirectory = (prefix) => {
|
|
782
|
+
const created = mkdtempSync(join(tmpdir(), prefix));
|
|
783
|
+
const metadata = lstatSync(created);
|
|
784
|
+
if (
|
|
785
|
+
!metadata.isDirectory() ||
|
|
786
|
+
metadata.isSymbolicLink() ||
|
|
787
|
+
!isAbsolute(created)
|
|
788
|
+
) {
|
|
789
|
+
throw new Error('Container-release tool temporary directory is not exact.');
|
|
790
|
+
}
|
|
791
|
+
const temporary = realpathSync(created);
|
|
792
|
+
const canonicalMetadata = lstatSync(temporary);
|
|
793
|
+
if (
|
|
794
|
+
!isAbsolute(temporary) ||
|
|
795
|
+
!canonicalMetadata.isDirectory() ||
|
|
796
|
+
canonicalMetadata.isSymbolicLink() ||
|
|
797
|
+
canonicalMetadata.dev !== metadata.dev ||
|
|
798
|
+
canonicalMetadata.ino !== metadata.ino
|
|
799
|
+
) {
|
|
800
|
+
throw new Error('Container-release tool temporary directory is not canonical.');
|
|
801
|
+
}
|
|
802
|
+
releaseToolTemporaryDirectories.add(temporary);
|
|
803
|
+
ensureReleaseBuilderSignalHandlers();
|
|
804
|
+
return temporary;
|
|
805
|
+
};
|
|
806
|
+
const removeExactReleaseToolTemporaryDirectory = (temporary) => {
|
|
807
|
+
if (!releaseToolTemporaryDirectories.has(temporary)) {
|
|
808
|
+
throw new Error('Container-release tool temporary directory is not owned.');
|
|
809
|
+
}
|
|
810
|
+
const metadata = lstatSync(temporary);
|
|
811
|
+
if (
|
|
812
|
+
!metadata.isDirectory() ||
|
|
813
|
+
metadata.isSymbolicLink() ||
|
|
814
|
+
!isAbsolute(temporary) ||
|
|
815
|
+
realpathSync(temporary) !== temporary
|
|
816
|
+
) {
|
|
817
|
+
throw new Error(
|
|
818
|
+
'Container-release tool temporary directory changed identity before cleanup.',
|
|
819
|
+
);
|
|
820
|
+
}
|
|
821
|
+
rmSync(temporary, { force: true, recursive: true });
|
|
822
|
+
if (existsSync(temporary)) {
|
|
823
|
+
throw new Error('Container-release tool temporary directory cleanup failed.');
|
|
824
|
+
}
|
|
825
|
+
releaseToolTemporaryDirectories.delete(temporary);
|
|
826
|
+
removeReleaseBuilderSignalHandlersWhenIdle();
|
|
827
|
+
};
|
|
828
|
+
const removeAllReleaseToolTemporaryDirectories = () => {
|
|
829
|
+
const cleanupErrors = [];
|
|
830
|
+
for (const temporary of [...releaseToolTemporaryDirectories]) {
|
|
831
|
+
try {
|
|
832
|
+
removeExactReleaseToolTemporaryDirectory(temporary);
|
|
833
|
+
} catch (error) {
|
|
834
|
+
cleanupErrors.push(error);
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
if (cleanupErrors.length > 0) {
|
|
838
|
+
throw new AggregateError(
|
|
839
|
+
cleanupErrors,
|
|
840
|
+
'Exact container-release tool temporary cleanup failed.',
|
|
841
|
+
);
|
|
842
|
+
}
|
|
843
|
+
};
|
|
844
|
+
const releaseBuilderCleanupDiagnostic = (builder) =>
|
|
845
|
+
'docker buildx rm ' + builder.name +
|
|
846
|
+
' (ownership lease: ' + builder.leasePath + ')';
|
|
847
|
+
const listExactReleaseBuilderNames = ({ signal } = {}) => {
|
|
848
|
+
const inventory = spawnSync(
|
|
849
|
+
'docker',
|
|
850
|
+
['buildx', 'ls', '--format', '{{json .Name}}'],
|
|
851
|
+
{
|
|
852
|
+
cwd: repositoryRoot,
|
|
853
|
+
encoding: 'utf8',
|
|
854
|
+
env: process.env,
|
|
855
|
+
maxBuffer: 1024 * 1024,
|
|
856
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
857
|
+
timeout: signal ? 5_000 : undefined,
|
|
858
|
+
},
|
|
859
|
+
);
|
|
860
|
+
if (inventory.error || inventory.signal || inventory.status !== 0) {
|
|
861
|
+
throw new Error(
|
|
862
|
+
'Invocation-owned Buildx inventory failed while proving exact cleanup: ' +
|
|
863
|
+
String(
|
|
864
|
+
inventory.stderr ||
|
|
865
|
+
inventory.error?.message ||
|
|
866
|
+
inventory.signal ||
|
|
867
|
+
inventory.status,
|
|
868
|
+
).slice(-2_000),
|
|
869
|
+
);
|
|
870
|
+
}
|
|
871
|
+
const lines = inventory.stdout.trim() === ''
|
|
872
|
+
? []
|
|
873
|
+
: inventory.stdout.trim().split(/\\r?\\n/u);
|
|
874
|
+
if (lines.length > 256) {
|
|
875
|
+
throw new Error('Invocation-owned Buildx inventory is unbounded.');
|
|
876
|
+
}
|
|
877
|
+
const names = new Set();
|
|
878
|
+
for (const line of lines) {
|
|
879
|
+
let name;
|
|
880
|
+
try {
|
|
881
|
+
name = JSON.parse(line);
|
|
882
|
+
} catch {
|
|
883
|
+
throw new Error('Invocation-owned Buildx inventory is not exact JSON.');
|
|
884
|
+
}
|
|
885
|
+
if (
|
|
886
|
+
typeof name !== 'string' ||
|
|
887
|
+
name.length === 0 ||
|
|
888
|
+
name.length > 256 ||
|
|
889
|
+
names.has(name)
|
|
890
|
+
) {
|
|
891
|
+
throw new Error('Invocation-owned Buildx inventory has an invalid identity.');
|
|
892
|
+
}
|
|
893
|
+
names.add(name);
|
|
894
|
+
}
|
|
895
|
+
return names;
|
|
896
|
+
};
|
|
897
|
+
const removeExactReleaseBuilder = (builder, { signal } = {}) => {
|
|
898
|
+
readReleaseBuilderLease(builder.leasePath, builder.name);
|
|
899
|
+
const cleanup = spawnSync(
|
|
900
|
+
'docker',
|
|
901
|
+
['buildx', 'rm', builder.name],
|
|
902
|
+
{
|
|
903
|
+
cwd: repositoryRoot,
|
|
904
|
+
encoding: 'utf8',
|
|
905
|
+
env: process.env,
|
|
906
|
+
maxBuffer: 1024 * 1024,
|
|
907
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
908
|
+
timeout: signal ? 5_000 : undefined,
|
|
909
|
+
},
|
|
910
|
+
);
|
|
911
|
+
if (cleanup.error || cleanup.signal || cleanup.status !== 0) {
|
|
912
|
+
let builderNames;
|
|
913
|
+
try {
|
|
914
|
+
builderNames = listExactReleaseBuilderNames({ signal });
|
|
915
|
+
} catch (inventoryError) {
|
|
916
|
+
const error = new AggregateError(
|
|
917
|
+
[
|
|
918
|
+
cleanup.error ?? new Error(String(cleanup.stderr || cleanup.status)),
|
|
919
|
+
inventoryError,
|
|
920
|
+
],
|
|
921
|
+
'Invocation-owned Buildx cleanup and exact absence proof both failed; ' +
|
|
922
|
+
'retain ' + releaseBuilderCleanupDiagnostic(builder) + '.',
|
|
923
|
+
);
|
|
924
|
+
if (signal) {
|
|
925
|
+
process.stderr.write(error.message + '\\n');
|
|
926
|
+
return false;
|
|
927
|
+
}
|
|
928
|
+
throw error;
|
|
929
|
+
}
|
|
930
|
+
if (!builderNames.has(builder.name)) {
|
|
931
|
+
unlinkSync(builder.leasePath);
|
|
932
|
+
process.stderr.write(
|
|
933
|
+
'ebk-release-builder-already-absent ' +
|
|
934
|
+
JSON.stringify({ builder: builder.name, leasePath: builder.leasePath }) +
|
|
935
|
+
'\\n',
|
|
936
|
+
);
|
|
937
|
+
return true;
|
|
938
|
+
}
|
|
939
|
+
const diagnostic = [cleanup.stdout, cleanup.stderr]
|
|
940
|
+
.filter(Boolean)
|
|
941
|
+
.join('\\n')
|
|
942
|
+
.slice(-2_000);
|
|
943
|
+
const error = new Error(
|
|
944
|
+
'Invocation-owned Buildx cleanup failed; use only the exact retained ' +
|
|
945
|
+
'hard-kill cleanup command ' + releaseBuilderCleanupDiagnostic(builder) +
|
|
946
|
+
(diagnostic ? ': ' + diagnostic : ''),
|
|
947
|
+
);
|
|
948
|
+
if (signal) {
|
|
949
|
+
process.stderr.write(error.message + '\\n');
|
|
950
|
+
return false;
|
|
951
|
+
}
|
|
952
|
+
throw error;
|
|
953
|
+
}
|
|
954
|
+
unlinkSync(builder.leasePath);
|
|
955
|
+
return true;
|
|
956
|
+
};
|
|
957
|
+
const recoverReleaseBuilders = () => {
|
|
958
|
+
const leaseRoot = releaseBuilderLeaseRoot();
|
|
959
|
+
const entries = readdirSync(leaseRoot, { withFileTypes: true }).sort(
|
|
960
|
+
(left, right) =>
|
|
961
|
+
left.name < right.name ? -1 : left.name > right.name ? 1 : 0,
|
|
962
|
+
);
|
|
963
|
+
if (entries.length > 64) {
|
|
964
|
+
throw new Error('Container-release builder lease inventory is unbounded.');
|
|
965
|
+
}
|
|
966
|
+
for (const entry of entries) {
|
|
967
|
+
const matched = /^(ebk-release-[a-f0-9]{32})\\.json$/.exec(entry.name);
|
|
968
|
+
if (!entry.isFile() || !matched) {
|
|
969
|
+
throw new Error(
|
|
970
|
+
'Container-release builder lease directory contains an unexpected entry.',
|
|
971
|
+
);
|
|
972
|
+
}
|
|
973
|
+
const leasePath = join(leaseRoot, entry.name);
|
|
974
|
+
const lease = readReleaseBuilderLease(leasePath, matched[1]);
|
|
975
|
+
const builderNames = listExactReleaseBuilderNames();
|
|
976
|
+
if (builderNames.has(lease.builder)) {
|
|
977
|
+
throw new Error(
|
|
978
|
+
'A retained invocation-owned Buildx builder still exists; inspect it and use only the exact cleanup command ' +
|
|
979
|
+
releaseBuilderCleanupDiagnostic({ leasePath, name: lease.builder }) + '.',
|
|
980
|
+
);
|
|
981
|
+
}
|
|
982
|
+
unlinkSync(leasePath);
|
|
983
|
+
process.stderr.write(
|
|
984
|
+
'ebk-release-builder-recovered ' +
|
|
985
|
+
JSON.stringify({ builder: lease.builder, leasePath }) +
|
|
986
|
+
'\\n',
|
|
987
|
+
);
|
|
988
|
+
}
|
|
989
|
+
};
|
|
990
|
+
const cleanupReleaseBuilder = ({ signal } = {}) => {
|
|
991
|
+
const builder = releaseBuilder;
|
|
992
|
+
if (!builder) {
|
|
993
|
+
removeReleaseBuilderSignalHandlersWhenIdle();
|
|
994
|
+
return;
|
|
995
|
+
}
|
|
996
|
+
releaseBuilder = undefined;
|
|
997
|
+
const removed = removeExactReleaseBuilder(builder, { signal });
|
|
998
|
+
removeReleaseBuilderSignalHandlersWhenIdle();
|
|
999
|
+
return removed;
|
|
1000
|
+
};
|
|
1001
|
+
const handleReleaseBuilderSignal = async (signal) => {
|
|
1002
|
+
if (releaseBuilderSignal) return;
|
|
1003
|
+
releaseBuilderSignal = signal;
|
|
1004
|
+
removeReleaseBuilderSignalHandlers();
|
|
1005
|
+
const cleanupErrors = [];
|
|
1006
|
+
let childStopped = false;
|
|
1007
|
+
try {
|
|
1008
|
+
await stopExactReleaseBuildChild(signal);
|
|
1009
|
+
childStopped = true;
|
|
1010
|
+
} catch (error) {
|
|
1011
|
+
cleanupErrors.push(error);
|
|
1012
|
+
}
|
|
1013
|
+
if (childStopped) {
|
|
1014
|
+
try {
|
|
1015
|
+
cleanupReleaseBuilder({ signal });
|
|
1016
|
+
} catch (error) {
|
|
1017
|
+
cleanupErrors.push(error);
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
try {
|
|
1021
|
+
removeAllReleaseToolTemporaryDirectories();
|
|
1022
|
+
} catch (error) {
|
|
1023
|
+
cleanupErrors.push(error);
|
|
1024
|
+
}
|
|
1025
|
+
if (cleanupErrors.length > 0) {
|
|
1026
|
+
process.stderr.write(
|
|
1027
|
+
'Invocation-owned Buildx signal cleanup failed closed; the exact ' +
|
|
1028
|
+
'ownership lease was retained: ' +
|
|
1029
|
+
cleanupErrors
|
|
1030
|
+
.map((error) => String(error?.message ?? error))
|
|
1031
|
+
.join('; ')
|
|
1032
|
+
.slice(-2_000) + '\\n',
|
|
1033
|
+
);
|
|
1034
|
+
}
|
|
1035
|
+
try {
|
|
1036
|
+
removeReleaseBuilderSignalHandlers();
|
|
1037
|
+
} finally {
|
|
1038
|
+
process.kill(process.pid, signal);
|
|
1039
|
+
}
|
|
1040
|
+
};
|
|
1041
|
+
const ensureReleaseBuilder = () => {
|
|
1042
|
+
if (releaseBuilder) return releaseBuilder;
|
|
1043
|
+
const name = 'ebk-release-' + randomBytes(16).toString('hex');
|
|
1044
|
+
const leaseRoot = releaseBuilderLeaseRoot();
|
|
1045
|
+
const leasePath = join(leaseRoot, name + '.json');
|
|
1046
|
+
const builder = {
|
|
1047
|
+
leasePath,
|
|
1048
|
+
leaseRoot,
|
|
1049
|
+
name,
|
|
1050
|
+
};
|
|
1051
|
+
writeFileSync(
|
|
1052
|
+
leasePath,
|
|
1053
|
+
JSON.stringify({
|
|
1054
|
+
builder: name,
|
|
1055
|
+
cleanup: ['docker', 'buildx', 'rm', name],
|
|
1056
|
+
createdAt: new Date().toISOString(),
|
|
1057
|
+
driver: 'docker-container',
|
|
1058
|
+
kind: 'ebk-container-release-builder-lease',
|
|
1059
|
+
ownerPid: process.pid,
|
|
1060
|
+
schemaVersion: 1,
|
|
1061
|
+
}) + '\\n',
|
|
1062
|
+
{ encoding: 'utf8', flag: 'wx', mode: 0o600 },
|
|
1063
|
+
);
|
|
1064
|
+
hardenPrivateReleaseBuilderPath(leasePath, 'file');
|
|
1065
|
+
releaseBuilder = builder;
|
|
1066
|
+
ensureReleaseBuilderSignalHandlers();
|
|
1067
|
+
process.stderr.write(
|
|
1068
|
+
'ebk-release-builder-ownership ' +
|
|
1069
|
+
JSON.stringify({
|
|
1070
|
+
builder: name,
|
|
1071
|
+
hardKillCleanup: ['docker', 'buildx', 'rm', name],
|
|
1072
|
+
leasePath,
|
|
1073
|
+
}) +
|
|
1074
|
+
'\\n',
|
|
1075
|
+
);
|
|
1076
|
+
try {
|
|
1077
|
+
execute(
|
|
1078
|
+
'docker',
|
|
1079
|
+
['buildx', 'create', '--name', name, '--driver', 'docker-container'],
|
|
1080
|
+
'Invocation-owned native Buildx builder creation',
|
|
1081
|
+
);
|
|
1082
|
+
} catch (error) {
|
|
1083
|
+
try {
|
|
1084
|
+
cleanupReleaseBuilder();
|
|
1085
|
+
} catch (cleanupError) {
|
|
1086
|
+
throw new AggregateError(
|
|
1087
|
+
[error, cleanupError],
|
|
1088
|
+
'Invocation-owned Buildx creation and cleanup both failed.',
|
|
1089
|
+
);
|
|
1090
|
+
}
|
|
1091
|
+
throw error;
|
|
1092
|
+
}
|
|
1093
|
+
return builder;
|
|
1094
|
+
};
|
|
368
1095
|
const awsJson = (args, label) => {
|
|
369
1096
|
const raw = execute('aws', args, label);
|
|
370
1097
|
try {
|
|
@@ -419,6 +1146,18 @@ const caller = awsJson(
|
|
|
419
1146
|
if (caller?.Account !== accountId) {
|
|
420
1147
|
throw new Error('Container release AWS caller differs from the target account.');
|
|
421
1148
|
}
|
|
1149
|
+
execute(
|
|
1150
|
+
process.execPath,
|
|
1151
|
+
[
|
|
1152
|
+
safePath(
|
|
1153
|
+
'tools/stage-authority-render.mjs',
|
|
1154
|
+
'Workspace ownership doctor',
|
|
1155
|
+
),
|
|
1156
|
+
'--stage=' + stage,
|
|
1157
|
+
'--ownership-doctor=true',
|
|
1158
|
+
],
|
|
1159
|
+
'Workspace stage ownership',
|
|
1160
|
+
);
|
|
422
1161
|
const controls = readJson(
|
|
423
1162
|
safePath('operations/release.json', 'Release controls', { base: sliceRoot }),
|
|
424
1163
|
'Release controls',
|
|
@@ -760,7 +1499,8 @@ const acquireSyft = async () => {
|
|
|
760
1499
|
if (!release) {
|
|
761
1500
|
throw new Error('No reviewed Syft release exists for ' + platformKey + '.');
|
|
762
1501
|
}
|
|
763
|
-
const temporary =
|
|
1502
|
+
const temporary = createReleaseToolTemporaryDirectory('ebk-container-syft-');
|
|
1503
|
+
try {
|
|
764
1504
|
const supplied = process.env.EBK_SYFT_ARCHIVE_PATH?.trim();
|
|
765
1505
|
const archive = supplied
|
|
766
1506
|
? safePath(relative(repositoryRoot, resolve(repositoryRoot, supplied)), 'Supplied Syft archive')
|
|
@@ -798,6 +1538,7 @@ const acquireSyft = async () => {
|
|
|
798
1538
|
chmodSync(path, 0o700);
|
|
799
1539
|
}
|
|
800
1540
|
const version = String(execute(path, ['version'], 'Syft version'));
|
|
1541
|
+
await yieldToReleaseSignals();
|
|
801
1542
|
if (
|
|
802
1543
|
!new RegExp('(?:Version|version):?\\\\s*' + SYFT_VERSION.replaceAll('.', '\\\\.')).test(
|
|
803
1544
|
version,
|
|
@@ -805,7 +1546,18 @@ const acquireSyft = async () => {
|
|
|
805
1546
|
) {
|
|
806
1547
|
throw new Error('Syft runtime version differs from reviewed policy.');
|
|
807
1548
|
}
|
|
808
|
-
|
|
1549
|
+
return { path, temporary };
|
|
1550
|
+
} catch (error) {
|
|
1551
|
+
try {
|
|
1552
|
+
removeExactReleaseToolTemporaryDirectory(temporary);
|
|
1553
|
+
} catch (cleanupError) {
|
|
1554
|
+
throw new AggregateError(
|
|
1555
|
+
[error, cleanupError],
|
|
1556
|
+
'Syft acquisition and exact temporary cleanup both failed.',
|
|
1557
|
+
);
|
|
1558
|
+
}
|
|
1559
|
+
throw error;
|
|
1560
|
+
}
|
|
809
1561
|
};
|
|
810
1562
|
const acquireCrane = async () => {
|
|
811
1563
|
const platformKey = process.platform + '-' + process.arch;
|
|
@@ -813,7 +1565,8 @@ const acquireCrane = async () => {
|
|
|
813
1565
|
if (!release) {
|
|
814
1566
|
throw new Error('No reviewed Crane release exists for ' + platformKey + '.');
|
|
815
1567
|
}
|
|
816
|
-
const temporary =
|
|
1568
|
+
const temporary = createReleaseToolTemporaryDirectory('ebk-container-crane-');
|
|
1569
|
+
try {
|
|
817
1570
|
const supplied = process.env.EBK_CRANE_ARCHIVE_PATH?.trim();
|
|
818
1571
|
const archive = supplied
|
|
819
1572
|
? safePath(
|
|
@@ -850,6 +1603,7 @@ const acquireCrane = async () => {
|
|
|
850
1603
|
const path = join(temporary, 'crane');
|
|
851
1604
|
chmodSync(path, 0o700);
|
|
852
1605
|
const version = String(execute(path, ['version'], 'Crane version')).trim();
|
|
1606
|
+
await yieldToReleaseSignals();
|
|
853
1607
|
if (
|
|
854
1608
|
!new RegExp('(?:^|\\s|v)' + CRANE_VERSION.replaceAll('.', '\\.') + '(?:$|\\s)').test(
|
|
855
1609
|
version,
|
|
@@ -857,7 +1611,18 @@ const acquireCrane = async () => {
|
|
|
857
1611
|
) {
|
|
858
1612
|
throw new Error('Crane runtime version differs from reviewed policy.');
|
|
859
1613
|
}
|
|
860
|
-
|
|
1614
|
+
return { path, temporary };
|
|
1615
|
+
} catch (error) {
|
|
1616
|
+
try {
|
|
1617
|
+
removeExactReleaseToolTemporaryDirectory(temporary);
|
|
1618
|
+
} catch (cleanupError) {
|
|
1619
|
+
throw new AggregateError(
|
|
1620
|
+
[error, cleanupError],
|
|
1621
|
+
'Crane acquisition and exact temporary cleanup both failed.',
|
|
1622
|
+
);
|
|
1623
|
+
}
|
|
1624
|
+
throw error;
|
|
1625
|
+
}
|
|
861
1626
|
};
|
|
862
1627
|
const parseCycloneDx = (value, label) => {
|
|
863
1628
|
if (
|
|
@@ -957,8 +1722,8 @@ const npmClosureFor = (syftDocument, options = {}) => {
|
|
|
957
1722
|
}
|
|
958
1723
|
return unique;
|
|
959
1724
|
};
|
|
960
|
-
const deriveExpectedProductionClosure = (syft, input) => {
|
|
961
|
-
const temporary =
|
|
1725
|
+
const deriveExpectedProductionClosure = async (syft, input) => {
|
|
1726
|
+
const temporary = createReleaseToolTemporaryDirectory('ebk-container-closure-');
|
|
962
1727
|
const deployed = join(temporary, 'deployed');
|
|
963
1728
|
try {
|
|
964
1729
|
execute(
|
|
@@ -977,16 +1742,24 @@ const deriveExpectedProductionClosure = (syft, input) => {
|
|
|
977
1742
|
deployed,
|
|
978
1743
|
],
|
|
979
1744
|
'Independent production closure deployment',
|
|
980
|
-
{
|
|
1745
|
+
{
|
|
1746
|
+
env: { COREPACK_ENABLE_DOWNLOAD_PROMPT: '0' },
|
|
1747
|
+
failureDiagnostics: 'bounded-closure',
|
|
1748
|
+
},
|
|
981
1749
|
);
|
|
1750
|
+
await yieldToReleaseSignals();
|
|
982
1751
|
const raw = String(
|
|
983
1752
|
execute(
|
|
984
1753
|
syft.path,
|
|
985
1754
|
['scan', 'dir:' + deployed, '--output', 'syft-json'],
|
|
986
1755
|
'Independent production closure inventory',
|
|
987
|
-
{
|
|
1756
|
+
{
|
|
1757
|
+
env: { SYFT_CHECK_FOR_APP_UPDATE: 'false' },
|
|
1758
|
+
failureDiagnostics: 'bounded-closure',
|
|
1759
|
+
},
|
|
988
1760
|
),
|
|
989
1761
|
);
|
|
1762
|
+
await yieldToReleaseSignals();
|
|
990
1763
|
let inventory;
|
|
991
1764
|
try {
|
|
992
1765
|
inventory = JSON.parse(raw);
|
|
@@ -1041,7 +1814,7 @@ const deriveExpectedProductionClosure = (syft, input) => {
|
|
|
1041
1814
|
}
|
|
1042
1815
|
return { digest: supplyChainDigest(packages), packages };
|
|
1043
1816
|
} finally {
|
|
1044
|
-
|
|
1817
|
+
removeExactReleaseToolTemporaryDirectory(temporary);
|
|
1045
1818
|
}
|
|
1046
1819
|
};
|
|
1047
1820
|
const validateRetainedSbom = (entry, label) => {
|
|
@@ -1719,6 +2492,7 @@ if (mode === 'promote') {
|
|
|
1719
2492
|
slice,
|
|
1720
2493
|
'binding.json',
|
|
1721
2494
|
);
|
|
2495
|
+
await yieldToReleaseSignals();
|
|
1722
2496
|
immutableWrite(output, binding);
|
|
1723
2497
|
process.stdout.write(
|
|
1724
2498
|
JSON.stringify({
|
|
@@ -1731,21 +2505,26 @@ if (mode === 'promote') {
|
|
|
1731
2505
|
}) + '\\n',
|
|
1732
2506
|
);
|
|
1733
2507
|
} finally {
|
|
1734
|
-
|
|
2508
|
+
removeExactReleaseToolTemporaryDirectory(crane.temporary);
|
|
1735
2509
|
}
|
|
1736
2510
|
process.exit(0);
|
|
1737
2511
|
}
|
|
1738
2512
|
|
|
1739
2513
|
if (mode === 'platform') {
|
|
1740
|
-
|
|
1741
|
-
|
|
2514
|
+
let syft;
|
|
2515
|
+
let crane;
|
|
2516
|
+
let platformError;
|
|
1742
2517
|
try {
|
|
1743
|
-
|
|
1744
|
-
|
|
2518
|
+
syft = await acquireSyft();
|
|
2519
|
+
crane = stage === 'development' ? await acquireCrane() : undefined;
|
|
2520
|
+
recoverReleaseBuilders();
|
|
2521
|
+
const expectedClosures = new Map();
|
|
2522
|
+
for (const input of containerInputs) {
|
|
2523
|
+
expectedClosures.set(
|
|
1745
2524
|
input.declared.id,
|
|
1746
|
-
deriveExpectedProductionClosure(syft, input),
|
|
1747
|
-
|
|
1748
|
-
|
|
2525
|
+
await deriveExpectedProductionClosure(syft, input),
|
|
2526
|
+
);
|
|
2527
|
+
}
|
|
1749
2528
|
requireReviewedCheckout();
|
|
1750
2529
|
for (const input of containerInputs) requireCandidateAuthority(input);
|
|
1751
2530
|
login();
|
|
@@ -1788,11 +2567,13 @@ if (mode === 'platform') {
|
|
|
1788
2567
|
'Exact staging retirement child promotion',
|
|
1789
2568
|
);
|
|
1790
2569
|
} else {
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
[
|
|
2570
|
+
const platformBuilder = ensureReleaseBuilder();
|
|
2571
|
+
try {
|
|
2572
|
+
await executeObservedBuildx([
|
|
1794
2573
|
'buildx',
|
|
1795
2574
|
'build',
|
|
2575
|
+
'--builder',
|
|
2576
|
+
platformBuilder.name,
|
|
1796
2577
|
...(packageRegistry
|
|
1797
2578
|
? [
|
|
1798
2579
|
'--build-arg',
|
|
@@ -1814,9 +2595,10 @@ if (mode === 'platform') {
|
|
|
1814
2595
|
'--tag',
|
|
1815
2596
|
taggedReference,
|
|
1816
2597
|
relative(repositoryRoot, input.context) || '.',
|
|
1817
|
-
],
|
|
1818
|
-
|
|
1819
|
-
|
|
2598
|
+
], 'Native container build and push');
|
|
2599
|
+
} finally {
|
|
2600
|
+
cleanupReleaseBuilder();
|
|
2601
|
+
}
|
|
1820
2602
|
}
|
|
1821
2603
|
const imageDigest = exactImageByTag(repositoryName, tag);
|
|
1822
2604
|
const imageReference = registry + '/' + repositoryName + '@' + imageDigest;
|
|
@@ -1991,6 +2773,7 @@ if (mode === 'platform') {
|
|
|
1991
2773
|
evidence,
|
|
1992
2774
|
);
|
|
1993
2775
|
}
|
|
2776
|
+
await yieldToReleaseSignals();
|
|
1994
2777
|
process.stdout.write(
|
|
1995
2778
|
JSON.stringify({
|
|
1996
2779
|
artifactCount: containerInputs.length,
|
|
@@ -1999,12 +2782,33 @@ if (mode === 'platform') {
|
|
|
1999
2782
|
stage,
|
|
2000
2783
|
}) + '\\n',
|
|
2001
2784
|
);
|
|
2785
|
+
} catch (error) {
|
|
2786
|
+
platformError = error;
|
|
2002
2787
|
} finally {
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2788
|
+
const cleanupErrors = [];
|
|
2789
|
+
for (const cleanup of [
|
|
2790
|
+
() => cleanupReleaseBuilder(),
|
|
2791
|
+
...(syft
|
|
2792
|
+
? [() => removeExactReleaseToolTemporaryDirectory(syft.temporary)]
|
|
2793
|
+
: []),
|
|
2794
|
+
...(crane
|
|
2795
|
+
? [() => removeExactReleaseToolTemporaryDirectory(crane.temporary)]
|
|
2796
|
+
: []),
|
|
2797
|
+
]) {
|
|
2798
|
+
try {
|
|
2799
|
+
cleanup();
|
|
2800
|
+
} catch (error) {
|
|
2801
|
+
cleanupErrors.push(error);
|
|
2802
|
+
}
|
|
2803
|
+
}
|
|
2804
|
+
if (cleanupErrors.length > 0) {
|
|
2805
|
+
throw new AggregateError(
|
|
2806
|
+
[...(platformError ? [platformError] : []), ...cleanupErrors],
|
|
2807
|
+
'Container platform release and independent owned-resource cleanup failed.',
|
|
2808
|
+
);
|
|
2006
2809
|
}
|
|
2007
2810
|
}
|
|
2811
|
+
if (platformError) throw platformError;
|
|
2008
2812
|
process.exit(0);
|
|
2009
2813
|
}
|
|
2010
2814
|
|
|
@@ -2216,6 +3020,7 @@ const output = resolve(
|
|
|
2216
3020
|
slice,
|
|
2217
3021
|
'binding.json',
|
|
2218
3022
|
);
|
|
3023
|
+
await yieldToReleaseSignals();
|
|
2219
3024
|
immutableWrite(output, binding);
|
|
2220
3025
|
process.stdout.write(
|
|
2221
3026
|
JSON.stringify({
|
|
@@ -2228,7 +3033,7 @@ process.stdout.write(
|
|
|
2228
3033
|
);
|
|
2229
3034
|
} finally {
|
|
2230
3035
|
if (assemblyCrane) {
|
|
2231
|
-
|
|
3036
|
+
removeExactReleaseToolTemporaryDirectory(assemblyCrane.temporary);
|
|
2232
3037
|
}
|
|
2233
3038
|
}
|
|
2234
3039
|
`;
|