@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
|
@@ -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,32 @@ const packageRegistryInput =
|
|
|
144
206
|
const localFederated =
|
|
145
207
|
process.env.GITHUB_ACTIONS !== 'true' &&
|
|
146
208
|
process.env.EBK_LOCAL_DEPLOYMENT_MODE === 'federated';
|
|
209
|
+
const localRunId = process.env.EBK_LOCAL_CONTAINER_RUN_ID?.trim() ?? '';
|
|
147
210
|
if (localFederated) {
|
|
148
211
|
const policy = JSON.parse(
|
|
149
212
|
readFileSync(join(repositoryRoot, 'ebk.repository-policy.json'), 'utf8'),
|
|
150
213
|
);
|
|
214
|
+
const selectedDeploymentProfile =
|
|
215
|
+
process.env.EBK_DEPLOYMENT_PROFILE?.trim() ?? '';
|
|
216
|
+
const admittedStages = {
|
|
217
|
+
starter: ['development', 'production'],
|
|
218
|
+
'production-isolated': ['development', 'staging'],
|
|
219
|
+
'fully-isolated': ['development'],
|
|
220
|
+
}[policy.deploymentProfile];
|
|
151
221
|
if (
|
|
152
|
-
policy.deploymentProfile
|
|
153
|
-
|
|
222
|
+
selectedDeploymentProfile !== policy.deploymentProfile ||
|
|
223
|
+
!admittedStages ||
|
|
224
|
+
!admittedStages.includes(stage) ||
|
|
154
225
|
policy.deploymentAccounts?.[stage] !== accountId ||
|
|
155
226
|
policy.deploymentRegion !== region
|
|
156
227
|
) {
|
|
157
228
|
throw new Error(
|
|
158
|
-
'Local container release requires
|
|
229
|
+
'Local container release requires the exact committed profile and one of its locally admitted stages.',
|
|
159
230
|
);
|
|
160
231
|
}
|
|
161
232
|
}
|
|
162
233
|
const runId = localFederated
|
|
163
|
-
?
|
|
234
|
+
? localRunId
|
|
164
235
|
: process.env.GITHUB_RUN_ID?.trim() ?? '';
|
|
165
236
|
const runAttempt = localFederated
|
|
166
237
|
? '1'
|
|
@@ -359,12 +430,657 @@ const execute = (command, args, label, options = {}) => {
|
|
|
359
430
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
360
431
|
});
|
|
361
432
|
} catch (error) {
|
|
433
|
+
if (options.failureDiagnostics === 'bounded-closure') {
|
|
434
|
+
const diagnosticStream = (value) => {
|
|
435
|
+
const raw = value === undefined || value === null ? '' : String(value);
|
|
436
|
+
if (raw.length === 0) return '[empty]';
|
|
437
|
+
if (hasSensitiveSupplyChainShape(raw)) {
|
|
438
|
+
return '[redacted-sensitive-output]';
|
|
439
|
+
}
|
|
440
|
+
const bytes = Buffer.from(raw, 'utf8');
|
|
441
|
+
const truncated = bytes.byteLength > 1_024;
|
|
442
|
+
const tail = truncated
|
|
443
|
+
? bytes.subarray(bytes.byteLength - 1_024).toString('utf8')
|
|
444
|
+
: raw;
|
|
445
|
+
return JSON.stringify((truncated ? '[truncated]\\n' : '') + tail);
|
|
446
|
+
};
|
|
447
|
+
const status = Number.isSafeInteger(error?.status)
|
|
448
|
+
? String(error.status)
|
|
449
|
+
: 'unavailable';
|
|
450
|
+
const signal =
|
|
451
|
+
typeof error?.signal === 'string' && /^[A-Z0-9]+$/.test(error.signal)
|
|
452
|
+
? error.signal
|
|
453
|
+
: 'none';
|
|
454
|
+
throw new Error(
|
|
455
|
+
label +
|
|
456
|
+
' failed without complete evidence: ' +
|
|
457
|
+
'status=' +
|
|
458
|
+
status +
|
|
459
|
+
'; signal=' +
|
|
460
|
+
signal +
|
|
461
|
+
'; stdout=' +
|
|
462
|
+
diagnosticStream(error?.stdout) +
|
|
463
|
+
'; stderr=' +
|
|
464
|
+
diagnosticStream(error?.stderr),
|
|
465
|
+
);
|
|
466
|
+
}
|
|
362
467
|
throw new Error(
|
|
363
468
|
label + ' failed without complete evidence: ' +
|
|
364
469
|
String(error?.stderr ?? error?.message ?? error).slice(0, 2_000),
|
|
365
470
|
);
|
|
366
471
|
}
|
|
367
472
|
};
|
|
473
|
+
let releaseBuilder;
|
|
474
|
+
let releaseBuildChild;
|
|
475
|
+
let releaseBuildStopPromise;
|
|
476
|
+
let releaseBuilderSignal;
|
|
477
|
+
const releaseBuilderSignalHandlers = new Map();
|
|
478
|
+
const releaseToolTemporaryDirectories = new Set();
|
|
479
|
+
const yieldToReleaseSignals = () =>
|
|
480
|
+
new Promise((resolve) => setImmediate(resolve));
|
|
481
|
+
const stopExactReleaseBuildChild = async (signal = 'SIGTERM') => {
|
|
482
|
+
if (releaseBuildStopPromise) return releaseBuildStopPromise;
|
|
483
|
+
const observed = releaseBuildChild;
|
|
484
|
+
if (!observed) return;
|
|
485
|
+
releaseBuildStopPromise = (async () => {
|
|
486
|
+
const child = observed.child;
|
|
487
|
+
if (hostOperatingSystem() === 'win32') {
|
|
488
|
+
const taskkill = join(process.env.SystemRoot ?? '', 'System32', 'taskkill.exe');
|
|
489
|
+
if (!isAbsolute(taskkill) || !existsSync(taskkill) || realpathSync(taskkill) !== taskkill) {
|
|
490
|
+
throw new Error('Exact Windows Buildx cleanup requires canonical SystemRoot.');
|
|
491
|
+
}
|
|
492
|
+
const stopped = spawnSync(
|
|
493
|
+
taskkill,
|
|
494
|
+
['/PID', String(child.pid), '/T', '/F'],
|
|
495
|
+
{
|
|
496
|
+
cwd: repositoryRoot,
|
|
497
|
+
encoding: 'utf8',
|
|
498
|
+
env: process.env,
|
|
499
|
+
maxBuffer: 1024 * 1024,
|
|
500
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
501
|
+
windowsHide: true,
|
|
502
|
+
},
|
|
503
|
+
);
|
|
504
|
+
if (
|
|
505
|
+
child.exitCode === null &&
|
|
506
|
+
(stopped.error || stopped.signal || stopped.status !== 0)
|
|
507
|
+
) {
|
|
508
|
+
throw new Error('Exact Windows Buildx process-tree cleanup failed.');
|
|
509
|
+
}
|
|
510
|
+
} else if (child.pid) {
|
|
511
|
+
try {
|
|
512
|
+
process.kill(-child.pid, signal);
|
|
513
|
+
} catch (error) {
|
|
514
|
+
if (error?.code !== 'ESRCH') throw error;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
if (child.exitCode === null) {
|
|
518
|
+
const closed = await Promise.race([
|
|
519
|
+
observed.close.then(() => true),
|
|
520
|
+
new Promise((resolve) => setTimeout(() => resolve(false), 5_000)),
|
|
521
|
+
]);
|
|
522
|
+
if (!closed && hostOperatingSystem() !== 'win32' && child.pid) {
|
|
523
|
+
try {
|
|
524
|
+
process.kill(-child.pid, 'SIGKILL');
|
|
525
|
+
} catch (error) {
|
|
526
|
+
if (error?.code !== 'ESRCH') throw error;
|
|
527
|
+
}
|
|
528
|
+
const killed = await Promise.race([
|
|
529
|
+
observed.close.then(() => true),
|
|
530
|
+
new Promise((resolve) => setTimeout(() => resolve(false), 5_000)),
|
|
531
|
+
]);
|
|
532
|
+
if (!killed) {
|
|
533
|
+
throw new Error('Exact Buildx process group did not terminate.');
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
})().finally(() => {
|
|
538
|
+
if (releaseBuildChild === observed) releaseBuildChild = undefined;
|
|
539
|
+
releaseBuildStopPromise = undefined;
|
|
540
|
+
});
|
|
541
|
+
return releaseBuildStopPromise;
|
|
542
|
+
};
|
|
543
|
+
const executeObservedBuildx = async (args, label) => {
|
|
544
|
+
if (releaseBuildChild) {
|
|
545
|
+
throw new Error('Only one invocation-owned Buildx child may run at a time.');
|
|
546
|
+
}
|
|
547
|
+
const child = spawn('docker', args, {
|
|
548
|
+
cwd: repositoryRoot,
|
|
549
|
+
detached: hostOperatingSystem() !== 'win32',
|
|
550
|
+
env: process.env,
|
|
551
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
552
|
+
windowsHide: true,
|
|
553
|
+
});
|
|
554
|
+
const stdout = [];
|
|
555
|
+
const stderr = [];
|
|
556
|
+
let outputBytes = 0;
|
|
557
|
+
const retain = (chunks, stream, chunk) => {
|
|
558
|
+
outputBytes += chunk.byteLength;
|
|
559
|
+
if (outputBytes > MAX_OUTPUT_BYTES) {
|
|
560
|
+
void stopExactReleaseBuildChild('SIGTERM');
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
chunks.push(chunk);
|
|
564
|
+
stream.write(chunk);
|
|
565
|
+
};
|
|
566
|
+
child.stdout.on('data', (chunk) => retain(stdout, process.stdout, chunk));
|
|
567
|
+
child.stderr.on('data', (chunk) => retain(stderr, process.stderr, chunk));
|
|
568
|
+
const close = new Promise((resolve) => {
|
|
569
|
+
child.once('error', (error) => resolve({ error }));
|
|
570
|
+
child.once('close', (status, signal) => resolve({ signal, status }));
|
|
571
|
+
});
|
|
572
|
+
releaseBuildChild = { child, close };
|
|
573
|
+
const result = await close;
|
|
574
|
+
await stopExactReleaseBuildChild();
|
|
575
|
+
if (
|
|
576
|
+
outputBytes > MAX_OUTPUT_BYTES ||
|
|
577
|
+
result.error ||
|
|
578
|
+
result.signal ||
|
|
579
|
+
result.status !== 0
|
|
580
|
+
) {
|
|
581
|
+
throw new Error(
|
|
582
|
+
label + ' failed without complete evidence: ' +
|
|
583
|
+
Buffer.concat(stderr).toString('utf8').slice(-2_000),
|
|
584
|
+
);
|
|
585
|
+
}
|
|
586
|
+
return Buffer.concat(stdout).toString('utf8');
|
|
587
|
+
};
|
|
588
|
+
const runWindowsPrivateAcl = (script, path, kind) => {
|
|
589
|
+
const systemRoot = process.env.SystemRoot;
|
|
590
|
+
if (!systemRoot || !isAbsolute(systemRoot)) {
|
|
591
|
+
throw new Error('Windows private-path hardening requires an absolute SystemRoot.');
|
|
592
|
+
}
|
|
593
|
+
const powershell = join(
|
|
594
|
+
systemRoot,
|
|
595
|
+
'System32',
|
|
596
|
+
'WindowsPowerShell',
|
|
597
|
+
'v1.0',
|
|
598
|
+
'powershell.exe',
|
|
599
|
+
);
|
|
600
|
+
const result = spawnSync(
|
|
601
|
+
powershell,
|
|
602
|
+
[
|
|
603
|
+
'-NoLogo',
|
|
604
|
+
'-NoProfile',
|
|
605
|
+
'-NonInteractive',
|
|
606
|
+
'-EncodedCommand',
|
|
607
|
+
Buffer.from(script, 'utf16le').toString('base64'),
|
|
608
|
+
],
|
|
609
|
+
{
|
|
610
|
+
cwd: repositoryRoot,
|
|
611
|
+
encoding: 'utf8',
|
|
612
|
+
env: {
|
|
613
|
+
...process.env,
|
|
614
|
+
EBK_PRIVATE_KIND: kind,
|
|
615
|
+
EBK_PRIVATE_PATH: path,
|
|
616
|
+
},
|
|
617
|
+
maxBuffer: 1024 * 1024,
|
|
618
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
619
|
+
timeout: 15_000,
|
|
620
|
+
windowsHide: true,
|
|
621
|
+
},
|
|
622
|
+
);
|
|
623
|
+
if (result.error || result.signal || result.status !== 0) {
|
|
624
|
+
throw new Error(
|
|
625
|
+
'Windows private-path ACL operation failed closed: ' +
|
|
626
|
+
String(result.stderr || result.error?.message || result.signal || result.status)
|
|
627
|
+
.slice(-2_000),
|
|
628
|
+
);
|
|
629
|
+
}
|
|
630
|
+
};
|
|
631
|
+
const assertPrivateReleaseBuilderPathIdentity = (path, kind) => {
|
|
632
|
+
const metadata = lstatSync(path);
|
|
633
|
+
if (
|
|
634
|
+
metadata.isSymbolicLink() ||
|
|
635
|
+
(kind === 'directory' ? !metadata.isDirectory() : !metadata.isFile()) ||
|
|
636
|
+
realpathSync(path) !== path
|
|
637
|
+
) {
|
|
638
|
+
throw new Error(
|
|
639
|
+
'Container-release builder ownership path failed canonical type validation.',
|
|
640
|
+
);
|
|
641
|
+
}
|
|
642
|
+
return metadata;
|
|
643
|
+
};
|
|
644
|
+
const assertPrivateReleaseBuilderPath = (path, kind) => {
|
|
645
|
+
const metadata = assertPrivateReleaseBuilderPathIdentity(path, kind);
|
|
646
|
+
if (hostOperatingSystem() === 'win32') {
|
|
647
|
+
runWindowsPrivateAcl(WINDOWS_ASSERT_PRIVATE_ACL, path, kind);
|
|
648
|
+
return metadata;
|
|
649
|
+
}
|
|
650
|
+
const expectedMode = kind === 'directory' ? 0o700 : 0o600;
|
|
651
|
+
if (
|
|
652
|
+
(metadata.mode & 0o777) !== expectedMode ||
|
|
653
|
+
(typeof process.getuid === 'function' && metadata.uid !== process.getuid())
|
|
654
|
+
) {
|
|
655
|
+
throw new Error(
|
|
656
|
+
'Container-release builder ownership path is not current-user private.',
|
|
657
|
+
);
|
|
658
|
+
}
|
|
659
|
+
return metadata;
|
|
660
|
+
};
|
|
661
|
+
const hardenPrivateReleaseBuilderPath = (path, kind) => {
|
|
662
|
+
assertPrivateReleaseBuilderPathIdentity(path, kind);
|
|
663
|
+
if (hostOperatingSystem() === 'win32') {
|
|
664
|
+
runWindowsPrivateAcl(WINDOWS_HARDEN_PRIVATE_ACL, path, kind);
|
|
665
|
+
} else {
|
|
666
|
+
chmodSync(path, kind === 'directory' ? 0o700 : 0o600);
|
|
667
|
+
}
|
|
668
|
+
return assertPrivateReleaseBuilderPath(path, kind);
|
|
669
|
+
};
|
|
670
|
+
const assertCanonicalAncestorsBeforeCreate = (requested) => {
|
|
671
|
+
const requestedRelative = relative(repositoryRoot, requested);
|
|
672
|
+
if (
|
|
673
|
+
requestedRelative === '' ||
|
|
674
|
+
requestedRelative === '..' ||
|
|
675
|
+
requestedRelative.startsWith('..' + sep) ||
|
|
676
|
+
isAbsolute(requestedRelative)
|
|
677
|
+
) {
|
|
678
|
+
throw new Error('Container-release builder ownership path escapes its repository.');
|
|
679
|
+
}
|
|
680
|
+
let cursor = repositoryRoot;
|
|
681
|
+
for (const segment of requestedRelative.split(sep)) {
|
|
682
|
+
cursor = join(cursor, segment);
|
|
683
|
+
if (!existsSync(cursor)) break;
|
|
684
|
+
const metadata = lstatSync(cursor);
|
|
685
|
+
if (metadata.isSymbolicLink() || realpathSync(cursor) !== cursor) {
|
|
686
|
+
throw new Error(
|
|
687
|
+
'Container-release builder ownership path has a symbolic or noncanonical ancestor.',
|
|
688
|
+
);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
};
|
|
692
|
+
const releaseBuilderLeaseRoot = () => {
|
|
693
|
+
const requested = resolve(
|
|
694
|
+
repositoryRoot,
|
|
695
|
+
'.ebk/cache/container-release-builders',
|
|
696
|
+
);
|
|
697
|
+
assertCanonicalAncestorsBeforeCreate(requested);
|
|
698
|
+
mkdirSync(requested, { mode: 0o700, recursive: true });
|
|
699
|
+
hardenPrivateReleaseBuilderPath(requested, 'directory');
|
|
700
|
+
const canonical = realpathSync(requested);
|
|
701
|
+
if (canonical !== requested) {
|
|
702
|
+
throw new Error(
|
|
703
|
+
'Container-release builder leases require one repository-private owned directory.',
|
|
704
|
+
);
|
|
705
|
+
}
|
|
706
|
+
return canonical;
|
|
707
|
+
};
|
|
708
|
+
const readReleaseBuilderLease = (leasePath, expectedName) => {
|
|
709
|
+
const metadata = assertPrivateReleaseBuilderPath(leasePath, 'file');
|
|
710
|
+
if (
|
|
711
|
+
metadata.nlink !== 1 ||
|
|
712
|
+
metadata.size < 2 ||
|
|
713
|
+
metadata.size > 16 * 1024
|
|
714
|
+
) {
|
|
715
|
+
throw new Error('Container-release builder lease is not one private file.');
|
|
716
|
+
}
|
|
717
|
+
let lease;
|
|
718
|
+
try {
|
|
719
|
+
lease = JSON.parse(readFileSync(leasePath, 'utf8'));
|
|
720
|
+
} catch {
|
|
721
|
+
throw new Error('Container-release builder lease is invalid JSON.');
|
|
722
|
+
}
|
|
723
|
+
const keys = Object.keys(lease ?? {}).sort();
|
|
724
|
+
if (
|
|
725
|
+
JSON.stringify(keys) !==
|
|
726
|
+
JSON.stringify([
|
|
727
|
+
'builder',
|
|
728
|
+
'cleanup',
|
|
729
|
+
'createdAt',
|
|
730
|
+
'driver',
|
|
731
|
+
'kind',
|
|
732
|
+
'ownerPid',
|
|
733
|
+
'schemaVersion',
|
|
734
|
+
]) ||
|
|
735
|
+
lease.kind !== 'ebk-container-release-builder-lease' ||
|
|
736
|
+
lease.schemaVersion !== 1 ||
|
|
737
|
+
lease.builder !== expectedName ||
|
|
738
|
+
!/^ebk-release-[a-f0-9]{32}$/.test(lease.builder) ||
|
|
739
|
+
lease.driver !== 'docker-container' ||
|
|
740
|
+
JSON.stringify(lease.cleanup) !==
|
|
741
|
+
JSON.stringify(['docker', 'buildx', 'rm', lease.builder]) ||
|
|
742
|
+
!Number.isSafeInteger(lease.ownerPid) ||
|
|
743
|
+
lease.ownerPid <= 0 ||
|
|
744
|
+
!Number.isFinite(Date.parse(lease.createdAt)) ||
|
|
745
|
+
new Date(lease.createdAt).toISOString() !== lease.createdAt
|
|
746
|
+
) {
|
|
747
|
+
throw new Error('Container-release builder lease has an invalid identity.');
|
|
748
|
+
}
|
|
749
|
+
return lease;
|
|
750
|
+
};
|
|
751
|
+
const removeReleaseBuilderSignalHandlers = () => {
|
|
752
|
+
for (const [signal, handler] of releaseBuilderSignalHandlers) {
|
|
753
|
+
process.removeListener(signal, handler);
|
|
754
|
+
}
|
|
755
|
+
releaseBuilderSignalHandlers.clear();
|
|
756
|
+
};
|
|
757
|
+
const ensureReleaseBuilderSignalHandlers = () => {
|
|
758
|
+
if (releaseBuilderSignalHandlers.size > 0) return;
|
|
759
|
+
for (const signal of ['SIGINT', 'SIGTERM']) {
|
|
760
|
+
const handler = () => void handleReleaseBuilderSignal(signal);
|
|
761
|
+
releaseBuilderSignalHandlers.set(signal, handler);
|
|
762
|
+
process.on(signal, handler);
|
|
763
|
+
}
|
|
764
|
+
};
|
|
765
|
+
const removeReleaseBuilderSignalHandlersWhenIdle = () => {
|
|
766
|
+
if (!releaseBuilder && releaseToolTemporaryDirectories.size === 0) {
|
|
767
|
+
removeReleaseBuilderSignalHandlers();
|
|
768
|
+
}
|
|
769
|
+
};
|
|
770
|
+
const createReleaseToolTemporaryDirectory = (prefix) => {
|
|
771
|
+
const created = mkdtempSync(join(tmpdir(), prefix));
|
|
772
|
+
const metadata = lstatSync(created);
|
|
773
|
+
if (
|
|
774
|
+
!metadata.isDirectory() ||
|
|
775
|
+
metadata.isSymbolicLink() ||
|
|
776
|
+
!isAbsolute(created)
|
|
777
|
+
) {
|
|
778
|
+
throw new Error('Container-release tool temporary directory is not exact.');
|
|
779
|
+
}
|
|
780
|
+
const temporary = realpathSync(created);
|
|
781
|
+
const canonicalMetadata = lstatSync(temporary);
|
|
782
|
+
if (
|
|
783
|
+
!isAbsolute(temporary) ||
|
|
784
|
+
!canonicalMetadata.isDirectory() ||
|
|
785
|
+
canonicalMetadata.isSymbolicLink() ||
|
|
786
|
+
canonicalMetadata.dev !== metadata.dev ||
|
|
787
|
+
canonicalMetadata.ino !== metadata.ino
|
|
788
|
+
) {
|
|
789
|
+
throw new Error('Container-release tool temporary directory is not canonical.');
|
|
790
|
+
}
|
|
791
|
+
releaseToolTemporaryDirectories.add(temporary);
|
|
792
|
+
ensureReleaseBuilderSignalHandlers();
|
|
793
|
+
return temporary;
|
|
794
|
+
};
|
|
795
|
+
const removeExactReleaseToolTemporaryDirectory = (temporary) => {
|
|
796
|
+
if (!releaseToolTemporaryDirectories.has(temporary)) {
|
|
797
|
+
throw new Error('Container-release tool temporary directory is not owned.');
|
|
798
|
+
}
|
|
799
|
+
const metadata = lstatSync(temporary);
|
|
800
|
+
if (
|
|
801
|
+
!metadata.isDirectory() ||
|
|
802
|
+
metadata.isSymbolicLink() ||
|
|
803
|
+
!isAbsolute(temporary) ||
|
|
804
|
+
realpathSync(temporary) !== temporary
|
|
805
|
+
) {
|
|
806
|
+
throw new Error(
|
|
807
|
+
'Container-release tool temporary directory changed identity before cleanup.',
|
|
808
|
+
);
|
|
809
|
+
}
|
|
810
|
+
rmSync(temporary, { force: true, recursive: true });
|
|
811
|
+
if (existsSync(temporary)) {
|
|
812
|
+
throw new Error('Container-release tool temporary directory cleanup failed.');
|
|
813
|
+
}
|
|
814
|
+
releaseToolTemporaryDirectories.delete(temporary);
|
|
815
|
+
removeReleaseBuilderSignalHandlersWhenIdle();
|
|
816
|
+
};
|
|
817
|
+
const removeAllReleaseToolTemporaryDirectories = () => {
|
|
818
|
+
const cleanupErrors = [];
|
|
819
|
+
for (const temporary of [...releaseToolTemporaryDirectories]) {
|
|
820
|
+
try {
|
|
821
|
+
removeExactReleaseToolTemporaryDirectory(temporary);
|
|
822
|
+
} catch (error) {
|
|
823
|
+
cleanupErrors.push(error);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
if (cleanupErrors.length > 0) {
|
|
827
|
+
throw new AggregateError(
|
|
828
|
+
cleanupErrors,
|
|
829
|
+
'Exact container-release tool temporary cleanup failed.',
|
|
830
|
+
);
|
|
831
|
+
}
|
|
832
|
+
};
|
|
833
|
+
const releaseBuilderCleanupDiagnostic = (builder) =>
|
|
834
|
+
'docker buildx rm ' + builder.name +
|
|
835
|
+
' (ownership lease: ' + builder.leasePath + ')';
|
|
836
|
+
const listExactReleaseBuilderNames = ({ signal } = {}) => {
|
|
837
|
+
const inventory = spawnSync(
|
|
838
|
+
'docker',
|
|
839
|
+
['buildx', 'ls', '--format', '{{json .Name}}'],
|
|
840
|
+
{
|
|
841
|
+
cwd: repositoryRoot,
|
|
842
|
+
encoding: 'utf8',
|
|
843
|
+
env: process.env,
|
|
844
|
+
maxBuffer: 1024 * 1024,
|
|
845
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
846
|
+
timeout: signal ? 5_000 : undefined,
|
|
847
|
+
},
|
|
848
|
+
);
|
|
849
|
+
if (inventory.error || inventory.signal || inventory.status !== 0) {
|
|
850
|
+
throw new Error(
|
|
851
|
+
'Invocation-owned Buildx inventory failed while proving exact cleanup: ' +
|
|
852
|
+
String(
|
|
853
|
+
inventory.stderr ||
|
|
854
|
+
inventory.error?.message ||
|
|
855
|
+
inventory.signal ||
|
|
856
|
+
inventory.status,
|
|
857
|
+
).slice(-2_000),
|
|
858
|
+
);
|
|
859
|
+
}
|
|
860
|
+
const lines = inventory.stdout.trim() === ''
|
|
861
|
+
? []
|
|
862
|
+
: inventory.stdout.trim().split(/\\r?\\n/u);
|
|
863
|
+
if (lines.length > 256) {
|
|
864
|
+
throw new Error('Invocation-owned Buildx inventory is unbounded.');
|
|
865
|
+
}
|
|
866
|
+
const names = new Set();
|
|
867
|
+
for (const line of lines) {
|
|
868
|
+
let name;
|
|
869
|
+
try {
|
|
870
|
+
name = JSON.parse(line);
|
|
871
|
+
} catch {
|
|
872
|
+
throw new Error('Invocation-owned Buildx inventory is not exact JSON.');
|
|
873
|
+
}
|
|
874
|
+
if (
|
|
875
|
+
typeof name !== 'string' ||
|
|
876
|
+
name.length === 0 ||
|
|
877
|
+
name.length > 256 ||
|
|
878
|
+
names.has(name)
|
|
879
|
+
) {
|
|
880
|
+
throw new Error('Invocation-owned Buildx inventory has an invalid identity.');
|
|
881
|
+
}
|
|
882
|
+
names.add(name);
|
|
883
|
+
}
|
|
884
|
+
return names;
|
|
885
|
+
};
|
|
886
|
+
const removeExactReleaseBuilder = (builder, { signal } = {}) => {
|
|
887
|
+
readReleaseBuilderLease(builder.leasePath, builder.name);
|
|
888
|
+
const cleanup = spawnSync(
|
|
889
|
+
'docker',
|
|
890
|
+
['buildx', 'rm', builder.name],
|
|
891
|
+
{
|
|
892
|
+
cwd: repositoryRoot,
|
|
893
|
+
encoding: 'utf8',
|
|
894
|
+
env: process.env,
|
|
895
|
+
maxBuffer: 1024 * 1024,
|
|
896
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
897
|
+
timeout: signal ? 5_000 : undefined,
|
|
898
|
+
},
|
|
899
|
+
);
|
|
900
|
+
if (cleanup.error || cleanup.signal || cleanup.status !== 0) {
|
|
901
|
+
let builderNames;
|
|
902
|
+
try {
|
|
903
|
+
builderNames = listExactReleaseBuilderNames({ signal });
|
|
904
|
+
} catch (inventoryError) {
|
|
905
|
+
const error = new AggregateError(
|
|
906
|
+
[
|
|
907
|
+
cleanup.error ?? new Error(String(cleanup.stderr || cleanup.status)),
|
|
908
|
+
inventoryError,
|
|
909
|
+
],
|
|
910
|
+
'Invocation-owned Buildx cleanup and exact absence proof both failed; ' +
|
|
911
|
+
'retain ' + releaseBuilderCleanupDiagnostic(builder) + '.',
|
|
912
|
+
);
|
|
913
|
+
if (signal) {
|
|
914
|
+
process.stderr.write(error.message + '\\n');
|
|
915
|
+
return false;
|
|
916
|
+
}
|
|
917
|
+
throw error;
|
|
918
|
+
}
|
|
919
|
+
if (!builderNames.has(builder.name)) {
|
|
920
|
+
unlinkSync(builder.leasePath);
|
|
921
|
+
process.stderr.write(
|
|
922
|
+
'ebk-release-builder-already-absent ' +
|
|
923
|
+
JSON.stringify({ builder: builder.name, leasePath: builder.leasePath }) +
|
|
924
|
+
'\\n',
|
|
925
|
+
);
|
|
926
|
+
return true;
|
|
927
|
+
}
|
|
928
|
+
const diagnostic = [cleanup.stdout, cleanup.stderr]
|
|
929
|
+
.filter(Boolean)
|
|
930
|
+
.join('\\n')
|
|
931
|
+
.slice(-2_000);
|
|
932
|
+
const error = new Error(
|
|
933
|
+
'Invocation-owned Buildx cleanup failed; use only the exact retained ' +
|
|
934
|
+
'hard-kill cleanup command ' + releaseBuilderCleanupDiagnostic(builder) +
|
|
935
|
+
(diagnostic ? ': ' + diagnostic : ''),
|
|
936
|
+
);
|
|
937
|
+
if (signal) {
|
|
938
|
+
process.stderr.write(error.message + '\\n');
|
|
939
|
+
return false;
|
|
940
|
+
}
|
|
941
|
+
throw error;
|
|
942
|
+
}
|
|
943
|
+
unlinkSync(builder.leasePath);
|
|
944
|
+
return true;
|
|
945
|
+
};
|
|
946
|
+
const recoverReleaseBuilders = () => {
|
|
947
|
+
const leaseRoot = releaseBuilderLeaseRoot();
|
|
948
|
+
const entries = readdirSync(leaseRoot, { withFileTypes: true }).sort(
|
|
949
|
+
(left, right) =>
|
|
950
|
+
left.name < right.name ? -1 : left.name > right.name ? 1 : 0,
|
|
951
|
+
);
|
|
952
|
+
if (entries.length > 64) {
|
|
953
|
+
throw new Error('Container-release builder lease inventory is unbounded.');
|
|
954
|
+
}
|
|
955
|
+
for (const entry of entries) {
|
|
956
|
+
const matched = /^(ebk-release-[a-f0-9]{32})\\.json$/.exec(entry.name);
|
|
957
|
+
if (!entry.isFile() || !matched) {
|
|
958
|
+
throw new Error(
|
|
959
|
+
'Container-release builder lease directory contains an unexpected entry.',
|
|
960
|
+
);
|
|
961
|
+
}
|
|
962
|
+
const leasePath = join(leaseRoot, entry.name);
|
|
963
|
+
const lease = readReleaseBuilderLease(leasePath, matched[1]);
|
|
964
|
+
const builderNames = listExactReleaseBuilderNames();
|
|
965
|
+
if (builderNames.has(lease.builder)) {
|
|
966
|
+
throw new Error(
|
|
967
|
+
'A retained invocation-owned Buildx builder still exists; inspect it and use only the exact cleanup command ' +
|
|
968
|
+
releaseBuilderCleanupDiagnostic({ leasePath, name: lease.builder }) + '.',
|
|
969
|
+
);
|
|
970
|
+
}
|
|
971
|
+
unlinkSync(leasePath);
|
|
972
|
+
process.stderr.write(
|
|
973
|
+
'ebk-release-builder-recovered ' +
|
|
974
|
+
JSON.stringify({ builder: lease.builder, leasePath }) +
|
|
975
|
+
'\\n',
|
|
976
|
+
);
|
|
977
|
+
}
|
|
978
|
+
};
|
|
979
|
+
const cleanupReleaseBuilder = ({ signal } = {}) => {
|
|
980
|
+
const builder = releaseBuilder;
|
|
981
|
+
if (!builder) {
|
|
982
|
+
removeReleaseBuilderSignalHandlersWhenIdle();
|
|
983
|
+
return;
|
|
984
|
+
}
|
|
985
|
+
releaseBuilder = undefined;
|
|
986
|
+
const removed = removeExactReleaseBuilder(builder, { signal });
|
|
987
|
+
removeReleaseBuilderSignalHandlersWhenIdle();
|
|
988
|
+
return removed;
|
|
989
|
+
};
|
|
990
|
+
const handleReleaseBuilderSignal = async (signal) => {
|
|
991
|
+
if (releaseBuilderSignal) return;
|
|
992
|
+
releaseBuilderSignal = signal;
|
|
993
|
+
removeReleaseBuilderSignalHandlers();
|
|
994
|
+
const cleanupErrors = [];
|
|
995
|
+
let childStopped = false;
|
|
996
|
+
try {
|
|
997
|
+
await stopExactReleaseBuildChild(signal);
|
|
998
|
+
childStopped = true;
|
|
999
|
+
} catch (error) {
|
|
1000
|
+
cleanupErrors.push(error);
|
|
1001
|
+
}
|
|
1002
|
+
if (childStopped) {
|
|
1003
|
+
try {
|
|
1004
|
+
cleanupReleaseBuilder({ signal });
|
|
1005
|
+
} catch (error) {
|
|
1006
|
+
cleanupErrors.push(error);
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
try {
|
|
1010
|
+
removeAllReleaseToolTemporaryDirectories();
|
|
1011
|
+
} catch (error) {
|
|
1012
|
+
cleanupErrors.push(error);
|
|
1013
|
+
}
|
|
1014
|
+
if (cleanupErrors.length > 0) {
|
|
1015
|
+
process.stderr.write(
|
|
1016
|
+
'Invocation-owned Buildx signal cleanup failed closed; the exact ' +
|
|
1017
|
+
'ownership lease was retained: ' +
|
|
1018
|
+
cleanupErrors
|
|
1019
|
+
.map((error) => String(error?.message ?? error))
|
|
1020
|
+
.join('; ')
|
|
1021
|
+
.slice(-2_000) + '\\n',
|
|
1022
|
+
);
|
|
1023
|
+
}
|
|
1024
|
+
try {
|
|
1025
|
+
removeReleaseBuilderSignalHandlers();
|
|
1026
|
+
} finally {
|
|
1027
|
+
process.kill(process.pid, signal);
|
|
1028
|
+
}
|
|
1029
|
+
};
|
|
1030
|
+
const ensureReleaseBuilder = () => {
|
|
1031
|
+
if (releaseBuilder) return releaseBuilder;
|
|
1032
|
+
const name = 'ebk-release-' + randomBytes(16).toString('hex');
|
|
1033
|
+
const leaseRoot = releaseBuilderLeaseRoot();
|
|
1034
|
+
const leasePath = join(leaseRoot, name + '.json');
|
|
1035
|
+
const builder = {
|
|
1036
|
+
leasePath,
|
|
1037
|
+
leaseRoot,
|
|
1038
|
+
name,
|
|
1039
|
+
};
|
|
1040
|
+
writeFileSync(
|
|
1041
|
+
leasePath,
|
|
1042
|
+
JSON.stringify({
|
|
1043
|
+
builder: name,
|
|
1044
|
+
cleanup: ['docker', 'buildx', 'rm', name],
|
|
1045
|
+
createdAt: new Date().toISOString(),
|
|
1046
|
+
driver: 'docker-container',
|
|
1047
|
+
kind: 'ebk-container-release-builder-lease',
|
|
1048
|
+
ownerPid: process.pid,
|
|
1049
|
+
schemaVersion: 1,
|
|
1050
|
+
}) + '\\n',
|
|
1051
|
+
{ encoding: 'utf8', flag: 'wx', mode: 0o600 },
|
|
1052
|
+
);
|
|
1053
|
+
hardenPrivateReleaseBuilderPath(leasePath, 'file');
|
|
1054
|
+
releaseBuilder = builder;
|
|
1055
|
+
ensureReleaseBuilderSignalHandlers();
|
|
1056
|
+
process.stderr.write(
|
|
1057
|
+
'ebk-release-builder-ownership ' +
|
|
1058
|
+
JSON.stringify({
|
|
1059
|
+
builder: name,
|
|
1060
|
+
hardKillCleanup: ['docker', 'buildx', 'rm', name],
|
|
1061
|
+
leasePath,
|
|
1062
|
+
}) +
|
|
1063
|
+
'\\n',
|
|
1064
|
+
);
|
|
1065
|
+
try {
|
|
1066
|
+
execute(
|
|
1067
|
+
'docker',
|
|
1068
|
+
['buildx', 'create', '--name', name, '--driver', 'docker-container'],
|
|
1069
|
+
'Invocation-owned native Buildx builder creation',
|
|
1070
|
+
);
|
|
1071
|
+
} catch (error) {
|
|
1072
|
+
try {
|
|
1073
|
+
cleanupReleaseBuilder();
|
|
1074
|
+
} catch (cleanupError) {
|
|
1075
|
+
throw new AggregateError(
|
|
1076
|
+
[error, cleanupError],
|
|
1077
|
+
'Invocation-owned Buildx creation and cleanup both failed.',
|
|
1078
|
+
);
|
|
1079
|
+
}
|
|
1080
|
+
throw error;
|
|
1081
|
+
}
|
|
1082
|
+
return builder;
|
|
1083
|
+
};
|
|
368
1084
|
const awsJson = (args, label) => {
|
|
369
1085
|
const raw = execute('aws', args, label);
|
|
370
1086
|
try {
|
|
@@ -760,7 +1476,8 @@ const acquireSyft = async () => {
|
|
|
760
1476
|
if (!release) {
|
|
761
1477
|
throw new Error('No reviewed Syft release exists for ' + platformKey + '.');
|
|
762
1478
|
}
|
|
763
|
-
const temporary =
|
|
1479
|
+
const temporary = createReleaseToolTemporaryDirectory('ebk-container-syft-');
|
|
1480
|
+
try {
|
|
764
1481
|
const supplied = process.env.EBK_SYFT_ARCHIVE_PATH?.trim();
|
|
765
1482
|
const archive = supplied
|
|
766
1483
|
? safePath(relative(repositoryRoot, resolve(repositoryRoot, supplied)), 'Supplied Syft archive')
|
|
@@ -798,6 +1515,7 @@ const acquireSyft = async () => {
|
|
|
798
1515
|
chmodSync(path, 0o700);
|
|
799
1516
|
}
|
|
800
1517
|
const version = String(execute(path, ['version'], 'Syft version'));
|
|
1518
|
+
await yieldToReleaseSignals();
|
|
801
1519
|
if (
|
|
802
1520
|
!new RegExp('(?:Version|version):?\\\\s*' + SYFT_VERSION.replaceAll('.', '\\\\.')).test(
|
|
803
1521
|
version,
|
|
@@ -805,7 +1523,18 @@ const acquireSyft = async () => {
|
|
|
805
1523
|
) {
|
|
806
1524
|
throw new Error('Syft runtime version differs from reviewed policy.');
|
|
807
1525
|
}
|
|
808
|
-
|
|
1526
|
+
return { path, temporary };
|
|
1527
|
+
} catch (error) {
|
|
1528
|
+
try {
|
|
1529
|
+
removeExactReleaseToolTemporaryDirectory(temporary);
|
|
1530
|
+
} catch (cleanupError) {
|
|
1531
|
+
throw new AggregateError(
|
|
1532
|
+
[error, cleanupError],
|
|
1533
|
+
'Syft acquisition and exact temporary cleanup both failed.',
|
|
1534
|
+
);
|
|
1535
|
+
}
|
|
1536
|
+
throw error;
|
|
1537
|
+
}
|
|
809
1538
|
};
|
|
810
1539
|
const acquireCrane = async () => {
|
|
811
1540
|
const platformKey = process.platform + '-' + process.arch;
|
|
@@ -813,7 +1542,8 @@ const acquireCrane = async () => {
|
|
|
813
1542
|
if (!release) {
|
|
814
1543
|
throw new Error('No reviewed Crane release exists for ' + platformKey + '.');
|
|
815
1544
|
}
|
|
816
|
-
const temporary =
|
|
1545
|
+
const temporary = createReleaseToolTemporaryDirectory('ebk-container-crane-');
|
|
1546
|
+
try {
|
|
817
1547
|
const supplied = process.env.EBK_CRANE_ARCHIVE_PATH?.trim();
|
|
818
1548
|
const archive = supplied
|
|
819
1549
|
? safePath(
|
|
@@ -850,6 +1580,7 @@ const acquireCrane = async () => {
|
|
|
850
1580
|
const path = join(temporary, 'crane');
|
|
851
1581
|
chmodSync(path, 0o700);
|
|
852
1582
|
const version = String(execute(path, ['version'], 'Crane version')).trim();
|
|
1583
|
+
await yieldToReleaseSignals();
|
|
853
1584
|
if (
|
|
854
1585
|
!new RegExp('(?:^|\\s|v)' + CRANE_VERSION.replaceAll('.', '\\.') + '(?:$|\\s)').test(
|
|
855
1586
|
version,
|
|
@@ -857,7 +1588,18 @@ const acquireCrane = async () => {
|
|
|
857
1588
|
) {
|
|
858
1589
|
throw new Error('Crane runtime version differs from reviewed policy.');
|
|
859
1590
|
}
|
|
860
|
-
|
|
1591
|
+
return { path, temporary };
|
|
1592
|
+
} catch (error) {
|
|
1593
|
+
try {
|
|
1594
|
+
removeExactReleaseToolTemporaryDirectory(temporary);
|
|
1595
|
+
} catch (cleanupError) {
|
|
1596
|
+
throw new AggregateError(
|
|
1597
|
+
[error, cleanupError],
|
|
1598
|
+
'Crane acquisition and exact temporary cleanup both failed.',
|
|
1599
|
+
);
|
|
1600
|
+
}
|
|
1601
|
+
throw error;
|
|
1602
|
+
}
|
|
861
1603
|
};
|
|
862
1604
|
const parseCycloneDx = (value, label) => {
|
|
863
1605
|
if (
|
|
@@ -957,8 +1699,8 @@ const npmClosureFor = (syftDocument, options = {}) => {
|
|
|
957
1699
|
}
|
|
958
1700
|
return unique;
|
|
959
1701
|
};
|
|
960
|
-
const deriveExpectedProductionClosure = (syft, input) => {
|
|
961
|
-
const temporary =
|
|
1702
|
+
const deriveExpectedProductionClosure = async (syft, input) => {
|
|
1703
|
+
const temporary = createReleaseToolTemporaryDirectory('ebk-container-closure-');
|
|
962
1704
|
const deployed = join(temporary, 'deployed');
|
|
963
1705
|
try {
|
|
964
1706
|
execute(
|
|
@@ -977,16 +1719,24 @@ const deriveExpectedProductionClosure = (syft, input) => {
|
|
|
977
1719
|
deployed,
|
|
978
1720
|
],
|
|
979
1721
|
'Independent production closure deployment',
|
|
980
|
-
{
|
|
1722
|
+
{
|
|
1723
|
+
env: { COREPACK_ENABLE_DOWNLOAD_PROMPT: '0' },
|
|
1724
|
+
failureDiagnostics: 'bounded-closure',
|
|
1725
|
+
},
|
|
981
1726
|
);
|
|
1727
|
+
await yieldToReleaseSignals();
|
|
982
1728
|
const raw = String(
|
|
983
1729
|
execute(
|
|
984
1730
|
syft.path,
|
|
985
1731
|
['scan', 'dir:' + deployed, '--output', 'syft-json'],
|
|
986
1732
|
'Independent production closure inventory',
|
|
987
|
-
{
|
|
1733
|
+
{
|
|
1734
|
+
env: { SYFT_CHECK_FOR_APP_UPDATE: 'false' },
|
|
1735
|
+
failureDiagnostics: 'bounded-closure',
|
|
1736
|
+
},
|
|
988
1737
|
),
|
|
989
1738
|
);
|
|
1739
|
+
await yieldToReleaseSignals();
|
|
990
1740
|
let inventory;
|
|
991
1741
|
try {
|
|
992
1742
|
inventory = JSON.parse(raw);
|
|
@@ -1041,7 +1791,7 @@ const deriveExpectedProductionClosure = (syft, input) => {
|
|
|
1041
1791
|
}
|
|
1042
1792
|
return { digest: supplyChainDigest(packages), packages };
|
|
1043
1793
|
} finally {
|
|
1044
|
-
|
|
1794
|
+
removeExactReleaseToolTemporaryDirectory(temporary);
|
|
1045
1795
|
}
|
|
1046
1796
|
};
|
|
1047
1797
|
const validateRetainedSbom = (entry, label) => {
|
|
@@ -1719,6 +2469,7 @@ if (mode === 'promote') {
|
|
|
1719
2469
|
slice,
|
|
1720
2470
|
'binding.json',
|
|
1721
2471
|
);
|
|
2472
|
+
await yieldToReleaseSignals();
|
|
1722
2473
|
immutableWrite(output, binding);
|
|
1723
2474
|
process.stdout.write(
|
|
1724
2475
|
JSON.stringify({
|
|
@@ -1731,21 +2482,26 @@ if (mode === 'promote') {
|
|
|
1731
2482
|
}) + '\\n',
|
|
1732
2483
|
);
|
|
1733
2484
|
} finally {
|
|
1734
|
-
|
|
2485
|
+
removeExactReleaseToolTemporaryDirectory(crane.temporary);
|
|
1735
2486
|
}
|
|
1736
2487
|
process.exit(0);
|
|
1737
2488
|
}
|
|
1738
2489
|
|
|
1739
2490
|
if (mode === 'platform') {
|
|
1740
|
-
|
|
1741
|
-
|
|
2491
|
+
let syft;
|
|
2492
|
+
let crane;
|
|
2493
|
+
let platformError;
|
|
1742
2494
|
try {
|
|
1743
|
-
|
|
1744
|
-
|
|
2495
|
+
syft = await acquireSyft();
|
|
2496
|
+
crane = stage === 'development' ? await acquireCrane() : undefined;
|
|
2497
|
+
recoverReleaseBuilders();
|
|
2498
|
+
const expectedClosures = new Map();
|
|
2499
|
+
for (const input of containerInputs) {
|
|
2500
|
+
expectedClosures.set(
|
|
1745
2501
|
input.declared.id,
|
|
1746
|
-
deriveExpectedProductionClosure(syft, input),
|
|
1747
|
-
|
|
1748
|
-
|
|
2502
|
+
await deriveExpectedProductionClosure(syft, input),
|
|
2503
|
+
);
|
|
2504
|
+
}
|
|
1749
2505
|
requireReviewedCheckout();
|
|
1750
2506
|
for (const input of containerInputs) requireCandidateAuthority(input);
|
|
1751
2507
|
login();
|
|
@@ -1788,11 +2544,13 @@ if (mode === 'platform') {
|
|
|
1788
2544
|
'Exact staging retirement child promotion',
|
|
1789
2545
|
);
|
|
1790
2546
|
} else {
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
[
|
|
2547
|
+
const platformBuilder = ensureReleaseBuilder();
|
|
2548
|
+
try {
|
|
2549
|
+
await executeObservedBuildx([
|
|
1794
2550
|
'buildx',
|
|
1795
2551
|
'build',
|
|
2552
|
+
'--builder',
|
|
2553
|
+
platformBuilder.name,
|
|
1796
2554
|
...(packageRegistry
|
|
1797
2555
|
? [
|
|
1798
2556
|
'--build-arg',
|
|
@@ -1814,9 +2572,10 @@ if (mode === 'platform') {
|
|
|
1814
2572
|
'--tag',
|
|
1815
2573
|
taggedReference,
|
|
1816
2574
|
relative(repositoryRoot, input.context) || '.',
|
|
1817
|
-
],
|
|
1818
|
-
|
|
1819
|
-
|
|
2575
|
+
], 'Native container build and push');
|
|
2576
|
+
} finally {
|
|
2577
|
+
cleanupReleaseBuilder();
|
|
2578
|
+
}
|
|
1820
2579
|
}
|
|
1821
2580
|
const imageDigest = exactImageByTag(repositoryName, tag);
|
|
1822
2581
|
const imageReference = registry + '/' + repositoryName + '@' + imageDigest;
|
|
@@ -1991,6 +2750,7 @@ if (mode === 'platform') {
|
|
|
1991
2750
|
evidence,
|
|
1992
2751
|
);
|
|
1993
2752
|
}
|
|
2753
|
+
await yieldToReleaseSignals();
|
|
1994
2754
|
process.stdout.write(
|
|
1995
2755
|
JSON.stringify({
|
|
1996
2756
|
artifactCount: containerInputs.length,
|
|
@@ -1999,12 +2759,33 @@ if (mode === 'platform') {
|
|
|
1999
2759
|
stage,
|
|
2000
2760
|
}) + '\\n',
|
|
2001
2761
|
);
|
|
2762
|
+
} catch (error) {
|
|
2763
|
+
platformError = error;
|
|
2002
2764
|
} finally {
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2765
|
+
const cleanupErrors = [];
|
|
2766
|
+
for (const cleanup of [
|
|
2767
|
+
() => cleanupReleaseBuilder(),
|
|
2768
|
+
...(syft
|
|
2769
|
+
? [() => removeExactReleaseToolTemporaryDirectory(syft.temporary)]
|
|
2770
|
+
: []),
|
|
2771
|
+
...(crane
|
|
2772
|
+
? [() => removeExactReleaseToolTemporaryDirectory(crane.temporary)]
|
|
2773
|
+
: []),
|
|
2774
|
+
]) {
|
|
2775
|
+
try {
|
|
2776
|
+
cleanup();
|
|
2777
|
+
} catch (error) {
|
|
2778
|
+
cleanupErrors.push(error);
|
|
2779
|
+
}
|
|
2780
|
+
}
|
|
2781
|
+
if (cleanupErrors.length > 0) {
|
|
2782
|
+
throw new AggregateError(
|
|
2783
|
+
[...(platformError ? [platformError] : []), ...cleanupErrors],
|
|
2784
|
+
'Container platform release and independent owned-resource cleanup failed.',
|
|
2785
|
+
);
|
|
2006
2786
|
}
|
|
2007
2787
|
}
|
|
2788
|
+
if (platformError) throw platformError;
|
|
2008
2789
|
process.exit(0);
|
|
2009
2790
|
}
|
|
2010
2791
|
|
|
@@ -2216,6 +2997,7 @@ const output = resolve(
|
|
|
2216
2997
|
slice,
|
|
2217
2998
|
'binding.json',
|
|
2218
2999
|
);
|
|
3000
|
+
await yieldToReleaseSignals();
|
|
2219
3001
|
immutableWrite(output, binding);
|
|
2220
3002
|
process.stdout.write(
|
|
2221
3003
|
JSON.stringify({
|
|
@@ -2228,7 +3010,7 @@ process.stdout.write(
|
|
|
2228
3010
|
);
|
|
2229
3011
|
} finally {
|
|
2230
3012
|
if (assemblyCrane) {
|
|
2231
|
-
|
|
3013
|
+
removeExactReleaseToolTemporaryDirectory(assemblyCrane.temporary);
|
|
2232
3014
|
}
|
|
2233
3015
|
}
|
|
2234
3016
|
`;
|