@empire-builder-kit/nx 1.0.0-rc.2 → 1.0.0-rc.21

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.
Files changed (253) hide show
  1. package/executors.json +10 -0
  2. package/package.json +4 -4
  3. package/src/cli/output.js +1 -1
  4. package/src/developer-agent/model.js +4 -4
  5. package/src/developer-agent/model.js.map +1 -1
  6. package/src/developer-agent/operation-registry.js +67 -10
  7. package/src/developer-agent/operation-registry.js.map +1 -1
  8. package/src/developer-agent/planning.js +7 -9
  9. package/src/developer-agent/planning.js.map +1 -1
  10. package/src/developer-agent/workspace-inspection.js +12 -0
  11. package/src/developer-agent/workspace-inspection.js.map +1 -1
  12. package/src/executors/blueprint-trust/blueprint-trust.js +6 -0
  13. package/src/executors/blueprint-trust/blueprint-trust.js.map +1 -1
  14. package/src/executors/deployment-plan/deployment-plan.js +5 -0
  15. package/src/executors/deployment-plan/deployment-plan.js.map +1 -1
  16. package/src/executors/foundation-preflight/foundation-preflight.d.ts +2 -0
  17. package/src/executors/foundation-preflight/foundation-preflight.js +6 -2
  18. package/src/executors/foundation-preflight/foundation-preflight.js.map +1 -1
  19. package/src/executors/foundation-preflight/schema.json +10 -0
  20. package/src/executors/foundation-profile-preflight/foundation-profile-preflight.d.ts +2 -0
  21. package/src/executors/foundation-profile-preflight/foundation-profile-preflight.js +2 -1
  22. package/src/executors/foundation-profile-preflight/foundation-profile-preflight.js.map +1 -1
  23. package/src/executors/foundation-profile-preflight/schema.json +19 -3
  24. package/src/executors/github-bootstrap/github-bootstrap.js +1 -0
  25. package/src/executors/github-bootstrap/github-bootstrap.js.map +1 -1
  26. package/src/executors/infrastructure-plan/infrastructure-plan.d.ts +229 -5
  27. package/src/executors/infrastructure-plan/infrastructure-plan.js +2298 -175
  28. package/src/executors/infrastructure-plan/infrastructure-plan.js.map +1 -1
  29. package/src/executors/infrastructure-plan/schema.json +16 -0
  30. package/src/executors/local-deploy/fixtures/local-deploy-state-machine.mjs +53 -0
  31. package/src/executors/local-deploy/local-approval.d.ts +23 -0
  32. package/src/executors/local-deploy/local-approval.js +43 -0
  33. package/src/executors/local-deploy/local-approval.js.map +1 -0
  34. package/src/executors/local-deploy/local-deploy.d.ts +69 -0
  35. package/src/executors/local-deploy/local-deploy.js +911 -0
  36. package/src/executors/local-deploy/local-deploy.js.map +1 -0
  37. package/src/executors/local-deploy/schema.json +42 -0
  38. package/src/executors/router-waf-rehearsal/router-waf-rehearsal.d.ts +3 -0
  39. package/src/executors/router-waf-rehearsal/router-waf-rehearsal.js +94 -0
  40. package/src/executors/router-waf-rehearsal/router-waf-rehearsal.js.map +1 -0
  41. package/src/executors/router-waf-rehearsal/schema.json +9 -0
  42. package/src/executors/secret-metadata/schema.json +5 -0
  43. package/src/executors/secret-metadata/secret-metadata.d.ts +12 -1
  44. package/src/executors/secret-metadata/secret-metadata.js +68 -16
  45. package/src/executors/secret-metadata/secret-metadata.js.map +1 -1
  46. package/src/executors/sst-lifecycle/logging-preflight.d.ts +5 -0
  47. package/src/executors/sst-lifecycle/logging-preflight.js +23 -13
  48. package/src/executors/sst-lifecycle/logging-preflight.js.map +1 -1
  49. package/src/executors/sst-lifecycle/run-sst-command.d.ts +8 -1
  50. package/src/executors/sst-lifecycle/run-sst-command.js +144 -12
  51. package/src/executors/sst-lifecycle/run-sst-command.js.map +1 -1
  52. package/src/executors/sst-lifecycle/schema.json +13 -1
  53. package/src/executors/sst-lifecycle/sst-environment-source.d.ts +25 -0
  54. package/src/executors/sst-lifecycle/sst-environment-source.js +213 -0
  55. package/src/executors/sst-lifecycle/sst-environment-source.js.map +1 -0
  56. package/src/foundation/index.d.ts +2 -0
  57. package/src/foundation/index.js +2 -0
  58. package/src/foundation/index.js.map +1 -1
  59. package/src/foundation/logging-preflight.js +1 -1
  60. package/src/foundation/logging-preflight.js.map +1 -1
  61. package/src/foundation/logging.d.ts +3 -1
  62. package/src/foundation/logging.js +1 -1
  63. package/src/foundation/logging.js.map +1 -1
  64. package/src/foundation/partial-state.d.ts +10 -0
  65. package/src/foundation/partial-state.js +21 -0
  66. package/src/foundation/partial-state.js.map +1 -0
  67. package/src/foundation/router-waf.d.ts +98 -0
  68. package/src/foundation/router-waf.js +401 -0
  69. package/src/foundation/router-waf.js.map +1 -0
  70. package/src/generators/function/function.js +2 -1
  71. package/src/generators/function/function.js.map +1 -1
  72. package/src/generators/post-generation-install.d.ts +1 -0
  73. package/src/generators/post-generation-install.js +134 -67
  74. package/src/generators/post-generation-install.js.map +1 -1
  75. package/src/generators/preset/generator.js +23 -3
  76. package/src/generators/preset/generator.js.map +1 -1
  77. package/src/generators/preset/schema.d.ts +7 -0
  78. package/src/generators/preset/schema.json +47 -0
  79. package/src/generators/preset/tool-versions.d.ts +5 -5
  80. package/src/generators/preset/tool-versions.js +4 -4
  81. package/src/generators/preset/workspace-files-ci-acceptance.d.ts +1 -0
  82. package/src/generators/preset/workspace-files-ci-acceptance.js +791 -0
  83. package/src/generators/preset/workspace-files-ci-acceptance.js.map +1 -0
  84. package/src/generators/preset/workspace-files-developer-agent.d.ts +2 -0
  85. package/src/generators/preset/workspace-files-developer-agent.js +25 -11
  86. package/src/generators/preset/workspace-files-developer-agent.js.map +1 -1
  87. package/src/generators/preset/workspace-files-foundation-workload-roles.js +5 -2
  88. package/src/generators/preset/workspace-files-foundation-workload-roles.js.map +1 -1
  89. package/src/generators/preset/workspace-files-performance-load.js +2 -1
  90. package/src/generators/preset/workspace-files-performance-load.js.map +1 -1
  91. package/src/generators/preset/workspace-files-workload-role-baseline.js +254 -42
  92. package/src/generators/preset/workspace-files-workload-role-baseline.js.map +1 -1
  93. package/src/generators/preset/workspace-files.d.ts +8 -4
  94. package/src/generators/preset/workspace-files.js +1039 -68
  95. package/src/generators/preset/workspace-files.js.map +1 -1
  96. package/src/generators/repository-policy/repository-policy.js +65 -3
  97. package/src/generators/repository-policy/repository-policy.js.map +1 -1
  98. package/src/generators/repository-policy/schema.d.ts +6 -0
  99. package/src/generators/repository-policy/schema.json +46 -0
  100. package/src/generators/slice/built-in-plan-api-files.js +2 -1
  101. package/src/generators/slice/built-in-plan-api-files.js.map +1 -1
  102. package/src/generators/slice/built-in-plan-authorization-infrastructure-files.js +19 -1
  103. package/src/generators/slice/built-in-plan-authorization-infrastructure-files.js.map +1 -1
  104. package/src/generators/slice/built-in-plan-data-files.js +16 -5
  105. package/src/generators/slice/built-in-plan-data-files.js.map +1 -1
  106. package/src/generators/slice/built-in-plan-data-retention-job-files.js +10 -6
  107. package/src/generators/slice/built-in-plan-data-retention-job-files.js.map +1 -1
  108. package/src/generators/slice/built-in-plan-database-lifecycle-files.js +25 -10
  109. package/src/generators/slice/built-in-plan-database-lifecycle-files.js.map +1 -1
  110. package/src/generators/slice/built-in-plan-foundation-files.js +2 -3
  111. package/src/generators/slice/built-in-plan-foundation-files.js.map +1 -1
  112. package/src/generators/slice/built-in-plan-infrastructure-files.js +364 -29
  113. package/src/generators/slice/built-in-plan-infrastructure-files.js.map +1 -1
  114. package/src/generators/slice/built-in-plan-infrastructure-safety-files.js +67 -11
  115. package/src/generators/slice/built-in-plan-infrastructure-safety-files.js.map +1 -1
  116. package/src/generators/slice/built-in-plan-metadata-files.js +1 -0
  117. package/src/generators/slice/built-in-plan-metadata-files.js.map +1 -1
  118. package/src/generators/slice/built-in-plan-operations-files.js +442 -5
  119. package/src/generators/slice/built-in-plan-operations-files.js.map +1 -1
  120. package/src/generators/slice/built-in-plan-performance-files.d.ts +2 -1
  121. package/src/generators/slice/built-in-plan-performance-files.js +41 -47
  122. package/src/generators/slice/built-in-plan-performance-files.js.map +1 -1
  123. package/src/generators/slice/built-in-plan-project-files.js +14 -1
  124. package/src/generators/slice/built-in-plan-project-files.js.map +1 -1
  125. package/src/generators/slice/built-in-plan-release-files.js +235 -56
  126. package/src/generators/slice/built-in-plan-release-files.js.map +1 -1
  127. package/src/generators/slice/built-in-plan-testing-files.js +92 -5
  128. package/src/generators/slice/built-in-plan-testing-files.js.map +1 -1
  129. package/src/generators/slice/built-in-plan-web-files.js +13 -0
  130. package/src/generators/slice/built-in-plan-web-files.js.map +1 -1
  131. package/src/generators/slice/built-in-plan-workload-role-files.js +5 -2
  132. package/src/generators/slice/built-in-plan-workload-role-files.js.map +1 -1
  133. package/src/generators/slice/built-in-plan.d.ts +2 -1
  134. package/src/generators/slice/built-in-plan.js +8 -5
  135. package/src/generators/slice/built-in-plan.js.map +1 -1
  136. package/src/generators/slice/slice.js +11 -3
  137. package/src/generators/slice/slice.js.map +1 -1
  138. package/src/generators/upgrade/upgrade.js +35 -0
  139. package/src/generators/upgrade/upgrade.js.map +1 -1
  140. package/src/generators/workload/frozen-container.d.ts +3 -2
  141. package/src/generators/workload/frozen-container.js +6 -4
  142. package/src/generators/workload/frozen-container.js.map +1 -1
  143. package/src/generators/workload/workload.js +2 -2
  144. package/src/generators/workload/workload.js.map +1 -1
  145. package/src/git-policy/github-bootstrap.d.ts +3 -1
  146. package/src/git-policy/github-bootstrap.js +22 -5
  147. package/src/git-policy/github-bootstrap.js.map +1 -1
  148. package/src/git-policy/routing.d.ts +2 -0
  149. package/src/git-policy/routing.js +12 -1
  150. package/src/git-policy/routing.js.map +1 -1
  151. package/src/infrastructure-change/local-capability.d.ts +73 -0
  152. package/src/infrastructure-change/local-capability.js +114 -0
  153. package/src/infrastructure-change/local-capability.js.map +1 -0
  154. package/src/infrastructure-change/model.d.ts +25 -4
  155. package/src/infrastructure-change/model.js +1 -0
  156. package/src/infrastructure-change/model.js.map +1 -1
  157. package/src/infrastructure-change/normalize.d.ts +4 -0
  158. package/src/infrastructure-change/normalize.js +47 -7
  159. package/src/infrastructure-change/normalize.js.map +1 -1
  160. package/src/infrastructure-change/plan.d.ts +30 -3
  161. package/src/infrastructure-change/plan.js +323 -13
  162. package/src/infrastructure-change/plan.js.map +1 -1
  163. package/src/infrastructure-change/risk.d.ts +3 -1
  164. package/src/infrastructure-change/risk.js +96 -16
  165. package/src/infrastructure-change/risk.js.map +1 -1
  166. package/src/local-dev/environment-inspector.d.ts +1 -0
  167. package/src/local-dev/environment-inspector.js +21 -9
  168. package/src/local-dev/environment-inspector.js.map +1 -1
  169. package/src/local-dev/private-state.d.ts +2 -0
  170. package/src/local-dev/private-state.js +3 -1
  171. package/src/local-dev/private-state.js.map +1 -1
  172. package/src/performance/cost-controls.d.ts +5 -3
  173. package/src/performance/cost-controls.js +30 -24
  174. package/src/performance/cost-controls.js.map +1 -1
  175. package/src/performance/model.d.ts +1 -1
  176. package/src/performance/model.js +0 -2
  177. package/src/performance/model.js.map +1 -1
  178. package/src/performance/test-fixtures.js +0 -2
  179. package/src/performance/test-fixtures.js.map +1 -1
  180. package/src/release/source-authority.d.ts +1 -0
  181. package/src/release/source-authority.js +136 -9
  182. package/src/release/source-authority.js.map +1 -1
  183. package/src/repository-policy/deployment-plan.d.ts +4 -1
  184. package/src/repository-policy/deployment-plan.js +8 -0
  185. package/src/repository-policy/deployment-plan.js.map +1 -1
  186. package/src/repository-policy/foundation-profile.js +1 -2
  187. package/src/repository-policy/foundation-profile.js.map +1 -1
  188. package/src/repository-policy/policy.d.ts +25 -1
  189. package/src/repository-policy/policy.js +145 -4
  190. package/src/repository-policy/policy.js.map +1 -1
  191. package/src/schemas/performance-policy-v1.json +0 -2
  192. package/src/schemas/repository-policy-v1.json +41 -0
  193. package/src/secrets/operator.js +22 -4
  194. package/src/secrets/operator.js.map +1 -1
  195. package/src/secrets/verification.js +9 -1
  196. package/src/secrets/verification.js.map +1 -1
  197. package/src/sst-environment-source-format.d.ts +3 -0
  198. package/src/sst-environment-source-format.js +179 -0
  199. package/src/sst-environment-source-format.js.map +1 -0
  200. package/src/supply-chain/blueprint-trust-git.js +72 -21
  201. package/src/supply-chain/blueprint-trust-git.js.map +1 -1
  202. package/src/supply-chain/blueprint-verification-authority.js +55 -3
  203. package/src/supply-chain/blueprint-verification-authority.js.map +1 -1
  204. package/src/supply-chain/blueprint-verification-execution.js +17 -2
  205. package/src/supply-chain/blueprint-verification-execution.js.map +1 -1
  206. package/src/supply-chain/build-output.d.ts +7 -1
  207. package/src/supply-chain/build-output.js +160 -20
  208. package/src/supply-chain/build-output.js.map +1 -1
  209. package/src/supply-chain/generated-command.js +131 -43
  210. package/src/supply-chain/generated-command.js.map +1 -1
  211. package/src/supply-chain/generated-container-release-command.js +187 -38
  212. package/src/supply-chain/generated-container-release-command.js.map +1 -1
  213. package/src/supply-chain/generated-ecr-collector-command.js +12 -2
  214. package/src/supply-chain/generated-ecr-collector-command.js.map +1 -1
  215. package/src/supply-chain/generated-scanner-command.js +114 -54
  216. package/src/supply-chain/generated-scanner-command.js.map +1 -1
  217. package/src/supply-chain/inventory.d.ts +17 -0
  218. package/src/supply-chain/inventory.js +114 -3
  219. package/src/supply-chain/inventory.js.map +1 -1
  220. package/src/supply-chain/pnpm-toolchain-authority.d.ts +4 -3
  221. package/src/supply-chain/pnpm-toolchain-authority.js +20 -34
  222. package/src/supply-chain/pnpm-toolchain-authority.js.map +1 -1
  223. package/src/supply-chain/policy.js +4 -1
  224. package/src/supply-chain/policy.js.map +1 -1
  225. package/src/supply-chain/sbom.d.ts +1 -1
  226. package/src/supply-chain/sbom.js +30 -5
  227. package/src/supply-chain/sbom.js.map +1 -1
  228. package/src/supply-chain/scanner.js +10 -1
  229. package/src/supply-chain/scanner.js.map +1 -1
  230. package/src/workload-roles/account-baseline.d.ts +11 -0
  231. package/src/workload-roles/account-baseline.js +253 -16
  232. package/src/workload-roles/account-baseline.js.map +1 -1
  233. package/src/workload-roles/authority.d.ts +3 -1
  234. package/src/workload-roles/authority.js +48 -2
  235. package/src/workload-roles/authority.js.map +1 -1
  236. package/src/workload-roles/aws-s3-state.js +27 -0
  237. package/src/workload-roles/aws-s3-state.js.map +1 -1
  238. package/src/workload-roles/boundary.d.ts +2 -1
  239. package/src/workload-roles/boundary.js +9 -2
  240. package/src/workload-roles/boundary.js.map +1 -1
  241. package/src/workload-roles/handler.js +52 -24
  242. package/src/workload-roles/handler.js.map +1 -1
  243. package/src/workload-roles/injection.js +1 -1
  244. package/src/workload-roles/injection.js.map +1 -1
  245. package/src/workload-roles/provisioner.js +12 -4
  246. package/src/workload-roles/provisioner.js.map +1 -1
  247. package/src/workload-roles/registration.d.ts +1 -0
  248. package/src/workload-roles/registration.js +5 -0
  249. package/src/workload-roles/registration.js.map +1 -1
  250. package/src/workload-roles/stage-boundary.js +1 -1
  251. package/src/workload-roles/stage-boundary.js.map +1 -1
  252. package/src/workload-roles/standard-slice.js +1 -0
  253. package/src/workload-roles/standard-slice.js.map +1 -1
@@ -0,0 +1,791 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderWorkspaceCiAcceptanceFiles = renderWorkspaceCiAcceptanceFiles;
4
+ function renderWorkspaceCiAcceptanceFiles() {
5
+ return {
6
+ 'tools/ci/workspace-acceptance.mjs': `import {
7
+ appendFileSync,
8
+ existsSync,
9
+ lstatSync,
10
+ mkdirSync,
11
+ readFileSync,
12
+ realpathSync,
13
+ writeFileSync,
14
+ } from 'node:fs';
15
+ import { spawnSync } from 'node:child_process';
16
+ import { createHash } from 'node:crypto';
17
+ import path from 'node:path';
18
+ import { pathToFileURL } from 'node:url';
19
+ import { inflateRawSync } from 'node:zlib';
20
+
21
+ const WORKFLOW = '.github/workflows/ci.yml';
22
+ const KIND = 'ebk-workspace-protected-route-acceptance';
23
+ const SCHEMA_VERSION = 2;
24
+ const MAX_ARCHIVE_BYTES = 1024 * 1024;
25
+ const MAX_MANIFEST_BYTES = 256 * 1024;
26
+ const ROUTES = Object.freeze({
27
+ 'protected-develop-promotion': Object.freeze({
28
+ base: 'main',
29
+ head: 'develop',
30
+ historyOnly: false,
31
+ }),
32
+ 'protected-main-sync': Object.freeze({
33
+ base: 'develop',
34
+ head: 'main',
35
+ historyOnly: true,
36
+ }),
37
+ });
38
+ const INPUTS = Object.freeze([
39
+ WORKFLOW,
40
+ '.node-version',
41
+ 'ebk.repository-policy.json',
42
+ 'package.json',
43
+ 'pnpm-lock.yaml',
44
+ 'supply-chain/blueprint-trust-policy.json',
45
+ 'supply-chain/blueprint-trust-snapshot.json',
46
+ ]);
47
+
48
+ function sha256(value) {
49
+ return createHash('sha256').update(value).digest('hex');
50
+ }
51
+
52
+ function artifactDigest(value) {
53
+ if (typeof value !== 'string' || !/^sha256:[a-f0-9]{64}$/u.test(value)) {
54
+ throw new Error('Workspace acceptance artifact digest is invalid.');
55
+ }
56
+ return value;
57
+ }
58
+
59
+ function artifactSize(value) {
60
+ if (!Number.isSafeInteger(value) || value < 1 || value > MAX_ARCHIVE_BYTES) {
61
+ throw new Error('Workspace acceptance artifact size is invalid.');
62
+ }
63
+ return value;
64
+ }
65
+
66
+ function artifactId(value) {
67
+ if (!Number.isSafeInteger(value) || value < 1) {
68
+ throw new Error('Workspace acceptance artifact identity is invalid.');
69
+ }
70
+ return String(value);
71
+ }
72
+
73
+ function file(root, relative, limit = 16 * 1024 * 1024) {
74
+ const absolute = path.join(root, relative);
75
+ const entry = lstatSync(absolute);
76
+ if (
77
+ entry.isSymbolicLink() ||
78
+ !entry.isFile() ||
79
+ entry.size < 1 ||
80
+ entry.size > limit
81
+ ) {
82
+ throw new Error(\`Workspace acceptance input is invalid: \${relative}\`);
83
+ }
84
+ return readFileSync(absolute);
85
+ }
86
+
87
+ function git(root, args) {
88
+ const result = spawnSync('git', ['-C', root, ...args], {
89
+ encoding: 'utf8',
90
+ shell: false,
91
+ windowsHide: true,
92
+ });
93
+ if (result.error || result.status !== 0) {
94
+ throw new Error(
95
+ \`Workspace acceptance git failed: \${result.stderr || result.error?.message}\`,
96
+ );
97
+ }
98
+ return result.stdout.trim();
99
+ }
100
+
101
+ function rootIdentity(requested) {
102
+ const root = realpathSync(requested);
103
+ if (root !== path.resolve(requested) || !lstatSync(root).isDirectory()) {
104
+ throw new Error('Workspace acceptance root is not canonical.');
105
+ }
106
+ const commit = git(root, ['rev-parse', 'HEAD']);
107
+ const tree = git(root, ['rev-parse', 'HEAD^{tree}']);
108
+ if (
109
+ !/^[a-f0-9]{40}$/u.test(commit) ||
110
+ !/^[a-f0-9]{40}$/u.test(tree) ||
111
+ git(root, ['status', '--porcelain=v1', '--untracked-files=no'])
112
+ ) {
113
+ throw new Error('Workspace acceptance source is invalid or dirty.');
114
+ }
115
+ return { root, source: { commit, tree } };
116
+ }
117
+
118
+ function digests(root) {
119
+ return Object.fromEntries(
120
+ INPUTS.map((relative) => [relative, sha256(file(root, relative))]),
121
+ );
122
+ }
123
+
124
+ function integer(value, label) {
125
+ if (typeof value !== 'string' || !/^[1-9]\\d{0,19}$/u.test(value)) {
126
+ throw new Error(\`Workspace acceptance \${label} is invalid.\`);
127
+ }
128
+ return value;
129
+ }
130
+
131
+ function commit(value, label) {
132
+ if (typeof value !== 'string' || !/^[a-f0-9]{40}$/u.test(value)) {
133
+ throw new Error(\`Workspace acceptance \${label} commit is invalid.\`);
134
+ }
135
+ return value;
136
+ }
137
+
138
+ function repository(value) {
139
+ if (
140
+ typeof value !== 'string' ||
141
+ value.length > 200 ||
142
+ !/^[A-Za-z0-9_.-]+\\/[A-Za-z0-9_.-]+$/u.test(value)
143
+ ) {
144
+ throw new Error('Workspace acceptance repository is invalid.');
145
+ }
146
+ return value;
147
+ }
148
+
149
+ // GitHub resolves pull_request workflows through an ephemeral merge ref. The
150
+ // workflow bytes and exact source tree are bound independently in the sealed
151
+ // manifest, while this check binds the observable GitHub route.
152
+ function isPullRequestWorkflowRef(value, expectedRepository) {
153
+ const prefix = \`\${expectedRepository}/\${WORKFLOW}@refs/pull/\`;
154
+ return (
155
+ typeof value === 'string' &&
156
+ value.startsWith(prefix) &&
157
+ /^[1-9]\\d{0,9}\\/merge$/u.test(value.slice(prefix.length))
158
+ );
159
+ }
160
+
161
+ function routeDefinition(value) {
162
+ if (typeof value !== 'string' || !Object.hasOwn(ROUTES, value)) {
163
+ throw new Error('Workspace acceptance route is invalid.');
164
+ }
165
+ return ROUTES[value];
166
+ }
167
+
168
+ function routeForBranches(base, head) {
169
+ const matches = Object.entries(ROUTES).filter(
170
+ ([, route]) => route.base === base && route.head === head,
171
+ );
172
+ if (matches.length !== 1) {
173
+ throw new Error('Workspace acceptance branch route is invalid.');
174
+ }
175
+ return { name: matches[0][0], ...matches[0][1] };
176
+ }
177
+
178
+ function routeForProtectedPush(ref) {
179
+ if (ref === 'refs/heads/main') {
180
+ return {
181
+ name: 'protected-develop-promotion',
182
+ ...ROUTES['protected-develop-promotion'],
183
+ };
184
+ }
185
+ if (ref === 'refs/heads/develop') {
186
+ return {
187
+ name: 'protected-main-sync',
188
+ ...ROUTES['protected-main-sync'],
189
+ };
190
+ }
191
+ throw new Error('Workspace merge lookup lacks protected branch authority.');
192
+ }
193
+
194
+ function canonical(value) {
195
+ if (Array.isArray(value)) return value.map(canonical);
196
+ if (value !== null && typeof value === 'object') {
197
+ return Object.fromEntries(
198
+ Object.keys(value)
199
+ .sort()
200
+ .map((key) => [key, canonical(value[key])]),
201
+ );
202
+ }
203
+ return value;
204
+ }
205
+
206
+ export function sealWorkspaceAcceptance({
207
+ environment,
208
+ output,
209
+ root: requested,
210
+ }) {
211
+ const { root, source } = rootIdentity(requested);
212
+ const expectedRepository = repository(environment.GITHUB_REPOSITORY);
213
+ const runId = integer(environment.GITHUB_RUN_ID, 'run id');
214
+ const runAttempt = integer(environment.GITHUB_RUN_ATTEMPT, 'run attempt');
215
+ const route = routeForBranches(
216
+ environment.GITHUB_BASE_REF,
217
+ environment.GITHUB_HEAD_REF,
218
+ );
219
+ const baseCommit = commit(environment.EBK_BASE_COMMIT, 'base');
220
+ const baseTree = git(root, ['rev-parse', \`\${baseCommit}^{tree}\`]);
221
+ if (
222
+ environment.GITHUB_EVENT_NAME !== 'pull_request' ||
223
+ environment.EBK_HEAD_REPOSITORY !== expectedRepository ||
224
+ !isPullRequestWorkflowRef(
225
+ environment.GITHUB_WORKFLOW_REF,
226
+ expectedRepository,
227
+ ) ||
228
+ environment.EBK_CI_CANDIDATE_SHA !== source.commit
229
+ ) {
230
+ throw new Error('Workspace acceptance is not an exact protected route.');
231
+ }
232
+ if (existsSync(output)) {
233
+ throw new Error('Workspace acceptance output already exists.');
234
+ }
235
+ if (route.historyOnly && baseTree !== source.tree) {
236
+ return Object.freeze({
237
+ base: route.base,
238
+ head: route.head,
239
+ historyOnly: true,
240
+ reason: 'protected main sync changes protected source',
241
+ route: route.name,
242
+ sealed: false,
243
+ });
244
+ }
245
+ const manifest = {
246
+ base: route.base,
247
+ baseSource: { commit: baseCommit, tree: baseTree },
248
+ eventName: 'pull_request',
249
+ head: route.head,
250
+ headRepository: expectedRepository,
251
+ historyOnly: route.historyOnly,
252
+ inputs: digests(root),
253
+ kind: KIND,
254
+ repository: expectedRepository,
255
+ route: route.name,
256
+ runAttempt,
257
+ runId,
258
+ schemaVersion: SCHEMA_VERSION,
259
+ source,
260
+ workflow: WORKFLOW,
261
+ };
262
+ mkdirSync(path.dirname(output), { recursive: true, mode: 0o700 });
263
+ writeFileSync(output, \`\${JSON.stringify(manifest, null, 2)}\\n\`, {
264
+ encoding: 'utf8',
265
+ mode: 0o600,
266
+ });
267
+ return manifest;
268
+ }
269
+
270
+ export function verifyWorkspaceAcceptance({
271
+ baseCommit: requestedBaseCommit,
272
+ headCommit,
273
+ manifestPath,
274
+ repository: requestedRepository,
275
+ root: requested,
276
+ route: requestedRoute,
277
+ runAttempt,
278
+ runId,
279
+ }) {
280
+ const { root, source } = rootIdentity(requested);
281
+ const expectedRepository = repository(requestedRepository);
282
+ const route = {
283
+ name: requestedRoute,
284
+ ...routeDefinition(requestedRoute),
285
+ };
286
+ runId = integer(runId, 'run id');
287
+ runAttempt = integer(runAttempt, 'run attempt');
288
+ const baseCommit = commit(requestedBaseCommit, 'base');
289
+ headCommit = commit(headCommit, 'head');
290
+ const baseTree = git(root, ['rev-parse', \`\${baseCommit}^{tree}\`]);
291
+ const headTree = git(root, ['rev-parse', \`\${headCommit}^{tree}\`]);
292
+ if (headTree !== source.tree) {
293
+ throw new Error(
294
+ 'Workspace acceptance head tree differs from the merged tree.',
295
+ );
296
+ }
297
+ if (route.historyOnly && baseTree !== headTree) {
298
+ throw new Error('Workspace acceptance sync changes protected source.');
299
+ }
300
+ const manifest = JSON.parse(
301
+ file(
302
+ path.dirname(manifestPath),
303
+ path.basename(manifestPath),
304
+ 256 * 1024,
305
+ ).toString('utf8'),
306
+ );
307
+ if (manifest?.kind !== KIND) {
308
+ throw new Error('Workspace acceptance kind is unsupported.');
309
+ }
310
+ if (manifest.schemaVersion !== SCHEMA_VERSION) {
311
+ throw new Error(
312
+ \`Workspace acceptance schema is unsupported; expected schema v\${SCHEMA_VERSION}.\`,
313
+ );
314
+ }
315
+ if (manifest.route !== route.name) {
316
+ throw new Error('Workspace acceptance route differs from the merged route.');
317
+ }
318
+ const expected = {
319
+ base: route.base,
320
+ baseSource: { commit: baseCommit, tree: baseTree },
321
+ eventName: 'pull_request',
322
+ head: route.head,
323
+ headRepository: expectedRepository,
324
+ historyOnly: route.historyOnly,
325
+ inputs: digests(root),
326
+ kind: KIND,
327
+ repository: expectedRepository,
328
+ route: route.name,
329
+ runAttempt,
330
+ runId,
331
+ schemaVersion: SCHEMA_VERSION,
332
+ source: { commit: headCommit, tree: headTree },
333
+ workflow: WORKFLOW,
334
+ };
335
+ if (
336
+ JSON.stringify(canonical(manifest)) !== JSON.stringify(canonical(expected))
337
+ ) {
338
+ throw new Error('Workspace acceptance differs from the merged tree.');
339
+ }
340
+ return manifest;
341
+ }
342
+
343
+ async function json(url, token, fetchImpl) {
344
+ const response = await fetchImpl(url, {
345
+ headers: {
346
+ Accept: 'application/vnd.github+json',
347
+ Authorization: \`Bearer \${token}\`,
348
+ 'X-GitHub-Api-Version': '2022-11-28',
349
+ },
350
+ });
351
+ const text = await response.text();
352
+ if (!response.ok || text.length > 2 * 1024 * 1024) {
353
+ throw new Error(\`GitHub acceptance lookup failed (\${response.status}).\`);
354
+ }
355
+ return JSON.parse(text);
356
+ }
357
+
358
+ async function boundedResponseBytes(response, limit) {
359
+ if (!response.ok || !response.body) {
360
+ throw new Error(
361
+ \`Workspace acceptance artifact download failed (\${response.status}).\`,
362
+ );
363
+ }
364
+ const reader = response.body.getReader();
365
+ const chunks = [];
366
+ let total = 0;
367
+ while (true) {
368
+ const { done, value } = await reader.read();
369
+ if (done) break;
370
+ if (!(value instanceof Uint8Array)) {
371
+ throw new Error('Workspace acceptance artifact stream is invalid.');
372
+ }
373
+ total += value.byteLength;
374
+ if (total > limit) {
375
+ await reader.cancel();
376
+ throw new Error('Workspace acceptance artifact exceeds its byte bound.');
377
+ }
378
+ chunks.push(Buffer.from(value));
379
+ }
380
+ if (total < 1) {
381
+ throw new Error('Workspace acceptance artifact is empty.');
382
+ }
383
+ return Buffer.concat(chunks, total);
384
+ }
385
+
386
+ function crc32(value) {
387
+ let crc = 0xffffffff;
388
+ for (const byte of value) {
389
+ crc ^= byte;
390
+ for (let bit = 0; bit < 8; bit += 1) {
391
+ crc = (crc >>> 1) ^ (0xedb88320 & -(crc & 1));
392
+ }
393
+ }
394
+ return (crc ^ 0xffffffff) >>> 0;
395
+ }
396
+
397
+ // The acceptance upload contains exactly one manifest. Parse that bounded ZIP
398
+ // directly so no unverified archive bytes reach a filesystem extractor.
399
+ function acceptanceManifestFromArchive(archive) {
400
+ const minimumEocd = 22;
401
+ const minimumOffset = Math.max(0, archive.length - 65_557);
402
+ let eocd = -1;
403
+ for (
404
+ let offset = archive.length - minimumEocd;
405
+ offset >= minimumOffset;
406
+ offset -= 1
407
+ ) {
408
+ if (
409
+ archive.readUInt32LE(offset) === 0x06054b50 &&
410
+ offset + minimumEocd + archive.readUInt16LE(offset + 20) ===
411
+ archive.length
412
+ ) {
413
+ eocd = offset;
414
+ break;
415
+ }
416
+ }
417
+ if (
418
+ eocd < 0 ||
419
+ archive.readUInt16LE(eocd + 4) !== 0 ||
420
+ archive.readUInt16LE(eocd + 6) !== 0 ||
421
+ archive.readUInt16LE(eocd + 8) !== 1 ||
422
+ archive.readUInt16LE(eocd + 10) !== 1
423
+ ) {
424
+ throw new Error('Workspace acceptance archive shape is invalid.');
425
+ }
426
+ const centralSize = archive.readUInt32LE(eocd + 12);
427
+ const centralOffset = archive.readUInt32LE(eocd + 16);
428
+ if (
429
+ centralOffset + centralSize !== eocd ||
430
+ centralSize < 46 ||
431
+ archive.readUInt32LE(centralOffset) !== 0x02014b50
432
+ ) {
433
+ throw new Error('Workspace acceptance central directory is invalid.');
434
+ }
435
+ const flags = archive.readUInt16LE(centralOffset + 8);
436
+ const method = archive.readUInt16LE(centralOffset + 10);
437
+ const expectedCrc = archive.readUInt32LE(centralOffset + 16);
438
+ const compressedSize = archive.readUInt32LE(centralOffset + 20);
439
+ const manifestSize = archive.readUInt32LE(centralOffset + 24);
440
+ const nameSize = archive.readUInt16LE(centralOffset + 28);
441
+ const extraSize = archive.readUInt16LE(centralOffset + 30);
442
+ const commentSize = archive.readUInt16LE(centralOffset + 32);
443
+ const disk = archive.readUInt16LE(centralOffset + 34);
444
+ const madeBy = archive.readUInt16LE(centralOffset + 4);
445
+ const externalAttributes = archive.readUInt32LE(centralOffset + 38);
446
+ const localOffset = archive.readUInt32LE(centralOffset + 42);
447
+ const centralEnd = centralOffset + 46 + nameSize + extraSize + commentSize;
448
+ const name = archive
449
+ .subarray(centralOffset + 46, centralOffset + 46 + nameSize)
450
+ .toString('utf8');
451
+ const unixMode = madeBy >>> 8 === 3 ? externalAttributes >>> 16 : 0;
452
+ if (
453
+ centralEnd !== eocd ||
454
+ name !== 'manifest.json' ||
455
+ disk !== 0 ||
456
+ (flags & ~0x0808) !== 0 ||
457
+ (method !== 0 && method !== 8) ||
458
+ compressedSize < 1 ||
459
+ manifestSize < 1 ||
460
+ manifestSize > MAX_MANIFEST_BYTES ||
461
+ (unixMode !== 0 && (unixMode & 0o170000) !== 0o100000) ||
462
+ localOffset + 30 > centralOffset ||
463
+ archive.readUInt32LE(localOffset) !== 0x04034b50 ||
464
+ archive.readUInt16LE(localOffset + 6) !== flags ||
465
+ archive.readUInt16LE(localOffset + 8) !== method
466
+ ) {
467
+ throw new Error('Workspace acceptance archive entry is invalid.');
468
+ }
469
+ const localNameSize = archive.readUInt16LE(localOffset + 26);
470
+ const localExtraSize = archive.readUInt16LE(localOffset + 28);
471
+ const localNameStart = localOffset + 30;
472
+ const localNameEnd = localNameStart + localNameSize;
473
+ const dataStart = localNameEnd + localExtraSize;
474
+ const dataEnd = dataStart + compressedSize;
475
+ if (
476
+ localNameSize !== nameSize ||
477
+ archive.subarray(localNameStart, localNameEnd).toString('utf8') !== name ||
478
+ dataEnd > centralOffset
479
+ ) {
480
+ throw new Error('Workspace acceptance local archive entry is invalid.');
481
+ }
482
+ const compressed = archive.subarray(dataStart, dataEnd);
483
+ const manifest =
484
+ method === 0
485
+ ? Buffer.from(compressed)
486
+ : inflateRawSync(compressed, {
487
+ maxOutputLength: MAX_MANIFEST_BYTES,
488
+ });
489
+ if (manifest.length !== manifestSize || crc32(manifest) !== expectedCrc) {
490
+ throw new Error('Workspace acceptance manifest archive authority differs.');
491
+ }
492
+ return manifest;
493
+ }
494
+
495
+ export async function downloadWorkspaceAcceptance({
496
+ artifactDigest: requestedDigest,
497
+ artifactId: requestedId,
498
+ artifactSize: requestedSize,
499
+ environment,
500
+ fetchImpl = fetch,
501
+ output,
502
+ }) {
503
+ const expectedRepository = repository(environment.GITHUB_REPOSITORY);
504
+ const token = environment.GH_TOKEN;
505
+ const id = integer(requestedId, 'artifact id');
506
+ const digest = artifactDigest(requestedDigest);
507
+ const size = Number(integer(requestedSize, 'artifact size'));
508
+ artifactSize(size);
509
+ if (typeof token !== 'string' || token.length < 1) {
510
+ throw new Error('Workspace acceptance download token is missing.');
511
+ }
512
+ const api = environment.GITHUB_API_URL ?? 'https://api.github.com';
513
+ const response = await fetchImpl(
514
+ \`\${api}/repos/\${expectedRepository}/actions/artifacts/\${id}/zip\`,
515
+ {
516
+ headers: {
517
+ Accept: 'application/vnd.github+json',
518
+ Authorization: \`Bearer \${token}\`,
519
+ 'X-GitHub-Api-Version': '2022-11-28',
520
+ },
521
+ redirect: 'follow',
522
+ },
523
+ );
524
+ const archive = await boundedResponseBytes(response, MAX_ARCHIVE_BYTES);
525
+ if (archive.length !== size || \`sha256:\${sha256(archive)}\` !== digest) {
526
+ throw new Error(
527
+ 'Workspace acceptance archive differs from GitHub authority.',
528
+ );
529
+ }
530
+ const manifest = acceptanceManifestFromArchive(archive);
531
+ if (existsSync(output)) {
532
+ throw new Error('Workspace acceptance restore output already exists.');
533
+ }
534
+ mkdirSync(output, { recursive: true, mode: 0o700 });
535
+ writeFileSync(path.join(output, 'manifest.json'), manifest, {
536
+ mode: 0o600,
537
+ });
538
+ return { digest, id, size };
539
+ }
540
+
541
+ // Declining reuse is always safe: the complete verification lane runs. Reuse
542
+ // is claimed only when one exact protected route, the identical reviewed tree,
543
+ // one successful workflow run, and one retained artifact all agree.
544
+ export async function resolveWorkspaceAcceptance({
545
+ environment,
546
+ fetchImpl = fetch,
547
+ root: requested,
548
+ }) {
549
+ const { root, source } = rootIdentity(requested);
550
+ const expectedRepository = repository(environment.GITHUB_REPOSITORY);
551
+ const token = environment.GH_TOKEN;
552
+ const route = routeForProtectedPush(environment.GITHUB_REF);
553
+ if (
554
+ typeof token !== 'string' ||
555
+ token.length < 1 ||
556
+ environment.GITHUB_EVENT_NAME !== 'push' ||
557
+ environment.GITHUB_SHA !== source.commit
558
+ ) {
559
+ throw new Error('Workspace merge lookup lacks protected-push authority.');
560
+ }
561
+ const api = environment.GITHUB_API_URL ?? 'https://api.github.com';
562
+ try {
563
+ const pulls = await json(
564
+ \`\${api}/repos/\${expectedRepository}/commits/\${source.commit}/pulls\`,
565
+ token,
566
+ fetchImpl,
567
+ );
568
+ const eligible = pulls.filter(
569
+ (pull) =>
570
+ pull?.merged_at &&
571
+ pull?.merge_commit_sha === source.commit &&
572
+ pull?.base?.ref === route.base &&
573
+ pull?.head?.ref === route.head &&
574
+ pull?.head?.repo?.full_name === expectedRepository,
575
+ );
576
+ if (eligible.length !== 1) {
577
+ return {
578
+ reason: \`eligible \${route.name} merges: \${eligible.length}\`,
579
+ reused: false,
580
+ };
581
+ }
582
+ const pull = eligible[0];
583
+ const headCommit = pull.head?.sha;
584
+ if (
585
+ typeof headCommit !== 'string' ||
586
+ !/^[a-f0-9]{40}$/u.test(headCommit)
587
+ ) {
588
+ return {
589
+ reason: 'protected-route head commit is not exact',
590
+ reused: false,
591
+ };
592
+ }
593
+ const mergeParents = git(root, [
594
+ 'rev-list',
595
+ '--parents',
596
+ '-n',
597
+ '1',
598
+ source.commit,
599
+ ]).split(' ');
600
+ if (
601
+ mergeParents.length !== 3 ||
602
+ mergeParents[0] !== source.commit ||
603
+ mergeParents[2] !== headCommit
604
+ ) {
605
+ return {
606
+ reason: 'protected-route merge parents are not exact',
607
+ reused: false,
608
+ };
609
+ }
610
+ const baseCommit = mergeParents[1];
611
+ const baseTree = git(root, ['rev-parse', \`\${baseCommit}^{tree}\`]);
612
+ const headTree = git(root, ['rev-parse', \`\${headCommit}^{tree}\`]);
613
+ if (headTree !== source.tree) {
614
+ return {
615
+ reason: 'merged tree differs from the reviewed protected-route tree',
616
+ reused: false,
617
+ };
618
+ }
619
+ if (route.historyOnly && baseTree !== headTree) {
620
+ return {
621
+ reason: 'protected-main-sync changes protected source',
622
+ reused: false,
623
+ };
624
+ }
625
+ const query = new URL(
626
+ \`\${api}/repos/\${expectedRepository}/actions/workflows/ci.yml/runs\`,
627
+ );
628
+ query.searchParams.set('event', 'pull_request');
629
+ query.searchParams.set('head_sha', headCommit);
630
+ query.searchParams.set('status', 'success');
631
+ query.searchParams.set('per_page', '100');
632
+ const observed = await json(query.href, token, fetchImpl);
633
+ // GitHub may clear a completed run's associated pull_requests array after
634
+ // the pull request merges. The exact merged PR was already established by
635
+ // the commit lookup above; bind its reviewed head to the protected workflow
636
+ // run directly instead of relying on that unstable, redundant association.
637
+ const runs = observed.workflow_runs.filter(
638
+ (run) =>
639
+ run?.conclusion === 'success' &&
640
+ run?.event === 'pull_request' &&
641
+ run?.head_sha === headCommit &&
642
+ run?.head_branch === route.head &&
643
+ run?.head_repository?.full_name === expectedRepository &&
644
+ run?.path === WORKFLOW &&
645
+ Number.isSafeInteger(run.id) &&
646
+ Number.isSafeInteger(run.run_attempt),
647
+ );
648
+ runs.sort(
649
+ (left, right) =>
650
+ right.run_attempt - left.run_attempt || right.id - left.id,
651
+ );
652
+ for (const run of runs) {
653
+ const artifactName = \`workspace-acceptance-\${headCommit}-\${run.id}-\${run.run_attempt}\`;
654
+ const retained = await json(
655
+ \`\${api}/repos/\${expectedRepository}/actions/runs/\${run.id}/artifacts?per_page=100\`,
656
+ token,
657
+ fetchImpl,
658
+ );
659
+ const artifacts = Array.isArray(retained?.artifacts)
660
+ ? retained.artifacts.filter(
661
+ (artifact) =>
662
+ artifact?.name === artifactName && artifact?.expired === false,
663
+ )
664
+ : [];
665
+ if (artifacts.length === 1) {
666
+ const [artifact] = artifacts;
667
+ const id = artifactId(artifact.id);
668
+ const digest = artifactDigest(artifact.digest);
669
+ const size = String(artifactSize(artifact.size_in_bytes));
670
+ if (
671
+ artifact.archive_download_url !==
672
+ \`\${api}/repos/\${expectedRepository}/actions/artifacts/\${id}/zip\` ||
673
+ artifact.workflow_run?.id !== run.id ||
674
+ artifact.workflow_run?.head_sha !== headCommit
675
+ ) {
676
+ continue;
677
+ }
678
+ return {
679
+ artifactDigest: digest,
680
+ artifactId: id,
681
+ artifactName,
682
+ artifactSize: size,
683
+ baseCommit,
684
+ headCommit,
685
+ historyOnly: route.historyOnly,
686
+ reused: true,
687
+ route: route.name,
688
+ runAttempt: String(run.run_attempt),
689
+ runId: String(run.id),
690
+ };
691
+ }
692
+ }
693
+ return {
694
+ reason:
695
+ 'no successful protected-route run retains the acceptance artifact',
696
+ reused: false,
697
+ };
698
+ } catch (error) {
699
+ return {
700
+ reason: \`acceptance resolution failed: \${error?.message ?? error}\`,
701
+ reused: false,
702
+ };
703
+ }
704
+ }
705
+
706
+ async function main(argv) {
707
+ const [operation, ...args] = argv;
708
+ if (operation === 'seal' && args.length === 1) {
709
+ const result = sealWorkspaceAcceptance({
710
+ environment: process.env,
711
+ output: path.resolve(args[0]),
712
+ root: process.cwd(),
713
+ });
714
+ const output = process.env.GITHUB_OUTPUT;
715
+ if (typeof output !== 'string' || !path.isAbsolute(output)) {
716
+ throw new Error('Workspace acceptance output authority is missing.');
717
+ }
718
+ appendFileSync(output, \`sealed=\${String(result.sealed !== false)}\\n\`, 'utf8');
719
+ if (result.sealed === false) {
720
+ console.log(
721
+ \`::warning title=Protected sync evidence declined::\${result.reason}; no reusable acceptance artifact was sealed.\`,
722
+ );
723
+ }
724
+ return;
725
+ }
726
+ if (operation === 'verify' && args.length === 6) {
727
+ verifyWorkspaceAcceptance({
728
+ baseCommit: args[2],
729
+ headCommit: args[1],
730
+ manifestPath: path.resolve(args[0]),
731
+ repository: process.env.GITHUB_REPOSITORY,
732
+ root: process.cwd(),
733
+ route: args[3],
734
+ runAttempt: args[5],
735
+ runId: args[4],
736
+ });
737
+ return;
738
+ }
739
+ if (operation === 'download' && args.length === 4) {
740
+ await downloadWorkspaceAcceptance({
741
+ artifactDigest: args[2],
742
+ artifactId: args[1],
743
+ artifactSize: args[3],
744
+ environment: process.env,
745
+ output: path.resolve(args[0]),
746
+ });
747
+ return;
748
+ }
749
+ if (operation === 'resolve' && args.length === 0) {
750
+ const result = await resolveWorkspaceAcceptance({
751
+ environment: process.env,
752
+ root: process.cwd(),
753
+ });
754
+ const output = process.env.GITHUB_OUTPUT;
755
+ if (typeof output !== 'string' || !path.isAbsolute(output)) {
756
+ throw new Error('Workspace acceptance output authority is missing.');
757
+ }
758
+ if (result.reused !== true && result.reason) {
759
+ console.warn(
760
+ \`Workspace acceptance reuse declined (\${result.reason}); the complete verification lane runs instead.\`,
761
+ );
762
+ }
763
+ for (const [name, value] of Object.entries({
764
+ artifact_digest: result.artifactDigest ?? '',
765
+ artifact_id: result.artifactId ?? '',
766
+ artifact_name: result.artifactName ?? '',
767
+ artifact_size: result.artifactSize ?? '',
768
+ base_commit: result.baseCommit ?? '',
769
+ head_commit: result.headCommit ?? '',
770
+ history_only: String(result.historyOnly === true),
771
+ reused: String(result.reused),
772
+ route: result.route ?? '',
773
+ run_attempt: result.runAttempt ?? '',
774
+ run_id: result.runId ?? '',
775
+ })) {
776
+ appendFileSync(output, \`\${name}=\${value}\\n\`, 'utf8');
777
+ }
778
+ return;
779
+ }
780
+ throw new Error(
781
+ 'Usage: workspace-acceptance.mjs seal <manifest> | download <output> <artifact-id> <artifact-digest> <artifact-size> | verify <manifest> <head> <base> <route> <run> <attempt> | resolve',
782
+ );
783
+ }
784
+
785
+ if (import.meta.url === pathToFileURL(process.argv[1] ?? '').href) {
786
+ await main(process.argv.slice(2));
787
+ }
788
+ `,
789
+ };
790
+ }
791
+ //# sourceMappingURL=workspace-files-ci-acceptance.js.map