@cyclonedx/cdxgen 12.3.0 → 12.3.2

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 (121) hide show
  1. package/README.md +15 -5
  2. package/bin/audit.js +7 -0
  3. package/bin/cdxgen.js +241 -81
  4. package/bin/repl.js +138 -0
  5. package/data/rules/ai-agent-governance.yaml +249 -0
  6. package/data/rules/dependency-sources.yaml +41 -0
  7. package/data/rules/mcp-servers.yaml +304 -0
  8. package/data/rules/package-integrity.yaml +123 -0
  9. package/lib/audit/index.js +353 -29
  10. package/lib/audit/index.poku.js +247 -7
  11. package/lib/audit/reporters.js +26 -0
  12. package/lib/audit/scoring.js +262 -13
  13. package/lib/audit/scoring.poku.js +179 -0
  14. package/lib/audit/targets.js +391 -2
  15. package/lib/audit/targets.poku.js +416 -3
  16. package/lib/cli/index.js +588 -45
  17. package/lib/cli/index.poku.js +735 -1
  18. package/lib/evinser/evinser.js +8 -5
  19. package/lib/helpers/agentFormulationParser.js +318 -0
  20. package/lib/helpers/aiInventory.js +262 -0
  21. package/lib/helpers/aiInventory.poku.js +111 -0
  22. package/lib/helpers/analyzer.js +1769 -0
  23. package/lib/helpers/analyzer.poku.js +284 -3
  24. package/lib/helpers/auditCategories.js +76 -0
  25. package/lib/helpers/ciParsers/githubActions.js +140 -16
  26. package/lib/helpers/ciParsers/githubActions.poku.js +110 -0
  27. package/lib/helpers/communityAiConfigParser.js +672 -0
  28. package/lib/helpers/communityAiConfigParser.poku.js +63 -0
  29. package/lib/helpers/depsUtils.js +108 -0
  30. package/lib/helpers/depsUtils.poku.js +72 -1
  31. package/lib/helpers/display.js +325 -3
  32. package/lib/helpers/display.poku.js +301 -0
  33. package/lib/helpers/formulationParsers.js +28 -0
  34. package/lib/helpers/formulationParsers.poku.js +504 -1
  35. package/lib/helpers/jsonLike.js +102 -0
  36. package/lib/helpers/jsonLike.poku.js +34 -0
  37. package/lib/helpers/mcp.js +248 -0
  38. package/lib/helpers/mcp.poku.js +101 -0
  39. package/lib/helpers/mcpConfigParser.js +656 -0
  40. package/lib/helpers/mcpConfigParser.poku.js +126 -0
  41. package/lib/helpers/mcpDiscovery.js +84 -0
  42. package/lib/helpers/mcpDiscovery.poku.js +21 -0
  43. package/lib/helpers/protobom.js +3 -3
  44. package/lib/helpers/provenanceUtils.js +29 -4
  45. package/lib/helpers/provenanceUtils.poku.js +29 -3
  46. package/lib/helpers/registryProvenance.js +210 -0
  47. package/lib/helpers/registryProvenance.poku.js +144 -0
  48. package/lib/helpers/rustFormulationParser.js +330 -0
  49. package/lib/helpers/source.js +21 -2
  50. package/lib/helpers/source.poku.js +38 -0
  51. package/lib/helpers/utils.js +1331 -83
  52. package/lib/helpers/utils.poku.js +599 -188
  53. package/lib/helpers/vsixutils.js +12 -4
  54. package/lib/helpers/vsixutils.poku.js +34 -0
  55. package/lib/managers/binary.js +36 -12
  56. package/lib/managers/binary.poku.js +68 -0
  57. package/lib/managers/docker.js +59 -9
  58. package/lib/managers/docker.poku.js +61 -0
  59. package/lib/managers/piptree.js +12 -7
  60. package/lib/managers/piptree.poku.js +44 -0
  61. package/lib/stages/postgen/annotator.js +2 -1
  62. package/lib/stages/postgen/annotator.poku.js +15 -0
  63. package/lib/stages/postgen/auditBom.js +20 -6
  64. package/lib/stages/postgen/auditBom.poku.js +694 -1
  65. package/lib/stages/postgen/postgen.js +262 -11
  66. package/lib/stages/postgen/postgen.poku.js +306 -2
  67. package/lib/stages/postgen/ruleEngine.js +49 -1
  68. package/lib/stages/postgen/spdxConverter.poku.js +70 -0
  69. package/lib/stages/pregen/pregen.js +6 -4
  70. package/package.json +1 -1
  71. package/types/bin/repl.d.ts.map +1 -1
  72. package/types/lib/audit/index.d.ts.map +1 -1
  73. package/types/lib/audit/reporters.d.ts.map +1 -1
  74. package/types/lib/audit/scoring.d.ts.map +1 -1
  75. package/types/lib/audit/targets.d.ts +12 -0
  76. package/types/lib/audit/targets.d.ts.map +1 -1
  77. package/types/lib/cli/index.d.ts +2 -8
  78. package/types/lib/cli/index.d.ts.map +1 -1
  79. package/types/lib/evinser/evinser.d.ts.map +1 -1
  80. package/types/lib/helpers/agentFormulationParser.d.ts +19 -0
  81. package/types/lib/helpers/agentFormulationParser.d.ts.map +1 -0
  82. package/types/lib/helpers/aiInventory.d.ts +23 -0
  83. package/types/lib/helpers/aiInventory.d.ts.map +1 -0
  84. package/types/lib/helpers/analyzer.d.ts +10 -0
  85. package/types/lib/helpers/analyzer.d.ts.map +1 -1
  86. package/types/lib/helpers/auditCategories.d.ts +12 -0
  87. package/types/lib/helpers/auditCategories.d.ts.map +1 -0
  88. package/types/lib/helpers/ciParsers/githubActions.d.ts.map +1 -1
  89. package/types/lib/helpers/communityAiConfigParser.d.ts +29 -0
  90. package/types/lib/helpers/communityAiConfigParser.d.ts.map +1 -0
  91. package/types/lib/helpers/depsUtils.d.ts +8 -0
  92. package/types/lib/helpers/depsUtils.d.ts.map +1 -1
  93. package/types/lib/helpers/display.d.ts +17 -1
  94. package/types/lib/helpers/display.d.ts.map +1 -1
  95. package/types/lib/helpers/formulationParsers.d.ts.map +1 -1
  96. package/types/lib/helpers/jsonLike.d.ts +4 -0
  97. package/types/lib/helpers/jsonLike.d.ts.map +1 -0
  98. package/types/lib/helpers/mcp.d.ts +29 -0
  99. package/types/lib/helpers/mcp.d.ts.map +1 -0
  100. package/types/lib/helpers/mcpConfigParser.d.ts +30 -0
  101. package/types/lib/helpers/mcpConfigParser.d.ts.map +1 -0
  102. package/types/lib/helpers/mcpDiscovery.d.ts +5 -0
  103. package/types/lib/helpers/mcpDiscovery.d.ts.map +1 -0
  104. package/types/lib/helpers/provenanceUtils.d.ts +5 -3
  105. package/types/lib/helpers/provenanceUtils.d.ts.map +1 -1
  106. package/types/lib/helpers/registryProvenance.d.ts +9 -0
  107. package/types/lib/helpers/registryProvenance.d.ts.map +1 -1
  108. package/types/lib/helpers/rustFormulationParser.d.ts +17 -0
  109. package/types/lib/helpers/rustFormulationParser.d.ts.map +1 -0
  110. package/types/lib/helpers/source.d.ts.map +1 -1
  111. package/types/lib/helpers/utils.d.ts +31 -1
  112. package/types/lib/helpers/utils.d.ts.map +1 -1
  113. package/types/lib/helpers/vsixutils.d.ts.map +1 -1
  114. package/types/lib/managers/binary.d.ts.map +1 -1
  115. package/types/lib/managers/docker.d.ts.map +1 -1
  116. package/types/lib/managers/piptree.d.ts.map +1 -1
  117. package/types/lib/stages/postgen/annotator.d.ts.map +1 -1
  118. package/types/lib/stages/postgen/auditBom.d.ts.map +1 -1
  119. package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
  120. package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
  121. package/types/lib/stages/pregen/pregen.d.ts.map +1 -1
@@ -1,3 +1,4 @@
1
+ import esmock from "esmock";
1
2
  import { assert, describe, it } from "poku";
2
3
 
3
4
  import {
@@ -7,11 +8,12 @@ import {
7
8
  normalizePackageName,
8
9
  } from "./targets.js";
9
10
 
10
- function makeBom(components) {
11
+ function makeBom(components, extra = {}) {
11
12
  return {
12
13
  bomFormat: "CycloneDX",
13
14
  components,
14
15
  specVersion: "1.6",
16
+ ...extra,
15
17
  };
16
18
  }
17
19
 
@@ -25,7 +27,7 @@ describe("normalizePackageName()", () => {
25
27
  });
26
28
 
27
29
  describe("extractPurlTargetsFromBom()", () => {
28
- it("extracts only npm and pypi purls", () => {
30
+ it("extracts supported npm, pypi, and cargo purls", () => {
29
31
  const bom = makeBom([
30
32
  {
31
33
  "bom-ref": "pkg:npm/left-pad@1.3.0",
@@ -41,6 +43,12 @@ describe("extractPurlTargetsFromBom()", () => {
41
43
  name: "requests",
42
44
  purl: "pkg:pypi/requests@2.32.3",
43
45
  },
46
+ {
47
+ "bom-ref": "pkg:cargo/serde@1.0.217",
48
+ name: "serde",
49
+ properties: [{ name: "cdx:cargo:dependencyKind", value: "dev" }],
50
+ purl: "pkg:cargo/serde@1.0.217",
51
+ },
44
52
  {
45
53
  "bom-ref": "pkg:gem/rails@8.0.0",
46
54
  name: "rails",
@@ -50,7 +58,7 @@ describe("extractPurlTargetsFromBom()", () => {
50
58
 
51
59
  const extracted = extractPurlTargetsFromBom(bom, "bom.json");
52
60
 
53
- assert.strictEqual(extracted.targets.length, 2);
61
+ assert.strictEqual(extracted.targets.length, 3);
54
62
  assert.strictEqual(extracted.skipped.length, 1);
55
63
  assert.strictEqual(extracted.targets[0].type, "npm");
56
64
  assert.strictEqual(
@@ -62,6 +70,8 @@ describe("extractPurlTargetsFromBom()", () => {
62
70
  "cdx:npm:provenanceKeyId",
63
71
  );
64
72
  assert.strictEqual(extracted.targets[1].type, "pypi");
73
+ assert.strictEqual(extracted.targets[2].type, "cargo");
74
+ assert.strictEqual(extracted.targets[2].developmentOnly, true);
65
75
  assert.strictEqual(extracted.skipped[0].reason, "unsupported-ecosystem");
66
76
  });
67
77
 
@@ -132,6 +142,110 @@ describe("collectAuditTargets()", () => {
132
142
  assert.strictEqual(npmTarget.properties.length, 2);
133
143
  });
134
144
 
145
+ it("recognizes Cargo trusted-publishing and target-specific metadata", () => {
146
+ const inputBoms = [
147
+ {
148
+ bomJson: makeBom([
149
+ {
150
+ "bom-ref": "pkg:cargo/ring@0.17.8",
151
+ name: "ring",
152
+ properties: [
153
+ { name: "cdx:cargo:target", value: 'cfg(target_os = "linux")' },
154
+ { name: "cdx:cargo:trustedPublishing", value: "true" },
155
+ ],
156
+ purl: "pkg:cargo/ring@0.17.8",
157
+ },
158
+ {
159
+ "bom-ref": "pkg:cargo/serde@1.0.217",
160
+ name: "serde",
161
+ purl: "pkg:cargo/serde@1.0.217",
162
+ },
163
+ ]),
164
+ source: "cargo-trusted.json",
165
+ },
166
+ ];
167
+
168
+ const collected = collectAuditTargets(inputBoms, { trusted: "include" });
169
+
170
+ assert.deepStrictEqual(
171
+ collected.targets.map((target) => target.purl),
172
+ ["pkg:cargo/serde@1.0.217", "pkg:cargo/ring@0.17.8"],
173
+ );
174
+ assert.strictEqual(collected.stats.trustedTargets, 1);
175
+ assert.strictEqual(collected.stats.platformSpecificTargets, 1);
176
+ });
177
+
178
+ it("prioritizes runtime-facing Cargo crates ahead of build-only workspace crates", () => {
179
+ const inputBoms = [
180
+ {
181
+ bomJson: makeBom(
182
+ [
183
+ {
184
+ "bom-ref": "pkg:cargo/root@1.0.0",
185
+ name: "root",
186
+ purl: "pkg:cargo/root@1.0.0",
187
+ },
188
+ {
189
+ "bom-ref": "pkg:cargo/runtime-helper@1.0.0",
190
+ name: "runtime-helper",
191
+ properties: [
192
+ { name: "cdx:cargo:dependencyKind", value: "runtime" },
193
+ {
194
+ name: "cdx:cargo:workspaceDependencyResolved",
195
+ value: "true",
196
+ },
197
+ ],
198
+ purl: "pkg:cargo/runtime-helper@1.0.0",
199
+ },
200
+ {
201
+ "bom-ref": "pkg:cargo/build-helper@1.0.0",
202
+ name: "build-helper",
203
+ properties: [
204
+ { name: "cdx:cargo:dependencyKind", value: "build" },
205
+ {
206
+ name: "cdx:cargo:workspaceDependencyResolved",
207
+ value: "true",
208
+ },
209
+ ],
210
+ purl: "pkg:cargo/build-helper@1.0.0",
211
+ },
212
+ ],
213
+ {
214
+ dependencies: [
215
+ {
216
+ ref: "pkg:cargo/root@1.0.0",
217
+ dependsOn: [
218
+ "pkg:cargo/runtime-helper@1.0.0",
219
+ "pkg:cargo/build-helper@1.0.0",
220
+ ],
221
+ },
222
+ ],
223
+ metadata: {
224
+ component: {
225
+ "bom-ref": "pkg:cargo/root@1.0.0",
226
+ },
227
+ },
228
+ },
229
+ ),
230
+ source: "cargo-priority.json",
231
+ },
232
+ ];
233
+
234
+ const collected = collectAuditTargets(inputBoms, {
235
+ maxTargets: 2,
236
+ trusted: "include",
237
+ });
238
+
239
+ assert.deepStrictEqual(
240
+ collected.targets.map((target) => target.purl),
241
+ ["pkg:cargo/runtime-helper@1.0.0", "pkg:cargo/build-helper@1.0.0"],
242
+ );
243
+ assert.strictEqual(collected.targets[0].runtimeFacingCargo, true);
244
+ assert.strictEqual(collected.targets[1].buildOnlyWorkspace, true);
245
+ assert.strictEqual(collected.stats.buildOnlyWorkspaceTargets, 1);
246
+ assert.strictEqual(collected.stats.cargoRuntimeFacingTargets, 1);
247
+ });
248
+
135
249
  it("respects maxTargets when supplied", () => {
136
250
  const inputBoms = [
137
251
  {
@@ -226,6 +340,162 @@ describe("collectAuditTargets()", () => {
226
340
  assert.strictEqual(collected.stats.truncatedTargets, 1);
227
341
  });
228
342
 
343
+ it("can prioritize direct runtime dependencies ahead of transitive platform-specific packages", () => {
344
+ const inputBoms = [
345
+ {
346
+ bomJson: makeBom(
347
+ [
348
+ {
349
+ "bom-ref": "pkg:npm/direct-runtime@1.0.0",
350
+ name: "direct-runtime",
351
+ purl: "pkg:npm/direct-runtime@1.0.0",
352
+ scope: "required",
353
+ },
354
+ {
355
+ "bom-ref": "pkg:npm/transitive-platform@1.0.0",
356
+ name: "transitive-platform",
357
+ properties: [{ name: "cdx:npm:os", value: "darwin" }],
358
+ purl: "pkg:npm/transitive-platform@1.0.0",
359
+ },
360
+ ],
361
+ {
362
+ dependencies: [
363
+ {
364
+ dependsOn: ["pkg:npm/direct-runtime@1.0.0"],
365
+ ref: "pkg:application/root-app@1.0.0",
366
+ },
367
+ ],
368
+ metadata: {
369
+ component: {
370
+ "bom-ref": "pkg:application/root-app@1.0.0",
371
+ name: "root-app",
372
+ type: "application",
373
+ },
374
+ },
375
+ },
376
+ ),
377
+ source: "priority-runtime.json",
378
+ },
379
+ ];
380
+
381
+ const collected = collectAuditTargets(inputBoms, {
382
+ maxTargets: 1,
383
+ prioritizeDirectRuntime: true,
384
+ trusted: "include",
385
+ });
386
+
387
+ assert.strictEqual(collected.targets.length, 1);
388
+ assert.strictEqual(
389
+ collected.targets[0].purl,
390
+ "pkg:npm/direct-runtime@1.0.0",
391
+ );
392
+ assert.strictEqual(collected.targets[0].directDependency, true);
393
+ assert.strictEqual(collected.stats.directRuntimeTargets, 1);
394
+ assert.strictEqual(collected.stats.platformSpecificTargets, 1);
395
+ });
396
+
397
+ it("prioritizes direct runtime dependencies by default", () => {
398
+ const inputBoms = [
399
+ {
400
+ bomJson: makeBom(
401
+ [
402
+ {
403
+ "bom-ref": "pkg:npm/direct-runtime@1.0.0",
404
+ name: "direct-runtime",
405
+ purl: "pkg:npm/direct-runtime@1.0.0",
406
+ scope: "required",
407
+ },
408
+ {
409
+ "bom-ref": "pkg:npm/transitive-platform@1.0.0",
410
+ name: "transitive-platform",
411
+ properties: [{ name: "cdx:npm:os", value: "darwin" }],
412
+ purl: "pkg:npm/transitive-platform@1.0.0",
413
+ },
414
+ ],
415
+ {
416
+ dependencies: [
417
+ {
418
+ dependsOn: ["pkg:npm/direct-runtime@1.0.0"],
419
+ ref: "pkg:application/root-app@1.0.0",
420
+ },
421
+ ],
422
+ metadata: {
423
+ component: {
424
+ "bom-ref": "pkg:application/root-app@1.0.0",
425
+ name: "root-app",
426
+ type: "application",
427
+ },
428
+ },
429
+ },
430
+ ),
431
+ source: "priority-runtime-default.json",
432
+ },
433
+ ];
434
+
435
+ const collected = collectAuditTargets(inputBoms, {
436
+ maxTargets: 1,
437
+ trusted: "include",
438
+ });
439
+
440
+ assert.strictEqual(collected.targets.length, 1);
441
+ assert.strictEqual(
442
+ collected.targets[0].purl,
443
+ "pkg:npm/direct-runtime@1.0.0",
444
+ );
445
+ });
446
+
447
+ it("uses explicit required scope and evidence occurrences to improve prioritization", () => {
448
+ const inputBoms = [
449
+ {
450
+ bomJson: makeBom([
451
+ {
452
+ "bom-ref": "pkg:npm/implicit-required@1.0.0",
453
+ name: "implicit-required",
454
+ purl: "pkg:npm/implicit-required@1.0.0",
455
+ },
456
+ {
457
+ "bom-ref": "pkg:npm/evidence-backed@1.0.0",
458
+ evidence: {
459
+ occurrences: [
460
+ { location: "src/a.js#1" },
461
+ { location: "src/b.js#1" },
462
+ { location: "src/c.js#1" },
463
+ ],
464
+ },
465
+ name: "evidence-backed",
466
+ purl: "pkg:npm/evidence-backed@1.0.0",
467
+ },
468
+ {
469
+ "bom-ref": "pkg:npm/explicit-required@1.0.0",
470
+ evidence: {
471
+ occurrences: [{ location: "src/main.js#1" }],
472
+ },
473
+ name: "explicit-required",
474
+ purl: "pkg:npm/explicit-required@1.0.0",
475
+ scope: "required",
476
+ },
477
+ ]),
478
+ source: "priority-evidence.json",
479
+ },
480
+ ];
481
+
482
+ const collected = collectAuditTargets(inputBoms, {
483
+ maxTargets: 3,
484
+ trusted: "include",
485
+ });
486
+
487
+ assert.deepStrictEqual(
488
+ collected.targets.map((target) => target.purl),
489
+ [
490
+ "pkg:npm/explicit-required@1.0.0",
491
+ "pkg:npm/evidence-backed@1.0.0",
492
+ "pkg:npm/implicit-required@1.0.0",
493
+ ],
494
+ );
495
+ assert.strictEqual(collected.targets[0].explicitRequiredScope, true);
496
+ assert.strictEqual(collected.targets[1].occurrenceCount, 3);
497
+ });
498
+
229
499
  it("excludes trusted-publishing-backed targets by default", () => {
230
500
  const inputBoms = [
231
501
  {
@@ -329,3 +599,146 @@ describe("collectAuditTargets()", () => {
329
599
  assert.strictEqual(collected.stats.trustedTargets, 1);
330
600
  });
331
601
  });
602
+
603
+ describe("enrichInputBomsWithRegistryMetadata()", () => {
604
+ it("adds registry trusted-publishing properties for npm targets so default selection can exclude them", async () => {
605
+ const inputBoms = [
606
+ {
607
+ bomJson: makeBom([
608
+ {
609
+ "bom-ref": "pkg:npm/@sec-ant/readable-stream@0.4.1",
610
+ name: "readable-stream",
611
+ purl: "pkg:npm/%40sec-ant/readable-stream@0.4.1",
612
+ },
613
+ {
614
+ "bom-ref": "pkg:npm/plain@1.0.0",
615
+ name: "plain",
616
+ purl: "pkg:npm/plain@1.0.0",
617
+ },
618
+ ]),
619
+ source: "registry-enrichment.json",
620
+ },
621
+ ];
622
+ const { enrichInputBomsWithRegistryMetadata: enrichWithMock } =
623
+ await esmock("./targets.js", {
624
+ "../helpers/utils.js": {
625
+ getCratesMetadata: async (pkgList) => pkgList,
626
+ getNpmMetadata: async (pkgList) =>
627
+ pkgList.map((pkg) =>
628
+ pkg.name === "readable-stream"
629
+ ? {
630
+ ...pkg,
631
+ properties: [
632
+ ...(pkg.properties || []),
633
+ { name: "cdx:npm:trustedPublishing", value: "true" },
634
+ {
635
+ name: "cdx:npm:provenanceUrl",
636
+ value:
637
+ "https://registry.npmjs.org/-/npm/v1/attestations/readable-stream",
638
+ },
639
+ ],
640
+ }
641
+ : pkg,
642
+ ),
643
+ getPyMetadata: async (pkgList) => pkgList,
644
+ },
645
+ });
646
+
647
+ await enrichWithMock(inputBoms);
648
+
649
+ const enrichedProperties = inputBoms[0].bomJson.components[0].properties;
650
+ assert.ok(
651
+ enrichedProperties.some(
652
+ (property) => property.name === "cdx:npm:trustedPublishing",
653
+ ),
654
+ );
655
+ const collected = collectAuditTargets(inputBoms);
656
+ assert.deepStrictEqual(
657
+ collected.targets.map((target) => target.purl),
658
+ ["pkg:npm/plain@1.0.0"],
659
+ );
660
+ });
661
+
662
+ it("adds registry trusted-publishing properties for pypi targets", async () => {
663
+ const inputBoms = [
664
+ {
665
+ bomJson: makeBom([
666
+ {
667
+ "bom-ref": "pkg:pypi/example@1.0.0",
668
+ name: "example",
669
+ purl: "pkg:pypi/example@1.0.0",
670
+ },
671
+ ]),
672
+ source: "pypi-enrichment.json",
673
+ },
674
+ ];
675
+ const { enrichInputBomsWithRegistryMetadata: enrichWithMock } =
676
+ await esmock("./targets.js", {
677
+ "../helpers/utils.js": {
678
+ getCratesMetadata: async (pkgList) => pkgList,
679
+ getNpmMetadata: async (pkgList) => pkgList,
680
+ getPyMetadata: async (pkgList) =>
681
+ pkgList.map((pkg) => ({
682
+ ...pkg,
683
+ properties: [
684
+ ...(pkg.properties || []),
685
+ { name: "cdx:pypi:trustedPublishing", value: "true" },
686
+ { name: "cdx:pypi:uploaderVerified", value: "true" },
687
+ ],
688
+ })),
689
+ },
690
+ });
691
+
692
+ await enrichWithMock(inputBoms);
693
+
694
+ assert.ok(
695
+ inputBoms[0].bomJson.components[0].properties.some(
696
+ (property) => property.name === "cdx:pypi:trustedPublishing",
697
+ ),
698
+ );
699
+ });
700
+
701
+ it("adds registry metadata for cargo targets", async () => {
702
+ const inputBoms = [
703
+ {
704
+ bomJson: makeBom([
705
+ {
706
+ "bom-ref": "pkg:cargo/serde@1.0.217",
707
+ name: "serde",
708
+ purl: "pkg:cargo/serde@1.0.217",
709
+ },
710
+ ]),
711
+ source: "cargo-enrichment.json",
712
+ },
713
+ ];
714
+ const { enrichInputBomsWithRegistryMetadata: enrichWithMock } =
715
+ await esmock("./targets.js", {
716
+ "../helpers/utils.js": {
717
+ getCratesMetadata: async (pkgList) =>
718
+ pkgList.map((pkg) => ({
719
+ ...pkg,
720
+ properties: [
721
+ ...(pkg.properties || []),
722
+ { name: "cdx:cargo:trustedPublishing", value: "true" },
723
+ { name: "cdx:cargo:yanked", value: "true" },
724
+ ],
725
+ })),
726
+ getNpmMetadata: async (pkgList) => pkgList,
727
+ getPyMetadata: async (pkgList) => pkgList,
728
+ },
729
+ });
730
+
731
+ await enrichWithMock(inputBoms);
732
+
733
+ assert.ok(
734
+ inputBoms[0].bomJson.components[0].properties.some(
735
+ (property) => property.name === "cdx:cargo:trustedPublishing",
736
+ ),
737
+ );
738
+ assert.ok(
739
+ inputBoms[0].bomJson.components[0].properties.some(
740
+ (property) => property.name === "cdx:cargo:yanked",
741
+ ),
742
+ );
743
+ });
744
+ });