@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
@@ -6,6 +6,8 @@ function renderSupplyChainCheckCommand() {
6
6
  createSupplyChainInventory,
7
7
  createInstalledLicenseFindings,
8
8
  createSupplyChainScannerInput,
9
+ assertWorkspaceImporterCoverage,
10
+ deriveWorkspaceManifestPathsFromPnpmLock,
9
11
  discoverLifecycleScripts,
10
12
  evaluateSupplyChainPolicy,
11
13
  frameworkActionPinInventory,
@@ -15,6 +17,7 @@ function renderSupplyChainCheckCommand() {
15
17
  assertSupplyChainScannerSubject,
16
18
  requireActiveVendoredSourceRegistry,
17
19
  validateReviewedBuildPermissions,
20
+ workspacePackageGlobs,
18
21
  vendoredSourceRegistryDigest,
19
22
  verifyActionPinInventory,
20
23
  } from '@empire-builder-kit/nx/supply-chain';
@@ -164,48 +167,51 @@ function hasExactKeys(value, keys) {
164
167
  );
165
168
  }
166
169
 
167
- function workspaceManifests() {
168
- const listed = spawnSync(
169
- 'pnpm',
170
- ['list', '--recursive', '--depth=-1', '--json'],
171
- {
172
- cwd: workspaceRoot,
173
- encoding: 'utf8',
174
- maxBuffer: MAX_INPUT_BYTES,
175
- shell: false,
176
- },
177
- );
178
- if (listed.status !== 0) {
179
- throw new Error(
180
- 'pnpm workspace inventory failed: ' +
181
- String(listed.stderr || listed.stdout).trim().slice(0, 2_000),
182
- );
183
- }
184
- let projects;
185
- try {
186
- const parsed = JSON.parse(listed.stdout);
187
- projects = Array.isArray(parsed) ? parsed : [parsed];
188
- } catch {
189
- throw new Error('pnpm workspace inventory did not return JSON.');
190
- }
191
- if (projects.length === 0 || projects.length > 2_000) {
192
- throw new Error('pnpm workspace inventory is empty or exceeds 2,000 projects.');
193
- }
194
- const manifests = {};
195
- for (const [index, project] of projects.entries()) {
196
- if (!project || typeof project !== 'object' || typeof project.path !== 'string') {
197
- throw new Error('pnpm workspace project ' + index + ' has no exact path.');
170
+ function discoverGlobbedManifestPaths(globs) {
171
+ // Walk only the directory depth each glob declares so a manifest present on
172
+ // disk but absent from the lockfile importers is still observed.
173
+ const discovered = new Set();
174
+ const walk = (segments, index, prefix) => {
175
+ if (index === segments.length) {
176
+ const manifest = prefix ? prefix + '/package.json' : 'package.json';
177
+ if (existsSync(insideWorkspace(manifest))) discovered.add(manifest);
178
+ return;
179
+ }
180
+ const segment = segments[index];
181
+ const directory = prefix ? insideWorkspace(prefix) : workspaceRoot;
182
+ if (!existsSync(directory) || !statSync(directory).isDirectory()) return;
183
+ if (segment === '*' || segment === '**') {
184
+ for (const entry of readdirSync(directory, { withFileTypes: true })) {
185
+ if (!entry.isDirectory() || entry.name.startsWith('.')) continue;
186
+ if (entry.name === 'node_modules') continue;
187
+ const next = prefix ? prefix + '/' + entry.name : entry.name;
188
+ walk(segments, index + 1, next);
189
+ if (segment === '**') walk(segments, index, next);
190
+ }
191
+ return;
198
192
  }
199
- const root = realpathSync(insideWorkspace(project.path));
200
- const child = relative(workspaceRoot, root);
201
- if (child === '..' || child.startsWith('..' + sep)) {
202
- throw new Error('pnpm workspace project escapes the repository.');
193
+ if (segment.includes('*')) {
194
+ throw new Error(
195
+ 'Workspace package glob segment ' + segment + ' is not supported by the manifest drift sweep.',
196
+ );
203
197
  }
204
- const path = (child ? child.split(sep).join('/') + '/' : '') + 'package.json';
205
- manifests[path] = readJson(path);
198
+ walk(segments, index + 1, prefix ? prefix + '/' + segment : segment);
199
+ };
200
+ for (const glob of globs) {
201
+ walk(glob.split('/').filter((segment) => segment !== '' && segment !== '.'), 0, '');
206
202
  }
207
- if (!Object.hasOwn(manifests, 'package.json')) {
208
- manifests['package.json'] = readJson('package.json');
203
+ return [...discovered];
204
+ }
205
+
206
+ function workspaceManifests(lockfile, workspacePolicy) {
207
+ const importerPaths = deriveWorkspaceManifestPathsFromPnpmLock(lockfile);
208
+ assertWorkspaceImporterCoverage(
209
+ discoverGlobbedManifestPaths(workspacePackageGlobs(workspacePolicy)),
210
+ importerPaths,
211
+ );
212
+ const manifests = {};
213
+ for (const path of importerPaths) {
214
+ manifests[path] = readJson(path);
209
215
  }
210
216
  return manifests;
211
217
  }
@@ -254,6 +260,7 @@ const ignoredDirectories = new Set([
254
260
  '.nx',
255
261
  '.open-next',
256
262
  '.sst',
263
+ '.venv',
257
264
  'coverage',
258
265
  'dist',
259
266
  'node_modules',
@@ -392,6 +399,11 @@ const workspacePolicy = readBounded(
392
399
  MAX_INPUT_BYTES,
393
400
  'pnpm workspace policy',
394
401
  );
402
+ const lockfile = readBounded(
403
+ 'pnpm-lock.yaml',
404
+ MAX_LOCK_BYTES,
405
+ 'pnpm lockfile',
406
+ );
395
407
  const packageMetadata = installedPackageMetadata();
396
408
  const lifecycleScripts = discoverLifecycleScripts(packageMetadata);
397
409
  const buildPermissions = records(
@@ -434,8 +446,8 @@ const inventory = createSupplyChainInventory({
434
446
  'supply-chain/downloaded-tools.json',
435
447
  ),
436
448
  lifecycleScripts,
437
- lockfile: readBounded('pnpm-lock.yaml', MAX_LOCK_BYTES, 'pnpm lockfile'),
438
- manifests: workspaceManifests(),
449
+ lockfile,
450
+ manifests: workspaceManifests(lockfile, workspacePolicy),
439
451
  nodeVersion: readBounded(
440
452
  '.node-version',
441
453
  64,
@@ -464,7 +476,7 @@ const containerInventoryDigest = digest({
464
476
  if (options.protected) {
465
477
  const normalizedScanner = createSupplyChainScannerInput(scannerInput);
466
478
  const requiredCoverage = [
467
- ...(inventory.resolvedPackages.length > 0 ? ['npm'] : []),
479
+ 'npm',
468
480
  ...(inventory.containers.length > 0 || workflowContainers.length > 0
469
481
  ? ['container']
470
482
  : []),
@@ -486,6 +498,78 @@ if (options.protected) {
486
498
  resultDigests.push(reference);
487
499
  const result = JSON.parse(bytes);
488
500
  if (reference.coverage === 'npm') {
501
+ const packageManager =
502
+ /^pnpm@(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)\+sha512\.[a-f0-9]{128}$/.exec(
503
+ inventory.packageManager,
504
+ );
505
+ if (!packageManager?.[1]) {
506
+ throw new Error(
507
+ 'Supply-chain inventory package manager is not one exact pnpm authority.',
508
+ );
509
+ }
510
+ const expectedPackageManagerInput = {
511
+ results: [
512
+ {
513
+ packages: [
514
+ {
515
+ package: {
516
+ ecosystem: 'npm',
517
+ name: 'pnpm',
518
+ version: packageManager[1],
519
+ },
520
+ },
521
+ ],
522
+ },
523
+ ],
524
+ };
525
+ const expectedPackageManagerInputBytes =
526
+ JSON.stringify(expectedPackageManagerInput, null, 2) + '\n';
527
+ if (
528
+ !hasExactKeys(result, [
529
+ 'kind',
530
+ 'lockfile',
531
+ 'packageManager',
532
+ 'schemaVersion',
533
+ ]) ||
534
+ result.kind !== 'ebk-osv-npm-results' ||
535
+ result.schemaVersion !== 1 ||
536
+ !hasExactKeys(result.packageManager, [
537
+ 'authority',
538
+ 'input',
539
+ 'inputSha256',
540
+ 'result',
541
+ ]) ||
542
+ result.packageManager.authority !== inventory.packageManager ||
543
+ JSON.stringify(canonical(result.packageManager.input)) !==
544
+ JSON.stringify(canonical(expectedPackageManagerInput)) ||
545
+ result.packageManager.inputSha256 !==
546
+ digest(expectedPackageManagerInputBytes)
547
+ ) {
548
+ throw new Error(
549
+ 'npm scanner result does not bind the exact package-manager authority and custom input.',
550
+ );
551
+ }
552
+ const packageManagerResults = result.packageManager.result;
553
+ const scannedPackageManagers =
554
+ packageManagerResults && Array.isArray(packageManagerResults.results)
555
+ ? packageManagerResults.results.flatMap((entry) =>
556
+ entry && Array.isArray(entry.packages)
557
+ ? entry.packages
558
+ .map((scanned) => scanned?.package)
559
+ .filter(Boolean)
560
+ : [],
561
+ )
562
+ : [];
563
+ if (
564
+ scannedPackageManagers.length !== 1 ||
565
+ scannedPackageManagers[0].ecosystem !== 'npm' ||
566
+ scannedPackageManagers[0].name !== 'pnpm' ||
567
+ scannedPackageManagers[0].version !== packageManager[1]
568
+ ) {
569
+ throw new Error(
570
+ 'npm scanner result does not prove the exact package-manager scan.',
571
+ );
572
+ }
489
573
  normalizedVulnerabilities.push(
490
574
  ...normalizeOsvScannerResults({
491
575
  coverage: 'npm',
@@ -494,7 +578,11 @@ if (options.protected) {
494
578
  resultGroups: [
495
579
  {
496
580
  context: { releases: [], scope: 'unknown', slices: [] },
497
- document: result,
581
+ document: result.lockfile,
582
+ },
583
+ {
584
+ context: { releases: [], scope: 'unknown', slices: [] },
585
+ document: packageManagerResults,
498
586
  },
499
587
  ],
500
588
  }),
@@ -1 +1 @@
1
- {"version":3,"file":"generated-command.js","sourceRoot":"","sources":["../../../../../packages/nx/src/supply-chain/generated-command.ts"],"names":[],"mappings":";;AAAA,sEA0qBC;AA1qBD,SAAgB,6BAA6B;IAC3C,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwqBlB,CAAC;AACF,CAAC"}
1
+ {"version":3,"file":"generated-command.js","sourceRoot":"","sources":["../../../../../packages/nx/src/supply-chain/generated-command.ts"],"names":[],"mappings":";;AAAA,sEAkwBC;AAlwBD,SAAgB,6BAA6B;IAC3C,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgwBlB,CAAC;AACF,CAAC"}
@@ -6,6 +6,16 @@ const generated_ecr_collector_command_js_1 = require("./generated-ecr-collector-
6
6
  const safe_reference_1 = require("@empire-builder-kit/runtime/safe-reference");
7
7
  exports.CRANE_VERSION = '0.21.7';
8
8
  exports.CRANE_RELEASES = Object.freeze({
9
+ 'darwin-arm64': {
10
+ archiveFormat: 'tar-gzip',
11
+ sha256: '1858c55dcd6053fe869bcb0c4ec20666383ddce445ad0f7e15e1e506b1f7fe52',
12
+ source: 'https://github.com/google/go-containerregistry/releases/download/v0.21.7/go-containerregistry_Darwin_arm64.tar.gz',
13
+ },
14
+ 'darwin-x64': {
15
+ archiveFormat: 'tar-gzip',
16
+ sha256: '63a7dd15168d4dcac37933c7f6745438f2943d5898a1cf7896ad3341d8519bf2',
17
+ source: 'https://github.com/google/go-containerregistry/releases/download/v0.21.7/go-containerregistry_Darwin_x86_64.tar.gz',
18
+ },
9
19
  'linux-arm64': {
10
20
  archiveFormat: 'tar-gzip',
11
21
  sha256: 'b6ee979d9411dfb05ce35ab9e156fe5de7def11a230764a7856ffa2eb971fa88',
@@ -19,7 +29,7 @@ exports.CRANE_RELEASES = Object.freeze({
19
29
  });
20
30
  function validatedReleases(releases) {
21
31
  if (Object.keys(releases).length === 0 ||
22
- Object.entries(releases).some(([platform, release]) => !/^linux-(?:arm64|x64)$/.test(platform) ||
32
+ Object.entries(releases).some(([platform, release]) => !/^(?:darwin|linux)-(?:arm64|x64)$/.test(platform) ||
23
33
  !['binary', 'tar-gzip'].includes(release.archiveFormat) ||
24
34
  !/^[a-f0-9]{64}$/.test(release.sha256) ||
25
35
  !/^https:\/\/github\.com\/anchore\/syft\/releases\/download\/v\d+\.\d+\.\d+\/[A-Za-z0-9._-]+$/.test(release.source))) {
@@ -29,10 +39,10 @@ function validatedReleases(releases) {
29
39
  }
30
40
  function validatedCraneReleases(releases) {
31
41
  if (Object.keys(releases).length === 0 ||
32
- Object.entries(releases).some(([platform, release]) => !/^linux-(?:arm64|x64)$/.test(platform) ||
42
+ Object.entries(releases).some(([platform, release]) => !/^(?:darwin|linux)-(?:arm64|x64)$/.test(platform) ||
33
43
  release.archiveFormat !== 'tar-gzip' ||
34
44
  !/^[a-f0-9]{64}$/.test(release.sha256) ||
35
- !/^https:\/\/github\.com\/google\/go-containerregistry\/releases\/download\/v\d+\.\d+\.\d+\/go-containerregistry_Linux_(?:arm64|x86_64)\.tar\.gz$/.test(release.source))) {
45
+ !/^https:\/\/github\.com\/google\/go-containerregistry\/releases\/download\/v\d+\.\d+\.\d+\/go-containerregistry_(?:Darwin|Linux)_(?:arm64|x86_64)\.tar\.gz$/.test(release.source))) {
36
46
  throw new Error('Container-release Crane assets must be exact official integrity-bound releases.');
37
47
  }
38
48
  return releases;
@@ -129,23 +139,82 @@ const sourceCommit =
129
139
  const stage = process.env.EBK_STAGE?.trim() ?? '';
130
140
  const accountId = process.env.AWS_EXPECTED_ACCOUNT_ID?.trim() ?? '';
131
141
  const region = process.env.AWS_REGION?.trim() ?? '';
132
- const runId = process.env.GITHUB_RUN_ID?.trim() ?? '';
133
- const runAttempt = process.env.GITHUB_RUN_ATTEMPT?.trim() ?? '';
134
- const workflow = process.env.GITHUB_WORKFLOW_REF?.trim() ?? '';
142
+ const packageRegistryInput =
143
+ process.env.EBK_CONTAINER_PACKAGE_REGISTRY?.trim() ?? '';
144
+ const localFederated =
145
+ process.env.GITHUB_ACTIONS !== 'true' &&
146
+ process.env.EBK_LOCAL_DEPLOYMENT_MODE === 'federated';
147
+ if (localFederated) {
148
+ const policy = JSON.parse(
149
+ readFileSync(join(repositoryRoot, 'ebk.repository-policy.json'), 'utf8'),
150
+ );
151
+ if (
152
+ policy.deploymentProfile !== 'starter' ||
153
+ stage === 'production' ||
154
+ policy.deploymentAccounts?.[stage] !== accountId ||
155
+ policy.deploymentRegion !== region
156
+ ) {
157
+ throw new Error(
158
+ 'Local container release requires a locally admitted exact starter deployment target; production requires protected GitHub authority.',
159
+ );
160
+ }
161
+ }
162
+ const runId = localFederated
163
+ ? (BigInt('0x' + sourceCommit.slice(0, 15)) + 1n).toString()
164
+ : process.env.GITHUB_RUN_ID?.trim() ?? '';
165
+ const runAttempt = localFederated
166
+ ? '1'
167
+ : process.env.GITHUB_RUN_ATTEMPT?.trim() ?? '';
168
+ const workflow = localFederated
169
+ ? 'local-federated/' + stage + '/' + accountId + '/' + region
170
+ : process.env.GITHUB_WORKFLOW_REF?.trim() ?? '';
135
171
  if (
136
172
  !COMMIT.test(deploymentSourceCommit) ||
137
173
  !COMMIT.test(sourceCommit) ||
138
174
  !['development', 'staging', 'production'].includes(stage) ||
139
175
  !/^\\d{12}$/.test(accountId) ||
140
176
  !AWS_REGION_NAME.test(region) ||
177
+ (!localFederated && process.env.GITHUB_ACTIONS !== 'true') ||
141
178
  !/^[1-9]\\d*$/.test(runId) ||
142
179
  !/^[1-9]\\d*$/.test(runAttempt) ||
143
180
  !REFERENCE.test(workflow)
144
181
  ) {
145
182
  throw new Error(
146
- 'Container release requires one exact protected source, run, account, Region, and stage.',
183
+ 'Container release requires one exact GitHub or local-federated source, run, account, Region, and stage.',
147
184
  );
148
185
  }
186
+ const packageRegistry = (() => {
187
+ if (packageRegistryInput === '') return undefined;
188
+ if (packageRegistryInput.length > 2_048) {
189
+ throw new Error('Container package registry authority is invalid.');
190
+ }
191
+ let parsed;
192
+ try {
193
+ parsed = new URL(packageRegistryInput);
194
+ } catch {
195
+ throw new Error('Container package registry authority is invalid.');
196
+ }
197
+ const normalized = parsed.href;
198
+ const canonicalInput =
199
+ packageRegistryInput === normalized ||
200
+ packageRegistryInput + '/' === normalized;
201
+ const localPlaintext =
202
+ parsed.protocol === 'http:' &&
203
+ ['127.0.0.1', 'localhost', 'host.docker.internal', '[::1]'].includes(
204
+ parsed.hostname,
205
+ );
206
+ if (
207
+ !canonicalInput ||
208
+ (parsed.protocol !== 'https:' && !localPlaintext) ||
209
+ parsed.username !== '' ||
210
+ parsed.password !== '' ||
211
+ parsed.search !== '' ||
212
+ parsed.hash !== ''
213
+ ) {
214
+ throw new Error('Container package registry authority is invalid.');
215
+ }
216
+ return normalized.endsWith('/') ? normalized.slice(0, -1) : normalized;
217
+ })();
149
218
  const requireReviewedCheckout = () => {
150
219
  validateReviewedReleaseCheckout({
151
220
  deploymentSourceCommit,
@@ -332,11 +401,12 @@ const describeRepository = (repositoryName) => {
332
401
  throw new Error('ECR repository lookup returned invalid JSON.');
333
402
  }
334
403
  }
335
- const error = String(result.stderr ?? '');
404
+ const error = String(result.stderr ?? '').trimStart();
405
+ const notFound =
406
+ 'An error occurred (RepositoryNotFoundException) when calling the DescribeRepositories operation:';
336
407
  if (
337
- !error.startsWith(
338
- 'An error occurred (RepositoryNotFoundException) when calling the DescribeRepositories operation:',
339
- )
408
+ !error.startsWith(notFound) &&
409
+ !error.startsWith('aws: [ERROR]: ' + notFound)
340
410
  ) {
341
411
  throw new Error('ECR repository lookup failed outside the create-if-absent path.');
342
412
  }
@@ -792,7 +862,7 @@ const acquireCrane = async () => {
792
862
  const parseCycloneDx = (value, label) => {
793
863
  if (
794
864
  value?.bomFormat !== 'CycloneDX' ||
795
- value.specVersion !== '1.6' ||
865
+ value.specVersion !== '1.7' ||
796
866
  value.version !== 1 ||
797
867
  !/^urn:uuid:[a-fA-F0-9-]{36}$/.test(value.serialNumber ?? '') ||
798
868
  !Array.isArray(value.components) ||
@@ -801,17 +871,30 @@ const parseCycloneDx = (value, label) => {
801
871
  !value.metadata ||
802
872
  typeof value.metadata !== 'object'
803
873
  ) {
804
- throw new Error(label + ' is not complete CycloneDX 1.6.');
874
+ throw new Error(label + ' is not complete CycloneDX 1.7.');
805
875
  }
806
876
  return value;
807
877
  };
878
+ const isVersionlessSyftFileComponent = (component) =>
879
+ component?.type === 'file' &&
880
+ component.version === undefined &&
881
+ component.purl === undefined &&
882
+ typeof component.name === 'string' &&
883
+ component.name.startsWith('/') &&
884
+ component.name.length <= 4_096 &&
885
+ Array.isArray(component.hashes) &&
886
+ component.hashes.length === 2 &&
887
+ component.hashes[0]?.alg === 'SHA-1' &&
888
+ /^[a-f0-9]{40}$/.test(component.hashes[0]?.content ?? '') &&
889
+ component.hashes[1]?.alg === 'SHA-256' &&
890
+ /^[a-f0-9]{64}$/.test(component.hashes[1]?.content ?? '');
808
891
  const componentSetFor = (sbom) =>
809
892
  sbom.components
810
893
  .map((component) => ({
811
894
  name: component?.name,
812
895
  purl: component?.purl ?? '',
813
896
  type: component?.type,
814
- version: component?.version,
897
+ version: component?.version ?? '',
815
898
  }))
816
899
  .sort((left, right) =>
817
900
  JSON.stringify(left) < JSON.stringify(right)
@@ -881,8 +964,12 @@ const deriveExpectedProductionClosure = (syft, input) => {
881
964
  execute(
882
965
  'pnpm',
883
966
  [
967
+ '--config.store-dir=' +
968
+ safePath('.ebk/cache/pnpm-store', 'Workspace pnpm store'),
969
+ '--config.inject-workspace-packages=true',
884
970
  '--filter',
885
971
  input.packageName,
972
+ '--trust-lockfile',
886
973
  'deploy',
887
974
  '--prod',
888
975
  '--offline',
@@ -906,18 +993,51 @@ const deriveExpectedProductionClosure = (syft, input) => {
906
993
  } catch {
907
994
  throw new Error('Independent production closure inventory is invalid JSON.');
908
995
  }
996
+ const sourceManifest = readJson(
997
+ input.packageManifestPath,
998
+ 'Container package manifest',
999
+ );
1000
+ const deployedManifest = readJson(
1001
+ join(deployed, 'package.json'),
1002
+ 'Deployed container package manifest',
1003
+ );
1004
+ if (
1005
+ sourceManifest.name !== input.packageName ||
1006
+ typeof sourceManifest.version !== 'string' ||
1007
+ sourceManifest.version.length === 0 ||
1008
+ sourceManifest.version.length > 128 ||
1009
+ deployedManifest.name !== sourceManifest.name ||
1010
+ deployedManifest.version !== sourceManifest.version
1011
+ ) {
1012
+ throw new Error(
1013
+ 'Independent production closure changed the workload package identity.',
1014
+ );
1015
+ }
909
1016
  const packages = npmClosureFor(inventory);
910
1017
  if (
911
- !packages.some(
1018
+ packages.some(
912
1019
  ({ name, version }) =>
913
- name === input.packageName &&
914
- version === readJson(
915
- input.packageManifestPath,
916
- 'Container package manifest',
917
- ).version,
1020
+ name === sourceManifest.name && version !== sourceManifest.version,
918
1021
  )
919
1022
  ) {
920
- throw new Error('Independent production closure omits the workload package.');
1023
+ throw new Error(
1024
+ 'Independent production closure contains a conflicting workload package identity.',
1025
+ );
1026
+ }
1027
+ if (!packages.some(({ name }) => name === sourceManifest.name)) {
1028
+ packages.push({
1029
+ name: sourceManifest.name,
1030
+ version: sourceManifest.version,
1031
+ });
1032
+ packages.sort(
1033
+ (left, right) =>
1034
+ (left.name < right.name ? -1 : left.name > right.name ? 1 : 0) ||
1035
+ (left.version < right.version
1036
+ ? -1
1037
+ : left.version > right.version
1038
+ ? 1
1039
+ : 0),
1040
+ );
921
1041
  }
922
1042
  return { digest: supplyChainDigest(packages), packages };
923
1043
  } finally {
@@ -1210,13 +1330,26 @@ if (stage === 'development') {
1210
1330
  process.env.EBK_STAGING_PROMOTION_EXPECTED_ACCOUNT_ID?.trim() ?? '';
1211
1331
  const expectedSourceRegion =
1212
1332
  process.env.EBK_STAGING_PROMOTION_REGION?.trim() ?? '';
1333
+ const deploymentProfile = process.env.EBK_DEPLOYMENT_PROFILE?.trim() ?? '';
1334
+ if (
1335
+ deploymentProfile !== 'starter' &&
1336
+ deploymentProfile !== 'production-isolated' &&
1337
+ deploymentProfile !== 'fully-isolated'
1338
+ ) {
1339
+ throw new Error('Container promotion requires one exact deployment profile.');
1340
+ }
1341
+ const sameAccountPromotion = deploymentProfile === 'starter';
1213
1342
  if (
1214
1343
  !/^\\d{12}$/.test(expectedSourceAccountId) ||
1215
1344
  !AWS_REGION_NAME.test(expectedSourceRegion) ||
1216
- expectedSourceAccountId === accountId
1345
+ (sameAccountPromotion
1346
+ ? expectedSourceAccountId !== accountId || expectedSourceRegion !== region
1347
+ : expectedSourceAccountId === accountId)
1217
1348
  ) {
1218
1349
  throw new Error(
1219
- 'Development retirement promotion requires one independent staging account and Region.',
1350
+ sameAccountPromotion
1351
+ ? 'Starter promotion requires the exact shared account and Region.'
1352
+ : 'Isolated promotion requires one independent staging account and exact Region.',
1220
1353
  );
1221
1354
  }
1222
1355
  const sourceBindingPath = safePath(
@@ -1310,13 +1443,26 @@ if (mode === 'promote') {
1310
1443
  process.env.EBK_STAGING_PROMOTION_EXPECTED_ACCOUNT_ID?.trim() ?? '';
1311
1444
  const expectedSourceRegion =
1312
1445
  process.env.EBK_STAGING_PROMOTION_REGION?.trim() ?? '';
1446
+ const deploymentProfile = process.env.EBK_DEPLOYMENT_PROFILE?.trim() ?? '';
1447
+ if (
1448
+ deploymentProfile !== 'starter' &&
1449
+ deploymentProfile !== 'production-isolated' &&
1450
+ deploymentProfile !== 'fully-isolated'
1451
+ ) {
1452
+ throw new Error('OCI promotion requires one exact deployment profile.');
1453
+ }
1454
+ const sameAccountPromotion = deploymentProfile === 'starter';
1313
1455
  if (
1314
1456
  !/^\\d{12}$/.test(expectedSourceAccountId) ||
1315
1457
  !AWS_REGION_NAME.test(expectedSourceRegion) ||
1316
- expectedSourceAccountId === accountId
1458
+ (sameAccountPromotion
1459
+ ? expectedSourceAccountId !== accountId || expectedSourceRegion !== region
1460
+ : expectedSourceAccountId === accountId)
1317
1461
  ) {
1318
1462
  throw new Error(
1319
- 'OCI promotion requires one bounded independent staging account and Region.',
1463
+ sameAccountPromotion
1464
+ ? 'Starter OCI promotion requires the exact shared account and Region.'
1465
+ : 'Isolated OCI promotion requires one bounded independent staging account and exact Region.',
1320
1466
  );
1321
1467
  }
1322
1468
  const sourceBindingInput =
@@ -1591,15 +1737,6 @@ if (mode === 'promote') {
1591
1737
  }
1592
1738
 
1593
1739
  if (mode === 'platform') {
1594
- const nativeArchitecture = process.arch === 'x64' ? 'amd64' : process.arch;
1595
- if (
1596
- process.platform !== 'linux' ||
1597
- requestedPlatform !== 'linux/' + nativeArchitecture
1598
- ) {
1599
- throw new Error(
1600
- 'Platform evidence must run on the matching native Linux architecture.',
1601
- );
1602
- }
1603
1740
  const syft = await acquireSyft();
1604
1741
  const crane = stage === 'development' ? await acquireCrane() : undefined;
1605
1742
  try {
@@ -1656,6 +1793,12 @@ if (mode === 'platform') {
1656
1793
  [
1657
1794
  'buildx',
1658
1795
  'build',
1796
+ ...(packageRegistry
1797
+ ? [
1798
+ '--build-arg',
1799
+ 'NPM_CONFIG_REGISTRY=' + packageRegistry,
1800
+ ]
1801
+ : []),
1659
1802
  '--file',
1660
1803
  relative(repositoryRoot, input.dockerfile),
1661
1804
  '--label',
@@ -1796,14 +1939,20 @@ if (mode === 'platform') {
1796
1939
  }
1797
1940
  const componentSet = componentSetFor(sbom);
1798
1941
  if (
1799
- componentSet.some(
1942
+ sbom.components.some(
1800
1943
  (component) =>
1801
- typeof component.name !== 'string' ||
1944
+ typeof component?.name !== 'string' ||
1945
+ component.name.length === 0 ||
1802
1946
  typeof component.type !== 'string' ||
1803
- typeof component.version !== 'string',
1947
+ component.type.length === 0 ||
1948
+ !(
1949
+ (typeof component.version === 'string' &&
1950
+ component.version.length > 0) ||
1951
+ isVersionlessSyftFileComponent(component)
1952
+ ),
1804
1953
  )
1805
1954
  ) {
1806
- throw new Error('Platform SBOM contains invalid or development components.');
1955
+ throw new Error('Platform SBOM contains an invalid component identity.');
1807
1956
  }
1808
1957
  const serializedSbom = JSON.stringify(sbom, null, 2) + '\\n';
1809
1958
  const relativeSbomPath =
@@ -1 +1 @@
1
- {"version":3,"file":"generated-container-release-command.js","sourceRoot":"","sources":["../../../../../packages/nx/src/supply-chain/generated-container-release-command.ts"],"names":[],"mappings":"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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA08D1E,CAAC;AACF,CAAC"}
1
+ {"version":3,"file":"generated-container-release-command.js","sourceRoot":"","sources":["../../../../../packages/nx/src/supply-chain/generated-container-release-command.ts"],"names":[],"mappings":"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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqlE1E,CAAC;AACF,CAAC"}
@@ -6,6 +6,16 @@ const common_js_1 = require("./common.js");
6
6
  const safe_reference_1 = require("@empire-builder-kit/runtime/safe-reference");
7
7
  exports.SYFT_VERSION = '1.50.0';
8
8
  exports.SYFT_COLLECTOR_RELEASES = Object.freeze({
9
+ 'darwin-arm64': {
10
+ archiveFormat: 'tar-gzip',
11
+ sha256: 'e32fdb9d47823fa633748a1efca2528fd77c37469ea93c9e40ab835da44e4cce',
12
+ source: 'https://github.com/anchore/syft/releases/download/v1.50.0/syft_1.50.0_darwin_arm64.tar.gz',
13
+ },
14
+ 'darwin-x64': {
15
+ archiveFormat: 'tar-gzip',
16
+ sha256: 'd11a8c7bc27114853bd7c1e1b2f3be3ddda3a1de17aee585329f04c369341c75',
17
+ source: 'https://github.com/anchore/syft/releases/download/v1.50.0/syft_1.50.0_darwin_amd64.tar.gz',
18
+ },
9
19
  'linux-arm64': {
10
20
  archiveFormat: 'tar-gzip',
11
21
  sha256: '887c57cbcc2d0e8c5c110a4571a3fc7150058b24d74f993ee4663516e5c8ce86',
@@ -934,7 +944,7 @@ try {
934
944
  }
935
945
  if (
936
946
  sbom?.bomFormat !== 'CycloneDX' ||
937
- sbom.specVersion !== '1.6' ||
947
+ sbom.specVersion !== '1.7' ||
938
948
  sbom.version !== 1 ||
939
949
  typeof sbom.serialNumber !== 'string' ||
940
950
  !/^urn:uuid:[a-fA-F0-9-]{36}$/.test(sbom.serialNumber) ||
@@ -945,7 +955,7 @@ try {
945
955
  typeof sbom.metadata !== 'object'
946
956
  ) {
947
957
  throw new Error(
948
- 'Syft output is not complete CycloneDX 1.6 evidence for ' +
958
+ 'Syft output is not complete CycloneDX 1.7 evidence for ' +
949
959
  platform.platform + '.',
950
960
  );
951
961
  }